Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1653139 > unrolled thread
| Started by | Vitaly Kuznetsov <vkuznets@redhat.com> |
|---|---|
| First post | 2017-05-30 13:40 +0200 |
| Last post | 2017-05-31 17:10 +0200 |
| Articles | 4 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls Vitaly Kuznetsov <vkuznets@redhat.com> - 2017-05-30 13:40 +0200
Re: [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls Andy Shevchenko <andy.shevchenko@gmail.com> - 2017-05-30 19:10 +0200
RE: [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls Jork Loeser <Jork.Loeser@microsoft.com> - 2017-05-30 21:20 +0200
Re: [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls Vitaly Kuznetsov <vkuznets@redhat.com> - 2017-05-31 17:10 +0200
| From | Vitaly Kuznetsov <vkuznets@redhat.com> |
|---|---|
| Date | 2017-05-30 13:40 +0200 |
| Subject | [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls |
| Message-ID | <tMNFf-6JG-5@gated-at.bofh.it> |
Hyper-V hosts may support more than 64 vCPUs, we need to use
HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX/LIST_EX hypercalls in this
case.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Acked-by: K. Y. Srinivasan <kys@microsoft.com>
---
Changes since v4:
- Use __set_bit(), minor code style changes [Andy Shevchenko]
---
arch/x86/hyperv/mmu.c | 150 ++++++++++++++++++++++++++++++++++++-
arch/x86/include/uapi/asm/hyperv.h | 10 +++
2 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c
index 8ccd680..b08e7ca 100644
--- a/arch/x86/hyperv/mmu.c
+++ b/arch/x86/hyperv/mmu.c
@@ -15,11 +15,60 @@ struct hv_flush_pcpu {
__u64 gva_list[];
};
+/* HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressListEx hypercalls */
+struct hv_flush_pcpu_ex {
+ __u64 address_space;
+ __u64 flags;
+ struct {
+ __u64 format;
+ __u64 valid_bank_mask;
+ __u64 bank_contents[];
+ } hv_vp_set;
+ __u64 gva_list[];
+};
+
/* Each gva in gva_list encodes up to 4096 pages to flush */
#define HV_TLB_FLUSH_UNIT (PAGE_SIZE * PAGE_SIZE)
static struct hv_flush_pcpu __percpu *pcpu_flush;
+static struct hv_flush_pcpu_ex __percpu *pcpu_flush_ex;
+
+static inline int cpumask_to_vp_set(struct hv_flush_pcpu_ex *flush,
+ const struct cpumask *cpus)
+{
+ int cpu, vcpu, vcpu_bank, vcpu_offset, cur_bank, nr_bank = 0;
+ bool has_cpus;
+
+ /*
+ * We can't be sure that translated vCPU numbers will always be
+ * in ascending order, so iterate over all possible banks and
+ * check all vCPUs in it instead.
+ */
+ for (cur_bank = 0; cur_bank < ms_hyperv.max_vp_index/64; cur_bank++) {
+ has_cpus = false;
+ for_each_cpu(cpu, cpus) {
+ vcpu = hv_cpu_number_to_vp_number(cpu);
+ vcpu_bank = vcpu / 64;
+ vcpu_offset = vcpu % 64;
+
+ if (vcpu_bank != cur_bank)
+ continue;
+ __set_bit(vcpu_offset, (unsigned long *)
+ &flush->hv_vp_set.bank_contents[nr_bank]);
+ if (!has_cpus) {
+ __set_bit(vcpu_bank, (unsigned long *)
+ &flush->hv_vp_set.valid_bank_mask);
+ has_cpus = true;
+ }
+ }
+ if (has_cpus)
+ nr_bank++;
+ }
+
+ return nr_bank;
+}
+
static void hyperv_flush_tlb_others(const struct cpumask *cpus,
struct mm_struct *mm, unsigned long start,
unsigned long end)
@@ -106,16 +155,113 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus,
native_flush_tlb_others(cpus, mm, start, end);
}
+static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
+ struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+ struct hv_flush_pcpu_ex *flush;
+ unsigned long cur, flags;
+ u64 status = U64_MAX;
+ int nr_bank = 0, max_gvas, gva_n;
+
+ if (!pcpu_flush_ex || !hv_hypercall_pg)
+ goto do_native;
+
+ if (cpumask_empty(cpus))
+ return;
+
+ local_irq_save(flags);
+
+ flush = this_cpu_ptr(pcpu_flush_ex);
+
+ if (mm) {
+ flush->address_space = virt_to_phys(mm->pgd);
+ flush->flags = 0;
+ } else {
+ flush->address_space = 0;
+ flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
+ }
+
+ flush->hv_vp_set.valid_bank_mask = 0;
+
+ if (cpumask_equal(cpus, cpu_present_mask)) {
+ flush->hv_vp_set.format = HV_GENERIC_SET_ALL;
+ flush->flags |= HV_FLUSH_ALL_PROCESSORS;
+ } else {
+ flush->hv_vp_set.format = HV_GENERIC_SET_SPARCE_4K;
+ nr_bank = cpumask_to_vp_set(flush, cpus);
+ }
+
+ /*
+ * We can flush not more than max_gvas with one hypercall. Flush the
+ * whole address space if we were asked to do more.
+ */
+ max_gvas = (PAGE_SIZE - sizeof(*flush) - nr_bank*8) / 8;
+
+ if (end == TLB_FLUSH_ALL) {
+ flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
+ 0, nr_bank + 2, flush, NULL);
+ } else if (end && ((end - start)/HV_TLB_FLUSH_UNIT) > max_gvas) {
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
+ 0, nr_bank + 2, flush, NULL);
+ } else {
+ cur = start;
+ gva_n = nr_bank;
+ do {
+ flush->gva_list[gva_n] = cur & PAGE_MASK;
+ /*
+ * Lower 12 bits encode the number of additional
+ * pages to flush (in addition to the 'cur' page).
+ */
+ if (end >= cur + HV_TLB_FLUSH_UNIT)
+ flush->gva_list[gva_n] |= ~PAGE_MASK;
+ else if (end > cur)
+ flush->gva_list[gva_n] |=
+ (end - cur - 1) >> PAGE_SHIFT;
+
+ cur += HV_TLB_FLUSH_UNIT;
+ ++gva_n;
+
+ } while (cur < end);
+
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX,
+ gva_n, nr_bank + 2, flush, NULL);
+ }
+
+ local_irq_restore(flags);
+
+ if (!(status & 0xffff))
+ return;
+do_native:
+ native_flush_tlb_others(cpus, mm, start, end);
+}
+
void hyperv_setup_mmu_ops(void)
{
- if (ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED) {
+ if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
+ return;
+
+ if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) {
pr_info("Hyper-V: Using hypercall for remote TLB flush\n");
pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others;
+ } else {
+ pr_info("Hyper-V: Using ext hypercall for remote TLB flush\n");
+ pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others_ex;
}
}
void hyper_alloc_mmu(void)
{
- if (ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED)
+ if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
+ return;
+
+ if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
pcpu_flush = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
+ else
+ pcpu_flush_ex = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
}
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h
index 38808f1..a177517 100644
--- a/arch/x86/include/uapi/asm/hyperv.h
+++ b/arch/x86/include/uapi/asm/hyperv.h
@@ -152,6 +152,9 @@
*/
#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9)
+/* Recommend using the newer ExProcessorMasks interface */
+#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11)
+
/*
* Crash notification flag.
*/
@@ -242,6 +245,8 @@
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003
#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014
#define HVCALL_POST_MESSAGE 0x005c
#define HVCALL_SIGNAL_EVENT 0x005d
@@ -263,6 +268,11 @@
#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY 0x00000004
#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT 0x00000008
+enum HV_GENERIC_SET_FORMAT {
+ HV_GENERIC_SET_SPARCE_4K,
+ HV_GENERIC_SET_ALL,
+};
+
/* hypercall status code */
#define HV_STATUS_SUCCESS 0
#define HV_STATUS_INVALID_HYPERCALL_CODE 2
--
2.9.4
[toc] | [next] | [standalone]
| From | Andy Shevchenko <andy.shevchenko@gmail.com> |
|---|---|
| Date | 2017-05-30 19:10 +0200 |
| Subject | Re: [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls |
| Message-ID | <tMSOB-1GK-1@gated-at.bofh.it> |
| In reply to | #1653139 |
On Tue, May 30, 2017 at 2:34 PM, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> Hyper-V hosts may support more than 64 vCPUs, we need to use
> HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX/LIST_EX hypercalls in this
> case.
> +/* HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressListEx hypercalls */
> +struct hv_flush_pcpu_ex {
> + __u64 address_space;
> + __u64 flags;
> + struct {
> + __u64 format;
> + __u64 valid_bank_mask;
> + __u64 bank_contents[];
> + } hv_vp_set;
> + __u64 gva_list[];
> +};
Same question about use of uXX vs __uXX types.
> +static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
> + struct mm_struct *mm,
> + unsigned long start,
> + unsigned long end)
> +{
> + struct hv_flush_pcpu_ex *flush;
> + unsigned long cur, flags;
> + u64 status = U64_MAX;
> + int nr_bank = 0, max_gvas, gva_n;
> +
> + if (!pcpu_flush_ex || !hv_hypercall_pg)
> + goto do_native;
> +
> + if (cpumask_empty(cpus))
> + return;
> +
> + local_irq_save(flags);
> +
> + flush = this_cpu_ptr(pcpu_flush_ex);
> +
> + if (mm) {
> + flush->address_space = virt_to_phys(mm->pgd);
(u64), phys_addr_t is arch-dependent.
> + flush->flags = 0;
> + } else {
> + flush->address_space = 0;
> + flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
> + }
> +
> + flush->hv_vp_set.valid_bank_mask = 0;
> +
> + if (cpumask_equal(cpus, cpu_present_mask)) {
> + flush->hv_vp_set.format = HV_GENERIC_SET_ALL;
> + flush->flags |= HV_FLUSH_ALL_PROCESSORS;
> + } else {
> + flush->hv_vp_set.format = HV_GENERIC_SET_SPARCE_4K;
> + nr_bank = cpumask_to_vp_set(flush, cpus);
> + }
> +
> + /*
> + * We can flush not more than max_gvas with one hypercall. Flush the
> + * whole address space if we were asked to do more.
> + */
> + max_gvas = (PAGE_SIZE - sizeof(*flush) - nr_bank*8) / 8;
> +
> + if (end == TLB_FLUSH_ALL) {
> + flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
> + status = hv_do_rep_hypercall(
> + HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
> + 0, nr_bank + 2, flush, NULL);
> + } else if (end && ((end - start)/HV_TLB_FLUSH_UNIT) > max_gvas) {
> + status = hv_do_rep_hypercall(
> + HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
> + 0, nr_bank + 2, flush, NULL);
> + } else {
> + cur = start;
> + gva_n = nr_bank;
> + do {
> + flush->gva_list[gva_n] = cur & PAGE_MASK;
> + /*
> + * Lower 12 bits encode the number of additional
> + * pages to flush (in addition to the 'cur' page).
> + */
> + if (end >= cur + HV_TLB_FLUSH_UNIT)
> + flush->gva_list[gva_n] |= ~PAGE_MASK;
> + else if (end > cur)
> + flush->gva_list[gva_n] |=
> + (end - cur - 1) >> PAGE_SHIFT;
> +
> + cur += HV_TLB_FLUSH_UNIT;
> + ++gva_n;
Same comments as per previous similar code.
Moreover, since it's similar, can it have some common code shared?
> +
> + } while (cur < end);
> +
> + status = hv_do_rep_hypercall(
> + HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX,
> + gva_n, nr_bank + 2, flush, NULL);
> + }
> +
> + local_irq_restore(flags);
> +
> + if (!(status & 0xffff))
Magic.
--
With Best Regards,
Andy Shevchenko
[toc] | [prev] | [next] | [standalone]
| From | Jork Loeser <Jork.Loeser@microsoft.com> |
|---|---|
| Date | 2017-05-30 21:20 +0200 |
| Subject | RE: [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls |
| Message-ID | <tMUQq-2TU-21@gated-at.bofh.it> |
| In reply to | #1653139 |
> -----Original Message-----
> From: Vitaly Kuznetsov [mailto:vkuznets@redhat.com]
> Sent: Tuesday, May 30, 2017 04:34
> To: x86@kernel.org; devel@linuxdriverproject.org
> Cc: linux-kernel@vger.kernel.org; KY Srinivasan <kys@microsoft.com>; Haiyang
> Zhang <haiyangz@microsoft.com>; Stephen Hemminger
> <sthemmin@microsoft.com>; Thomas Gleixner <tglx@linutronix.de>; Ingo
> Molnar <mingo@redhat.com>; H. Peter Anvin <hpa@zytor.com>; Steven
> Rostedt <rostedt@goodmis.org>; Jork Loeser <Jork.Loeser@microsoft.com>;
> Simon Xiao <sixiao@microsoft.com>; Andy Lutomirski <luto@kernel.org>; Andy
> Shevchenko <andy.shevchenko@gmail.com>
> Subject: [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB
> flush hypercalls
>
> Hyper-V hosts may support more than 64 vCPUs, we need to use
> HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX/LIST_EX hypercalls in this case.
> +static inline int cpumask_to_vp_set(struct hv_flush_pcpu_ex *flush,
> + const struct cpumask *cpus)
> +{
> + int cpu, vcpu, vcpu_bank, vcpu_offset, cur_bank, nr_bank = 0;
> + bool has_cpus;
> +
> + /*
> + * We can't be sure that translated vCPU numbers will always be
> + * in ascending order, so iterate over all possible banks and
> + * check all vCPUs in it instead.
> + */
> + for (cur_bank = 0; cur_bank < ms_hyperv.max_vp_index/64;
> cur_bank++) {
> + has_cpus = false;
> + for_each_cpu(cpu, cpus) {
> + vcpu = hv_cpu_number_to_vp_number(cpu);
> + vcpu_bank = vcpu / 64;
> + vcpu_offset = vcpu % 64;
> +
> + if (vcpu_bank != cur_bank)
> + continue;
> + __set_bit(vcpu_offset, (unsigned long *)
> + &flush->hv_vp_set.bank_contents[nr_bank]);
> + if (!has_cpus) {
> + __set_bit(vcpu_bank, (unsigned long *)
> + &flush->hv_vp_set.valid_bank_mask);
> + has_cpus = true;
> + }
> + }
> + if (has_cpus)
> + nr_bank++;
> + }
> +
> + return nr_bank;
> +}
Note that the HV_VP_SET may contain empty banks. As such, consider enabling all (5) bits in the valid_bank_mask, and a single for_each(cpu, cpus) pass - setting the bits as per hv_cpu_number_to_vp_number(cpu).
Regards,
Jork
[toc] | [prev] | [next] | [standalone]
| From | Vitaly Kuznetsov <vkuznets@redhat.com> |
|---|---|
| Date | 2017-05-31 17:10 +0200 |
| Message-ID | <tNdq1-6tw-1@gated-at.bofh.it> |
| In reply to | #1653513 |
Jork Loeser <Jork.Loeser@microsoft.com> writes:
>> -----Original Message-----
>> From: Vitaly Kuznetsov [mailto:vkuznets@redhat.com]
>> Sent: Tuesday, May 30, 2017 04:34
>> To: x86@kernel.org; devel@linuxdriverproject.org
>> Cc: linux-kernel@vger.kernel.org; KY Srinivasan <kys@microsoft.com>; Haiyang
>> Zhang <haiyangz@microsoft.com>; Stephen Hemminger
>> <sthemmin@microsoft.com>; Thomas Gleixner <tglx@linutronix.de>; Ingo
>> Molnar <mingo@redhat.com>; H. Peter Anvin <hpa@zytor.com>; Steven
>> Rostedt <rostedt@goodmis.org>; Jork Loeser <Jork.Loeser@microsoft.com>;
>> Simon Xiao <sixiao@microsoft.com>; Andy Lutomirski <luto@kernel.org>; Andy
>> Shevchenko <andy.shevchenko@gmail.com>
>> Subject: [PATCH v5 09/10] x86/hyper-v: support extended CPU ranges for TLB
>> flush hypercalls
>>
>> Hyper-V hosts may support more than 64 vCPUs, we need to use
>> HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX/LIST_EX hypercalls in this case.
>
>> +static inline int cpumask_to_vp_set(struct hv_flush_pcpu_ex *flush,
>> + const struct cpumask *cpus)
>> +{
>> + int cpu, vcpu, vcpu_bank, vcpu_offset, cur_bank, nr_bank = 0;
>> + bool has_cpus;
>> +
>> + /*
>> + * We can't be sure that translated vCPU numbers will always be
>> + * in ascending order, so iterate over all possible banks and
>> + * check all vCPUs in it instead.
>> + */
>> + for (cur_bank = 0; cur_bank < ms_hyperv.max_vp_index/64;
>> cur_bank++) {
>> + has_cpus = false;
>> + for_each_cpu(cpu, cpus) {
>> + vcpu = hv_cpu_number_to_vp_number(cpu);
>> + vcpu_bank = vcpu / 64;
>> + vcpu_offset = vcpu % 64;
>> +
>> + if (vcpu_bank != cur_bank)
>> + continue;
>> + __set_bit(vcpu_offset, (unsigned long *)
>> + &flush->hv_vp_set.bank_contents[nr_bank]);
>> + if (!has_cpus) {
>> + __set_bit(vcpu_bank, (unsigned long *)
>> + &flush->hv_vp_set.valid_bank_mask);
>> + has_cpus = true;
>> + }
>> + }
>> + if (has_cpus)
>> + nr_bank++;
>> + }
>> +
>> + return nr_bank;
>> +}
>
> Note that the HV_VP_SET may contain empty banks. As such, consider
> enabling all (5) bits in the valid_bank_mask, and a single
> for_each(cpu, cpus) pass - setting the bits as per
> hv_cpu_number_to_vp_number(cpu).
>
Oh, I didn't know that! I'll switch to doing a single
pass. Unfortunately I have no Hyper-V setup with > 64 vCPUs so I can't
really test if it works or not (I mean empty banks, *_EX hypercalls
work).
--
Vitaly
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web