Merge 0bd957eb11 ("Merge tag 'core-kprobes-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip") into android-mainline
Baby steps for 5.8-rc1 merge. Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I5f243372fdad254935d82608d5544794a7d10f6c
This commit is contained in:
@@ -56,6 +56,11 @@ Description: The /dev/kmsg character device node provides userspace access
|
||||
seek after the last record available at the time
|
||||
the last SYSLOG_ACTION_CLEAR was issued.
|
||||
|
||||
Due to the record nature of this interface with a "read all"
|
||||
behavior and the specific positions each seek operation sets,
|
||||
SEEK_CUR is not supported, returning -ESPIPE (invalid seek) to
|
||||
errno whenever requested.
|
||||
|
||||
The output format consists of a prefix carrying the syslog
|
||||
prefix including priority and facility, the 64 bit message
|
||||
sequence number and the monotonic timestamp in microseconds,
|
||||
|
||||
@@ -482,21 +482,23 @@ Examples (OF)::
|
||||
%pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name
|
||||
%pfwP endpoint - Node name
|
||||
|
||||
Time and date (struct rtc_time)
|
||||
-------------------------------
|
||||
Time and date
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
%ptR YYYY-mm-ddTHH:MM:SS
|
||||
%ptRd YYYY-mm-dd
|
||||
%ptRt HH:MM:SS
|
||||
%ptR[dt][r]
|
||||
%pt[RT] YYYY-mm-ddTHH:MM:SS
|
||||
%pt[RT]d YYYY-mm-dd
|
||||
%pt[RT]t HH:MM:SS
|
||||
%pt[RT][dt][r]
|
||||
|
||||
For printing date and time as represented by struct rtc_time structure in
|
||||
human readable format.
|
||||
For printing date and time as represented by
|
||||
R struct rtc_time structure
|
||||
T time64_t type
|
||||
in human readable format.
|
||||
|
||||
By default year will be incremented by 1900 and month by 1. Use %ptRr (raw)
|
||||
to suppress this behaviour.
|
||||
By default year will be incremented by 1900 and month by 1.
|
||||
Use %pt[RT]r (raw) to suppress this behaviour.
|
||||
|
||||
Passed by reference.
|
||||
|
||||
|
||||
+1
-2
@@ -6193,7 +6193,6 @@ M: Yash Shah <yash.shah@sifive.com>
|
||||
L: linux-edac@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/edac/sifive_edac.c
|
||||
F: drivers/soc/sifive_l2_cache.c
|
||||
|
||||
EDAC-SKYLAKE
|
||||
M: Tony Luck <tony.luck@intel.com>
|
||||
@@ -14276,7 +14275,7 @@ M: Reinette Chatre <reinette.chatre@intel.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/x86/resctrl*
|
||||
F: arch/x86/include/asm/resctrl_sched.h
|
||||
F: arch/x86/include/asm/resctrl.h
|
||||
F: arch/x86/kernel/cpu/resctrl/
|
||||
F: tools/testing/selftests/resctrl/
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ SECTIONS
|
||||
#ifdef CONFIG_PPC64
|
||||
*(.tramp.ftrace.text);
|
||||
#endif
|
||||
NOINSTR_TEXT
|
||||
SCHED_TEXT
|
||||
CPUIDLE_TEXT
|
||||
LOCK_TEXT
|
||||
|
||||
@@ -113,9 +113,10 @@ struct cpuinfo_x86 {
|
||||
/* in KB - valid for CPUS which support this call: */
|
||||
unsigned int x86_cache_size;
|
||||
int x86_cache_alignment; /* In bytes */
|
||||
/* Cache QoS architectural values: */
|
||||
/* Cache QoS architectural values, valid only on the BSP: */
|
||||
int x86_cache_max_rmid; /* max index */
|
||||
int x86_cache_occ_scale; /* scale to bytes */
|
||||
int x86_cache_mbm_width_offset;
|
||||
int x86_power;
|
||||
unsigned long loops_per_jiffy;
|
||||
/* cpuid returned max cores value: */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_RESCTRL_SCHED_H
|
||||
#define _ASM_X86_RESCTRL_SCHED_H
|
||||
#ifndef _ASM_X86_RESCTRL_H
|
||||
#define _ASM_X86_RESCTRL_H
|
||||
|
||||
#ifdef CONFIG_X86_CPU_RESCTRL
|
||||
|
||||
@@ -84,10 +84,13 @@ static inline void resctrl_sched_in(void)
|
||||
__resctrl_sched_in();
|
||||
}
|
||||
|
||||
void resctrl_cpu_detect(struct cpuinfo_x86 *c);
|
||||
|
||||
#else
|
||||
|
||||
static inline void resctrl_sched_in(void) {}
|
||||
static inline void resctrl_cpu_detect(struct cpuinfo_x86 *c) {}
|
||||
|
||||
#endif /* CONFIG_X86_CPU_RESCTRL */
|
||||
|
||||
#endif /* _ASM_X86_RESCTRL_SCHED_H */
|
||||
#endif /* _ASM_X86_RESCTRL_H */
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/debugreg.h>
|
||||
#include <asm/resctrl.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
# include <asm/mmconfig.h>
|
||||
@@ -597,6 +598,8 @@ static void bsp_init_amd(struct cpuinfo_x86 *c)
|
||||
x86_amd_ls_cfg_ssbd_mask = 1ULL << bit;
|
||||
}
|
||||
}
|
||||
|
||||
resctrl_cpu_detect(c);
|
||||
}
|
||||
|
||||
static void early_detect_mem_encrypt(struct cpuinfo_x86 *c)
|
||||
|
||||
@@ -854,30 +854,6 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
|
||||
}
|
||||
}
|
||||
|
||||
static void init_cqm(struct cpuinfo_x86 *c)
|
||||
{
|
||||
if (!cpu_has(c, X86_FEATURE_CQM_LLC)) {
|
||||
c->x86_cache_max_rmid = -1;
|
||||
c->x86_cache_occ_scale = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* will be overridden if occupancy monitoring exists */
|
||||
c->x86_cache_max_rmid = cpuid_ebx(0xf);
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
|
||||
cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
|
||||
cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)) {
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
|
||||
cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
c->x86_cache_max_rmid = ecx;
|
||||
c->x86_cache_occ_scale = ebx;
|
||||
}
|
||||
}
|
||||
|
||||
void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
{
|
||||
u32 eax, ebx, ecx, edx;
|
||||
@@ -945,7 +921,6 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
|
||||
|
||||
init_scattered_cpuid_features(c);
|
||||
init_speculation_control(c);
|
||||
init_cqm(c);
|
||||
|
||||
/*
|
||||
* Clear/Set all flags overridden by options, after probe.
|
||||
@@ -1377,20 +1352,6 @@ static void generic_identify(struct cpuinfo_x86 *c)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void x86_init_cache_qos(struct cpuinfo_x86 *c)
|
||||
{
|
||||
/*
|
||||
* The heavy lifting of max_rmid and cache_occ_scale are handled
|
||||
* in get_cpu_cap(). Here we just set the max_rmid for the boot_cpu
|
||||
* in case CQM bits really aren't there in this CPU.
|
||||
*/
|
||||
if (c != &boot_cpu_data) {
|
||||
boot_cpu_data.x86_cache_max_rmid =
|
||||
min(boot_cpu_data.x86_cache_max_rmid,
|
||||
c->x86_cache_max_rmid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that ACPI/mptables have the same information about the
|
||||
* effective APIC id and update the package map.
|
||||
@@ -1503,7 +1464,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
|
||||
#endif
|
||||
|
||||
x86_init_rdrand(c);
|
||||
x86_init_cache_qos(c);
|
||||
setup_pku(c);
|
||||
|
||||
/*
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/cmdline.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/resctrl.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#include <linux/topology.h>
|
||||
@@ -322,6 +323,11 @@ static void early_init_intel(struct cpuinfo_x86 *c)
|
||||
detect_ht_early(c);
|
||||
}
|
||||
|
||||
static void bsp_init_intel(struct cpuinfo_x86 *c)
|
||||
{
|
||||
resctrl_cpu_detect(c);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/*
|
||||
* Early probe support logic for ppro memory erratum #50
|
||||
@@ -961,6 +967,7 @@ static const struct cpu_dev intel_cpu_dev = {
|
||||
#endif
|
||||
.c_detect_tlb = intel_detect_tlb,
|
||||
.c_early_init = early_init_intel,
|
||||
.c_bsp_init = bsp_init_intel,
|
||||
.c_init = init_intel,
|
||||
.c_x86_vendor = X86_VENDOR_INTEL,
|
||||
};
|
||||
|
||||
@@ -545,8 +545,7 @@ static int __wait_for_cpus(atomic_t *t, long long timeout)
|
||||
/*
|
||||
* Returns:
|
||||
* < 0 - on error
|
||||
* 0 - no update done
|
||||
* 1 - microcode was updated
|
||||
* 0 - success (no update done or microcode was updated)
|
||||
*/
|
||||
static int __reload_late(void *info)
|
||||
{
|
||||
@@ -573,11 +572,11 @@ static int __reload_late(void *info)
|
||||
else
|
||||
goto wait_for_siblings;
|
||||
|
||||
if (err > UCODE_NFOUND) {
|
||||
pr_warn("Error reloading microcode on CPU %d\n", cpu);
|
||||
if (err >= UCODE_NFOUND) {
|
||||
if (err == UCODE_ERROR)
|
||||
pr_warn("Error reloading microcode on CPU %d\n", cpu);
|
||||
|
||||
ret = -1;
|
||||
} else if (err == UCODE_UPDATED || err == UCODE_OK) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
wait_for_siblings:
|
||||
@@ -608,7 +607,7 @@ static int microcode_reload_late(void)
|
||||
atomic_set(&late_cpus_out, 0);
|
||||
|
||||
ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
|
||||
if (ret > 0)
|
||||
if (ret == 0)
|
||||
microcode_check();
|
||||
|
||||
pr_info("Reload completed, microcode revision: 0x%x\n", boot_cpu_data.microcode);
|
||||
@@ -649,7 +648,7 @@ static ssize_t reload_store(struct device *dev,
|
||||
put:
|
||||
put_online_cpus();
|
||||
|
||||
if (ret >= 0)
|
||||
if (ret == 0)
|
||||
ret = size;
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <linux/cpuhotplug.h>
|
||||
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/resctrl_sched.h>
|
||||
#include <asm/resctrl.h>
|
||||
#include "internal.h"
|
||||
|
||||
/* Mutex to protect rdtgroup access. */
|
||||
@@ -958,6 +958,36 @@ static __init void rdt_init_res_defs(void)
|
||||
|
||||
static enum cpuhp_state rdt_online;
|
||||
|
||||
/* Runs once on the BSP during boot. */
|
||||
void resctrl_cpu_detect(struct cpuinfo_x86 *c)
|
||||
{
|
||||
if (!cpu_has(c, X86_FEATURE_CQM_LLC)) {
|
||||
c->x86_cache_max_rmid = -1;
|
||||
c->x86_cache_occ_scale = -1;
|
||||
c->x86_cache_mbm_width_offset = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* will be overridden if occupancy monitoring exists */
|
||||
c->x86_cache_max_rmid = cpuid_ebx(0xf);
|
||||
|
||||
if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
|
||||
cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
|
||||
cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)) {
|
||||
u32 eax, ebx, ecx, edx;
|
||||
|
||||
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
|
||||
cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
c->x86_cache_max_rmid = ecx;
|
||||
c->x86_cache_occ_scale = ebx;
|
||||
if (c->x86_vendor == X86_VENDOR_INTEL)
|
||||
c->x86_cache_mbm_width_offset = eax & 0xff;
|
||||
else
|
||||
c->x86_cache_mbm_width_offset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int __init resctrl_late_init(void)
|
||||
{
|
||||
struct rdt_resource *r;
|
||||
|
||||
@@ -495,14 +495,16 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mon_event_read(struct rmid_read *rr, struct rdt_domain *d,
|
||||
struct rdtgroup *rdtgrp, int evtid, int first)
|
||||
void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
|
||||
struct rdt_domain *d, struct rdtgroup *rdtgrp,
|
||||
int evtid, int first)
|
||||
{
|
||||
/*
|
||||
* setup the parameters to send to the IPI to read the data.
|
||||
*/
|
||||
rr->rgrp = rdtgrp;
|
||||
rr->evtid = evtid;
|
||||
rr->r = r;
|
||||
rr->d = d;
|
||||
rr->val = 0;
|
||||
rr->first = first;
|
||||
@@ -539,7 +541,7 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mon_event_read(&rr, d, rdtgrp, evtid, false);
|
||||
mon_event_read(&rr, r, d, rdtgrp, evtid, false);
|
||||
|
||||
if (rr.val & RMID_VAL_ERROR)
|
||||
seq_puts(m, "Error\n");
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#define CQM_LIMBOCHECK_INTERVAL 1000
|
||||
|
||||
#define MBM_CNTR_WIDTH 24
|
||||
#define MBM_CNTR_WIDTH_BASE 24
|
||||
#define MBM_OVERFLOW_INTERVAL 1000
|
||||
#define MAX_MBA_BW 100u
|
||||
#define MBA_IS_LINEAR 0x4
|
||||
@@ -40,6 +40,12 @@
|
||||
|
||||
#define RMID_VAL_ERROR BIT_ULL(63)
|
||||
#define RMID_VAL_UNAVAIL BIT_ULL(62)
|
||||
/*
|
||||
* With the above fields in use 62 bits remain in MSR_IA32_QM_CTR for
|
||||
* data to be returned. The counter width is discovered from the hardware
|
||||
* as an offset from MBM_CNTR_WIDTH_BASE.
|
||||
*/
|
||||
#define MBM_CNTR_WIDTH_OFFSET_MAX (62 - MBM_CNTR_WIDTH_BASE)
|
||||
|
||||
|
||||
struct rdt_fs_context {
|
||||
@@ -87,6 +93,7 @@ union mon_data_bits {
|
||||
|
||||
struct rmid_read {
|
||||
struct rdtgroup *rgrp;
|
||||
struct rdt_resource *r;
|
||||
struct rdt_domain *d;
|
||||
int evtid;
|
||||
bool first;
|
||||
@@ -460,6 +467,7 @@ struct rdt_resource {
|
||||
struct list_head evt_list;
|
||||
int num_rmid;
|
||||
unsigned int mon_scale;
|
||||
unsigned int mbm_width;
|
||||
unsigned long fflags;
|
||||
};
|
||||
|
||||
@@ -587,8 +595,9 @@ void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
|
||||
unsigned int dom_id);
|
||||
void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
|
||||
struct rdt_domain *d);
|
||||
void mon_event_read(struct rmid_read *rr, struct rdt_domain *d,
|
||||
struct rdtgroup *rdtgrp, int evtid, int first);
|
||||
void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
|
||||
struct rdt_domain *d, struct rdtgroup *rdtgrp,
|
||||
int evtid, int first);
|
||||
void mbm_setup_overflow_handler(struct rdt_domain *dom,
|
||||
unsigned long delay_ms);
|
||||
void mbm_handle_overflow(struct work_struct *work);
|
||||
|
||||
@@ -214,9 +214,9 @@ void free_rmid(u32 rmid)
|
||||
list_add_tail(&entry->list, &rmid_free_lru);
|
||||
}
|
||||
|
||||
static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr)
|
||||
static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)
|
||||
{
|
||||
u64 shift = 64 - MBM_CNTR_WIDTH, chunks;
|
||||
u64 shift = 64 - width, chunks;
|
||||
|
||||
chunks = (cur_msr << shift) - (prev_msr << shift);
|
||||
return chunks >>= shift;
|
||||
@@ -256,7 +256,7 @@ static int __mon_event_count(u32 rmid, struct rmid_read *rr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
chunks = mbm_overflow_count(m->prev_msr, tval);
|
||||
chunks = mbm_overflow_count(m->prev_msr, tval, rr->r->mbm_width);
|
||||
m->chunks += chunks;
|
||||
m->prev_msr = tval;
|
||||
|
||||
@@ -278,7 +278,7 @@ static void mbm_bw_count(u32 rmid, struct rmid_read *rr)
|
||||
if (tval & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL))
|
||||
return;
|
||||
|
||||
chunks = mbm_overflow_count(m->prev_bw_msr, tval);
|
||||
chunks = mbm_overflow_count(m->prev_bw_msr, tval, rr->r->mbm_width);
|
||||
m->chunks_bw += chunks;
|
||||
m->chunks = m->chunks_bw;
|
||||
cur_bw = (chunks * r->mon_scale) >> 20;
|
||||
@@ -433,11 +433,12 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
|
||||
}
|
||||
}
|
||||
|
||||
static void mbm_update(struct rdt_domain *d, int rmid)
|
||||
static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
|
||||
{
|
||||
struct rmid_read rr;
|
||||
|
||||
rr.first = false;
|
||||
rr.r = r;
|
||||
rr.d = d;
|
||||
|
||||
/*
|
||||
@@ -510,6 +511,7 @@ void mbm_handle_overflow(struct work_struct *work)
|
||||
struct rdtgroup *prgrp, *crgrp;
|
||||
int cpu = smp_processor_id();
|
||||
struct list_head *head;
|
||||
struct rdt_resource *r;
|
||||
struct rdt_domain *d;
|
||||
|
||||
mutex_lock(&rdtgroup_mutex);
|
||||
@@ -517,16 +519,18 @@ void mbm_handle_overflow(struct work_struct *work)
|
||||
if (!static_branch_likely(&rdt_mon_enable_key))
|
||||
goto out_unlock;
|
||||
|
||||
d = get_domain_from_cpu(cpu, &rdt_resources_all[RDT_RESOURCE_L3]);
|
||||
r = &rdt_resources_all[RDT_RESOURCE_L3];
|
||||
|
||||
d = get_domain_from_cpu(cpu, r);
|
||||
if (!d)
|
||||
goto out_unlock;
|
||||
|
||||
list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
|
||||
mbm_update(d, prgrp->mon.rmid);
|
||||
mbm_update(r, d, prgrp->mon.rmid);
|
||||
|
||||
head = &prgrp->mon.crdtgrp_list;
|
||||
list_for_each_entry(crgrp, head, mon.crdtgrp_list)
|
||||
mbm_update(d, crgrp->mon.rmid);
|
||||
mbm_update(r, d, crgrp->mon.rmid);
|
||||
|
||||
if (is_mba_sc(NULL))
|
||||
update_mba_bw(prgrp, d);
|
||||
@@ -614,11 +618,18 @@ static void l3_mon_evt_init(struct rdt_resource *r)
|
||||
|
||||
int rdt_get_mon_l3_config(struct rdt_resource *r)
|
||||
{
|
||||
unsigned int mbm_offset = boot_cpu_data.x86_cache_mbm_width_offset;
|
||||
unsigned int cl_size = boot_cpu_data.x86_cache_size;
|
||||
int ret;
|
||||
|
||||
r->mon_scale = boot_cpu_data.x86_cache_occ_scale;
|
||||
r->num_rmid = boot_cpu_data.x86_cache_max_rmid + 1;
|
||||
r->mbm_width = MBM_CNTR_WIDTH_BASE;
|
||||
|
||||
if (mbm_offset > 0 && mbm_offset <= MBM_CNTR_WIDTH_OFFSET_MAX)
|
||||
r->mbm_width += mbm_offset;
|
||||
else if (mbm_offset > MBM_CNTR_WIDTH_OFFSET_MAX)
|
||||
pr_warn("Ignoring impossible MBM counter offset\n");
|
||||
|
||||
/*
|
||||
* A reasonable upper limit on the max threshold is the number
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/resctrl_sched.h>
|
||||
#include <asm/resctrl.h>
|
||||
#include <asm/perf_event.h>
|
||||
|
||||
#include "../../events/perf_event.h" /* For X86_CONFIG() */
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include <uapi/linux/magic.h>
|
||||
|
||||
#include <asm/resctrl_sched.h>
|
||||
#include <asm/resctrl.h>
|
||||
#include "internal.h"
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
|
||||
@@ -2472,7 +2472,7 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
|
||||
goto out_destroy;
|
||||
|
||||
if (is_mbm_event(mevt->evtid))
|
||||
mon_event_read(&rr, d, prgrp, mevt->evtid, true);
|
||||
mon_event_read(&rr, r, d, prgrp, mevt->evtid, true);
|
||||
}
|
||||
kernfs_activate(kn);
|
||||
return 0;
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
#include <asm/debugreg.h>
|
||||
#include <asm/switch_to.h>
|
||||
#include <asm/vm86.h>
|
||||
#include <asm/resctrl_sched.h>
|
||||
#include <asm/resctrl.h>
|
||||
#include <asm/proto.h>
|
||||
|
||||
#include "process.h"
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
#include <asm/switch_to.h>
|
||||
#include <asm/xen/hypervisor.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/resctrl_sched.h>
|
||||
#include <asm/resctrl.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/fsgsbase.h>
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
|
||||
@@ -3403,7 +3403,7 @@ static const struct attribute_group *amd64_edac_attr_groups[] = {
|
||||
static int hw_info_get(struct amd64_pvt *pvt)
|
||||
{
|
||||
u16 pci_id1, pci_id2;
|
||||
int ret = -EINVAL;
|
||||
int ret;
|
||||
|
||||
if (pvt->fam >= 0x17) {
|
||||
pvt->umc = kcalloc(fam_type->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL);
|
||||
|
||||
@@ -44,14 +44,6 @@ static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32)
|
||||
" PCI Access Write Error at 0x%x\n", reg);
|
||||
}
|
||||
|
||||
static char * const bridge_str[] = {
|
||||
[NORTH_A] = "NORTH A",
|
||||
[NORTH_B] = "NORTH B",
|
||||
[SOUTH_A] = "SOUTH A",
|
||||
[SOUTH_B] = "SOUTH B",
|
||||
[NO_BRIDGE] = "NO BRIDGE",
|
||||
};
|
||||
|
||||
/* Support up to two AMD8131 chipsets on a platform */
|
||||
static struct amd8131_dev_info amd8131_devices[] = {
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ struct axp_mc_drvdata {
|
||||
char msg[128];
|
||||
};
|
||||
|
||||
/* derived from "DRAM Address Multiplexing" in the ARAMDA XP Functional Spec */
|
||||
/* derived from "DRAM Address Multiplexing" in the ARMADA XP Functional Spec */
|
||||
static uint32_t axp_mc_calc_address(struct axp_mc_drvdata *drvdata,
|
||||
uint8_t cs, uint8_t bank, uint16_t row,
|
||||
uint16_t col)
|
||||
@@ -160,12 +160,12 @@ static void axp_mc_check(struct mem_ctl_info *mci)
|
||||
if (cnt_sbe)
|
||||
cnt_sbe--;
|
||||
else
|
||||
dev_warn(mci->pdev, "inconsistent SBE count detected");
|
||||
dev_warn(mci->pdev, "inconsistent SBE count detected\n");
|
||||
} else {
|
||||
if (cnt_dbe)
|
||||
cnt_dbe--;
|
||||
else
|
||||
dev_warn(mci->pdev, "inconsistent DBE count detected");
|
||||
dev_warn(mci->pdev, "inconsistent DBE count detected\n");
|
||||
}
|
||||
|
||||
/* report earlier errors */
|
||||
@@ -304,7 +304,7 @@ static int axp_mc_probe(struct platform_device *pdev)
|
||||
|
||||
config = readl(base + SDRAM_CONFIG_REG);
|
||||
if (!(config & SDRAM_CONFIG_ECC_MASK)) {
|
||||
dev_warn(&pdev->dev, "SDRAM ECC is not enabled");
|
||||
dev_warn(&pdev->dev, "SDRAM ECC is not enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -532,9 +532,9 @@ static int aurora_l2_probe(struct platform_device *pdev)
|
||||
|
||||
l2x0_aux_ctrl = readl(base + L2X0_AUX_CTRL);
|
||||
if (!(l2x0_aux_ctrl & AURORA_ACR_PARITY_EN))
|
||||
dev_warn(&pdev->dev, "tag parity is not enabled");
|
||||
dev_warn(&pdev->dev, "tag parity is not enabled\n");
|
||||
if (!(l2x0_aux_ctrl & AURORA_ACR_ECC_EN))
|
||||
dev_warn(&pdev->dev, "data ECC is not enabled");
|
||||
dev_warn(&pdev->dev, "data ECC is not enabled\n");
|
||||
|
||||
dci = edac_device_alloc_ctl_info(sizeof(*drvdata),
|
||||
"cpu", 1, "L", 1, 2, NULL, 0, 0);
|
||||
@@ -618,7 +618,7 @@ static int __init armada_xp_edac_init(void)
|
||||
|
||||
res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
|
||||
if (res)
|
||||
pr_warn("Aramda XP EDAC drivers fail to register\n");
|
||||
pr_warn("Armada XP EDAC drivers fail to register\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -122,10 +122,22 @@ static int i10nm_get_all_munits(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct res_config i10nm_cfg0 = {
|
||||
.type = I10NM,
|
||||
.decs_did = 0x3452,
|
||||
.busno_cfg_offset = 0xcc,
|
||||
};
|
||||
|
||||
static struct res_config i10nm_cfg1 = {
|
||||
.type = I10NM,
|
||||
.decs_did = 0x3452,
|
||||
.busno_cfg_offset = 0xd0,
|
||||
};
|
||||
|
||||
static const struct x86_cpu_id i10nm_cpuids[] = {
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D, &i10nm_cfg0),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &i10nm_cfg0),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &i10nm_cfg1),
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
|
||||
@@ -161,7 +173,7 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci)
|
||||
mtr, mcddrtcfg, imc->mc, i, j);
|
||||
|
||||
if (IS_DIMM_PRESENT(mtr))
|
||||
ndimms += skx_get_dimm_info(mtr, 0, dimm,
|
||||
ndimms += skx_get_dimm_info(mtr, 0, 0, dimm,
|
||||
imc, i, j);
|
||||
else if (IS_NVDIMM_PRESENT(mcddrtcfg, j))
|
||||
ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
|
||||
@@ -234,6 +246,7 @@ static int __init i10nm_init(void)
|
||||
{
|
||||
u8 mc = 0, src_id = 0, node_id = 0;
|
||||
const struct x86_cpu_id *id;
|
||||
struct res_config *cfg;
|
||||
const char *owner;
|
||||
struct skx_dev *d;
|
||||
int rc, i, off[3] = {0xd0, 0xc8, 0xcc};
|
||||
@@ -249,11 +262,17 @@ static int __init i10nm_init(void)
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
cfg = (struct res_config *)id->driver_data;
|
||||
|
||||
/* Newer steppings have different offset for ATOM_TREMONT_D/ICELAKE_X */
|
||||
if (boot_cpu_data.x86_stepping >= 4)
|
||||
cfg->busno_cfg_offset = 0xd0;
|
||||
|
||||
rc = skx_get_hi_lo(0x09a2, off, &tolm, &tohm);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = skx_get_all_bus_mappings(0x3452, 0xcc, I10NM, &i10nm_edac_list);
|
||||
rc = skx_get_all_bus_mappings(cfg, &i10nm_edac_list);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
if (rc == 0) {
|
||||
|
||||
+19
-14
@@ -157,33 +157,35 @@ fail:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct res_config skx_cfg = {
|
||||
.type = SKX,
|
||||
.decs_did = 0x2016,
|
||||
.busno_cfg_offset = 0xcc,
|
||||
};
|
||||
|
||||
static const struct x86_cpu_id skx_cpuids[] = {
|
||||
X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &skx_cfg),
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, skx_cpuids);
|
||||
|
||||
#define SKX_GET_MTMTR(dev, reg) \
|
||||
pci_read_config_dword((dev), 0x87c, &(reg))
|
||||
|
||||
static bool skx_check_ecc(struct pci_dev *pdev)
|
||||
static bool skx_check_ecc(u32 mcmtr)
|
||||
{
|
||||
u32 mtmtr;
|
||||
|
||||
SKX_GET_MTMTR(pdev, mtmtr);
|
||||
|
||||
return !!GET_BITFIELD(mtmtr, 2, 2);
|
||||
return !!GET_BITFIELD(mcmtr, 2, 2);
|
||||
}
|
||||
|
||||
static int skx_get_dimm_config(struct mem_ctl_info *mci)
|
||||
{
|
||||
struct skx_pvt *pvt = mci->pvt_info;
|
||||
u32 mtr, mcmtr, amap, mcddrtcfg;
|
||||
struct skx_imc *imc = pvt->imc;
|
||||
u32 mtr, amap, mcddrtcfg;
|
||||
struct dimm_info *dimm;
|
||||
int i, j;
|
||||
int ndimms;
|
||||
|
||||
/* Only the mcmtr on the first channel is effective */
|
||||
pci_read_config_dword(imc->chan[0].cdev, 0x87c, &mcmtr);
|
||||
|
||||
for (i = 0; i < SKX_NUM_CHANNELS; i++) {
|
||||
ndimms = 0;
|
||||
pci_read_config_dword(imc->chan[i].cdev, 0x8C, &amap);
|
||||
@@ -193,14 +195,14 @@ static int skx_get_dimm_config(struct mem_ctl_info *mci)
|
||||
pci_read_config_dword(imc->chan[i].cdev,
|
||||
0x80 + 4 * j, &mtr);
|
||||
if (IS_DIMM_PRESENT(mtr)) {
|
||||
ndimms += skx_get_dimm_info(mtr, amap, dimm, imc, i, j);
|
||||
ndimms += skx_get_dimm_info(mtr, mcmtr, amap, dimm, imc, i, j);
|
||||
} else if (IS_NVDIMM_PRESENT(mcddrtcfg, j)) {
|
||||
ndimms += skx_get_nvdimm_info(dimm, imc, i, j,
|
||||
EDAC_MOD_STR);
|
||||
nvdimm_count++;
|
||||
}
|
||||
}
|
||||
if (ndimms && !skx_check_ecc(imc->chan[0].cdev)) {
|
||||
if (ndimms && !skx_check_ecc(mcmtr)) {
|
||||
skx_printk(KERN_ERR, "ECC is disabled on imc %d\n", imc->mc);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -641,6 +643,7 @@ static inline void teardown_skx_debug(void) {}
|
||||
static int __init skx_init(void)
|
||||
{
|
||||
const struct x86_cpu_id *id;
|
||||
struct res_config *cfg;
|
||||
const struct munit *m;
|
||||
const char *owner;
|
||||
int rc = 0, i, off[3] = {0xd0, 0xd4, 0xd8};
|
||||
@@ -657,11 +660,13 @@ static int __init skx_init(void)
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
cfg = (struct res_config *)id->driver_data;
|
||||
|
||||
rc = skx_get_hi_lo(0x2034, off, &skx_tolm, &skx_tohm);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = skx_get_all_bus_mappings(0x2016, 0xcc, SKX, &skx_edac_list);
|
||||
rc = skx_get_all_bus_mappings(cfg, &skx_edac_list);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
if (rc == 0) {
|
||||
|
||||
@@ -197,12 +197,11 @@ static int get_width(u32 mtr)
|
||||
}
|
||||
|
||||
/*
|
||||
* We use the per-socket device @did to count how many sockets are present,
|
||||
* We use the per-socket device @cfg->did to count how many sockets are present,
|
||||
* and to detemine which PCI buses are associated with each socket. Allocate
|
||||
* and build the full list of all the skx_dev structures that we need here.
|
||||
*/
|
||||
int skx_get_all_bus_mappings(unsigned int did, int off, enum type type,
|
||||
struct list_head **list)
|
||||
int skx_get_all_bus_mappings(struct res_config *cfg, struct list_head **list)
|
||||
{
|
||||
struct pci_dev *pdev, *prev;
|
||||
struct skx_dev *d;
|
||||
@@ -211,7 +210,7 @@ int skx_get_all_bus_mappings(unsigned int did, int off, enum type type,
|
||||
|
||||
prev = NULL;
|
||||
for (;;) {
|
||||
pdev = pci_get_device(PCI_VENDOR_ID_INTEL, did, prev);
|
||||
pdev = pci_get_device(PCI_VENDOR_ID_INTEL, cfg->decs_did, prev);
|
||||
if (!pdev)
|
||||
break;
|
||||
ndev++;
|
||||
@@ -221,7 +220,7 @@ int skx_get_all_bus_mappings(unsigned int did, int off, enum type type,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (pci_read_config_dword(pdev, off, ®)) {
|
||||
if (pci_read_config_dword(pdev, cfg->busno_cfg_offset, ®)) {
|
||||
kfree(d);
|
||||
pci_dev_put(pdev);
|
||||
skx_printk(KERN_ERR, "Failed to read bus idx\n");
|
||||
@@ -230,7 +229,7 @@ int skx_get_all_bus_mappings(unsigned int did, int off, enum type type,
|
||||
|
||||
d->bus[0] = GET_BITFIELD(reg, 0, 7);
|
||||
d->bus[1] = GET_BITFIELD(reg, 8, 15);
|
||||
if (type == SKX) {
|
||||
if (cfg->type == SKX) {
|
||||
d->seg = pci_domain_nr(pdev->bus);
|
||||
d->bus[2] = GET_BITFIELD(reg, 16, 23);
|
||||
d->bus[3] = GET_BITFIELD(reg, 24, 31);
|
||||
@@ -304,7 +303,7 @@ static int skx_get_dimm_attr(u32 reg, int lobit, int hibit, int add,
|
||||
#define numrow(reg) skx_get_dimm_attr(reg, 2, 4, 12, 1, 6, "rows")
|
||||
#define numcol(reg) skx_get_dimm_attr(reg, 0, 1, 10, 0, 2, "cols")
|
||||
|
||||
int skx_get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
|
||||
int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
|
||||
struct skx_imc *imc, int chan, int dimmno)
|
||||
{
|
||||
int banks = 16, ranks, rows, cols, npages;
|
||||
@@ -324,8 +323,8 @@ int skx_get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
|
||||
imc->mc, chan, dimmno, size, npages,
|
||||
banks, 1 << ranks, rows, cols);
|
||||
|
||||
imc->chan[chan].dimms[dimmno].close_pg = GET_BITFIELD(mtr, 0, 0);
|
||||
imc->chan[chan].dimms[dimmno].bank_xor_enable = GET_BITFIELD(mtr, 9, 9);
|
||||
imc->chan[chan].dimms[dimmno].close_pg = GET_BITFIELD(mcmtr, 0, 0);
|
||||
imc->chan[chan].dimms[dimmno].bank_xor_enable = GET_BITFIELD(mcmtr, 9, 9);
|
||||
imc->chan[chan].dimms[dimmno].fine_grain_bank = GET_BITFIELD(amap, 0, 0);
|
||||
imc->chan[chan].dimms[dimmno].rowbits = rows;
|
||||
imc->chan[chan].dimms[dimmno].colbits = cols;
|
||||
|
||||
@@ -112,6 +112,14 @@ struct decoded_addr {
|
||||
int bank_group;
|
||||
};
|
||||
|
||||
struct res_config {
|
||||
enum type type;
|
||||
/* Configuration agent device ID */
|
||||
unsigned int decs_did;
|
||||
/* Default bus number configuration register offset */
|
||||
int busno_cfg_offset;
|
||||
};
|
||||
|
||||
typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci);
|
||||
typedef bool (*skx_decode_f)(struct decoded_addr *res);
|
||||
typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len);
|
||||
@@ -123,12 +131,11 @@ void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log);
|
||||
int skx_get_src_id(struct skx_dev *d, int off, u8 *id);
|
||||
int skx_get_node_id(struct skx_dev *d, u8 *id);
|
||||
|
||||
int skx_get_all_bus_mappings(unsigned int did, int off, enum type,
|
||||
struct list_head **list);
|
||||
int skx_get_all_bus_mappings(struct res_config *cfg, struct list_head **list);
|
||||
|
||||
int skx_get_hi_lo(unsigned int did, int off[], u64 *tolm, u64 *tohm);
|
||||
|
||||
int skx_get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
|
||||
int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm,
|
||||
struct skx_imc *imc, int chan, int dimmno);
|
||||
|
||||
int skx_get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc,
|
||||
|
||||
@@ -1278,7 +1278,7 @@ OCX_DEBUGFS_ATTR(lne23_badcnt, OCX_LNE_BAD_CNT(23));
|
||||
|
||||
OCX_DEBUGFS_ATTR(com_int, OCX_COM_INT_W1S);
|
||||
|
||||
struct debugfs_entry *ocx_dfs_ents[] = {
|
||||
static struct debugfs_entry *ocx_dfs_ents[] = {
|
||||
&debugfs_tlk0_ecc_ctl,
|
||||
&debugfs_tlk1_ecc_ctl,
|
||||
&debugfs_tlk2_ecc_ctl,
|
||||
@@ -1919,19 +1919,19 @@ err_free:
|
||||
|
||||
L2C_DEBUGFS_ATTR(tad_int, L2C_TAD_INT_W1S);
|
||||
|
||||
struct debugfs_entry *l2c_tad_dfs_ents[] = {
|
||||
static struct debugfs_entry *l2c_tad_dfs_ents[] = {
|
||||
&debugfs_tad_int,
|
||||
};
|
||||
|
||||
L2C_DEBUGFS_ATTR(cbc_int, L2C_CBC_INT_W1S);
|
||||
|
||||
struct debugfs_entry *l2c_cbc_dfs_ents[] = {
|
||||
static struct debugfs_entry *l2c_cbc_dfs_ents[] = {
|
||||
&debugfs_cbc_int,
|
||||
};
|
||||
|
||||
L2C_DEBUGFS_ATTR(mci_int, L2C_MCI_INT_W1S);
|
||||
|
||||
struct debugfs_entry *l2c_mci_dfs_ents[] = {
|
||||
static struct debugfs_entry *l2c_mci_dfs_ents[] = {
|
||||
&debugfs_mci_int,
|
||||
};
|
||||
|
||||
|
||||
@@ -1349,7 +1349,6 @@ static int xgene_edac_l3_remove(struct xgene_edac_dev_ctx *l3)
|
||||
#define WORD_ALIGNED_ERR_MASK BIT(28)
|
||||
#define PAGE_ACCESS_ERR_MASK BIT(27)
|
||||
#define WRITE_ACCESS_MASK BIT(26)
|
||||
#define RBERRADDR_RD(src) ((src) & 0x03FFFFFF)
|
||||
|
||||
static const char * const soc_mem_err_v1[] = {
|
||||
"10GbE0",
|
||||
@@ -1483,13 +1482,11 @@ static void xgene_edac_rb_report(struct edac_device_ctl_info *edac_dev)
|
||||
return;
|
||||
if (reg & STICKYERR_MASK) {
|
||||
bool write;
|
||||
u32 address;
|
||||
|
||||
dev_err(edac_dev->dev, "IOB bus access error(s)\n");
|
||||
if (regmap_read(ctx->edac->rb_map, RBEIR, ®))
|
||||
return;
|
||||
write = reg & WRITE_ACCESS_MASK ? 1 : 0;
|
||||
address = RBERRADDR_RD(reg);
|
||||
if (reg & AGENT_OFFLINE_ERR_MASK)
|
||||
dev_err(edac_dev->dev,
|
||||
"IOB bus %s access to offline agent error\n",
|
||||
|
||||
@@ -182,16 +182,10 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
|
||||
RPI_FIRMWARE_GET_FIRMWARE_REVISION,
|
||||
&packet, sizeof(packet));
|
||||
|
||||
if (ret == 0) {
|
||||
struct tm tm;
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
time64_to_tm(packet, 0, &tm);
|
||||
|
||||
dev_info(fw->cl.dev,
|
||||
"Attached to firmware from %04ld-%02d-%02d %02d:%02d\n",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min);
|
||||
}
|
||||
dev_info(fw->cl.dev, "Attached to firmware from %ptT\n", &packet);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -661,7 +661,6 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
|
||||
u8 *data = pulse8->data + 1;
|
||||
u8 cmd[2];
|
||||
int err;
|
||||
struct tm tm;
|
||||
time64_t date;
|
||||
|
||||
pulse8->vers = 0;
|
||||
@@ -682,10 +681,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
|
||||
if (err)
|
||||
return err;
|
||||
date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
||||
time64_to_tm(date, 0, &tm);
|
||||
dev_info(pulse8->dev, "Firmware build date %04ld.%02d.%02d %02d:%02d:%02d\n",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
dev_info(pulse8->dev, "Firmware build date %ptT\n", &date);
|
||||
|
||||
dev_dbg(pulse8->dev, "Persistent config:\n");
|
||||
cmd[0] = MSGCODE_GET_AUTO_ENABLED;
|
||||
|
||||
@@ -329,6 +329,8 @@ rollback:
|
||||
|
||||
/**
|
||||
* fsverity_ioctl_enable() - enable verity on a file
|
||||
* @filp: file to enable verity on
|
||||
* @uarg: user pointer to fsverity_enable_arg
|
||||
*
|
||||
* Enable fs-verity on a file. See the "FS_IOC_ENABLE_VERITY" section of
|
||||
* Documentation/filesystems/fsverity.rst for the documentation.
|
||||
|
||||
@@ -61,7 +61,7 @@ struct merkle_tree_params {
|
||||
u64 level_start[FS_VERITY_MAX_LEVELS];
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* fsverity_info - cached verity metadata for an inode
|
||||
*
|
||||
* When a verity file is first opened, an instance of this struct is allocated
|
||||
@@ -134,7 +134,7 @@ void __init fsverity_check_hash_algs(void);
|
||||
|
||||
/* init.c */
|
||||
|
||||
extern void __printf(3, 4) __cold
|
||||
void __printf(3, 4) __cold
|
||||
fsverity_msg(const struct inode *inode, const char *level,
|
||||
const char *fmt, ...);
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
/**
|
||||
* fsverity_ioctl_measure() - get a verity file's measurement
|
||||
* @filp: file to get measurement of
|
||||
* @_uarg: user pointer to fsverity_digest
|
||||
*
|
||||
* Retrieve the file measurement that the kernel is enforcing for reads from a
|
||||
* verity file. See the "FS_IOC_MEASURE_VERITY" section of
|
||||
|
||||
@@ -330,6 +330,7 @@ EXPORT_SYMBOL_GPL(fsverity_prepare_setattr);
|
||||
|
||||
/**
|
||||
* fsverity_cleanup_inode() - free the inode's verity info, if present
|
||||
* @inode: an inode being evicted
|
||||
*
|
||||
* Filesystems must call this on inode eviction to free ->i_verity_info.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,9 @@ static struct key *fsverity_keyring;
|
||||
|
||||
/**
|
||||
* fsverity_verify_signature() - check a verity file's signature
|
||||
* @vi: the file's fsverity_info
|
||||
* @desc: the file's fsverity_descriptor
|
||||
* @desc_size: size of @desc
|
||||
*
|
||||
* If the file's fs-verity descriptor includes a signature of the file
|
||||
* measurement, verify it against the certificates in the fs-verity keyring.
|
||||
|
||||
@@ -179,6 +179,7 @@ out:
|
||||
|
||||
/**
|
||||
* fsverity_verify_page() - verify a data page
|
||||
* @page: the page to verity
|
||||
*
|
||||
* Verify a page that has just been read from a verity file. The page must be a
|
||||
* pagecache page that is still locked and not yet uptodate.
|
||||
@@ -206,6 +207,7 @@ EXPORT_SYMBOL_GPL(fsverity_verify_page);
|
||||
#ifdef CONFIG_BLOCK
|
||||
/**
|
||||
* fsverity_verify_bio() - verify a 'read' bio that has just completed
|
||||
* @bio: the bio to verify
|
||||
*
|
||||
* Verify a set of pages that have just been read from a verity file. The pages
|
||||
* must be pagecache pages that are still locked and not yet uptodate. Pages
|
||||
@@ -264,6 +266,7 @@ EXPORT_SYMBOL_GPL(fsverity_verify_bio);
|
||||
|
||||
/**
|
||||
* fsverity_enqueue_verify_work() - enqueue work on the fs-verity workqueue
|
||||
* @work: the work to enqueue
|
||||
*
|
||||
* Enqueue verification work for asynchronous processing.
|
||||
*/
|
||||
|
||||
@@ -53,6 +53,9 @@ extern char __ctors_start[], __ctors_end[];
|
||||
/* Start and end of .opd section - used for function descriptors. */
|
||||
extern char __start_opd[], __end_opd[];
|
||||
|
||||
/* Start and end of instrumentation protected text section */
|
||||
extern char __noinstr_text_start[], __noinstr_text_end[];
|
||||
|
||||
extern __visible const void __nosave_begin, __nosave_end;
|
||||
|
||||
/* Function descriptor handling (if any). Override in asm/sections.h */
|
||||
|
||||
@@ -545,6 +545,15 @@
|
||||
. = ALIGN((align)); \
|
||||
__end_rodata = .;
|
||||
|
||||
/*
|
||||
* Non-instrumentable text section
|
||||
*/
|
||||
#define NOINSTR_TEXT \
|
||||
ALIGN_FUNCTION(); \
|
||||
__noinstr_text_start = .; \
|
||||
*(.noinstr.text) \
|
||||
__noinstr_text_end = .;
|
||||
|
||||
/*
|
||||
* .text section. Map to function alignment to avoid address changes
|
||||
* during second ld run in second ld pass when generating System.map
|
||||
@@ -556,6 +565,7 @@
|
||||
#define TEXT_TEXT \
|
||||
ALIGN_FUNCTION(); \
|
||||
*(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \
|
||||
NOINSTR_TEXT \
|
||||
*(TEXT_CFI_MAIN) \
|
||||
*(.text..refcount) \
|
||||
*(.text..ftrace) \
|
||||
|
||||
@@ -120,12 +120,65 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
|
||||
/* Annotate a C jump table to allow objtool to follow the code flow */
|
||||
#define __annotate_jump_table __section(.rodata..c_jump_table)
|
||||
|
||||
#ifdef CONFIG_DEBUG_ENTRY
|
||||
/* Begin/end of an instrumentation safe region */
|
||||
#define instrumentation_begin() ({ \
|
||||
asm volatile("%c0:\n\t" \
|
||||
".pushsection .discard.instr_begin\n\t" \
|
||||
".long %c0b - .\n\t" \
|
||||
".popsection\n\t" : : "i" (__COUNTER__)); \
|
||||
})
|
||||
|
||||
/*
|
||||
* Because instrumentation_{begin,end}() can nest, objtool validation considers
|
||||
* _begin() a +1 and _end() a -1 and computes a sum over the instructions.
|
||||
* When the value is greater than 0, we consider instrumentation allowed.
|
||||
*
|
||||
* There is a problem with code like:
|
||||
*
|
||||
* noinstr void foo()
|
||||
* {
|
||||
* instrumentation_begin();
|
||||
* ...
|
||||
* if (cond) {
|
||||
* instrumentation_begin();
|
||||
* ...
|
||||
* instrumentation_end();
|
||||
* }
|
||||
* bar();
|
||||
* instrumentation_end();
|
||||
* }
|
||||
*
|
||||
* If instrumentation_end() would be an empty label, like all the other
|
||||
* annotations, the inner _end(), which is at the end of a conditional block,
|
||||
* would land on the instruction after the block.
|
||||
*
|
||||
* If we then consider the sum of the !cond path, we'll see that the call to
|
||||
* bar() is with a 0-value, even though, we meant it to happen with a positive
|
||||
* value.
|
||||
*
|
||||
* To avoid this, have _end() be a NOP instruction, this ensures it will be
|
||||
* part of the condition block and does not escape.
|
||||
*/
|
||||
#define instrumentation_end() ({ \
|
||||
asm volatile("%c0: nop\n\t" \
|
||||
".pushsection .discard.instr_end\n\t" \
|
||||
".long %c0b - .\n\t" \
|
||||
".popsection\n\t" : : "i" (__COUNTER__)); \
|
||||
})
|
||||
#endif /* CONFIG_DEBUG_ENTRY */
|
||||
|
||||
#else
|
||||
#define annotate_reachable()
|
||||
#define annotate_unreachable()
|
||||
#define __annotate_jump_table
|
||||
#endif
|
||||
|
||||
#ifndef instrumentation_begin
|
||||
#define instrumentation_begin() do { } while(0)
|
||||
#define instrumentation_end() do { } while(0)
|
||||
#endif
|
||||
|
||||
#ifndef ASM_UNREACHABLE
|
||||
# define ASM_UNREACHABLE
|
||||
#endif
|
||||
|
||||
@@ -118,6 +118,10 @@ struct ftrace_likely_data {
|
||||
#define notrace __attribute__((__no_instrument_function__))
|
||||
#endif
|
||||
|
||||
/* Section for code which can't be instrumented at all */
|
||||
#define noinstr \
|
||||
noinline notrace __attribute((__section__(".noinstr.text")))
|
||||
|
||||
/*
|
||||
* it doesn't make sense on ARM (currently the only user of __naked)
|
||||
* to trace naked functions because then mcount is called without
|
||||
|
||||
@@ -134,7 +134,7 @@ static inline int con_debug_leave(void)
|
||||
*/
|
||||
|
||||
#define CON_PRINTBUFFER (1)
|
||||
#define CON_CONSDEV (2) /* Last on the command line */
|
||||
#define CON_CONSDEV (2) /* Preferred console, /dev/console */
|
||||
#define CON_ENABLED (4)
|
||||
#define CON_BOOT (8)
|
||||
#define CON_ANYTIME (16) /* Safe to call when cpu is offline */
|
||||
|
||||
@@ -121,23 +121,23 @@ static inline struct fsverity_info *fsverity_get_info(const struct inode *inode)
|
||||
|
||||
/* enable.c */
|
||||
|
||||
extern int fsverity_ioctl_enable(struct file *filp, const void __user *arg);
|
||||
int fsverity_ioctl_enable(struct file *filp, const void __user *arg);
|
||||
|
||||
/* measure.c */
|
||||
|
||||
extern int fsverity_ioctl_measure(struct file *filp, void __user *arg);
|
||||
int fsverity_ioctl_measure(struct file *filp, void __user *arg);
|
||||
|
||||
/* open.c */
|
||||
|
||||
extern int fsverity_file_open(struct inode *inode, struct file *filp);
|
||||
extern int fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
extern void fsverity_cleanup_inode(struct inode *inode);
|
||||
int fsverity_file_open(struct inode *inode, struct file *filp);
|
||||
int fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
void fsverity_cleanup_inode(struct inode *inode);
|
||||
|
||||
/* verify.c */
|
||||
|
||||
extern bool fsverity_verify_page(struct page *page);
|
||||
extern void fsverity_verify_bio(struct bio *bio);
|
||||
extern void fsverity_enqueue_verify_work(struct work_struct *work);
|
||||
bool fsverity_verify_page(struct page *page);
|
||||
void fsverity_verify_bio(struct bio *bio);
|
||||
void fsverity_enqueue_verify_work(struct work_struct *work);
|
||||
|
||||
#else /* !CONFIG_FS_VERITY */
|
||||
|
||||
@@ -200,6 +200,7 @@ static inline void fsverity_enqueue_verify_work(struct work_struct *work)
|
||||
|
||||
/**
|
||||
* fsverity_active() - do reads from the inode need to go through fs-verity?
|
||||
* @inode: inode to check
|
||||
*
|
||||
* This checks whether ->i_verity_info has been set.
|
||||
*
|
||||
@@ -207,6 +208,8 @@ static inline void fsverity_enqueue_verify_work(struct work_struct *work)
|
||||
* be verified or not. Don't use IS_VERITY() for this purpose; it's subject to
|
||||
* a race condition where the file is being read concurrently with
|
||||
* FS_IOC_ENABLE_VERITY completing. (S_VERITY is set before ->i_verity_info.)
|
||||
*
|
||||
* Return: true if reads need to go through fs-verity, otherwise false
|
||||
*/
|
||||
static inline bool fsverity_active(const struct inode *inode)
|
||||
{
|
||||
|
||||
@@ -465,6 +465,8 @@ struct module {
|
||||
void __percpu *percpu;
|
||||
unsigned int percpu_size;
|
||||
#endif
|
||||
void *noinstr_text_start;
|
||||
unsigned int noinstr_text_size;
|
||||
|
||||
#ifdef CONFIG_TRACEPOINTS
|
||||
unsigned int num_tracepoints;
|
||||
@@ -496,6 +498,12 @@ struct module {
|
||||
unsigned int num_ftrace_callsites;
|
||||
unsigned long *ftrace_callsites;
|
||||
#endif
|
||||
#ifdef CONFIG_KPROBES
|
||||
void *kprobes_text_start;
|
||||
unsigned int kprobes_text_size;
|
||||
unsigned long *kprobe_blacklist;
|
||||
unsigned int num_kprobe_blacklist;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
bool klp; /* Is this a livepatch module? */
|
||||
|
||||
@@ -384,8 +384,7 @@ extern int kptr_restrict;
|
||||
printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
|
||||
#define pr_info_once(fmt, ...) \
|
||||
printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
|
||||
#define pr_cont_once(fmt, ...) \
|
||||
printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__)
|
||||
/* no pr_cont_once, don't do that... */
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define pr_devel_once(fmt, ...) \
|
||||
|
||||
+84
-1
@@ -2179,6 +2179,24 @@ int kprobe_add_area_blacklist(unsigned long start, unsigned long end)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove all symbols in given area from kprobe blacklist */
|
||||
static void kprobe_remove_area_blacklist(unsigned long start, unsigned long end)
|
||||
{
|
||||
struct kprobe_blacklist_entry *ent, *n;
|
||||
|
||||
list_for_each_entry_safe(ent, n, &kprobe_blacklist, list) {
|
||||
if (ent->start_addr < start || ent->start_addr >= end)
|
||||
continue;
|
||||
list_del(&ent->list);
|
||||
kfree(ent);
|
||||
}
|
||||
}
|
||||
|
||||
static void kprobe_remove_ksym_blacklist(unsigned long entry)
|
||||
{
|
||||
kprobe_remove_area_blacklist(entry, entry + 1);
|
||||
}
|
||||
|
||||
int __init __weak arch_populate_kprobe_blacklist(void)
|
||||
{
|
||||
return 0;
|
||||
@@ -2211,10 +2229,62 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
|
||||
/* Symbols in __kprobes_text are blacklisted */
|
||||
ret = kprobe_add_area_blacklist((unsigned long)__kprobes_text_start,
|
||||
(unsigned long)__kprobes_text_end);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Symbols in noinstr section are blacklisted */
|
||||
ret = kprobe_add_area_blacklist((unsigned long)__noinstr_text_start,
|
||||
(unsigned long)__noinstr_text_end);
|
||||
|
||||
return ret ? : arch_populate_kprobe_blacklist();
|
||||
}
|
||||
|
||||
static void add_module_kprobe_blacklist(struct module *mod)
|
||||
{
|
||||
unsigned long start, end;
|
||||
int i;
|
||||
|
||||
if (mod->kprobe_blacklist) {
|
||||
for (i = 0; i < mod->num_kprobe_blacklist; i++)
|
||||
kprobe_add_ksym_blacklist(mod->kprobe_blacklist[i]);
|
||||
}
|
||||
|
||||
start = (unsigned long)mod->kprobes_text_start;
|
||||
if (start) {
|
||||
end = start + mod->kprobes_text_size;
|
||||
kprobe_add_area_blacklist(start, end);
|
||||
}
|
||||
|
||||
start = (unsigned long)mod->noinstr_text_start;
|
||||
if (start) {
|
||||
end = start + mod->noinstr_text_size;
|
||||
kprobe_add_area_blacklist(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_module_kprobe_blacklist(struct module *mod)
|
||||
{
|
||||
unsigned long start, end;
|
||||
int i;
|
||||
|
||||
if (mod->kprobe_blacklist) {
|
||||
for (i = 0; i < mod->num_kprobe_blacklist; i++)
|
||||
kprobe_remove_ksym_blacklist(mod->kprobe_blacklist[i]);
|
||||
}
|
||||
|
||||
start = (unsigned long)mod->kprobes_text_start;
|
||||
if (start) {
|
||||
end = start + mod->kprobes_text_size;
|
||||
kprobe_remove_area_blacklist(start, end);
|
||||
}
|
||||
|
||||
start = (unsigned long)mod->noinstr_text_start;
|
||||
if (start) {
|
||||
end = start + mod->noinstr_text_size;
|
||||
kprobe_remove_area_blacklist(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
/* Module notifier call back, checking kprobes on the module */
|
||||
static int kprobes_module_callback(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
@@ -2225,6 +2295,11 @@ static int kprobes_module_callback(struct notifier_block *nb,
|
||||
unsigned int i;
|
||||
int checkcore = (val == MODULE_STATE_GOING);
|
||||
|
||||
if (val == MODULE_STATE_COMING) {
|
||||
mutex_lock(&kprobe_mutex);
|
||||
add_module_kprobe_blacklist(mod);
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
}
|
||||
if (val != MODULE_STATE_GOING && val != MODULE_STATE_LIVE)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
@@ -2255,6 +2330,8 @@ static int kprobes_module_callback(struct notifier_block *nb,
|
||||
kill_kprobe(p);
|
||||
}
|
||||
}
|
||||
if (val == MODULE_STATE_GOING)
|
||||
remove_module_kprobe_blacklist(mod);
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
@@ -2420,6 +2497,7 @@ static const struct file_operations debugfs_kprobes_operations = {
|
||||
/* kprobes/blacklist -- shows which functions can not be probed */
|
||||
static void *kprobe_blacklist_seq_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
mutex_lock(&kprobe_mutex);
|
||||
return seq_list_start(&kprobe_blacklist, *pos);
|
||||
}
|
||||
|
||||
@@ -2446,10 +2524,15 @@ static int kprobe_blacklist_seq_show(struct seq_file *m, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kprobe_blacklist_seq_stop(struct seq_file *f, void *v)
|
||||
{
|
||||
mutex_unlock(&kprobe_mutex);
|
||||
}
|
||||
|
||||
static const struct seq_operations kprobe_blacklist_seq_ops = {
|
||||
.start = kprobe_blacklist_seq_start,
|
||||
.next = kprobe_blacklist_seq_next,
|
||||
.stop = kprobe_seq_stop, /* Reuse void function */
|
||||
.stop = kprobe_blacklist_seq_stop,
|
||||
.show = kprobe_blacklist_seq_show,
|
||||
};
|
||||
|
||||
|
||||
@@ -3155,6 +3155,9 @@ static int find_module_sections(struct module *mod, struct load_info *info)
|
||||
}
|
||||
#endif
|
||||
|
||||
mod->noinstr_text_start = section_objs(info, ".noinstr.text", 1,
|
||||
&mod->noinstr_text_size);
|
||||
|
||||
#ifdef CONFIG_TRACEPOINTS
|
||||
mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs",
|
||||
sizeof(*mod->tracepoints_ptrs),
|
||||
@@ -3198,6 +3201,13 @@ static int find_module_sections(struct module *mod, struct load_info *info)
|
||||
mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
|
||||
sizeof(*mod->ei_funcs),
|
||||
&mod->num_ei_funcs);
|
||||
#endif
|
||||
#ifdef CONFIG_KPROBES
|
||||
mod->kprobes_text_start = section_objs(info, ".kprobes.text", 1,
|
||||
&mod->kprobes_text_size);
|
||||
mod->kprobe_blacklist = section_objs(info, "_kprobe_blacklist",
|
||||
sizeof(unsigned long),
|
||||
&mod->num_kprobe_blacklist);
|
||||
#endif
|
||||
mod->extable = section_objs(info, "__ex_table",
|
||||
sizeof(*mod->extable), &mod->num_exentries);
|
||||
|
||||
@@ -6,6 +6,7 @@ struct console_cmdline
|
||||
{
|
||||
char name[16]; /* Name of the driver */
|
||||
int index; /* Minor dev. to use */
|
||||
bool user_specified; /* Specified by command line vs. platform */
|
||||
char *options; /* Options for the driver */
|
||||
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
|
||||
char *brl_options; /* Options for braille driver */
|
||||
|
||||
+96
-49
@@ -280,6 +280,7 @@ static struct console *exclusive_console;
|
||||
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
|
||||
|
||||
static int preferred_console = -1;
|
||||
static bool has_preferred_console;
|
||||
int console_set_on_cmdline;
|
||||
EXPORT_SYMBOL(console_set_on_cmdline);
|
||||
|
||||
@@ -974,6 +975,16 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
|
||||
user->idx = log_next_idx;
|
||||
user->seq = log_next_seq;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
/*
|
||||
* It isn't supported due to the record nature of this
|
||||
* interface: _SET _DATA and _END point to very specific
|
||||
* record positions, while _CUR would be more useful in case
|
||||
* of a byte-based log. Because of that, return the default
|
||||
* errno value for invalid seek operation.
|
||||
*/
|
||||
ret = -ESPIPE;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
@@ -2140,7 +2151,7 @@ asmlinkage __visible void early_printk(const char *fmt, ...)
|
||||
#endif
|
||||
|
||||
static int __add_preferred_console(char *name, int idx, char *options,
|
||||
char *brl_options)
|
||||
char *brl_options, bool user_specified)
|
||||
{
|
||||
struct console_cmdline *c;
|
||||
int i;
|
||||
@@ -2155,6 +2166,8 @@ static int __add_preferred_console(char *name, int idx, char *options,
|
||||
if (strcmp(c->name, name) == 0 && c->index == idx) {
|
||||
if (!brl_options)
|
||||
preferred_console = i;
|
||||
if (user_specified)
|
||||
c->user_specified = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2164,6 +2177,7 @@ static int __add_preferred_console(char *name, int idx, char *options,
|
||||
preferred_console = i;
|
||||
strlcpy(c->name, name, sizeof(c->name));
|
||||
c->options = options;
|
||||
c->user_specified = user_specified;
|
||||
braille_set_options(c, brl_options);
|
||||
|
||||
c->index = idx;
|
||||
@@ -2190,6 +2204,9 @@ static int __init console_setup(char *str)
|
||||
char *s, *options, *brl_options = NULL;
|
||||
int idx;
|
||||
|
||||
if (str[0] == 0)
|
||||
return 1;
|
||||
|
||||
if (_braille_console_setup(&str, &brl_options))
|
||||
return 1;
|
||||
|
||||
@@ -2218,7 +2235,7 @@ static int __init console_setup(char *str)
|
||||
idx = simple_strtoul(s, NULL, 10);
|
||||
*s = 0;
|
||||
|
||||
__add_preferred_console(buf, idx, options, brl_options);
|
||||
__add_preferred_console(buf, idx, options, brl_options, true);
|
||||
console_set_on_cmdline = 1;
|
||||
return 1;
|
||||
}
|
||||
@@ -2239,7 +2256,7 @@ __setup("console=", console_setup);
|
||||
*/
|
||||
int add_preferred_console(char *name, int idx, char *options)
|
||||
{
|
||||
return __add_preferred_console(name, idx, options, NULL);
|
||||
return __add_preferred_console(name, idx, options, NULL, false);
|
||||
}
|
||||
|
||||
bool console_suspend_enabled = true;
|
||||
@@ -2438,9 +2455,9 @@ again:
|
||||
printk_safe_enter_irqsave(flags);
|
||||
raw_spin_lock(&logbuf_lock);
|
||||
if (console_seq < log_first_seq) {
|
||||
len = sprintf(text,
|
||||
"** %llu printk messages dropped **\n",
|
||||
log_first_seq - console_seq);
|
||||
len = snprintf(text, sizeof(text),
|
||||
"** %llu printk messages dropped **\n",
|
||||
log_first_seq - console_seq);
|
||||
|
||||
/* messages are gone, move to first one */
|
||||
console_seq = log_first_seq;
|
||||
@@ -2651,6 +2668,63 @@ static int __init keep_bootcon_setup(char *str)
|
||||
|
||||
early_param("keep_bootcon", keep_bootcon_setup);
|
||||
|
||||
/*
|
||||
* This is called by register_console() to try to match
|
||||
* the newly registered console with any of the ones selected
|
||||
* by either the command line or add_preferred_console() and
|
||||
* setup/enable it.
|
||||
*
|
||||
* Care need to be taken with consoles that are statically
|
||||
* enabled such as netconsole
|
||||
*/
|
||||
static int try_enable_new_console(struct console *newcon, bool user_specified)
|
||||
{
|
||||
struct console_cmdline *c;
|
||||
int i;
|
||||
|
||||
for (i = 0, c = console_cmdline;
|
||||
i < MAX_CMDLINECONSOLES && c->name[0];
|
||||
i++, c++) {
|
||||
if (c->user_specified != user_specified)
|
||||
continue;
|
||||
if (!newcon->match ||
|
||||
newcon->match(newcon, c->name, c->index, c->options) != 0) {
|
||||
/* default matching */
|
||||
BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
|
||||
if (strcmp(c->name, newcon->name) != 0)
|
||||
continue;
|
||||
if (newcon->index >= 0 &&
|
||||
newcon->index != c->index)
|
||||
continue;
|
||||
if (newcon->index < 0)
|
||||
newcon->index = c->index;
|
||||
|
||||
if (_braille_register_console(newcon, c))
|
||||
return 0;
|
||||
|
||||
if (newcon->setup &&
|
||||
newcon->setup(newcon, c->options) != 0)
|
||||
return -EIO;
|
||||
}
|
||||
newcon->flags |= CON_ENABLED;
|
||||
if (i == preferred_console) {
|
||||
newcon->flags |= CON_CONSDEV;
|
||||
has_preferred_console = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some consoles, such as pstore and netconsole, can be enabled even
|
||||
* without matching. Accept the pre-enabled consoles only when match()
|
||||
* and setup() had a change to be called.
|
||||
*/
|
||||
if (newcon->flags & CON_ENABLED && c->user_specified == user_specified)
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* The console driver calls this routine during kernel initialization
|
||||
* to register the console printing procedure with printk() and to
|
||||
@@ -2672,11 +2746,9 @@ early_param("keep_bootcon", keep_bootcon_setup);
|
||||
*/
|
||||
void register_console(struct console *newcon)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
struct console *bcon = NULL;
|
||||
struct console_cmdline *c;
|
||||
static bool has_preferred;
|
||||
int err;
|
||||
|
||||
for_each_console(bcon) {
|
||||
if (WARN(bcon == newcon, "console '%s%d' already registered\n",
|
||||
@@ -2701,15 +2773,15 @@ void register_console(struct console *newcon)
|
||||
if (console_drivers && console_drivers->flags & CON_BOOT)
|
||||
bcon = console_drivers;
|
||||
|
||||
if (!has_preferred || bcon || !console_drivers)
|
||||
has_preferred = preferred_console >= 0;
|
||||
if (!has_preferred_console || bcon || !console_drivers)
|
||||
has_preferred_console = preferred_console >= 0;
|
||||
|
||||
/*
|
||||
* See if we want to use this console driver. If we
|
||||
* didn't select a console we take the first one
|
||||
* that registers here.
|
||||
*/
|
||||
if (!has_preferred) {
|
||||
if (!has_preferred_console) {
|
||||
if (newcon->index < 0)
|
||||
newcon->index = 0;
|
||||
if (newcon->setup == NULL ||
|
||||
@@ -2717,47 +2789,20 @@ void register_console(struct console *newcon)
|
||||
newcon->flags |= CON_ENABLED;
|
||||
if (newcon->device) {
|
||||
newcon->flags |= CON_CONSDEV;
|
||||
has_preferred = true;
|
||||
has_preferred_console = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* See if this console matches one we selected on
|
||||
* the command line.
|
||||
*/
|
||||
for (i = 0, c = console_cmdline;
|
||||
i < MAX_CMDLINECONSOLES && c->name[0];
|
||||
i++, c++) {
|
||||
if (!newcon->match ||
|
||||
newcon->match(newcon, c->name, c->index, c->options) != 0) {
|
||||
/* default matching */
|
||||
BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
|
||||
if (strcmp(c->name, newcon->name) != 0)
|
||||
continue;
|
||||
if (newcon->index >= 0 &&
|
||||
newcon->index != c->index)
|
||||
continue;
|
||||
if (newcon->index < 0)
|
||||
newcon->index = c->index;
|
||||
/* See if this console matches one we selected on the command line */
|
||||
err = try_enable_new_console(newcon, true);
|
||||
|
||||
if (_braille_register_console(newcon, c))
|
||||
return;
|
||||
/* If not, try to match against the platform default(s) */
|
||||
if (err == -ENOENT)
|
||||
err = try_enable_new_console(newcon, false);
|
||||
|
||||
if (newcon->setup &&
|
||||
newcon->setup(newcon, c->options) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
newcon->flags |= CON_ENABLED;
|
||||
if (i == preferred_console) {
|
||||
newcon->flags |= CON_CONSDEV;
|
||||
has_preferred = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(newcon->flags & CON_ENABLED))
|
||||
/* printk() messages are not printed to the Braille console. */
|
||||
if (err || newcon->flags & CON_BRL)
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -2779,6 +2824,8 @@ void register_console(struct console *newcon)
|
||||
console_drivers = newcon;
|
||||
if (newcon->next)
|
||||
newcon->next->flags &= ~CON_CONSDEV;
|
||||
/* Ensure this flag is always set for the head of the list */
|
||||
newcon->flags |= CON_CONSDEV;
|
||||
} else {
|
||||
newcon->next = console_drivers->next;
|
||||
console_drivers->next = newcon;
|
||||
@@ -3384,7 +3431,7 @@ out:
|
||||
EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
|
||||
|
||||
/**
|
||||
* kmsg_dump_rewind_nolock - reset the interator (unlocked version)
|
||||
* kmsg_dump_rewind_nolock - reset the iterator (unlocked version)
|
||||
* @dumper: registered kmsg dumper
|
||||
*
|
||||
* Reset the dumper's iterator so that kmsg_dump_get_line() and
|
||||
@@ -3402,7 +3449,7 @@ void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
|
||||
}
|
||||
|
||||
/**
|
||||
* kmsg_dump_rewind - reset the interator
|
||||
* kmsg_dump_rewind - reset the iterator
|
||||
* @dumper: registered kmsg dumper
|
||||
*
|
||||
* Reset the dumper's iterator so that kmsg_dump_get_line() and
|
||||
|
||||
+10
-3
@@ -494,7 +494,7 @@ struct_va_format(void)
|
||||
}
|
||||
|
||||
static void __init
|
||||
struct_rtc_time(void)
|
||||
time_and_date(void)
|
||||
{
|
||||
/* 1543210543 */
|
||||
const struct rtc_time tm = {
|
||||
@@ -505,14 +505,21 @@ struct_rtc_time(void)
|
||||
.tm_mon = 10,
|
||||
.tm_year = 118,
|
||||
};
|
||||
/* 2019-01-04T15:32:23 */
|
||||
time64_t t = 1546615943;
|
||||
|
||||
test("(%ptR?)", "%pt", &tm);
|
||||
test("(%pt?)", "%pt", &tm);
|
||||
test("2018-11-26T05:35:43", "%ptR", &tm);
|
||||
test("0118-10-26T05:35:43", "%ptRr", &tm);
|
||||
test("05:35:43|2018-11-26", "%ptRt|%ptRd", &tm, &tm);
|
||||
test("05:35:43|0118-10-26", "%ptRtr|%ptRdr", &tm, &tm);
|
||||
test("05:35:43|2018-11-26", "%ptRttr|%ptRdtr", &tm, &tm);
|
||||
test("05:35:43 tr|2018-11-26 tr", "%ptRt tr|%ptRd tr", &tm, &tm);
|
||||
|
||||
test("2019-01-04T15:32:23", "%ptT", &t);
|
||||
test("0119-00-04T15:32:23", "%ptTr", &t);
|
||||
test("15:32:23|2019-01-04", "%ptTt|%ptTd", &t, &t);
|
||||
test("15:32:23|0119-00-04", "%ptTtr|%ptTdr", &t, &t);
|
||||
}
|
||||
|
||||
static void __init
|
||||
@@ -678,7 +685,7 @@ test_pointer(void)
|
||||
uuid();
|
||||
dentry();
|
||||
struct_va_format();
|
||||
struct_rtc_time();
|
||||
time_and_date();
|
||||
struct_clk();
|
||||
bitmap();
|
||||
netdev_features();
|
||||
|
||||
+33
-6
@@ -34,6 +34,7 @@
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/of.h>
|
||||
#include <net/addrconf.h>
|
||||
@@ -58,7 +59,7 @@
|
||||
* @endp: A pointer to the end of the parsed string will be placed here
|
||||
* @base: The number base to use
|
||||
*
|
||||
* This function is obsolete. Please use kstrtoull instead.
|
||||
* This function has caveats. Please use kstrtoull instead.
|
||||
*/
|
||||
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
|
||||
{
|
||||
@@ -83,7 +84,7 @@ EXPORT_SYMBOL(simple_strtoull);
|
||||
* @endp: A pointer to the end of the parsed string will be placed here
|
||||
* @base: The number base to use
|
||||
*
|
||||
* This function is obsolete. Please use kstrtoul instead.
|
||||
* This function has caveats. Please use kstrtoul instead.
|
||||
*/
|
||||
unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
|
||||
{
|
||||
@@ -97,7 +98,7 @@ EXPORT_SYMBOL(simple_strtoul);
|
||||
* @endp: A pointer to the end of the parsed string will be placed here
|
||||
* @base: The number base to use
|
||||
*
|
||||
* This function is obsolete. Please use kstrtol instead.
|
||||
* This function has caveats. Please use kstrtol instead.
|
||||
*/
|
||||
long simple_strtol(const char *cp, char **endp, unsigned int base)
|
||||
{
|
||||
@@ -114,7 +115,7 @@ EXPORT_SYMBOL(simple_strtol);
|
||||
* @endp: A pointer to the end of the parsed string will be placed here
|
||||
* @base: The number base to use
|
||||
*
|
||||
* This function is obsolete. Please use kstrtoll instead.
|
||||
* This function has caveats. Please use kstrtoll instead.
|
||||
*/
|
||||
long long simple_strtoll(const char *cp, char **endp, unsigned int base)
|
||||
{
|
||||
@@ -1826,6 +1827,29 @@ char *rtc_str(char *buf, char *end, const struct rtc_time *tm,
|
||||
return buf;
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
char *time64_str(char *buf, char *end, const time64_t time,
|
||||
struct printf_spec spec, const char *fmt)
|
||||
{
|
||||
struct rtc_time rtc_time;
|
||||
struct tm tm;
|
||||
|
||||
time64_to_tm(time, 0, &tm);
|
||||
|
||||
rtc_time.tm_sec = tm.tm_sec;
|
||||
rtc_time.tm_min = tm.tm_min;
|
||||
rtc_time.tm_hour = tm.tm_hour;
|
||||
rtc_time.tm_mday = tm.tm_mday;
|
||||
rtc_time.tm_mon = tm.tm_mon;
|
||||
rtc_time.tm_year = tm.tm_year;
|
||||
rtc_time.tm_wday = tm.tm_wday;
|
||||
rtc_time.tm_yday = tm.tm_yday;
|
||||
|
||||
rtc_time.tm_isdst = 0;
|
||||
|
||||
return rtc_str(buf, end, &rtc_time, spec, fmt);
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec,
|
||||
const char *fmt)
|
||||
@@ -1833,8 +1857,10 @@ char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec,
|
||||
switch (fmt[1]) {
|
||||
case 'R':
|
||||
return rtc_str(buf, end, (const struct rtc_time *)ptr, spec, fmt);
|
||||
case 'T':
|
||||
return time64_str(buf, end, *(const time64_t *)ptr, spec, fmt);
|
||||
default:
|
||||
return error_string(buf, end, "(%ptR?)", spec);
|
||||
return error_string(buf, end, "(%pt?)", spec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2150,8 +2176,9 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
|
||||
* - 'd[234]' For a dentry name (optionally 2-4 last components)
|
||||
* - 'D[234]' Same as 'd' but for a struct file
|
||||
* - 'g' For block_device name (gendisk + partition number)
|
||||
* - 't[R][dt][r]' For time and date as represented:
|
||||
* - 't[RT][dt][r]' For time and date as represented by:
|
||||
* R struct rtc_time
|
||||
* T time64_t
|
||||
* - 'C' For a clock, it prints the name (Common Clock Framework) or address
|
||||
* (legacy clock framework) of the clock
|
||||
* - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
|
||||
|
||||
@@ -25,7 +25,7 @@ static struct kprobe kp = {
|
||||
};
|
||||
|
||||
/* kprobe pre_handler: called just before the probed instruction is executed */
|
||||
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
static int __kprobes handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
|
||||
@@ -54,7 +54,7 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
}
|
||||
|
||||
/* kprobe post_handler: called after the probed instruction is executed */
|
||||
static void handler_post(struct kprobe *p, struct pt_regs *regs,
|
||||
static void __kprobes handler_post(struct kprobe *p, struct pt_regs *regs,
|
||||
unsigned long flags)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
@@ -90,6 +90,8 @@ static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
|
||||
/* Return 0 because we don't handle the fault. */
|
||||
return 0;
|
||||
}
|
||||
/* NOKPROBE_SYMBOL() is also available */
|
||||
NOKPROBE_SYMBOL(handler_fault);
|
||||
|
||||
static int __init kprobe_init(void)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
|
||||
data->entry_stamp = ktime_get();
|
||||
return 0;
|
||||
}
|
||||
NOKPROBE_SYMBOL(entry_handler);
|
||||
|
||||
/*
|
||||
* Return-probe handler: Log the return value and duration. Duration may turn
|
||||
@@ -67,6 +68,7 @@ static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
|
||||
func_name, retval, (long long)delta);
|
||||
return 0;
|
||||
}
|
||||
NOKPROBE_SYMBOL(ret_handler);
|
||||
|
||||
static struct kretprobe my_kretprobe = {
|
||||
.handler = ret_handler,
|
||||
|
||||
@@ -951,7 +951,7 @@ static void check_section(const char *modname, struct elf_info *elf,
|
||||
|
||||
#define DATA_SECTIONS ".data", ".data.rel"
|
||||
#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
|
||||
".kprobes.text", ".cpuidle.text"
|
||||
".kprobes.text", ".cpuidle.text", ".noinstr.text"
|
||||
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
|
||||
".fixup", ".entry.text", ".exception.text", ".text.*", \
|
||||
".coldtext"
|
||||
|
||||
Reference in New Issue
Block a user