Merge tag 'kvmarm-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 updates for Linux 5.11 - PSCI relay at EL2 when "protected KVM" is enabled - New exception injection code - Simplification of AArch32 system register handling - Fix PMU accesses when no PMU is enabled - Expose CSV3 on non-Meltdown hosts - Cache hierarchy discovery fixes - PV steal-time cleanups - Allow function pointers at EL2 - Various host EL2 entry cleanups - Simplification of the EL2 vector allocation
This commit is contained in:
+25
-32
@@ -2312,9 +2312,6 @@ group_sched_out(struct perf_event *group_event,
|
||||
event_sched_out(event, cpuctx, ctx);
|
||||
|
||||
perf_pmu_enable(ctx->pmu);
|
||||
|
||||
if (group_event->attr.exclusive)
|
||||
cpuctx->exclusive = 0;
|
||||
}
|
||||
|
||||
#define DETACH_GROUP 0x01UL
|
||||
@@ -2583,11 +2580,8 @@ group_sched_in(struct perf_event *group_event,
|
||||
|
||||
pmu->start_txn(pmu, PERF_PMU_TXN_ADD);
|
||||
|
||||
if (event_sched_in(group_event, cpuctx, ctx)) {
|
||||
pmu->cancel_txn(pmu);
|
||||
perf_mux_hrtimer_restart(cpuctx);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (event_sched_in(group_event, cpuctx, ctx))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Schedule in siblings as one group (if any):
|
||||
@@ -2616,10 +2610,8 @@ group_error:
|
||||
}
|
||||
event_sched_out(group_event, cpuctx, ctx);
|
||||
|
||||
error:
|
||||
pmu->cancel_txn(pmu);
|
||||
|
||||
perf_mux_hrtimer_restart(cpuctx);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
@@ -2645,7 +2637,7 @@ static int group_can_go_on(struct perf_event *event,
|
||||
* If this group is exclusive and there are already
|
||||
* events on the CPU, it can't go on.
|
||||
*/
|
||||
if (event->attr.exclusive && cpuctx->active_oncpu)
|
||||
if (event->attr.exclusive && !list_empty(get_event_list(event)))
|
||||
return 0;
|
||||
/*
|
||||
* Otherwise, try to add it if all previous groups were able
|
||||
@@ -3679,6 +3671,7 @@ static int merge_sched_in(struct perf_event *event, void *data)
|
||||
|
||||
*can_add_hw = 0;
|
||||
ctx->rotate_necessary = 1;
|
||||
perf_mux_hrtimer_restart(cpuctx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -6374,14 +6367,13 @@ perf_output_sample_regs(struct perf_output_handle *handle,
|
||||
}
|
||||
|
||||
static void perf_sample_regs_user(struct perf_regs *regs_user,
|
||||
struct pt_regs *regs,
|
||||
struct pt_regs *regs_user_copy)
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if (user_mode(regs)) {
|
||||
regs_user->abi = perf_reg_abi(current);
|
||||
regs_user->regs = regs;
|
||||
} else if (!(current->flags & PF_KTHREAD)) {
|
||||
perf_get_regs_user(regs_user, regs, regs_user_copy);
|
||||
perf_get_regs_user(regs_user, regs);
|
||||
} else {
|
||||
regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
|
||||
regs_user->regs = NULL;
|
||||
@@ -7083,8 +7075,7 @@ void perf_prepare_sample(struct perf_event_header *header,
|
||||
}
|
||||
|
||||
if (sample_type & (PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER))
|
||||
perf_sample_regs_user(&data->regs_user, regs,
|
||||
&data->regs_user_copy);
|
||||
perf_sample_regs_user(&data->regs_user, regs);
|
||||
|
||||
if (sample_type & PERF_SAMPLE_REGS_USER) {
|
||||
/* regs dump ABI info */
|
||||
@@ -7186,6 +7177,7 @@ __perf_event_output(struct perf_event *event,
|
||||
struct perf_sample_data *data,
|
||||
struct pt_regs *regs,
|
||||
int (*output_begin)(struct perf_output_handle *,
|
||||
struct perf_sample_data *,
|
||||
struct perf_event *,
|
||||
unsigned int))
|
||||
{
|
||||
@@ -7198,7 +7190,7 @@ __perf_event_output(struct perf_event *event,
|
||||
|
||||
perf_prepare_sample(&header, data, event, regs);
|
||||
|
||||
err = output_begin(&handle, event, header.size);
|
||||
err = output_begin(&handle, data, event, header.size);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
@@ -7264,7 +7256,7 @@ perf_event_read_event(struct perf_event *event,
|
||||
int ret;
|
||||
|
||||
perf_event_header__init_id(&read_event.header, &sample, event);
|
||||
ret = perf_output_begin(&handle, event, read_event.header.size);
|
||||
ret = perf_output_begin(&handle, &sample, event, read_event.header.size);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@@ -7533,7 +7525,7 @@ static void perf_event_task_output(struct perf_event *event,
|
||||
|
||||
perf_event_header__init_id(&task_event->event_id.header, &sample, event);
|
||||
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
task_event->event_id.header.size);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -7636,7 +7628,7 @@ static void perf_event_comm_output(struct perf_event *event,
|
||||
return;
|
||||
|
||||
perf_event_header__init_id(&comm_event->event_id.header, &sample, event);
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
comm_event->event_id.header.size);
|
||||
|
||||
if (ret)
|
||||
@@ -7736,7 +7728,7 @@ static void perf_event_namespaces_output(struct perf_event *event,
|
||||
|
||||
perf_event_header__init_id(&namespaces_event->event_id.header,
|
||||
&sample, event);
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
namespaces_event->event_id.header.size);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -7863,7 +7855,7 @@ static void perf_event_cgroup_output(struct perf_event *event, void *data)
|
||||
|
||||
perf_event_header__init_id(&cgroup_event->event_id.header,
|
||||
&sample, event);
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
cgroup_event->event_id.header.size);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -7989,7 +7981,7 @@ static void perf_event_mmap_output(struct perf_event *event,
|
||||
}
|
||||
|
||||
perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
mmap_event->event_id.header.size);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -8299,7 +8291,7 @@ void perf_event_aux_event(struct perf_event *event, unsigned long head,
|
||||
int ret;
|
||||
|
||||
perf_event_header__init_id(&rec.header, &sample, event);
|
||||
ret = perf_output_begin(&handle, event, rec.header.size);
|
||||
ret = perf_output_begin(&handle, &sample, event, rec.header.size);
|
||||
|
||||
if (ret)
|
||||
return;
|
||||
@@ -8333,7 +8325,7 @@ void perf_log_lost_samples(struct perf_event *event, u64 lost)
|
||||
|
||||
perf_event_header__init_id(&lost_samples_event.header, &sample, event);
|
||||
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
lost_samples_event.header.size);
|
||||
if (ret)
|
||||
return;
|
||||
@@ -8388,7 +8380,7 @@ static void perf_event_switch_output(struct perf_event *event, void *data)
|
||||
|
||||
perf_event_header__init_id(&se->event_id.header, &sample, event);
|
||||
|
||||
ret = perf_output_begin(&handle, event, se->event_id.header.size);
|
||||
ret = perf_output_begin(&handle, &sample, event, se->event_id.header.size);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@@ -8463,7 +8455,7 @@ static void perf_log_throttle(struct perf_event *event, int enable)
|
||||
|
||||
perf_event_header__init_id(&throttle_event.header, &sample, event);
|
||||
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
throttle_event.header.size);
|
||||
if (ret)
|
||||
return;
|
||||
@@ -8506,7 +8498,7 @@ static void perf_event_ksymbol_output(struct perf_event *event, void *data)
|
||||
|
||||
perf_event_header__init_id(&ksymbol_event->event_id.header,
|
||||
&sample, event);
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
ksymbol_event->event_id.header.size);
|
||||
if (ret)
|
||||
return;
|
||||
@@ -8596,7 +8588,7 @@ static void perf_event_bpf_output(struct perf_event *event, void *data)
|
||||
|
||||
perf_event_header__init_id(&bpf_event->event_id.header,
|
||||
&sample, event);
|
||||
ret = perf_output_begin(&handle, event,
|
||||
ret = perf_output_begin(&handle, data, event,
|
||||
bpf_event->event_id.header.size);
|
||||
if (ret)
|
||||
return;
|
||||
@@ -8705,7 +8697,8 @@ static void perf_event_text_poke_output(struct perf_event *event, void *data)
|
||||
|
||||
perf_event_header__init_id(&text_poke_event->event_id.header, &sample, event);
|
||||
|
||||
ret = perf_output_begin(&handle, event, text_poke_event->event_id.header.size);
|
||||
ret = perf_output_begin(&handle, &sample, event,
|
||||
text_poke_event->event_id.header.size);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@@ -8786,7 +8779,7 @@ static void perf_log_itrace_start(struct perf_event *event)
|
||||
rec.tid = perf_event_tid(event, current);
|
||||
|
||||
perf_event_header__init_id(&rec.header, &sample, event);
|
||||
ret = perf_output_begin(&handle, event, rec.header.size);
|
||||
ret = perf_output_begin(&handle, &sample, event, rec.header.size);
|
||||
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
@@ -205,16 +205,12 @@ DEFINE_OUTPUT_COPY(__output_copy_user, arch_perf_out_copy_user)
|
||||
|
||||
static inline int get_recursion_context(int *recursion)
|
||||
{
|
||||
int rctx;
|
||||
unsigned int pc = preempt_count();
|
||||
unsigned char rctx = 0;
|
||||
|
||||
if (unlikely(in_nmi()))
|
||||
rctx = 3;
|
||||
else if (in_irq())
|
||||
rctx = 2;
|
||||
else if (in_softirq())
|
||||
rctx = 1;
|
||||
else
|
||||
rctx = 0;
|
||||
rctx += !!(pc & (NMI_MASK));
|
||||
rctx += !!(pc & (NMI_MASK | HARDIRQ_MASK));
|
||||
rctx += !!(pc & (NMI_MASK | HARDIRQ_MASK | SOFTIRQ_OFFSET));
|
||||
|
||||
if (recursion[rctx])
|
||||
return -1;
|
||||
|
||||
@@ -147,6 +147,7 @@ ring_buffer_has_space(unsigned long head, unsigned long tail,
|
||||
|
||||
static __always_inline int
|
||||
__perf_output_begin(struct perf_output_handle *handle,
|
||||
struct perf_sample_data *data,
|
||||
struct perf_event *event, unsigned int size,
|
||||
bool backward)
|
||||
{
|
||||
@@ -237,18 +238,16 @@ __perf_output_begin(struct perf_output_handle *handle,
|
||||
handle->size = (1UL << page_shift) - offset;
|
||||
|
||||
if (unlikely(have_lost)) {
|
||||
struct perf_sample_data sample_data;
|
||||
|
||||
lost_event.header.size = sizeof(lost_event);
|
||||
lost_event.header.type = PERF_RECORD_LOST;
|
||||
lost_event.header.misc = 0;
|
||||
lost_event.id = event->id;
|
||||
lost_event.lost = local_xchg(&rb->lost, 0);
|
||||
|
||||
perf_event_header__init_id(&lost_event.header,
|
||||
&sample_data, event);
|
||||
/* XXX mostly redundant; @data is already fully initializes */
|
||||
perf_event_header__init_id(&lost_event.header, data, event);
|
||||
perf_output_put(handle, lost_event);
|
||||
perf_event__output_id_sample(event, handle, &sample_data);
|
||||
perf_event__output_id_sample(event, handle, data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -263,22 +262,25 @@ out:
|
||||
}
|
||||
|
||||
int perf_output_begin_forward(struct perf_output_handle *handle,
|
||||
struct perf_event *event, unsigned int size)
|
||||
struct perf_sample_data *data,
|
||||
struct perf_event *event, unsigned int size)
|
||||
{
|
||||
return __perf_output_begin(handle, event, size, false);
|
||||
return __perf_output_begin(handle, data, event, size, false);
|
||||
}
|
||||
|
||||
int perf_output_begin_backward(struct perf_output_handle *handle,
|
||||
struct perf_sample_data *data,
|
||||
struct perf_event *event, unsigned int size)
|
||||
{
|
||||
return __perf_output_begin(handle, event, size, true);
|
||||
return __perf_output_begin(handle, data, event, size, true);
|
||||
}
|
||||
|
||||
int perf_output_begin(struct perf_output_handle *handle,
|
||||
struct perf_sample_data *data,
|
||||
struct perf_event *event, unsigned int size)
|
||||
{
|
||||
|
||||
return __perf_output_begin(handle, event, size,
|
||||
return __perf_output_begin(handle, data, event, size,
|
||||
unlikely(is_write_backward(event)));
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -788,8 +788,9 @@ static void put_pi_state(struct futex_pi_state *pi_state)
|
||||
*/
|
||||
if (pi_state->owner) {
|
||||
struct task_struct *owner;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
|
||||
raw_spin_lock_irqsave(&pi_state->pi_mutex.wait_lock, flags);
|
||||
owner = pi_state->owner;
|
||||
if (owner) {
|
||||
raw_spin_lock(&owner->pi_lock);
|
||||
@@ -797,7 +798,7 @@ static void put_pi_state(struct futex_pi_state *pi_state)
|
||||
raw_spin_unlock(&owner->pi_lock);
|
||||
}
|
||||
rt_mutex_proxy_unlock(&pi_state->pi_mutex, owner);
|
||||
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
|
||||
raw_spin_unlock_irqrestore(&pi_state->pi_mutex.wait_lock, flags);
|
||||
}
|
||||
|
||||
if (current->pi_state_cache) {
|
||||
|
||||
@@ -2765,7 +2765,9 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
|
||||
* (Note that this has to be done separately, because the graph cannot
|
||||
* detect such classes of deadlocks.)
|
||||
*
|
||||
* Returns: 0 on deadlock detected, 1 on OK, 2 on recursive read
|
||||
* Returns: 0 on deadlock detected, 1 on OK, 2 if another lock with the same
|
||||
* lock class is held but nest_lock is also held, i.e. we rely on the
|
||||
* nest_lock to avoid the deadlock.
|
||||
*/
|
||||
static int
|
||||
check_deadlock(struct task_struct *curr, struct held_lock *next)
|
||||
@@ -2788,7 +2790,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next)
|
||||
* lock class (i.e. read_lock(lock)+read_lock(lock)):
|
||||
*/
|
||||
if ((next->read == 2) && prev->read)
|
||||
return 2;
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We're holding the nest_lock, which serializes this lock's
|
||||
@@ -3592,16 +3594,13 @@ static int validate_chain(struct task_struct *curr,
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
/*
|
||||
* Mark recursive read, as we jump over it when
|
||||
* building dependencies (just like we jump over
|
||||
* trylock entries):
|
||||
*/
|
||||
if (ret == 2)
|
||||
hlock->read = 2;
|
||||
/*
|
||||
* Add dependency only if this lock is not the head
|
||||
* of the chain, and if it's not a secondary read-lock:
|
||||
* of the chain, and if the new lock introduces no more
|
||||
* lock dependency (because we already hold a lock with the
|
||||
* same lock class) nor deadlock (because the nest_lock
|
||||
* serializes nesting locks), see the comments for
|
||||
* check_deadlock().
|
||||
*/
|
||||
if (!chain_head && ret != 2) {
|
||||
if (!check_prevs_add(curr, hlock))
|
||||
|
||||
+2
-1
@@ -605,7 +605,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
|
||||
panic("panic_on_warn set ...\n");
|
||||
}
|
||||
|
||||
dump_stack();
|
||||
if (!regs)
|
||||
dump_stack();
|
||||
|
||||
print_irqtrace_events(current);
|
||||
|
||||
|
||||
+1
-1
@@ -4077,7 +4077,6 @@ void rcu_cpu_starting(unsigned int cpu)
|
||||
smp_mb(); /* Ensure RCU read-side usage follows above initialization. */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/*
|
||||
* The outgoing function has no further need of RCU, so remove it from
|
||||
* the rcu_node tree's ->qsmaskinitnext bit masks.
|
||||
@@ -4117,6 +4116,7 @@ void rcu_report_dead(unsigned int cpu)
|
||||
rdp->cpu_started = false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/*
|
||||
* The outgoing CPU has just passed through the dying-idle state, and we
|
||||
* are being invoked from the CPU that was IPIed to continue the offline
|
||||
|
||||
+14
-14
@@ -551,22 +551,22 @@ static int __init reboot_setup(char *str)
|
||||
break;
|
||||
|
||||
case 's':
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (isdigit(*(str+1))) {
|
||||
rc = kstrtoint(str+1, 0, &reboot_cpu);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else if (str[1] == 'm' && str[2] == 'p' &&
|
||||
isdigit(*(str+3))) {
|
||||
rc = kstrtoint(str+3, 0, &reboot_cpu);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else
|
||||
if (isdigit(*(str+1)))
|
||||
reboot_cpu = simple_strtoul(str+1, NULL, 0);
|
||||
else if (str[1] == 'm' && str[2] == 'p' &&
|
||||
isdigit(*(str+3)))
|
||||
reboot_cpu = simple_strtoul(str+3, NULL, 0);
|
||||
else
|
||||
*mode = REBOOT_SOFT;
|
||||
if (reboot_cpu >= num_possible_cpus()) {
|
||||
pr_err("Ignoring the CPU number in reboot= option. "
|
||||
"CPU %d exceeds possible cpu number %d\n",
|
||||
reboot_cpu, num_possible_cpus());
|
||||
reboot_cpu = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'g':
|
||||
*mode = REBOOT_GPIO;
|
||||
break;
|
||||
|
||||
@@ -251,7 +251,7 @@ static int sd_ctl_doflags(struct ctl_table *table, int write,
|
||||
unsigned long flags = *(unsigned long *)table->data;
|
||||
size_t data_size = 0;
|
||||
size_t len = 0;
|
||||
char *tmp;
|
||||
char *tmp, *buf;
|
||||
int idx;
|
||||
|
||||
if (write)
|
||||
@@ -269,17 +269,17 @@ static int sd_ctl_doflags(struct ctl_table *table, int write,
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = kcalloc(data_size + 1, sizeof(*tmp), GFP_KERNEL);
|
||||
if (!tmp)
|
||||
buf = kcalloc(data_size + 1, sizeof(*buf), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_set_bit(idx, &flags, __SD_FLAG_CNT) {
|
||||
char *name = sd_flag_debug[idx].name;
|
||||
|
||||
len += snprintf(tmp + len, strlen(name) + 2, "%s ", name);
|
||||
len += snprintf(buf + len, strlen(name) + 2, "%s ", name);
|
||||
}
|
||||
|
||||
tmp += *ppos;
|
||||
tmp = buf + *ppos;
|
||||
len -= *ppos;
|
||||
|
||||
if (len > *lenp)
|
||||
@@ -294,7 +294,7 @@ static int sd_ctl_doflags(struct ctl_table *table, int write,
|
||||
*lenp = len;
|
||||
*ppos += len;
|
||||
|
||||
kfree(tmp);
|
||||
kfree(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+45
-25
@@ -6172,21 +6172,21 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
|
||||
static int
|
||||
select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
|
||||
{
|
||||
unsigned long best_cap = 0;
|
||||
unsigned long task_util, best_cap = 0;
|
||||
int cpu, best_cpu = -1;
|
||||
struct cpumask *cpus;
|
||||
|
||||
sync_entity_load_avg(&p->se);
|
||||
|
||||
cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
|
||||
cpumask_and(cpus, sched_domain_span(sd), p->cpus_ptr);
|
||||
|
||||
task_util = uclamp_task_util(p);
|
||||
|
||||
for_each_cpu_wrap(cpu, cpus, target) {
|
||||
unsigned long cpu_cap = capacity_of(cpu);
|
||||
|
||||
if (!available_idle_cpu(cpu) && !sched_idle_cpu(cpu))
|
||||
continue;
|
||||
if (task_fits_capacity(p, cpu_cap))
|
||||
if (fits_capacity(task_util, cpu_cap))
|
||||
return cpu;
|
||||
|
||||
if (cpu_cap > best_cap) {
|
||||
@@ -6198,44 +6198,42 @@ select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
|
||||
return best_cpu;
|
||||
}
|
||||
|
||||
static inline bool asym_fits_capacity(int task_util, int cpu)
|
||||
{
|
||||
if (static_branch_unlikely(&sched_asym_cpucapacity))
|
||||
return fits_capacity(task_util, capacity_of(cpu));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try and locate an idle core/thread in the LLC cache domain.
|
||||
*/
|
||||
static int select_idle_sibling(struct task_struct *p, int prev, int target)
|
||||
{
|
||||
struct sched_domain *sd;
|
||||
unsigned long task_util;
|
||||
int i, recent_used_cpu;
|
||||
|
||||
/*
|
||||
* For asymmetric CPU capacity systems, our domain of interest is
|
||||
* sd_asym_cpucapacity rather than sd_llc.
|
||||
* On asymmetric system, update task utilization because we will check
|
||||
* that the task fits with cpu's capacity.
|
||||
*/
|
||||
if (static_branch_unlikely(&sched_asym_cpucapacity)) {
|
||||
sd = rcu_dereference(per_cpu(sd_asym_cpucapacity, target));
|
||||
/*
|
||||
* On an asymmetric CPU capacity system where an exclusive
|
||||
* cpuset defines a symmetric island (i.e. one unique
|
||||
* capacity_orig value through the cpuset), the key will be set
|
||||
* but the CPUs within that cpuset will not have a domain with
|
||||
* SD_ASYM_CPUCAPACITY. These should follow the usual symmetric
|
||||
* capacity path.
|
||||
*/
|
||||
if (!sd)
|
||||
goto symmetric;
|
||||
|
||||
i = select_idle_capacity(p, sd, target);
|
||||
return ((unsigned)i < nr_cpumask_bits) ? i : target;
|
||||
sync_entity_load_avg(&p->se);
|
||||
task_util = uclamp_task_util(p);
|
||||
}
|
||||
|
||||
symmetric:
|
||||
if (available_idle_cpu(target) || sched_idle_cpu(target))
|
||||
if ((available_idle_cpu(target) || sched_idle_cpu(target)) &&
|
||||
asym_fits_capacity(task_util, target))
|
||||
return target;
|
||||
|
||||
/*
|
||||
* If the previous CPU is cache affine and idle, don't be stupid:
|
||||
*/
|
||||
if (prev != target && cpus_share_cache(prev, target) &&
|
||||
(available_idle_cpu(prev) || sched_idle_cpu(prev)))
|
||||
(available_idle_cpu(prev) || sched_idle_cpu(prev)) &&
|
||||
asym_fits_capacity(task_util, prev))
|
||||
return prev;
|
||||
|
||||
/*
|
||||
@@ -6258,7 +6256,8 @@ symmetric:
|
||||
recent_used_cpu != target &&
|
||||
cpus_share_cache(recent_used_cpu, target) &&
|
||||
(available_idle_cpu(recent_used_cpu) || sched_idle_cpu(recent_used_cpu)) &&
|
||||
cpumask_test_cpu(p->recent_used_cpu, p->cpus_ptr)) {
|
||||
cpumask_test_cpu(p->recent_used_cpu, p->cpus_ptr) &&
|
||||
asym_fits_capacity(task_util, recent_used_cpu)) {
|
||||
/*
|
||||
* Replace recent_used_cpu with prev as it is a potential
|
||||
* candidate for the next wake:
|
||||
@@ -6267,6 +6266,26 @@ symmetric:
|
||||
return recent_used_cpu;
|
||||
}
|
||||
|
||||
/*
|
||||
* For asymmetric CPU capacity systems, our domain of interest is
|
||||
* sd_asym_cpucapacity rather than sd_llc.
|
||||
*/
|
||||
if (static_branch_unlikely(&sched_asym_cpucapacity)) {
|
||||
sd = rcu_dereference(per_cpu(sd_asym_cpucapacity, target));
|
||||
/*
|
||||
* On an asymmetric CPU capacity system where an exclusive
|
||||
* cpuset defines a symmetric island (i.e. one unique
|
||||
* capacity_orig value through the cpuset), the key will be set
|
||||
* but the CPUs within that cpuset will not have a domain with
|
||||
* SD_ASYM_CPUCAPACITY. These should follow the usual symmetric
|
||||
* capacity path.
|
||||
*/
|
||||
if (sd) {
|
||||
i = select_idle_capacity(p, sd, target);
|
||||
return ((unsigned)i < nr_cpumask_bits) ? i : target;
|
||||
}
|
||||
}
|
||||
|
||||
sd = rcu_dereference(per_cpu(sd_llc, target));
|
||||
if (!sd)
|
||||
return target;
|
||||
@@ -9031,7 +9050,8 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
|
||||
* emptying busiest.
|
||||
*/
|
||||
if (local->group_type == group_has_spare) {
|
||||
if (busiest->group_type > group_fully_busy) {
|
||||
if ((busiest->group_type > group_fully_busy) &&
|
||||
!(env->sd->flags & SD_SHARE_PKG_RESOURCES)) {
|
||||
/*
|
||||
* If busiest is overloaded, try to fill spare
|
||||
* capacity. This might end up creating spare capacity
|
||||
|
||||
+2
-2
@@ -44,8 +44,6 @@ int __read_mostly soft_watchdog_user_enabled = 1;
|
||||
int __read_mostly watchdog_thresh = 10;
|
||||
static int __read_mostly nmi_watchdog_available;
|
||||
|
||||
static struct cpumask watchdog_allowed_mask __read_mostly;
|
||||
|
||||
struct cpumask watchdog_cpumask __read_mostly;
|
||||
unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask);
|
||||
|
||||
@@ -162,6 +160,8 @@ static void lockup_detector_update_enable(void)
|
||||
int __read_mostly sysctl_softlockup_all_cpu_backtrace;
|
||||
#endif
|
||||
|
||||
static struct cpumask watchdog_allowed_mask __read_mostly;
|
||||
|
||||
/* Global variables, exported for sysctl */
|
||||
unsigned int __read_mostly softlockup_panic =
|
||||
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE;
|
||||
|
||||
Reference in New Issue
Block a user