Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 platform updates from Ingo Molnar: "The main changes include various Hyper-V optimizations such as faster hypercalls and faster/better TLB flushes - and there's also some Intel-MID cleanups" * 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: tracing/hyper-v: Trace hyperv_mmu_flush_tlb_others() x86/hyper-v: Support extended CPU ranges for TLB flush hypercalls x86/platform/intel-mid: Make several arrays static, to make code smaller MAINTAINERS: Add missed file for Hyper-V x86/hyper-v: Use hypercall for remote TLB flush hyper-v: Globalize vp_index x86/hyper-v: Implement rep hypercalls hyper-v: Use fast hypercall for HVCALL_SIGNAL_EVENT x86/hyper-v: Introduce fast hypercall implementation x86/hyper-v: Make hv_do_hypercall() inline x86/hyper-v: Include hyperv/ only when CONFIG_HYPERV is set x86/platform/intel-mid: Make 'bt_sfi_data' const x86/platform/intel-mid: Make IRQ allocation a bit more flexible x86/platform/intel-mid: Group timers callbacks together
This commit is contained in:
commit
57e88b43b8
|
@ -6312,6 +6312,7 @@ L: devel@linuxdriverproject.org
|
|||
S: Maintained
|
||||
F: Documentation/networking/netvsc.txt
|
||||
F: arch/x86/include/asm/mshyperv.h
|
||||
F: arch/x86/include/asm/trace/hyperv.h
|
||||
F: arch/x86/include/uapi/asm/hyperv.h
|
||||
F: arch/x86/kernel/cpu/mshyperv.c
|
||||
F: arch/x86/hyperv
|
||||
|
@ -6325,6 +6326,7 @@ F: drivers/uio/uio_hv_generic.c
|
|||
F: drivers/video/fbdev/hyperv_fb.c
|
||||
F: net/vmw_vsock/hyperv_transport.c
|
||||
F: include/linux/hyperv.h
|
||||
F: include/uapi/linux/hyperv.h
|
||||
F: tools/hv/
|
||||
F: Documentation/ABI/stable/sysfs-bus-vmbus
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ obj-$(CONFIG_KVM) += kvm/
|
|||
obj-$(CONFIG_XEN) += xen/
|
||||
|
||||
# Hyper-V paravirtualization support
|
||||
obj-$(CONFIG_HYPERVISOR_GUEST) += hyperv/
|
||||
obj-$(subst m,y,$(CONFIG_HYPERV)) += hyperv/
|
||||
|
||||
obj-y += realmode/
|
||||
obj-y += kernel/
|
||||
|
|
|
@ -1 +1 @@
|
|||
obj-y := hv_init.o
|
||||
obj-y := hv_init.o mmu.o
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
|
||||
#ifdef CONFIG_HYPERV_TSCPAGE
|
||||
|
||||
|
@ -75,10 +77,25 @@ static struct clocksource hyperv_cs_msr = {
|
|||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
};
|
||||
|
||||
static void *hypercall_pg;
|
||||
void *hv_hypercall_pg;
|
||||
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
|
||||
struct clocksource *hyperv_cs;
|
||||
EXPORT_SYMBOL_GPL(hyperv_cs);
|
||||
|
||||
u32 *hv_vp_index;
|
||||
EXPORT_SYMBOL_GPL(hv_vp_index);
|
||||
|
||||
static int hv_cpu_init(unsigned int cpu)
|
||||
{
|
||||
u64 msr_vp_index;
|
||||
|
||||
hv_get_vp_index(msr_vp_index);
|
||||
|
||||
hv_vp_index[smp_processor_id()] = msr_vp_index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is to be invoked early in the boot sequence after the
|
||||
* hypervisor has been detected.
|
||||
|
@ -94,6 +111,16 @@ void hyperv_init(void)
|
|||
if (x86_hyper != &x86_hyper_ms_hyperv)
|
||||
return;
|
||||
|
||||
/* Allocate percpu VP index */
|
||||
hv_vp_index = kmalloc_array(num_possible_cpus(), sizeof(*hv_vp_index),
|
||||
GFP_KERNEL);
|
||||
if (!hv_vp_index)
|
||||
return;
|
||||
|
||||
if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
|
||||
hv_cpu_init, NULL) < 0)
|
||||
goto free_vp_index;
|
||||
|
||||
/*
|
||||
* Setup the hypercall page and enable hypercalls.
|
||||
* 1. Register the guest ID
|
||||
|
@ -102,17 +129,19 @@ void hyperv_init(void)
|
|||
guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
|
||||
wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
|
||||
|
||||
hypercall_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
|
||||
if (hypercall_pg == NULL) {
|
||||
hv_hypercall_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
|
||||
if (hv_hypercall_pg == NULL) {
|
||||
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
|
||||
return;
|
||||
goto free_vp_index;
|
||||
}
|
||||
|
||||
rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
||||
hypercall_msr.enable = 1;
|
||||
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hypercall_pg);
|
||||
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
|
||||
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
||||
|
||||
hyper_alloc_mmu();
|
||||
|
||||
/*
|
||||
* Register Hyper-V specific clocksource.
|
||||
*/
|
||||
|
@ -148,6 +177,12 @@ register_msr_cs:
|
|||
hyperv_cs = &hyperv_cs_msr;
|
||||
if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
|
||||
clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100);
|
||||
|
||||
return;
|
||||
|
||||
free_vp_index:
|
||||
kfree(hv_vp_index);
|
||||
hv_vp_index = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -170,51 +205,6 @@ void hyperv_cleanup(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(hyperv_cleanup);
|
||||
|
||||
/*
|
||||
* hv_do_hypercall- Invoke the specified hypercall
|
||||
*/
|
||||
u64 hv_do_hypercall(u64 control, void *input, void *output)
|
||||
{
|
||||
u64 input_address = (input) ? virt_to_phys(input) : 0;
|
||||
u64 output_address = (output) ? virt_to_phys(output) : 0;
|
||||
#ifdef CONFIG_X86_64
|
||||
u64 hv_status = 0;
|
||||
|
||||
if (!hypercall_pg)
|
||||
return (u64)ULLONG_MAX;
|
||||
|
||||
__asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
|
||||
__asm__ __volatile__("call *%3" : "=a" (hv_status) :
|
||||
"c" (control), "d" (input_address),
|
||||
"m" (hypercall_pg));
|
||||
|
||||
return hv_status;
|
||||
|
||||
#else
|
||||
|
||||
u32 control_hi = control >> 32;
|
||||
u32 control_lo = control & 0xFFFFFFFF;
|
||||
u32 hv_status_hi = 1;
|
||||
u32 hv_status_lo = 1;
|
||||
u32 input_address_hi = input_address >> 32;
|
||||
u32 input_address_lo = input_address & 0xFFFFFFFF;
|
||||
u32 output_address_hi = output_address >> 32;
|
||||
u32 output_address_lo = output_address & 0xFFFFFFFF;
|
||||
|
||||
if (!hypercall_pg)
|
||||
return (u64)ULLONG_MAX;
|
||||
|
||||
__asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
|
||||
"=a"(hv_status_lo) : "d" (control_hi),
|
||||
"a" (control_lo), "b" (input_address_hi),
|
||||
"c" (input_address_lo), "D"(output_address_hi),
|
||||
"S"(output_address_lo), "m" (hypercall_pg));
|
||||
|
||||
return hv_status_lo | ((u64)hv_status_hi << 32);
|
||||
#endif /* !x86_64 */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_do_hypercall);
|
||||
|
||||
void hyperv_report_panic(struct pt_regs *regs)
|
||||
{
|
||||
static bool panic_reported;
|
||||
|
|
272
arch/x86/hyperv/mmu.c
Normal file
272
arch/x86/hyperv/mmu.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
#define pr_fmt(fmt) "Hyper-V: " fmt
|
||||
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/fpu/api.h>
|
||||
#include <asm/mshyperv.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <asm/trace/hyperv.h>
|
||||
|
||||
/* HvFlushVirtualAddressSpace, HvFlushVirtualAddressList hypercalls */
|
||||
struct hv_flush_pcpu {
|
||||
u64 address_space;
|
||||
u64 flags;
|
||||
u64 processor_mask;
|
||||
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 (4096 * PAGE_SIZE)
|
||||
|
||||
static struct hv_flush_pcpu __percpu *pcpu_flush;
|
||||
|
||||
static struct hv_flush_pcpu_ex __percpu *pcpu_flush_ex;
|
||||
|
||||
/*
|
||||
* Fills in gva_list starting from offset. Returns the number of items added.
|
||||
*/
|
||||
static inline int fill_gva_list(u64 gva_list[], int offset,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
int gva_n = offset;
|
||||
unsigned long cur = start, diff;
|
||||
|
||||
do {
|
||||
diff = end > cur ? end - cur : 0;
|
||||
|
||||
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 (diff >= HV_TLB_FLUSH_UNIT)
|
||||
gva_list[gva_n] |= ~PAGE_MASK;
|
||||
else if (diff)
|
||||
gva_list[gva_n] |= (diff - 1) >> PAGE_SHIFT;
|
||||
|
||||
cur += HV_TLB_FLUSH_UNIT;
|
||||
gva_n++;
|
||||
|
||||
} while (cur < end);
|
||||
|
||||
return gva_n - offset;
|
||||
}
|
||||
|
||||
/* Return the number of banks in the resulting vp_set */
|
||||
static inline int cpumask_to_vp_set(struct hv_flush_pcpu_ex *flush,
|
||||
const struct cpumask *cpus)
|
||||
{
|
||||
int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank = 1;
|
||||
|
||||
/*
|
||||
* Some banks may end up being empty but this is acceptable.
|
||||
*/
|
||||
for_each_cpu(cpu, cpus) {
|
||||
vcpu = hv_cpu_number_to_vp_number(cpu);
|
||||
vcpu_bank = vcpu / 64;
|
||||
vcpu_offset = vcpu % 64;
|
||||
|
||||
/* valid_bank_mask can represent up to 64 banks */
|
||||
if (vcpu_bank >= 64)
|
||||
return 0;
|
||||
|
||||
__set_bit(vcpu_offset, (unsigned long *)
|
||||
&flush->hv_vp_set.bank_contents[vcpu_bank]);
|
||||
if (vcpu_bank >= nr_bank)
|
||||
nr_bank = vcpu_bank + 1;
|
||||
}
|
||||
flush->hv_vp_set.valid_bank_mask = GENMASK_ULL(nr_bank - 1, 0);
|
||||
|
||||
return nr_bank;
|
||||
}
|
||||
|
||||
static void hyperv_flush_tlb_others(const struct cpumask *cpus,
|
||||
const struct flush_tlb_info *info)
|
||||
{
|
||||
int cpu, vcpu, gva_n, max_gvas;
|
||||
struct hv_flush_pcpu *flush;
|
||||
u64 status = U64_MAX;
|
||||
unsigned long flags;
|
||||
|
||||
trace_hyperv_mmu_flush_tlb_others(cpus, info);
|
||||
|
||||
if (!pcpu_flush || !hv_hypercall_pg)
|
||||
goto do_native;
|
||||
|
||||
if (cpumask_empty(cpus))
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
flush = this_cpu_ptr(pcpu_flush);
|
||||
|
||||
if (info->mm) {
|
||||
flush->address_space = virt_to_phys(info->mm->pgd);
|
||||
flush->flags = 0;
|
||||
} else {
|
||||
flush->address_space = 0;
|
||||
flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
|
||||
}
|
||||
|
||||
flush->processor_mask = 0;
|
||||
if (cpumask_equal(cpus, cpu_present_mask)) {
|
||||
flush->flags |= HV_FLUSH_ALL_PROCESSORS;
|
||||
} else {
|
||||
for_each_cpu(cpu, cpus) {
|
||||
vcpu = hv_cpu_number_to_vp_number(cpu);
|
||||
if (vcpu >= 64)
|
||||
goto do_native;
|
||||
|
||||
__set_bit(vcpu, (unsigned long *)
|
||||
&flush->processor_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)) / sizeof(flush->gva_list[0]);
|
||||
|
||||
if (info->end == TLB_FLUSH_ALL) {
|
||||
flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
|
||||
status = hv_do_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE,
|
||||
flush, NULL);
|
||||
} else if (info->end &&
|
||||
((info->end - info->start)/HV_TLB_FLUSH_UNIT) > max_gvas) {
|
||||
status = hv_do_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE,
|
||||
flush, NULL);
|
||||
} else {
|
||||
gva_n = fill_gva_list(flush->gva_list, 0,
|
||||
info->start, info->end);
|
||||
status = hv_do_rep_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST,
|
||||
gva_n, 0, flush, NULL);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (!(status & HV_HYPERCALL_RESULT_MASK))
|
||||
return;
|
||||
do_native:
|
||||
native_flush_tlb_others(cpus, info);
|
||||
}
|
||||
|
||||
static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
|
||||
const struct flush_tlb_info *info)
|
||||
{
|
||||
int nr_bank = 0, max_gvas, gva_n;
|
||||
struct hv_flush_pcpu_ex *flush;
|
||||
u64 status = U64_MAX;
|
||||
unsigned long flags;
|
||||
|
||||
trace_hyperv_mmu_flush_tlb_others(cpus, info);
|
||||
|
||||
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 (info->mm) {
|
||||
flush->address_space = virt_to_phys(info->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_SPARCE_4K;
|
||||
nr_bank = cpumask_to_vp_set(flush, cpus);
|
||||
}
|
||||
|
||||
if (!nr_bank) {
|
||||
flush->hv_vp_set.format = HV_GENERIC_SET_ALL;
|
||||
flush->flags |= HV_FLUSH_ALL_PROCESSORS;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 *
|
||||
sizeof(flush->hv_vp_set.bank_contents[0])) /
|
||||
sizeof(flush->gva_list[0]);
|
||||
|
||||
if (info->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 (info->end &&
|
||||
((info->end - info->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 {
|
||||
gva_n = fill_gva_list(flush->gva_list, nr_bank,
|
||||
info->start, info->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 & HV_HYPERCALL_RESULT_MASK))
|
||||
return;
|
||||
do_native:
|
||||
native_flush_tlb_others(cpus, info);
|
||||
}
|
||||
|
||||
void hyperv_setup_mmu_ops(void)
|
||||
{
|
||||
if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
|
||||
return;
|
||||
|
||||
setup_clear_cpu_cap(X86_FEATURE_PCID);
|
||||
|
||||
if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) {
|
||||
pr_info("Using hypercall for remote TLB flush\n");
|
||||
pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others;
|
||||
} else {
|
||||
pr_info("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))
|
||||
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);
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/hyperv.h>
|
||||
|
||||
/*
|
||||
|
@ -170,12 +172,155 @@ void hv_remove_crash_handler(void);
|
|||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
extern struct clocksource *hyperv_cs;
|
||||
extern void *hv_hypercall_pg;
|
||||
|
||||
static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
|
||||
{
|
||||
u64 input_address = input ? virt_to_phys(input) : 0;
|
||||
u64 output_address = output ? virt_to_phys(output) : 0;
|
||||
u64 hv_status;
|
||||
register void *__sp asm(_ASM_SP);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
if (!hv_hypercall_pg)
|
||||
return U64_MAX;
|
||||
|
||||
__asm__ __volatile__("mov %4, %%r8\n"
|
||||
"call *%5"
|
||||
: "=a" (hv_status), "+r" (__sp),
|
||||
"+c" (control), "+d" (input_address)
|
||||
: "r" (output_address), "m" (hv_hypercall_pg)
|
||||
: "cc", "memory", "r8", "r9", "r10", "r11");
|
||||
#else
|
||||
u32 input_address_hi = upper_32_bits(input_address);
|
||||
u32 input_address_lo = lower_32_bits(input_address);
|
||||
u32 output_address_hi = upper_32_bits(output_address);
|
||||
u32 output_address_lo = lower_32_bits(output_address);
|
||||
|
||||
if (!hv_hypercall_pg)
|
||||
return U64_MAX;
|
||||
|
||||
__asm__ __volatile__("call *%7"
|
||||
: "=A" (hv_status),
|
||||
"+c" (input_address_lo), "+r" (__sp)
|
||||
: "A" (control),
|
||||
"b" (input_address_hi),
|
||||
"D"(output_address_hi), "S"(output_address_lo),
|
||||
"m" (hv_hypercall_pg)
|
||||
: "cc", "memory");
|
||||
#endif /* !x86_64 */
|
||||
return hv_status;
|
||||
}
|
||||
|
||||
#define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)
|
||||
#define HV_HYPERCALL_FAST_BIT BIT(16)
|
||||
#define HV_HYPERCALL_VARHEAD_OFFSET 17
|
||||
#define HV_HYPERCALL_REP_COMP_OFFSET 32
|
||||
#define HV_HYPERCALL_REP_COMP_MASK GENMASK_ULL(43, 32)
|
||||
#define HV_HYPERCALL_REP_START_OFFSET 48
|
||||
#define HV_HYPERCALL_REP_START_MASK GENMASK_ULL(59, 48)
|
||||
|
||||
/* Fast hypercall with 8 bytes of input and no output */
|
||||
static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
|
||||
{
|
||||
u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
|
||||
register void *__sp asm(_ASM_SP);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
{
|
||||
__asm__ __volatile__("call *%4"
|
||||
: "=a" (hv_status), "+r" (__sp),
|
||||
"+c" (control), "+d" (input1)
|
||||
: "m" (hv_hypercall_pg)
|
||||
: "cc", "r8", "r9", "r10", "r11");
|
||||
}
|
||||
#else
|
||||
{
|
||||
u32 input1_hi = upper_32_bits(input1);
|
||||
u32 input1_lo = lower_32_bits(input1);
|
||||
|
||||
__asm__ __volatile__ ("call *%5"
|
||||
: "=A"(hv_status),
|
||||
"+c"(input1_lo),
|
||||
"+r"(__sp)
|
||||
: "A" (control),
|
||||
"b" (input1_hi),
|
||||
"m" (hv_hypercall_pg)
|
||||
: "cc", "edi", "esi");
|
||||
}
|
||||
#endif
|
||||
return hv_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rep hypercalls. Callers of this functions are supposed to ensure that
|
||||
* rep_count and varhead_size comply with Hyper-V hypercall definition.
|
||||
*/
|
||||
static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
|
||||
void *input, void *output)
|
||||
{
|
||||
u64 control = code;
|
||||
u64 status;
|
||||
u16 rep_comp;
|
||||
|
||||
control |= (u64)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET;
|
||||
control |= (u64)rep_count << HV_HYPERCALL_REP_COMP_OFFSET;
|
||||
|
||||
do {
|
||||
status = hv_do_hypercall(control, input, output);
|
||||
if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Bits 32-43 of status have 'Reps completed' data. */
|
||||
rep_comp = (status & HV_HYPERCALL_REP_COMP_MASK) >>
|
||||
HV_HYPERCALL_REP_COMP_OFFSET;
|
||||
|
||||
control &= ~HV_HYPERCALL_REP_START_MASK;
|
||||
control |= (u64)rep_comp << HV_HYPERCALL_REP_START_OFFSET;
|
||||
|
||||
touch_nmi_watchdog();
|
||||
} while (rep_comp < rep_count);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hypervisor's notion of virtual processor ID is different from
|
||||
* Linux' notion of CPU ID. This information can only be retrieved
|
||||
* in the context of the calling CPU. Setup a map for easy access
|
||||
* to this information.
|
||||
*/
|
||||
extern u32 *hv_vp_index;
|
||||
|
||||
/**
|
||||
* hv_cpu_number_to_vp_number() - Map CPU to VP.
|
||||
* @cpu_number: CPU number in Linux terms
|
||||
*
|
||||
* This function returns the mapping between the Linux processor
|
||||
* number and the hypervisor's virtual processor number, useful
|
||||
* in making hypercalls and such that talk about specific
|
||||
* processors.
|
||||
*
|
||||
* Return: Virtual processor number in Hyper-V terms
|
||||
*/
|
||||
static inline int hv_cpu_number_to_vp_number(int cpu_number)
|
||||
{
|
||||
return hv_vp_index[cpu_number];
|
||||
}
|
||||
|
||||
void hyperv_init(void);
|
||||
void hyperv_setup_mmu_ops(void);
|
||||
void hyper_alloc_mmu(void);
|
||||
void hyperv_report_panic(struct pt_regs *regs);
|
||||
bool hv_is_hypercall_page_setup(void);
|
||||
void hyperv_cleanup(void);
|
||||
#endif
|
||||
#else /* CONFIG_HYPERV */
|
||||
static inline void hyperv_init(void) {}
|
||||
static inline bool hv_is_hypercall_page_setup(void) { return false; }
|
||||
static inline void hyperv_cleanup(void) {}
|
||||
static inline void hyperv_setup_mmu_ops(void) {}
|
||||
#endif /* CONFIG_HYPERV */
|
||||
|
||||
#ifdef CONFIG_HYPERV_TSCPAGE
|
||||
struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
|
||||
static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg)
|
||||
|
|
40
arch/x86/include/asm/trace/hyperv.h
Normal file
40
arch/x86/include/asm/trace/hyperv.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM hyperv
|
||||
|
||||
#if !defined(_TRACE_HYPERV_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_HYPERV_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
|
||||
TRACE_EVENT(hyperv_mmu_flush_tlb_others,
|
||||
TP_PROTO(const struct cpumask *cpus,
|
||||
const struct flush_tlb_info *info),
|
||||
TP_ARGS(cpus, info),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, ncpus)
|
||||
__field(struct mm_struct *, mm)
|
||||
__field(unsigned long, addr)
|
||||
__field(unsigned long, end)
|
||||
),
|
||||
TP_fast_assign(__entry->ncpus = cpumask_weight(cpus);
|
||||
__entry->mm = info->mm;
|
||||
__entry->addr = info->start;
|
||||
__entry->end = info->end;
|
||||
),
|
||||
TP_printk("ncpus %d mm %p addr %lx, end %lx",
|
||||
__entry->ncpus, __entry->mm,
|
||||
__entry->addr, __entry->end)
|
||||
);
|
||||
|
||||
#endif /* CONFIG_HYPERV */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH asm/trace/
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE hyperv
|
||||
#endif /* _TRACE_HYPERV_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
|
@ -149,6 +149,9 @@
|
|||
*/
|
||||
#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9)
|
||||
|
||||
/* Recommend using the newer ExProcessorMasks interface */
|
||||
#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11)
|
||||
|
||||
/*
|
||||
* HV_VP_SET available
|
||||
*/
|
||||
|
@ -242,7 +245,11 @@
|
|||
(~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1))
|
||||
|
||||
/* Declare the various hypercall operations. */
|
||||
#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
|
||||
|
||||
|
@ -259,6 +266,16 @@
|
|||
#define HV_PROCESSOR_POWER_STATE_C2 2
|
||||
#define HV_PROCESSOR_POWER_STATE_C3 3
|
||||
|
||||
#define HV_FLUSH_ALL_PROCESSORS BIT(0)
|
||||
#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1)
|
||||
#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2)
|
||||
#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3)
|
||||
|
||||
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
|
||||
|
|
|
@ -250,6 +250,7 @@ static void __init ms_hyperv_init_platform(void)
|
|||
* Setup the hook to get control post apic initialization.
|
||||
*/
|
||||
x86_platform.apic_post_init = hyperv_init;
|
||||
hyperv_setup_mmu_ops();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -215,16 +215,23 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
|
|||
struct irq_alloc_info info;
|
||||
int polarity;
|
||||
int ret;
|
||||
u8 gsi;
|
||||
|
||||
if (dev->irq_managed && dev->irq > 0)
|
||||
return 0;
|
||||
|
||||
ret = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi);
|
||||
if (ret < 0) {
|
||||
dev_warn(&dev->dev, "Failed to read interrupt line: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (intel_mid_identify_cpu()) {
|
||||
case INTEL_MID_CPU_CHIP_TANGIER:
|
||||
polarity = IOAPIC_POL_HIGH;
|
||||
|
||||
/* Special treatment for IRQ0 */
|
||||
if (dev->irq == 0) {
|
||||
if (gsi == 0) {
|
||||
/*
|
||||
* Skip HS UART common registers device since it has
|
||||
* IRQ0 assigned and not used by the kernel.
|
||||
|
@ -253,10 +260,11 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
|
|||
* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
|
||||
* IOAPIC RTE entries, so we just enable RTE for the device.
|
||||
*/
|
||||
ret = mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC, &info);
|
||||
ret = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev->irq = ret;
|
||||
dev->irq_managed = 1;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -60,7 +60,7 @@ static int __init tng_bt_sfi_setup(struct bt_sfi_data *ddata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct bt_sfi_data tng_bt_sfi_data __initdata = {
|
||||
static const struct bt_sfi_data tng_bt_sfi_data __initdata = {
|
||||
.setup = tng_bt_sfi_setup,
|
||||
};
|
||||
|
||||
|
|
|
@ -30,13 +30,13 @@ static int tangier_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct irq_alloc_info info;
|
||||
struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
|
||||
int gsi, irq;
|
||||
int gsi = TANGIER_EXT_TIMER0_MSI;
|
||||
int irq;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
/* IOAPIC builds identity mapping between GSI and IRQ on MID */
|
||||
gsi = pdata->irq;
|
||||
ioapic_set_alloc_attr(&info, cpu_to_node(0), 1, 0);
|
||||
irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info);
|
||||
if (irq < 0) {
|
||||
|
@ -44,11 +44,11 @@ static int tangier_probe(struct platform_device *pdev)
|
|||
return irq;
|
||||
}
|
||||
|
||||
pdata->irq = irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct intel_mid_wdt_pdata tangier_pdata = {
|
||||
.irq = TANGIER_EXT_TIMER0_MSI,
|
||||
.probe = tangier_probe,
|
||||
};
|
||||
|
||||
|
|
|
@ -183,6 +183,7 @@ void __init x86_intel_mid_early_setup(void)
|
|||
|
||||
x86_init.timers.timer_init = intel_mid_time_init;
|
||||
x86_init.timers.setup_percpu_clockev = x86_init_noop;
|
||||
x86_init.timers.wallclock_init = intel_mid_rtc_init;
|
||||
|
||||
x86_init.irqs.pre_vector_init = x86_init_noop;
|
||||
|
||||
|
@ -191,7 +192,6 @@ void __init x86_intel_mid_early_setup(void)
|
|||
x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
|
||||
|
||||
x86_platform.calibrate_tsc = intel_mid_calibrate_tsc;
|
||||
x86_init.timers.wallclock_init = intel_mid_rtc_init;
|
||||
x86_platform.get_nmi_reason = intel_mid_get_nmi_reason;
|
||||
|
||||
x86_init.pci.init = intel_mid_pci_init;
|
||||
|
|
|
@ -444,7 +444,7 @@ static int mid_set_initial_state(struct mid_pwr *pwr, const u32 *states)
|
|||
static int pnw_set_initial_state(struct mid_pwr *pwr)
|
||||
{
|
||||
/* On Penwell SRAM must stay powered on */
|
||||
const u32 states[] = {
|
||||
static const u32 states[] = {
|
||||
0xf00fffff, /* PM_SSC(0) */
|
||||
0xffffffff, /* PM_SSC(1) */
|
||||
0xffffffff, /* PM_SSC(2) */
|
||||
|
@ -455,7 +455,7 @@ static int pnw_set_initial_state(struct mid_pwr *pwr)
|
|||
|
||||
static int tng_set_initial_state(struct mid_pwr *pwr)
|
||||
{
|
||||
const u32 states[] = {
|
||||
static const u32 states[] = {
|
||||
0xffffffff, /* PM_SSC(0) */
|
||||
0xffffffff, /* PM_SSC(1) */
|
||||
0xffffffff, /* PM_SSC(2) */
|
||||
|
|
|
@ -3,6 +3,7 @@ menu "Microsoft Hyper-V guest support"
|
|||
config HYPERV
|
||||
tristate "Microsoft Hyper-V client drivers"
|
||||
depends on X86 && ACPI && PCI && X86_LOCAL_APIC && HYPERVISOR_GUEST
|
||||
select PARAVIRT
|
||||
help
|
||||
Select this option to run Linux as a Hyper-V client operating
|
||||
system.
|
||||
|
|
|
@ -603,7 +603,7 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
|
|||
*/
|
||||
channel->numa_node = 0;
|
||||
channel->target_cpu = 0;
|
||||
channel->target_vp = hv_context.vp_index[0];
|
||||
channel->target_vp = hv_cpu_number_to_vp_number(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -687,7 +687,7 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
|
|||
}
|
||||
|
||||
channel->target_cpu = cur_cpu;
|
||||
channel->target_vp = hv_context.vp_index[cur_cpu];
|
||||
channel->target_vp = hv_cpu_number_to_vp_number(cur_cpu);
|
||||
}
|
||||
|
||||
static void vmbus_wait_for_unload(void)
|
||||
|
@ -809,21 +809,12 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
|
|||
/*
|
||||
* Setup state for signalling the host.
|
||||
*/
|
||||
newchannel->sig_event = (struct hv_input_signal_event *)
|
||||
(ALIGN((unsigned long)
|
||||
&newchannel->sig_buf,
|
||||
HV_HYPERCALL_PARAM_ALIGN));
|
||||
|
||||
newchannel->sig_event->connectionid.asu32 = 0;
|
||||
newchannel->sig_event->connectionid.u.id = VMBUS_EVENT_CONNECTION_ID;
|
||||
newchannel->sig_event->flag_number = 0;
|
||||
newchannel->sig_event->rsvdz = 0;
|
||||
newchannel->sig_event = VMBUS_EVENT_CONNECTION_ID;
|
||||
|
||||
if (vmbus_proto_version != VERSION_WS2008) {
|
||||
newchannel->is_dedicated_interrupt =
|
||||
(offer->is_dedicated_interrupt != 0);
|
||||
newchannel->sig_event->connectionid.u.id =
|
||||
offer->connection_id;
|
||||
newchannel->sig_event = offer->connection_id;
|
||||
}
|
||||
|
||||
memcpy(&newchannel->offermsg, offer,
|
||||
|
@ -1251,8 +1242,7 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
|
|||
return outgoing_channel;
|
||||
}
|
||||
|
||||
cur_cpu = hv_context.vp_index[get_cpu()];
|
||||
put_cpu();
|
||||
cur_cpu = hv_cpu_number_to_vp_number(smp_processor_id());
|
||||
list_for_each_safe(cur, tmp, &primary->sc_list) {
|
||||
cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
|
||||
if (cur_channel->state != CHANNEL_OPENED_STATE)
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <linux/hyperv.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/hyperv.h>
|
||||
#include <asm/mshyperv.h>
|
||||
|
||||
#include "hyperv_vmbus.h"
|
||||
|
||||
|
||||
|
@ -94,7 +96,8 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
|
|||
* the CPU attempting to connect may not be CPU 0.
|
||||
*/
|
||||
if (version >= VERSION_WIN8_1) {
|
||||
msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
|
||||
msg->target_vcpu =
|
||||
hv_cpu_number_to_vp_number(smp_processor_id());
|
||||
vmbus_connection.connect_cpu = smp_processor_id();
|
||||
} else {
|
||||
msg->target_vcpu = 0;
|
||||
|
@ -406,6 +409,6 @@ void vmbus_set_event(struct vmbus_channel *channel)
|
|||
if (!channel->is_dedicated_interrupt)
|
||||
vmbus_send_interrupt(child_relid);
|
||||
|
||||
hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL);
|
||||
hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_set_event);
|
||||
|
|
|
@ -234,7 +234,6 @@ int hv_synic_init(unsigned int cpu)
|
|||
union hv_synic_siefp siefp;
|
||||
union hv_synic_sint shared_sint;
|
||||
union hv_synic_scontrol sctrl;
|
||||
u64 vp_index;
|
||||
|
||||
/* Setup the Synic's message page */
|
||||
hv_get_simp(simp.as_uint64);
|
||||
|
@ -275,14 +274,6 @@ int hv_synic_init(unsigned int cpu)
|
|||
|
||||
hv_context.synic_initialized = true;
|
||||
|
||||
/*
|
||||
* Setup the mapping between Hyper-V's notion
|
||||
* of cpuid and Linux' notion of cpuid.
|
||||
* This array will be indexed using Linux cpuid.
|
||||
*/
|
||||
hv_get_vp_index(vp_index);
|
||||
hv_context.vp_index[cpu] = (u32)vp_index;
|
||||
|
||||
/*
|
||||
* Register the per-cpu clockevent source.
|
||||
*/
|
||||
|
|
|
@ -228,17 +228,6 @@ struct hv_context {
|
|||
|
||||
struct hv_per_cpu_context __percpu *cpu_context;
|
||||
|
||||
/*
|
||||
* Hypervisor's notion of virtual processor ID is different from
|
||||
* Linux' notion of CPU ID. This information can only be retrieved
|
||||
* in the context of the calling CPU. Setup a map for easy access
|
||||
* to this information:
|
||||
*
|
||||
* vp_index[a] is the Hyper-V's processor ID corresponding to
|
||||
* Linux cpuid 'a'.
|
||||
*/
|
||||
u32 vp_index[NR_CPUS];
|
||||
|
||||
/*
|
||||
* To manage allocations in a NUMA node.
|
||||
* Array indexed by numa node ID.
|
||||
|
|
|
@ -1454,23 +1454,6 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_free_mmio);
|
||||
|
||||
/**
|
||||
* vmbus_cpu_number_to_vp_number() - Map CPU to VP.
|
||||
* @cpu_number: CPU number in Linux terms
|
||||
*
|
||||
* This function returns the mapping between the Linux processor
|
||||
* number and the hypervisor's virtual processor number, useful
|
||||
* in making hypercalls and such that talk about specific
|
||||
* processors.
|
||||
*
|
||||
* Return: Virtual processor number in Hyper-V terms
|
||||
*/
|
||||
int vmbus_cpu_number_to_vp_number(int cpu_number)
|
||||
{
|
||||
return hv_context.vp_index[cpu_number];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_cpu_number_to_vp_number);
|
||||
|
||||
static int vmbus_acpi_add(struct acpi_device *device)
|
||||
{
|
||||
acpi_status result;
|
||||
|
|
|
@ -562,52 +562,6 @@ static void put_pcichild(struct hv_pci_dev *hv_pcidev,
|
|||
static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus);
|
||||
static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus);
|
||||
|
||||
|
||||
/*
|
||||
* Temporary CPU to vCPU mapping to address transitioning
|
||||
* vmbus_cpu_number_to_vp_number() being migrated to
|
||||
* hv_cpu_number_to_vp_number() in a separate patch. Once that patch
|
||||
* has been picked up in the main line, remove this code here and use
|
||||
* the official code.
|
||||
*/
|
||||
static struct hv_tmpcpumap
|
||||
{
|
||||
bool initialized;
|
||||
u32 vp_index[NR_CPUS];
|
||||
} hv_tmpcpumap;
|
||||
|
||||
static void hv_tmpcpumap_init_cpu(void *_unused)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
u64 vp_index;
|
||||
|
||||
hv_get_vp_index(vp_index);
|
||||
|
||||
hv_tmpcpumap.vp_index[cpu] = vp_index;
|
||||
}
|
||||
|
||||
static void hv_tmpcpumap_init(void)
|
||||
{
|
||||
if (hv_tmpcpumap.initialized)
|
||||
return;
|
||||
|
||||
memset(hv_tmpcpumap.vp_index, -1, sizeof(hv_tmpcpumap.vp_index));
|
||||
on_each_cpu(hv_tmpcpumap_init_cpu, NULL, true);
|
||||
hv_tmpcpumap.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* hv_tmp_cpu_nr_to_vp_nr() - Convert Linux CPU nr to Hyper-V vCPU nr
|
||||
*
|
||||
* Remove once vmbus_cpu_number_to_vp_number() has been converted to
|
||||
* hv_cpu_number_to_vp_number() and replace callers appropriately.
|
||||
*/
|
||||
static u32 hv_tmp_cpu_nr_to_vp_nr(int cpu)
|
||||
{
|
||||
return hv_tmpcpumap.vp_index[cpu];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* devfn_to_wslot() - Convert from Linux PCI slot to Windows
|
||||
* @devfn: The Linux representation of PCI slot
|
||||
|
@ -971,7 +925,7 @@ static void hv_irq_unmask(struct irq_data *data)
|
|||
var_size = 1 + HV_VP_SET_BANK_COUNT_MAX;
|
||||
|
||||
for_each_cpu_and(cpu, dest, cpu_online_mask) {
|
||||
cpu_vmbus = hv_tmp_cpu_nr_to_vp_nr(cpu);
|
||||
cpu_vmbus = hv_cpu_number_to_vp_number(cpu);
|
||||
|
||||
if (cpu_vmbus >= HV_VP_SET_BANK_COUNT_MAX * 64) {
|
||||
dev_err(&hbus->hdev->device,
|
||||
|
@ -986,7 +940,7 @@ static void hv_irq_unmask(struct irq_data *data)
|
|||
} else {
|
||||
for_each_cpu_and(cpu, dest, cpu_online_mask) {
|
||||
params->int_target.vp_mask |=
|
||||
(1ULL << hv_tmp_cpu_nr_to_vp_nr(cpu));
|
||||
(1ULL << hv_cpu_number_to_vp_number(cpu));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1063,7 +1017,7 @@ static u32 hv_compose_msi_req_v2(
|
|||
*/
|
||||
cpu = cpumask_first_and(affinity, cpu_online_mask);
|
||||
int_pkt->int_desc.processor_array[0] =
|
||||
hv_tmp_cpu_nr_to_vp_nr(cpu);
|
||||
hv_cpu_number_to_vp_number(cpu);
|
||||
int_pkt->int_desc.processor_count = 1;
|
||||
|
||||
return sizeof(*int_pkt);
|
||||
|
@ -2490,8 +2444,6 @@ static int hv_pci_probe(struct hv_device *hdev,
|
|||
return -ENOMEM;
|
||||
hbus->state = hv_pcibus_init;
|
||||
|
||||
hv_tmpcpumap_init();
|
||||
|
||||
/*
|
||||
* The PCI bus "domain" is what is called "segment" in ACPI and
|
||||
* other specs. Pull it from the instance ID, to get something
|
||||
|
|
|
@ -661,18 +661,6 @@ union hv_connection_id {
|
|||
} u;
|
||||
};
|
||||
|
||||
/* Definition of the hv_signal_event hypercall input structure. */
|
||||
struct hv_input_signal_event {
|
||||
union hv_connection_id connectionid;
|
||||
u16 flag_number;
|
||||
u16 rsvdz;
|
||||
};
|
||||
|
||||
struct hv_input_signal_event_buffer {
|
||||
u64 align8;
|
||||
struct hv_input_signal_event event;
|
||||
};
|
||||
|
||||
enum hv_numa_policy {
|
||||
HV_BALANCED = 0,
|
||||
HV_LOCALIZED,
|
||||
|
@ -754,8 +742,7 @@ struct vmbus_channel {
|
|||
} callback_mode;
|
||||
|
||||
bool is_dedicated_interrupt;
|
||||
struct hv_input_signal_event_buffer sig_buf;
|
||||
struct hv_input_signal_event *sig_event;
|
||||
u64 sig_event;
|
||||
|
||||
/*
|
||||
* Starting with win8, this field will be used to specify
|
||||
|
@ -1151,8 +1138,6 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
|
|||
resource_size_t size, resource_size_t align,
|
||||
bool fb_overlap_ok);
|
||||
void vmbus_free_mmio(resource_size_t start, resource_size_t size);
|
||||
int vmbus_cpu_number_to_vp_number(int cpu_number);
|
||||
u64 hv_do_hypercall(u64 control, void *input, void *output);
|
||||
|
||||
/*
|
||||
* GUID definitions of various offer types - services offered to the guest.
|
||||
|
|
Loading…
Reference in a new issue