xref: /openbmc/linux/arch/x86/hyperv/mmu.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12ffd9e33SVitaly Kuznetsov #define pr_fmt(fmt)  "Hyper-V: " fmt
22ffd9e33SVitaly Kuznetsov 
32ffd9e33SVitaly Kuznetsov #include <linux/hyperv.h>
42ffd9e33SVitaly Kuznetsov #include <linux/log2.h>
52ffd9e33SVitaly Kuznetsov #include <linux/slab.h>
62ffd9e33SVitaly Kuznetsov #include <linux/types.h>
72ffd9e33SVitaly Kuznetsov 
82ffd9e33SVitaly Kuznetsov #include <asm/fpu/api.h>
92ffd9e33SVitaly Kuznetsov #include <asm/mshyperv.h>
102ffd9e33SVitaly Kuznetsov #include <asm/msr.h>
112ffd9e33SVitaly Kuznetsov #include <asm/tlbflush.h>
1248a8b97cSPeter Zijlstra #include <asm/tlb.h>
132ffd9e33SVitaly Kuznetsov 
14773b79f7SVitaly Kuznetsov #define CREATE_TRACE_POINTS
15773b79f7SVitaly Kuznetsov #include <asm/trace/hyperv.h>
16773b79f7SVitaly Kuznetsov 
172ffd9e33SVitaly Kuznetsov /* Each gva in gva_list encodes up to 4096 pages to flush */
182ffd9e33SVitaly Kuznetsov #define HV_TLB_FLUSH_UNIT (4096 * PAGE_SIZE)
192ffd9e33SVitaly Kuznetsov 
200e4c88f3SVitaly Kuznetsov static u64 hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
210e4c88f3SVitaly Kuznetsov 				      const struct flush_tlb_info *info);
22628f54ccSVitaly Kuznetsov 
232ffd9e33SVitaly Kuznetsov /*
242ffd9e33SVitaly Kuznetsov  * Fills in gva_list starting from offset. Returns the number of items added.
252ffd9e33SVitaly Kuznetsov  */
fill_gva_list(u64 gva_list[],int offset,unsigned long start,unsigned long end)262ffd9e33SVitaly Kuznetsov static inline int fill_gva_list(u64 gva_list[], int offset,
272ffd9e33SVitaly Kuznetsov 				unsigned long start, unsigned long end)
282ffd9e33SVitaly Kuznetsov {
292ffd9e33SVitaly Kuznetsov 	int gva_n = offset;
302ffd9e33SVitaly Kuznetsov 	unsigned long cur = start, diff;
312ffd9e33SVitaly Kuznetsov 
322ffd9e33SVitaly Kuznetsov 	do {
332ffd9e33SVitaly Kuznetsov 		diff = end > cur ? end - cur : 0;
342ffd9e33SVitaly Kuznetsov 
352ffd9e33SVitaly Kuznetsov 		gva_list[gva_n] = cur & PAGE_MASK;
362ffd9e33SVitaly Kuznetsov 		/*
372ffd9e33SVitaly Kuznetsov 		 * Lower 12 bits encode the number of additional
382ffd9e33SVitaly Kuznetsov 		 * pages to flush (in addition to the 'cur' page).
392ffd9e33SVitaly Kuznetsov 		 */
404030b4c5STianyu Lan 		if (diff >= HV_TLB_FLUSH_UNIT) {
412ffd9e33SVitaly Kuznetsov 			gva_list[gva_n] |= ~PAGE_MASK;
422ffd9e33SVitaly Kuznetsov 			cur += HV_TLB_FLUSH_UNIT;
434030b4c5STianyu Lan 		}  else if (diff) {
444030b4c5STianyu Lan 			gva_list[gva_n] |= (diff - 1) >> PAGE_SHIFT;
454030b4c5STianyu Lan 			cur = end;
464030b4c5STianyu Lan 		}
474030b4c5STianyu Lan 
482ffd9e33SVitaly Kuznetsov 		gva_n++;
492ffd9e33SVitaly Kuznetsov 
502ffd9e33SVitaly Kuznetsov 	} while (cur < end);
512ffd9e33SVitaly Kuznetsov 
522ffd9e33SVitaly Kuznetsov 	return gva_n - offset;
532ffd9e33SVitaly Kuznetsov }
542ffd9e33SVitaly Kuznetsov 
cpu_is_lazy(int cpu)55493cc073SMichael Kelley static bool cpu_is_lazy(int cpu)
56493cc073SMichael Kelley {
57493cc073SMichael Kelley 	return per_cpu(cpu_tlbstate_shared.is_lazy, cpu);
58493cc073SMichael Kelley }
59493cc073SMichael Kelley 
hyperv_flush_tlb_multi(const struct cpumask * cpus,const struct flush_tlb_info * info)604ce94eabSNadav Amit static void hyperv_flush_tlb_multi(const struct cpumask *cpus,
612ffd9e33SVitaly Kuznetsov 				   const struct flush_tlb_info *info)
622ffd9e33SVitaly Kuznetsov {
632ffd9e33SVitaly Kuznetsov 	int cpu, vcpu, gva_n, max_gvas;
64c9c92beeSVitaly Kuznetsov 	struct hv_tlb_flush *flush;
65753ed9c9SJoseph Salisbury 	u64 status;
662ffd9e33SVitaly Kuznetsov 	unsigned long flags;
67493cc073SMichael Kelley 	bool do_lazy = !info->freed_tables;
682ffd9e33SVitaly Kuznetsov 
694ce94eabSNadav Amit 	trace_hyperv_mmu_flush_tlb_multi(cpus, info);
70773b79f7SVitaly Kuznetsov 
719a2d78e2SK. Y. Srinivasan 	if (!hv_hypercall_pg)
722ffd9e33SVitaly Kuznetsov 		goto do_native;
732ffd9e33SVitaly Kuznetsov 
742ffd9e33SVitaly Kuznetsov 	local_irq_save(flags);
752ffd9e33SVitaly Kuznetsov 
76*55e544e1SNischala Yelchuri 	flush = *this_cpu_ptr(hyperv_pcpu_input_arg);
7760d73a7cSVitaly Kuznetsov 
7860d73a7cSVitaly Kuznetsov 	if (unlikely(!flush)) {
7960d73a7cSVitaly Kuznetsov 		local_irq_restore(flags);
8060d73a7cSVitaly Kuznetsov 		goto do_native;
8160d73a7cSVitaly Kuznetsov 	}
822ffd9e33SVitaly Kuznetsov 
832ffd9e33SVitaly Kuznetsov 	if (info->mm) {
84617ab45cSVitaly Kuznetsov 		/*
85617ab45cSVitaly Kuznetsov 		 * AddressSpace argument must match the CR3 with PCID bits
86617ab45cSVitaly Kuznetsov 		 * stripped out.
87617ab45cSVitaly Kuznetsov 		 */
882ffd9e33SVitaly Kuznetsov 		flush->address_space = virt_to_phys(info->mm->pgd);
89617ab45cSVitaly Kuznetsov 		flush->address_space &= CR3_ADDR_MASK;
902ffd9e33SVitaly Kuznetsov 		flush->flags = 0;
912ffd9e33SVitaly Kuznetsov 	} else {
922ffd9e33SVitaly Kuznetsov 		flush->address_space = 0;
932ffd9e33SVitaly Kuznetsov 		flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
942ffd9e33SVitaly Kuznetsov 	}
952ffd9e33SVitaly Kuznetsov 
962ffd9e33SVitaly Kuznetsov 	flush->processor_mask = 0;
972ffd9e33SVitaly Kuznetsov 	if (cpumask_equal(cpus, cpu_present_mask)) {
982ffd9e33SVitaly Kuznetsov 		flush->flags |= HV_FLUSH_ALL_PROCESSORS;
992ffd9e33SVitaly Kuznetsov 	} else {
1000e4c88f3SVitaly Kuznetsov 		/*
1010e4c88f3SVitaly Kuznetsov 		 * From the supplied CPU set we need to figure out if we can get
1020e4c88f3SVitaly Kuznetsov 		 * away with cheaper HVCALL_FLUSH_VIRTUAL_ADDRESS_{LIST,SPACE}
1030e4c88f3SVitaly Kuznetsov 		 * hypercalls. This is possible when the highest VP number in
1040e4c88f3SVitaly Kuznetsov 		 * the set is < 64. As VP numbers are usually in ascending order
1050e4c88f3SVitaly Kuznetsov 		 * and match Linux CPU ids, here is an optimization: we check
1060e4c88f3SVitaly Kuznetsov 		 * the VP number for the highest bit in the supplied set first
1070e4c88f3SVitaly Kuznetsov 		 * so we can quickly find out if using *_EX hypercalls is a
1080e4c88f3SVitaly Kuznetsov 		 * must. We will also check all VP numbers when walking the
1090e4c88f3SVitaly Kuznetsov 		 * supplied CPU set to remain correct in all cases.
1100e4c88f3SVitaly Kuznetsov 		 */
11151500b71SVitaly Kuznetsov 		cpu = cpumask_last(cpus);
11251500b71SVitaly Kuznetsov 
11351500b71SVitaly Kuznetsov 		if (cpu < nr_cpumask_bits && hv_cpu_number_to_vp_number(cpu) >= 64)
1140e4c88f3SVitaly Kuznetsov 			goto do_ex_hypercall;
1150e4c88f3SVitaly Kuznetsov 
1162ffd9e33SVitaly Kuznetsov 		for_each_cpu(cpu, cpus) {
117493cc073SMichael Kelley 			if (do_lazy && cpu_is_lazy(cpu))
118493cc073SMichael Kelley 				continue;
1192ffd9e33SVitaly Kuznetsov 			vcpu = hv_cpu_number_to_vp_number(cpu);
120110d2a7fSVitaly Kuznetsov 			if (vcpu == VP_INVAL) {
121110d2a7fSVitaly Kuznetsov 				local_irq_restore(flags);
122110d2a7fSVitaly Kuznetsov 				goto do_native;
123110d2a7fSVitaly Kuznetsov 			}
124110d2a7fSVitaly Kuznetsov 
1252ffd9e33SVitaly Kuznetsov 			if (vcpu >= 64)
1260e4c88f3SVitaly Kuznetsov 				goto do_ex_hypercall;
1272ffd9e33SVitaly Kuznetsov 
1282ffd9e33SVitaly Kuznetsov 			__set_bit(vcpu, (unsigned long *)
1292ffd9e33SVitaly Kuznetsov 				  &flush->processor_mask);
1302ffd9e33SVitaly Kuznetsov 		}
13151500b71SVitaly Kuznetsov 
13251500b71SVitaly Kuznetsov 		/* nothing to flush if 'processor_mask' ends up being empty */
13351500b71SVitaly Kuznetsov 		if (!flush->processor_mask) {
13451500b71SVitaly Kuznetsov 			local_irq_restore(flags);
13551500b71SVitaly Kuznetsov 			return;
13651500b71SVitaly Kuznetsov 		}
1372ffd9e33SVitaly Kuznetsov 	}
1382ffd9e33SVitaly Kuznetsov 
1392ffd9e33SVitaly Kuznetsov 	/*
1402ffd9e33SVitaly Kuznetsov 	 * We can flush not more than max_gvas with one hypercall. Flush the
1412ffd9e33SVitaly Kuznetsov 	 * whole address space if we were asked to do more.
1422ffd9e33SVitaly Kuznetsov 	 */
1432ffd9e33SVitaly Kuznetsov 	max_gvas = (PAGE_SIZE - sizeof(*flush)) / sizeof(flush->gva_list[0]);
1442ffd9e33SVitaly Kuznetsov 
1452ffd9e33SVitaly Kuznetsov 	if (info->end == TLB_FLUSH_ALL) {
1462ffd9e33SVitaly Kuznetsov 		flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
1472ffd9e33SVitaly Kuznetsov 		status = hv_do_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE,
1482ffd9e33SVitaly Kuznetsov 					 flush, NULL);
1492ffd9e33SVitaly Kuznetsov 	} else if (info->end &&
1502ffd9e33SVitaly Kuznetsov 		   ((info->end - info->start)/HV_TLB_FLUSH_UNIT) > max_gvas) {
1512ffd9e33SVitaly Kuznetsov 		status = hv_do_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE,
1522ffd9e33SVitaly Kuznetsov 					 flush, NULL);
1532ffd9e33SVitaly Kuznetsov 	} else {
1542ffd9e33SVitaly Kuznetsov 		gva_n = fill_gva_list(flush->gva_list, 0,
1552ffd9e33SVitaly Kuznetsov 				      info->start, info->end);
1562ffd9e33SVitaly Kuznetsov 		status = hv_do_rep_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST,
1572ffd9e33SVitaly Kuznetsov 					     gva_n, 0, flush, NULL);
1582ffd9e33SVitaly Kuznetsov 	}
1590e4c88f3SVitaly Kuznetsov 	goto check_status;
1602ffd9e33SVitaly Kuznetsov 
1610e4c88f3SVitaly Kuznetsov do_ex_hypercall:
1620e4c88f3SVitaly Kuznetsov 	status = hyperv_flush_tlb_others_ex(cpus, info);
1630e4c88f3SVitaly Kuznetsov 
1640e4c88f3SVitaly Kuznetsov check_status:
1652ffd9e33SVitaly Kuznetsov 	local_irq_restore(flags);
1662ffd9e33SVitaly Kuznetsov 
167753ed9c9SJoseph Salisbury 	if (hv_result_success(status))
1682ffd9e33SVitaly Kuznetsov 		return;
1692ffd9e33SVitaly Kuznetsov do_native:
1704ce94eabSNadav Amit 	native_flush_tlb_multi(cpus, info);
1712ffd9e33SVitaly Kuznetsov }
1722ffd9e33SVitaly Kuznetsov 
hyperv_flush_tlb_others_ex(const struct cpumask * cpus,const struct flush_tlb_info * info)1730e4c88f3SVitaly Kuznetsov static u64 hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
174628f54ccSVitaly Kuznetsov 				      const struct flush_tlb_info *info)
175628f54ccSVitaly Kuznetsov {
176628f54ccSVitaly Kuznetsov 	int nr_bank = 0, max_gvas, gva_n;
177c9c92beeSVitaly Kuznetsov 	struct hv_tlb_flush_ex *flush;
1780e4c88f3SVitaly Kuznetsov 	u64 status;
179628f54ccSVitaly Kuznetsov 
1800e4c88f3SVitaly Kuznetsov 	if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
181753ed9c9SJoseph Salisbury 		return HV_STATUS_INVALID_PARAMETER;
182628f54ccSVitaly Kuznetsov 
183*55e544e1SNischala Yelchuri 	flush = *this_cpu_ptr(hyperv_pcpu_input_arg);
18460d73a7cSVitaly Kuznetsov 
185628f54ccSVitaly Kuznetsov 	if (info->mm) {
186617ab45cSVitaly Kuznetsov 		/*
187617ab45cSVitaly Kuznetsov 		 * AddressSpace argument must match the CR3 with PCID bits
188617ab45cSVitaly Kuznetsov 		 * stripped out.
189617ab45cSVitaly Kuznetsov 		 */
190628f54ccSVitaly Kuznetsov 		flush->address_space = virt_to_phys(info->mm->pgd);
191617ab45cSVitaly Kuznetsov 		flush->address_space &= CR3_ADDR_MASK;
192628f54ccSVitaly Kuznetsov 		flush->flags = 0;
193628f54ccSVitaly Kuznetsov 	} else {
194628f54ccSVitaly Kuznetsov 		flush->address_space = 0;
195628f54ccSVitaly Kuznetsov 		flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
196628f54ccSVitaly Kuznetsov 	}
197628f54ccSVitaly Kuznetsov 
198628f54ccSVitaly Kuznetsov 	flush->hv_vp_set.valid_bank_mask = 0;
199628f54ccSVitaly Kuznetsov 
200366f03b0SK. Y. Srinivasan 	flush->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
201493cc073SMichael Kelley 	nr_bank = cpumask_to_vpset_skip(&flush->hv_vp_set, cpus,
202493cc073SMichael Kelley 			info->freed_tables ? NULL : cpu_is_lazy);
2030f0caa52SVitaly Kuznetsov 	if (nr_bank < 0)
204753ed9c9SJoseph Salisbury 		return HV_STATUS_INVALID_PARAMETER;
205628f54ccSVitaly Kuznetsov 
206628f54ccSVitaly Kuznetsov 	/*
207628f54ccSVitaly Kuznetsov 	 * We can flush not more than max_gvas with one hypercall. Flush the
208628f54ccSVitaly Kuznetsov 	 * whole address space if we were asked to do more.
209628f54ccSVitaly Kuznetsov 	 */
210628f54ccSVitaly Kuznetsov 	max_gvas =
211628f54ccSVitaly Kuznetsov 		(PAGE_SIZE - sizeof(*flush) - nr_bank *
212628f54ccSVitaly Kuznetsov 		 sizeof(flush->hv_vp_set.bank_contents[0])) /
213628f54ccSVitaly Kuznetsov 		sizeof(flush->gva_list[0]);
214628f54ccSVitaly Kuznetsov 
215628f54ccSVitaly Kuznetsov 	if (info->end == TLB_FLUSH_ALL) {
216628f54ccSVitaly Kuznetsov 		flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
217628f54ccSVitaly Kuznetsov 		status = hv_do_rep_hypercall(
218628f54ccSVitaly Kuznetsov 			HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
219ab7ff471SMarcelo Henrique Cerri 			0, nr_bank, flush, NULL);
220628f54ccSVitaly Kuznetsov 	} else if (info->end &&
221628f54ccSVitaly Kuznetsov 		   ((info->end - info->start)/HV_TLB_FLUSH_UNIT) > max_gvas) {
222628f54ccSVitaly Kuznetsov 		status = hv_do_rep_hypercall(
223628f54ccSVitaly Kuznetsov 			HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
224ab7ff471SMarcelo Henrique Cerri 			0, nr_bank, flush, NULL);
225628f54ccSVitaly Kuznetsov 	} else {
226628f54ccSVitaly Kuznetsov 		gva_n = fill_gva_list(flush->gva_list, nr_bank,
227628f54ccSVitaly Kuznetsov 				      info->start, info->end);
228628f54ccSVitaly Kuznetsov 		status = hv_do_rep_hypercall(
229628f54ccSVitaly Kuznetsov 			HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX,
230ab7ff471SMarcelo Henrique Cerri 			gva_n, nr_bank, flush, NULL);
231628f54ccSVitaly Kuznetsov 	}
232628f54ccSVitaly Kuznetsov 
2330e4c88f3SVitaly Kuznetsov 	return status;
234628f54ccSVitaly Kuznetsov }
235628f54ccSVitaly Kuznetsov 
hyperv_setup_mmu_ops(void)2362ffd9e33SVitaly Kuznetsov void hyperv_setup_mmu_ops(void)
2372ffd9e33SVitaly Kuznetsov {
238628f54ccSVitaly Kuznetsov 	if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
239628f54ccSVitaly Kuznetsov 		return;
240628f54ccSVitaly Kuznetsov 
2412ffd9e33SVitaly Kuznetsov 	pr_info("Using hypercall for remote TLB flush\n");
2424ce94eabSNadav Amit 	pv_ops.mmu.flush_tlb_multi = hyperv_flush_tlb_multi;
2435c83511bSJuergen Gross 	pv_ops.mmu.tlb_remove_table = tlb_remove_table;
2442ffd9e33SVitaly Kuznetsov }
245