Commit 4d480dbf authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'hyperv-next-signed-20210426' of...

Merge tag 'hyperv-next-signed-20210426' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull Hyper-V updates from Wei Liu:

 - VMBus enhancement

 - Free page reporting support for Hyper-V balloon driver

 - Some patches for running Linux as Arm64 Hyper-V guest

 - A few misc clean-up patches

* tag 'hyperv-next-signed-20210426' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: (30 commits)
  drivers: hv: Create a consistent pattern for checking Hyper-V hypercall status
  x86/hyperv: Move hv_do_rep_hypercall to asm-generic
  video: hyperv_fb: Add ratelimit on error message
  Drivers: hv: vmbus: Increase wait time for VMbus unload
  Drivers: hv: vmbus: Initialize unload_event statically
  Drivers: hv: vmbus: Check for pending channel interrupts before taking a CPU offline
  Drivers: hv: vmbus: Drivers: hv: vmbus: Introduce CHANNELMSG_MODIFYCHANNEL_RESPONSE
  Drivers: hv: vmbus: Introduce and negotiate VMBus protocol version 5.3
  Drivers: hv: vmbus: Use after free in __vmbus_open()
  Drivers: hv: vmbus: remove unused function
  Drivers: hv: vmbus: Remove unused linux/version.h header
  x86/hyperv: remove unused linux/version.h header
  x86/Hyper-V: Support for free page reporting
  x86/hyperv: Fix unused variable 'hi' warning in hv_apic_read
  x86/hyperv: Fix unused variable 'msr_val' warning in hv_qlock_wait
  hv: hyperv.h: a few mundane typo fixes
  drivers: hv: Fix EXPORT_SYMBOL and tab spaces issue
  Drivers: hv: vmbus: Drop error message when 'No request id available'
  asm-generic/hyperv: Add missing function prototypes per -W1 warnings
  clocksource/drivers/hyper-v: Move handling of STIMER0 interrupts
  ...
parents 8e47c5f0 753ed9c9
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -60,9 +60,11 @@ static u32 hv_apic_read(u32 reg)
	switch (reg) {
	case APIC_EOI:
		rdmsr(HV_X64_MSR_EOI, reg_val, hi);
		(void)hi;
		return reg_val;
	case APIC_TASKPRI:
		rdmsr(HV_X64_MSR_TPR, reg_val, hi);
		(void)hi;
		return reg_val;

	default:
@@ -103,7 +105,7 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector)
	struct hv_send_ipi_ex *ipi_arg;
	unsigned long flags;
	int nr_bank = 0;
	int ret = 1;
	u64 status = HV_STATUS_INVALID_PARAMETER;

	if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
		return false;
@@ -128,19 +130,19 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector)
	if (!nr_bank)
		ipi_arg->vp_set.format = HV_GENERIC_SET_ALL;

	ret = hv_do_rep_hypercall(HVCALL_SEND_IPI_EX, 0, nr_bank,
	status = hv_do_rep_hypercall(HVCALL_SEND_IPI_EX, 0, nr_bank,
			      ipi_arg, NULL);

ipi_mask_ex_done:
	local_irq_restore(flags);
	return ((ret == 0) ? true : false);
	return hv_result_success(status);
}

static bool __send_ipi_mask(const struct cpumask *mask, int vector)
{
	int cur_cpu, vcpu;
	struct hv_send_ipi ipi_arg;
	int ret = 1;
	u64 status;

	trace_hyperv_send_ipi_mask(mask, vector);

@@ -184,9 +186,9 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector)
		__set_bit(vcpu, (unsigned long *)&ipi_arg.cpu_mask);
	}

	ret = hv_do_fast_hypercall16(HVCALL_SEND_IPI, ipi_arg.vector,
	status = hv_do_fast_hypercall16(HVCALL_SEND_IPI, ipi_arg.vector,
				     ipi_arg.cpu_mask);
	return ((ret == 0) ? true : false);
	return hv_result_success(status);

do_ex_hypercall:
	return __send_ipi_mask_ex(mask, vector);
@@ -195,6 +197,7 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector)
static bool __send_ipi_one(int cpu, int vector)
{
	int vp = hv_cpu_number_to_vp_number(cpu);
	u64 status;

	trace_hyperv_send_ipi_one(cpu, vector);

@@ -207,7 +210,8 @@ static bool __send_ipi_one(int cpu, int vector)
	if (vp >= 64)
		return __send_ipi_mask_ex(cpumask_of(cpu), vector);

	return !hv_do_fast_hypercall16(HVCALL_SEND_IPI, vector, BIT_ULL(vp));
	status = hv_do_fast_hypercall16(HVCALL_SEND_IPI, vector, BIT_ULL(vp));
	return hv_result_success(status);
}

static void hv_send_ipi(int cpu, int vector)
+53 −53
Original line number Diff line number Diff line
@@ -54,28 +54,6 @@ EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg);
u32 hv_max_vp_index;
EXPORT_SYMBOL_GPL(hv_max_vp_index);

