|
@@ -2414,6 +2414,11 @@ static bool can_dynamic_split(struct kvmppc_vcore *vc, struct core_info *cip)
|
|
if (!cpu_has_feature(CPU_FTR_ARCH_207S))
|
|
if (!cpu_has_feature(CPU_FTR_ARCH_207S))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
+ /* POWER9 currently requires all threads to be in the same MMU mode */
|
|
|
|
+ if (cpu_has_feature(CPU_FTR_ARCH_300) &&
|
|
|
|
+ kvm_is_radix(vc->kvm) != kvm_is_radix(cip->vc[0]->kvm))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
if (n_threads < cip->max_subcore_threads)
|
|
if (n_threads < cip->max_subcore_threads)
|
|
n_threads = cip->max_subcore_threads;
|
|
n_threads = cip->max_subcore_threads;
|
|
if (!subcore_config_ok(cip->n_subcores + 1, n_threads))
|
|
if (!subcore_config_ok(cip->n_subcores + 1, n_threads))
|
|
@@ -2452,9 +2457,6 @@ static void prepare_threads(struct kvmppc_vcore *vc)
|
|
for_each_runnable_thread(i, vcpu, vc) {
|
|
for_each_runnable_thread(i, vcpu, vc) {
|
|
if (signal_pending(vcpu->arch.run_task))
|
|
if (signal_pending(vcpu->arch.run_task))
|
|
vcpu->arch.ret = -EINTR;
|
|
vcpu->arch.ret = -EINTR;
|
|
- else if (kvm_is_radix(vc->kvm) != radix_enabled())
|
|
|
|
- /* can't actually run HPT guest on radix host yet... */
|
|
|
|
- vcpu->arch.ret = -EINVAL;
|
|
|
|
else if (vcpu->arch.vpa.update_pending ||
|
|
else if (vcpu->arch.vpa.update_pending ||
|
|
vcpu->arch.slb_shadow.update_pending ||
|
|
vcpu->arch.slb_shadow.update_pending ||
|
|
vcpu->arch.dtl.update_pending)
|
|
vcpu->arch.dtl.update_pending)
|
|
@@ -2643,6 +2645,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
int controlled_threads;
|
|
int controlled_threads;
|
|
int trap;
|
|
int trap;
|
|
bool is_power8;
|
|
bool is_power8;
|
|
|
|
+ bool hpt_on_radix;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Remove from the list any threads that have a signal pending
|
|
* Remove from the list any threads that have a signal pending
|
|
@@ -2671,9 +2674,13 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
* Make sure we are running on primary threads, and that secondary
|
|
* Make sure we are running on primary threads, and that secondary
|
|
* threads are offline. Also check if the number of threads in this
|
|
* threads are offline. Also check if the number of threads in this
|
|
* guest are greater than the current system threads per guest.
|
|
* guest are greater than the current system threads per guest.
|
|
|
|
+ * On POWER9, we need to be not in independent-threads mode if
|
|
|
|
+ * this is a HPT guest on a radix host.
|
|
*/
|
|
*/
|
|
- if ((controlled_threads > 1) &&
|
|
|
|
- ((vc->num_threads > threads_per_subcore) || !on_primary_thread())) {
|
|
|
|
|
|
+ hpt_on_radix = radix_enabled() && !kvm_is_radix(vc->kvm);
|
|
|
|
+ if (((controlled_threads > 1) &&
|
|
|
|
+ ((vc->num_threads > threads_per_subcore) || !on_primary_thread())) ||
|
|
|
|
+ (hpt_on_radix && vc->kvm->arch.threads_indep)) {
|
|
for_each_runnable_thread(i, vcpu, vc) {
|
|
for_each_runnable_thread(i, vcpu, vc) {
|
|
vcpu->arch.ret = -EBUSY;
|
|
vcpu->arch.ret = -EBUSY;
|
|
kvmppc_remove_runnable(vc, vcpu);
|
|
kvmppc_remove_runnable(vc, vcpu);
|
|
@@ -2739,7 +2746,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
is_power8 = cpu_has_feature(CPU_FTR_ARCH_207S)
|
|
is_power8 = cpu_has_feature(CPU_FTR_ARCH_207S)
|
|
&& !cpu_has_feature(CPU_FTR_ARCH_300);
|
|
&& !cpu_has_feature(CPU_FTR_ARCH_300);
|
|
|
|
|
|
- if (split > 1) {
|
|
|
|
|
|
+ if (split > 1 || hpt_on_radix) {
|
|
sip = &split_info;
|
|
sip = &split_info;
|
|
memset(&split_info, 0, sizeof(split_info));
|
|
memset(&split_info, 0, sizeof(split_info));
|
|
for (sub = 0; sub < core_info.n_subcores; ++sub)
|
|
for (sub = 0; sub < core_info.n_subcores; ++sub)
|
|
@@ -2761,13 +2768,24 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
split_info.subcore_size = subcore_size;
|
|
split_info.subcore_size = subcore_size;
|
|
} else {
|
|
} else {
|
|
split_info.subcore_size = 1;
|
|
split_info.subcore_size = 1;
|
|
|
|
+ if (hpt_on_radix) {
|
|
|
|
+ /* Use the split_info for LPCR/LPIDR changes */
|
|
|
|
+ split_info.lpcr_req = vc->lpcr;
|
|
|
|
+ split_info.lpidr_req = vc->kvm->arch.lpid;
|
|
|
|
+ split_info.host_lpcr = vc->kvm->arch.host_lpcr;
|
|
|
|
+ split_info.do_set = 1;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/* order writes to split_info before kvm_split_mode pointer */
|
|
/* order writes to split_info before kvm_split_mode pointer */
|
|
smp_wmb();
|
|
smp_wmb();
|
|
}
|
|
}
|
|
- for (thr = 0; thr < controlled_threads; ++thr)
|
|
|
|
|
|
+
|
|
|
|
+ for (thr = 0; thr < controlled_threads; ++thr) {
|
|
|
|
+ paca[pcpu + thr].kvm_hstate.tid = thr;
|
|
|
|
+ paca[pcpu + thr].kvm_hstate.napping = 0;
|
|
paca[pcpu + thr].kvm_hstate.kvm_split_mode = sip;
|
|
paca[pcpu + thr].kvm_hstate.kvm_split_mode = sip;
|
|
|
|
+ }
|
|
|
|
|
|
/* Initiate micro-threading (split-core) on POWER8 if required */
|
|
/* Initiate micro-threading (split-core) on POWER8 if required */
|
|
if (cmd_bit) {
|
|
if (cmd_bit) {
|
|
@@ -2820,8 +2838,10 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
* When doing micro-threading, poke the inactive threads as well.
|
|
* When doing micro-threading, poke the inactive threads as well.
|
|
* This gets them to the nap instruction after kvm_do_nap,
|
|
* This gets them to the nap instruction after kvm_do_nap,
|
|
* which reduces the time taken to unsplit later.
|
|
* which reduces the time taken to unsplit later.
|
|
|
|
+ * For POWER9 HPT guest on radix host, we need all the secondary
|
|
|
|
+ * threads woken up so they can do the LPCR/LPIDR change.
|
|
*/
|
|
*/
|
|
- if (cmd_bit) {
|
|
|
|
|
|
+ if (cmd_bit || hpt_on_radix) {
|
|
split_info.do_nap = 1; /* ask secondaries to nap when done */
|
|
split_info.do_nap = 1; /* ask secondaries to nap when done */
|
|
for (thr = 1; thr < threads_per_subcore; ++thr)
|
|
for (thr = 1; thr < threads_per_subcore; ++thr)
|
|
if (!(active & (1 << thr)))
|
|
if (!(active & (1 << thr)))
|
|
@@ -2879,8 +2899,17 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
|
cpu_relax();
|
|
cpu_relax();
|
|
++loops;
|
|
++loops;
|
|
}
|
|
}
|
|
- split_info.do_nap = 0;
|
|
|
|
|
|
+ } else if (hpt_on_radix) {
|
|
|
|
+ /* Wait for all threads to have seen final sync */
|
|
|
|
+ for (thr = 1; thr < controlled_threads; ++thr) {
|
|
|
|
+ while (paca[pcpu + thr].kvm_hstate.kvm_split_mode) {
|
|
|
|
+ HMT_low();
|
|
|
|
+ barrier();
|
|
|
|
+ }
|
|
|
|
+ HMT_medium();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ split_info.do_nap = 0;
|
|
|
|
|
|
kvmppc_set_host_core(pcpu);
|
|
kvmppc_set_host_core(pcpu);
|
|
|
|
|