void *hv_alloc_hyperv_page(void)
{
	BUILD_BUG_ON(PAGE_SIZE != HV_HYP_PAGE_SIZE);

	return (void *)__get_free_page(GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(hv_alloc_hyperv_page);

void *hv_alloc_hyperv_zeroed_page(void)
{
        BUILD_BUG_ON(PAGE_SIZE != HV_HYP_PAGE_SIZE);

        return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
}
EXPORT_SYMBOL_GPL(hv_alloc_hyperv_zeroed_page);

void hv_free_hyperv_page(unsigned long addr)
{
	free_page(addr);
}
EXPORT_SYMBOL_GPL(hv_free_hyperv_page);

static int hv_cpu_init(unsigned int cpu)
{
	u64 msr_vp_index;
@@ -97,7 +75,7 @@ static int hv_cpu_init(unsigned int cpu)
		*output_arg = page_address(pg + 1);
	}

	hv_get_vp_index(msr_vp_index);
	msr_vp_index = hv_get_register(HV_REGISTER_VP_INDEX);

	hv_vp_index[smp_processor_id()] = msr_vp_index;

@@ -349,7 +327,7 @@ static void __init hv_stimer_setup_percpu_clockev(void)
	 * Ignore any errors in setting up stimer clockevents
	 * as we can run with the LAPIC timer as a fallback.
	 */
	(void)hv_stimer_alloc();
	(void)hv_stimer_alloc(false);

	/*
	 * Still register the LAPIC timer, because the direct-mode STIMER is
@@ -369,7 +347,7 @@ static void __init hv_get_partition_id(void)
	local_irq_save(flags);
	output_page = *this_cpu_ptr(hyperv_pcpu_output_arg);
	status = hv_do_hypercall(HVCALL_GET_PARTITION_ID, NULL, output_page);
	if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) {
	if (!hv_result_success(status)) {
		/* No point in proceeding if this failed */
		pr_err("Failed to get partition ID: %lld\n", status);
		BUG();
@@ -520,6 +498,8 @@ void __init hyperv_init(void)
		x86_init.irqs.create_pci_msi_domain = hv_create_pci_msi_domain;
#endif

	/* Query the VMs extended capability once, so that it can be cached. */
	hv_query_ext_cap(0);
	return;

remove_cpuhp_state:
@@ -593,33 +573,6 @@ void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
}
EXPORT_SYMBOL_GPL(hyperv_report_panic);

/**
 * hyperv_report_panic_msg - report panic message to Hyper-V
 * @pa: physical address of the panic page containing the message
 * @size: size of the message in the page
 */
void hyperv_report_panic_msg(phys_addr_t pa, size_t size)
{
	/*
	 * P3 to contain the physical address of the panic page & P4 to
	 * contain the size of the panic data in that page. Rest of the
	 * registers are no-op when the NOTIFY_MSG flag is set.
	 */
	wrmsrl(HV_X64_MSR_CRASH_P0, 0);
	wrmsrl(HV_X64_MSR_CRASH_P1, 0);
	wrmsrl(HV_X64_MSR_CRASH_P2, 0);
	wrmsrl(HV_X64_MSR_CRASH_P3, pa);
	wrmsrl(HV_X64_MSR_CRASH_P4, size);

	/*
	 * Let Hyper-V know there is crash data available along with
	 * the panic message.
	 */
	wrmsrl(HV_X64_MSR_CRASH_CTL,
	       (HV_CRASH_CTL_CRASH_NOTIFY | HV_CRASH_CTL_CRASH_NOTIFY_MSG));
}
EXPORT_SYMBOL_GPL(hyperv_report_panic_msg);

bool hv_is_hyperv_initialized(void)
{
	union hv_x64_msr_hypercall_contents hypercall_msr;
@@ -650,7 +603,7 @@ EXPORT_SYMBOL_GPL(hv_is_hibernation_supported);

enum hv_isolation_type hv_get_isolation_type(void)
{
	if (!(ms_hyperv.features_b & HV_ISOLATION))
	if (!(ms_hyperv.priv_high & HV_ISOLATION))
		return HV_ISOLATION_TYPE_NONE;
	return FIELD_GET(HV_ISOLATION_TYPE, ms_hyperv.isolation_config_b);
}
@@ -661,3 +614,50 @@ bool hv_is_isolation_supported(void)
	return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE;
}
EXPORT_SYMBOL_GPL(hv_is_isolation_supported);

/* Bit mask of the extended capability to query: see HV_EXT_CAPABILITY_xxx */
bool hv_query_ext_cap(u64 cap_query)
{
	/*
	 * The address of the 'hv_extended_cap' variable will be used as an
	 * output parameter to the hypercall below and so it should be
	 * compatible with 'virt_to_phys'. Which means, it's address should be
	 * directly mapped. Use 'static' to keep it compatible; stack variables
	 * can be virtually mapped, making them imcompatible with
	 * 'virt_to_phys'.
	 * Hypercall input/output addresses should also be 8-byte aligned.
	 */
	static u64 hv_extended_cap __aligned(8);
	static bool hv_extended_cap_queried;
	u64 status;

	/*
	 * Querying extended capabilities is an extended hypercall. Check if the
	 * partition supports extended hypercall, first.
	 */
	if (!(ms_hyperv.priv_high & HV_ENABLE_EXTENDED_HYPERCALLS))
		return false;

	/* Extended capabilities do not change at runtime. */
	if (hv_extended_cap_queried)
		return hv_extended_cap & cap_query;

	status = hv_do_hypercall(HV_EXT_CALL_QUERY_CAPABILITIES, NULL,
				 &hv_extended_cap);

	/*
	 * The query extended capabilities hypercall should not fail under
	 * any normal circumstances. Avoid repeatedly making the hypercall, on
	 * error.
	 */
	hv_extended_cap_queried = true;
	status &= HV_HYPERCALL_RESULT_MASK;
	if (status != HV_STATUS_SUCCESS) {
		pr_err("Hyper-V: Extended query capabilities hypercall failed 0x%llx\n",
		       status);
		return false;
	}

	return hv_extended_cap & cap_query;
}
EXPORT_SYMBOL_GPL(hv_query_ext_cap);
+10 −16
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <linux/types.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/clockchips.h>
@@ -93,10 +92,9 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
	status = hv_do_rep_hypercall(HVCALL_DEPOSIT_MEMORY,
				     page_count, 0, input_page, NULL);
	local_irq_restore(flags);

	if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) {
	if (!hv_result_success(status)) {
		pr_err("Failed to deposit pages: %lld\n", status);
		ret = status;
		ret = hv_result(status);
		goto err_free_allocations;
	}

@@ -122,7 +120,7 @@ int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
	struct hv_add_logical_processor_out *output;
	u64 status;
	unsigned long flags;
	int ret = 0;
	int ret = HV_STATUS_SUCCESS;
	int pxm = node_to_pxm(node);

	/*
@@ -148,13 +146,11 @@ int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
					 input, output);
		local_irq_restore(flags);

		status &= HV_HYPERCALL_RESULT_MASK;

		if (status != HV_STATUS_INSUFFICIENT_MEMORY) {
			if (status != HV_STATUS_SUCCESS) {
		if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) {
			if (!hv_result_success(status)) {
				pr_err("%s: cpu %u apic ID %u, %lld\n", __func__,
				       lp_index, apic_id, status);
				ret = status;
				ret = hv_result(status);
			}
			break;
		}
@@ -169,7 +165,7 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
	struct hv_create_vp *input;
	u64 status;
	unsigned long irq_flags;
	int ret = 0;
	int ret = HV_STATUS_SUCCESS;
	int pxm = node_to_pxm(node);

	/* Root VPs don't seem to need pages deposited */
@@ -200,13 +196,11 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
		status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL);
		local_irq_restore(irq_flags);

		status &= HV_HYPERCALL_RESULT_MASK;

		if (status != HV_STATUS_INSUFFICIENT_MEMORY) {
			if (status != HV_STATUS_SUCCESS) {
		if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) {
			if (!hv_result_success(status)) {
				pr_err("%s: vcpu %u, lp %u, %lld\n", __func__,
				       vp_index, flags, status);
				ret = status;
				ret = hv_result(status);
			}
			break;
		}
+6 −2
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ static void hv_qlock_kick(int cpu)

static void hv_qlock_wait(u8 *byte, u8 val)
{
	unsigned long msr_val;
	unsigned long flags;

	if (in_nmi())
@@ -48,8 +47,13 @@ static void hv_qlock_wait(u8 *byte, u8 val)
	/*
	 * Only issue the rdmsrl() when the lock state has not changed.
	 */
	if (READ_ONCE(*byte) == val)
	if (READ_ONCE(*byte) == val) {
		unsigned long msr_val;

		rdmsrl(HV_X64_MSR_GUEST_IDLE, msr_val);

		(void)msr_val;
	}
	local_irq_restore(flags);
}

+3 −3
Original line number Diff line number Diff line
@@ -63,10 +63,10 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level,

	local_irq_restore(flags);

	if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS)
	if (!hv_result_success(status))
		pr_err("%s: hypercall failed, status %lld\n", __func__, status);

	return status & HV_HYPERCALL_RESULT_MASK;
	return hv_result(status);
}

static int hv_unmap_interrupt(u64 id, struct hv_interrupt_entry *old_entry)
@@ -88,7 +88,7 @@ static int hv_unmap_interrupt(u64 id, struct hv_interrupt_entry *old_entry)
	status = hv_do_hypercall(HVCALL_UNMAP_DEVICE_INTERRUPT, input, NULL);
	local_irq_restore(flags);

	return status & HV_HYPERCALL_RESULT_MASK;
	return hv_result(status);
}

#ifdef CONFIG_PCI_MSI
Loading