Merge tag 'hyperv-fixes-signed-20250718' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull hyperv fixes from Wei Liu: - Select use CONFIG_SYSFB only if EFI is enabled (Michael Kelley) - An assorted set of fixes to remove warnings for missing export.h header inclusion (Naman Jain) - An assorted set of fixes for when Linux run as the root partition for Microsoft Hypervisor (Mukesh Rathor, Nuno Das Neves, Stanislav Kinsburskii) - Fix the check for HYPERVISOR_CALLBACK_VECTOR (Naman Jain) - Fix fcopy tool to handle irregularities with size of ring buffer (Naman Jain) - Fix incorrect file path conversion in fcopy tool (Yasumasa Suenaga) * tag 'hyperv-fixes-signed-20250718' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: tools/hv: fcopy: Fix irregularities with size of ring buffer PCI: hv: Use the correct hypercall for unmasking interrupts on nested x86/hyperv: Expose hv_map_msi_interrupt() Drivers: hv: Use nested hypercall for post message and signal event x86/hyperv: Clean up hv_map/unmap_interrupt() return values x86/hyperv: Fix usage of cpu_online_mask to get valid cpu PCI: hv: Don't load the driver for baremetal root partition net: mana: Fix warnings for missing export.h header inclusion PCI: hv: Fix warnings for missing export.h header inclusion clocksource: hyper-v: Fix warnings for missing export.h header inclusion x86/hyperv: Fix warnings for missing export.h header inclusion Drivers: hv: Fix warnings for missing export.h header inclusion Drivers: hv: Fix the check for HYPERVISOR_CALLBACK_VECTOR tools/hv: fcopy: Fix incorrect file path conversion Drivers: hv: Select CONFIG_SYSFB only if EFI is enabled
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <clocksource/hyperv_timer.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
void *hv_hypercall_pg;
|
||||
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
|
||||
|
||||
+41
-28
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/mshyperv.h>
|
||||
|
||||
static int hv_map_interrupt(union hv_device_id device_id, bool level,
|
||||
@@ -46,7 +47,7 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level,
|
||||
if (nr_bank < 0) {
|
||||
local_irq_restore(flags);
|
||||
pr_err("%s: unable to generate VP set\n", __func__);
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
intr_desc->target.flags = HV_DEVICE_INTERRUPT_TARGET_PROCESSOR_SET;
|
||||
|
||||
@@ -66,7 +67,7 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level,
|
||||
if (!hv_result_success(status))
|
||||
hv_status_err(status, "\n");
|
||||
|
||||
return hv_result(status);
|
||||
return hv_result_to_errno(status);
|
||||
}
|
||||
|
||||
static int hv_unmap_interrupt(u64 id, struct hv_interrupt_entry *old_entry)
|
||||
@@ -88,7 +89,10 @@ 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 hv_result(status);
|
||||
if (!hv_result_success(status))
|
||||
hv_status_err(status, "\n");
|
||||
|
||||
return hv_result_to_errno(status);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
@@ -169,13 +173,34 @@ static union hv_device_id hv_build_pci_dev_id(struct pci_dev *dev)
|
||||
return dev_id;
|
||||
}
|
||||
|
||||
static int hv_map_msi_interrupt(struct pci_dev *dev, int cpu, int vector,
|
||||
struct hv_interrupt_entry *entry)
|
||||
/**
|
||||
* hv_map_msi_interrupt() - "Map" the MSI IRQ in the hypervisor.
|
||||
* @data: Describes the IRQ
|
||||
* @out_entry: Hypervisor (MSI) interrupt entry (can be NULL)
|
||||
*
|
||||
* Map the IRQ in the hypervisor by issuing a MAP_DEVICE_INTERRUPT hypercall.
|
||||
*
|
||||
* Return: 0 on success, -errno on failure
|
||||
*/
|
||||
int hv_map_msi_interrupt(struct irq_data *data,
|
||||
struct hv_interrupt_entry *out_entry)
|
||||
{
|
||||
union hv_device_id device_id = hv_build_pci_dev_id(dev);
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
struct hv_interrupt_entry dummy;
|
||||
union hv_device_id device_id;
|
||||
struct msi_desc *msidesc;
|
||||
struct pci_dev *dev;
|
||||
int cpu;
|
||||
|
||||
return hv_map_interrupt(device_id, false, cpu, vector, entry);
|
||||
msidesc = irq_data_get_msi_desc(data);
|
||||
dev = msi_desc_to_pci_dev(msidesc);
|
||||
device_id = hv_build_pci_dev_id(dev);
|
||||
cpu = cpumask_first(irq_data_get_effective_affinity_mask(data));
|
||||
|
||||
return hv_map_interrupt(device_id, false, cpu, cfg->vector,
|
||||
out_entry ? out_entry : &dummy);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_map_msi_interrupt);
|
||||
|
||||
static inline void entry_to_msi_msg(struct hv_interrupt_entry *entry, struct msi_msg *msg)
|
||||
{
|
||||
@@ -188,13 +213,11 @@ static inline void entry_to_msi_msg(struct hv_interrupt_entry *entry, struct msi
|
||||
static int hv_unmap_msi_interrupt(struct pci_dev *dev, struct hv_interrupt_entry *old_entry);
|
||||
static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
struct hv_interrupt_entry *stored_entry;
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
struct msi_desc *msidesc;
|
||||
struct pci_dev *dev;
|
||||
struct hv_interrupt_entry out_entry, *stored_entry;
|
||||
struct irq_cfg *cfg = irqd_cfg(data);
|
||||
const cpumask_t *affinity;
|
||||
int cpu;
|
||||
u64 status;
|
||||
int ret;
|
||||
|
||||
msidesc = irq_data_get_msi_desc(data);
|
||||
dev = msi_desc_to_pci_dev(msidesc);
|
||||
@@ -204,9 +227,6 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
return;
|
||||
}
|
||||
|
||||
affinity = irq_data_get_effective_affinity_mask(data);
|
||||
cpu = cpumask_first_and(affinity, cpu_online_mask);
|
||||
|
||||
if (data->chip_data) {
|
||||
/*
|
||||
* This interrupt is already mapped. Let's unmap first.
|
||||
@@ -219,14 +239,12 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
stored_entry = data->chip_data;
|
||||
data->chip_data = NULL;
|
||||
|
||||
status = hv_unmap_msi_interrupt(dev, stored_entry);
|
||||
ret = hv_unmap_msi_interrupt(dev, stored_entry);
|
||||
|
||||
kfree(stored_entry);
|
||||
|
||||
if (status != HV_STATUS_SUCCESS) {
|
||||
hv_status_debug(status, "failed to unmap\n");
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
stored_entry = kzalloc(sizeof(*stored_entry), GFP_ATOMIC);
|
||||
@@ -235,15 +253,14 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
return;
|
||||
}
|
||||
|
||||
status = hv_map_msi_interrupt(dev, cpu, cfg->vector, &out_entry);
|
||||
if (status != HV_STATUS_SUCCESS) {
|
||||
ret = hv_map_msi_interrupt(data, stored_entry);
|
||||
if (ret) {
|
||||
kfree(stored_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
*stored_entry = out_entry;
|
||||
data->chip_data = stored_entry;
|
||||
entry_to_msi_msg(&out_entry, msg);
|
||||
entry_to_msi_msg(data->chip_data, msg);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -257,7 +274,6 @@ static void hv_teardown_msi_irq(struct pci_dev *dev, struct irq_data *irqd)
|
||||
{
|
||||
struct hv_interrupt_entry old_entry;
|
||||
struct msi_msg msg;
|
||||
u64 status;
|
||||
|
||||
if (!irqd->chip_data) {
|
||||
pr_debug("%s: no chip data\n!", __func__);
|
||||
@@ -270,10 +286,7 @@ static void hv_teardown_msi_irq(struct pci_dev *dev, struct irq_data *irqd)
|
||||
kfree(irqd->chip_data);
|
||||
irqd->chip_data = NULL;
|
||||
|
||||
status = hv_unmap_msi_interrupt(dev, &old_entry);
|
||||
|
||||
if (status != HV_STATUS_SUCCESS)
|
||||
hv_status_err(status, "\n");
|
||||
(void)hv_unmap_msi_interrupt(dev, &old_entry);
|
||||
}
|
||||
|
||||
static void hv_msi_free_irq(struct irq_domain *domain,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/svm.h>
|
||||
#include <asm/sev.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/export.h>
|
||||
#include <hyperv/hvhdk.h>
|
||||
#include <asm/mshyperv.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
@@ -112,12 +112,6 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
|
||||
return hv_status;
|
||||
}
|
||||
|
||||
/* Hypercall to the L0 hypervisor */
|
||||
static inline u64 hv_do_nested_hypercall(u64 control, void *input, void *output)
|
||||
{
|
||||
return hv_do_hypercall(control | HV_HYPERCALL_NESTED, input, output);
|
||||
}
|
||||
|
||||
/* Fast hypercall with 8 bytes of input and no output */
|
||||
static inline u64 _hv_do_fast_hypercall8(u64 control, u64 input1)
|
||||
{
|
||||
@@ -165,13 +159,6 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
|
||||
return _hv_do_fast_hypercall8(control, input1);
|
||||
}
|
||||
|
||||
static inline u64 hv_do_fast_nested_hypercall8(u16 code, u64 input1)
|
||||
{
|
||||
u64 control = (u64)code | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_NESTED;
|
||||
|
||||
return _hv_do_fast_hypercall8(control, input1);
|
||||
}
|
||||
|
||||
/* Fast hypercall with 16 bytes of input */
|
||||
static inline u64 _hv_do_fast_hypercall16(u64 control, u64 input1, u64 input2)
|
||||
{
|
||||
@@ -223,13 +210,6 @@ static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
|
||||
return _hv_do_fast_hypercall16(control, input1, input2);
|
||||
}
|
||||
|
||||
static inline u64 hv_do_fast_nested_hypercall16(u16 code, u64 input1, u64 input2)
|
||||
{
|
||||
u64 control = (u64)code | HV_HYPERCALL_FAST_BIT | HV_HYPERCALL_NESTED;
|
||||
|
||||
return _hv_do_fast_hypercall16(control, input1, input2);
|
||||
}
|
||||
|
||||
extern struct hv_vp_assist_page **hv_vp_assist_page;
|
||||
|
||||
static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
|
||||
@@ -262,6 +242,8 @@ static inline void hv_apic_init(void) {}
|
||||
|
||||
struct irq_domain *hv_create_pci_msi_domain(void);
|
||||
|
||||
int hv_map_msi_interrupt(struct irq_data *data,
|
||||
struct hv_interrupt_entry *out_entry);
|
||||
int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector,
|
||||
struct hv_interrupt_entry *entry);
|
||||
int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/export.h>
|
||||
#include <clocksource/hyperv_timer.h>
|
||||
#include <hyperv/hvhdk.h>
|
||||
#include <asm/mshyperv.h>
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ config HYPERV
|
||||
select PARAVIRT
|
||||
select X86_HV_CALLBACK_VECTOR if X86
|
||||
select OF_EARLY_FLATTREE if OF
|
||||
select SYSFB if !HYPERV_VTL_MODE
|
||||
select SYSFB if EFI && !HYPERV_VTL_MODE
|
||||
help
|
||||
Select this option to run Linux as a Hyper-V client operating
|
||||
system.
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/uio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/mshyperv.h>
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/mshyperv.h>
|
||||
#include <linux/sched/isolation.h>
|
||||
|
||||
|
||||
@@ -519,7 +519,10 @@ void vmbus_set_event(struct vmbus_channel *channel)
|
||||
else
|
||||
WARN_ON_ONCE(1);
|
||||
} else {
|
||||
hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event);
|
||||
u64 control = HVCALL_SIGNAL_EVENT;
|
||||
|
||||
control |= hv_nested ? HV_HYPERCALL_NESTED : 0;
|
||||
hv_do_fast_hypercall8(control, channel->sig_event);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_set_event);
|
||||
|
||||
+4
-2
@@ -85,8 +85,10 @@ int hv_post_message(union hv_connection_id connection_id,
|
||||
else
|
||||
status = HV_STATUS_INVALID_PARAMETER;
|
||||
} else {
|
||||
status = hv_do_hypercall(HVCALL_POST_MESSAGE,
|
||||
aligned_msg, NULL);
|
||||
u64 control = HVCALL_POST_MESSAGE;
|
||||
|
||||
control |= hv_nested ? HV_HYPERCALL_NESTED : 0;
|
||||
status = hv_do_hypercall(control, aligned_msg, NULL);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/mshyperv.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <asm/mshyperv.h>
|
||||
#include <linux/resume_user_mode.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "mshv.h"
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/mshyperv.h>
|
||||
|
||||
#include "mshv_root.h"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/mshyperv.h>
|
||||
|
||||
#include "hyperv_vmbus.h"
|
||||
|
||||
@@ -2509,7 +2509,7 @@ static int vmbus_acpi_add(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HYPERVISOR_CALLBACK_VECTOR
|
||||
static int vmbus_set_irq(struct platform_device *pdev)
|
||||
{
|
||||
struct irq_data *data;
|
||||
@@ -2534,6 +2534,7 @@ static int vmbus_set_irq(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int vmbus_device_add(struct platform_device *pdev)
|
||||
{
|
||||
@@ -2549,11 +2550,11 @@ static int vmbus_device_add(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!__is_defined(HYPERVISOR_CALLBACK_VECTOR))
|
||||
ret = vmbus_set_irq(pdev);
|
||||
#ifndef HYPERVISOR_CALLBACK_VECTOR
|
||||
ret = vmbus_set_irq(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#endif
|
||||
for_each_of_range(&parser, &range) {
|
||||
struct resource *res;
|
||||
|
||||
|
||||
@@ -193,15 +193,13 @@ struct hyperv_root_ir_data {
|
||||
static void
|
||||
hyperv_root_ir_compose_msi_msg(struct irq_data *irq_data, struct msi_msg *msg)
|
||||
{
|
||||
u64 status;
|
||||
u32 vector;
|
||||
struct irq_cfg *cfg;
|
||||
int ioapic_id;
|
||||
const struct cpumask *affinity;
|
||||
int cpu;
|
||||
struct hv_interrupt_entry entry;
|
||||
struct hyperv_root_ir_data *data = irq_data->chip_data;
|
||||
struct hv_interrupt_entry entry;
|
||||
const struct cpumask *affinity;
|
||||
struct IO_APIC_route_entry e;
|
||||
struct irq_cfg *cfg;
|
||||
int cpu, ioapic_id;
|
||||
u32 vector;
|
||||
|
||||
cfg = irqd_cfg(irq_data);
|
||||
affinity = irq_data_get_effective_affinity_mask(irq_data);
|
||||
@@ -214,23 +212,16 @@ hyperv_root_ir_compose_msi_msg(struct irq_data *irq_data, struct msi_msg *msg)
|
||||
&& data->entry.ioapic_rte.as_uint64) {
|
||||
entry = data->entry;
|
||||
|
||||
status = hv_unmap_ioapic_interrupt(ioapic_id, &entry);
|
||||
|
||||
if (status != HV_STATUS_SUCCESS)
|
||||
hv_status_debug(status, "failed to unmap\n");
|
||||
(void)hv_unmap_ioapic_interrupt(ioapic_id, &entry);
|
||||
|
||||
data->entry.ioapic_rte.as_uint64 = 0;
|
||||
data->entry.source = 0; /* Invalid source */
|
||||
}
|
||||
|
||||
|
||||
status = hv_map_ioapic_interrupt(ioapic_id, data->is_level, cpu,
|
||||
vector, &entry);
|
||||
|
||||
if (status != HV_STATUS_SUCCESS) {
|
||||
hv_status_err(status, "map failed\n");
|
||||
if (hv_map_ioapic_interrupt(ioapic_id, data->is_level, cpu,
|
||||
vector, &entry))
|
||||
return;
|
||||
}
|
||||
|
||||
data->entry = entry;
|
||||
|
||||
@@ -322,10 +313,10 @@ static void hyperv_root_irq_remapping_free(struct irq_domain *domain,
|
||||
data = irq_data->chip_data;
|
||||
e = &data->entry;
|
||||
|
||||
if (e->source == HV_DEVICE_TYPE_IOAPIC
|
||||
&& e->ioapic_rte.as_uint64)
|
||||
hv_unmap_ioapic_interrupt(data->ioapic_id,
|
||||
&data->entry);
|
||||
if (e->source == HV_DEVICE_TYPE_IOAPIC &&
|
||||
e->ioapic_rte.as_uint64)
|
||||
(void)hv_unmap_ioapic_interrupt(data->ioapic_id,
|
||||
&data->entry);
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <net/mana/mana.h>
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/filter.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <net/checksum.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
struct hyperv_pci_block_ops hvpci_block_ops;
|
||||
EXPORT_SYMBOL_GPL(hvpci_block_ops);
|
||||
|
||||
@@ -600,7 +600,7 @@ static unsigned int hv_msi_get_int_vector(struct irq_data *data)
|
||||
#define hv_msi_prepare pci_msi_prepare
|
||||
|
||||
/**
|
||||
* hv_arch_irq_unmask() - "Unmask" the IRQ by setting its current
|
||||
* hv_irq_retarget_interrupt() - "Unmask" the IRQ by setting its current
|
||||
* affinity.
|
||||
* @data: Describes the IRQ
|
||||
*
|
||||
@@ -609,7 +609,7 @@ static unsigned int hv_msi_get_int_vector(struct irq_data *data)
|
||||
* is built out of this PCI bus's instance GUID and the function
|
||||
* number of the device.
|
||||
*/
|
||||
static void hv_arch_irq_unmask(struct irq_data *data)
|
||||
static void hv_irq_retarget_interrupt(struct irq_data *data)
|
||||
{
|
||||
struct msi_desc *msi_desc = irq_data_get_msi_desc(data);
|
||||
struct hv_retarget_device_interrupt *params;
|
||||
@@ -714,6 +714,20 @@ out:
|
||||
dev_err(&hbus->hdev->device,
|
||||
"%s() failed: %#llx", __func__, res);
|
||||
}
|
||||
|
||||
static void hv_arch_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
if (hv_root_partition())
|
||||
/*
|
||||
* In case of the nested root partition, the nested hypervisor
|
||||
* is taking care of interrupt remapping and thus the
|
||||
* MAP_DEVICE_INTERRUPT hypercall is required instead of
|
||||
* RETARGET_INTERRUPT.
|
||||
*/
|
||||
(void)hv_map_msi_interrupt(data, NULL);
|
||||
else
|
||||
hv_irq_retarget_interrupt(data);
|
||||
}
|
||||
#elif defined(CONFIG_ARM64)
|
||||
/*
|
||||
* SPI vectors to use for vPCI; arch SPIs range is [32, 1019], but leaving a bit
|
||||
@@ -4144,6 +4158,9 @@ static int __init init_hv_pci_drv(void)
|
||||
if (!hv_is_hyperv_initialized())
|
||||
return -ENODEV;
|
||||
|
||||
if (hv_root_partition() && !hv_nested)
|
||||
return -ENODEV;
|
||||
|
||||
ret = hv_pci_irqchip_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -35,7 +35,10 @@
|
||||
#define WIN8_SRV_MINOR 1
|
||||
#define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
|
||||
|
||||
#define FCOPY_UIO "/sys/bus/vmbus/devices/eb765408-105f-49b6-b4aa-c123b64d17d4/uio"
|
||||
#define FCOPY_DEVICE_PATH(subdir) \
|
||||
"/sys/bus/vmbus/devices/eb765408-105f-49b6-b4aa-c123b64d17d4/" #subdir
|
||||
#define FCOPY_UIO_PATH FCOPY_DEVICE_PATH(uio)
|
||||
#define FCOPY_CHANNELS_PATH FCOPY_DEVICE_PATH(channels)
|
||||
|
||||
#define FCOPY_VER_COUNT 1
|
||||
static const int fcopy_versions[] = {
|
||||
@@ -47,9 +50,62 @@ static const int fw_versions[] = {
|
||||
UTIL_FW_VERSION
|
||||
};
|
||||
|
||||
#define HV_RING_SIZE 0x4000 /* 16KB ring buffer size */
|
||||
static uint32_t get_ring_buffer_size(void)
|
||||
{
|
||||
char ring_path[PATH_MAX];
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct stat st;
|
||||
uint32_t ring_size = 0;
|
||||
int retry_count = 0;
|
||||
|
||||
static unsigned char desc[HV_RING_SIZE];
|
||||
/* Find the channel directory */
|
||||
dir = opendir(FCOPY_CHANNELS_PATH);
|
||||
if (!dir) {
|
||||
usleep(100 * 1000); /* Avoid race with kernel, wait 100ms and retry once */
|
||||
dir = opendir(FCOPY_CHANNELS_PATH);
|
||||
if (!dir) {
|
||||
syslog(LOG_ERR, "Failed to open channels directory: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
retry_once:
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 &&
|
||||
strcmp(entry->d_name, "..") != 0) {
|
||||
snprintf(ring_path, sizeof(ring_path), "%s/%s/ring",
|
||||
FCOPY_CHANNELS_PATH, entry->d_name);
|
||||
|
||||
if (stat(ring_path, &st) == 0) {
|
||||
/*
|
||||
* stat returns size of Tx, Rx rings combined,
|
||||
* so take half of it for individual ring size.
|
||||
*/
|
||||
ring_size = (uint32_t)st.st_size / 2;
|
||||
syslog(LOG_INFO, "Ring buffer size from %s: %u bytes",
|
||||
ring_path, ring_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ring_size && retry_count == 0) {
|
||||
retry_count = 1;
|
||||
rewinddir(dir);
|
||||
usleep(100 * 1000); /* Wait 100ms and retry once */
|
||||
goto retry_once;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (!ring_size)
|
||||
syslog(LOG_ERR, "Could not determine ring size");
|
||||
|
||||
return ring_size;
|
||||
}
|
||||
|
||||
static unsigned char *desc;
|
||||
|
||||
static int target_fd;
|
||||
static char target_fname[PATH_MAX];
|
||||
@@ -62,8 +118,11 @@ static int hv_fcopy_create_file(char *file_name, char *path_name, __u32 flags)
|
||||
|
||||
filesize = 0;
|
||||
p = path_name;
|
||||
snprintf(target_fname, sizeof(target_fname), "%s/%s",
|
||||
path_name, file_name);
|
||||
if (snprintf(target_fname, sizeof(target_fname), "%s/%s",
|
||||
path_name, file_name) >= sizeof(target_fname)) {
|
||||
syslog(LOG_ERR, "target file name is too long: %s/%s", path_name, file_name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the path is already in place; if not,
|
||||
@@ -270,7 +329,7 @@ static void wcstoutf8(char *dest, const __u16 *src, size_t dest_size)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
while (len < dest_size) {
|
||||
while (len < dest_size && *src) {
|
||||
if (src[len] < 0x80)
|
||||
dest[len++] = (char)(*src++);
|
||||
else
|
||||
@@ -282,27 +341,15 @@ static void wcstoutf8(char *dest, const __u16 *src, size_t dest_size)
|
||||
|
||||
static int hv_fcopy_start(struct hv_start_fcopy *smsg_in)
|
||||
{
|
||||
/*
|
||||
* file_name and path_name should have same length with appropriate
|
||||
* member of hv_start_fcopy.
|
||||
*/
|
||||
char file_name[W_MAX_PATH], path_name[W_MAX_PATH];
|
||||
|
||||
setlocale(LC_ALL, "en_US.utf8");
|
||||
size_t file_size, path_size;
|
||||
char *file_name, *path_name;
|
||||
char *in_file_name = (char *)smsg_in->file_name;
|
||||
char *in_path_name = (char *)smsg_in->path_name;
|
||||
|
||||
file_size = wcstombs(NULL, (const wchar_t *restrict)in_file_name, 0) + 1;
|
||||
path_size = wcstombs(NULL, (const wchar_t *restrict)in_path_name, 0) + 1;
|
||||
|
||||
file_name = (char *)malloc(file_size * sizeof(char));
|
||||
path_name = (char *)malloc(path_size * sizeof(char));
|
||||
|
||||
if (!file_name || !path_name) {
|
||||
free(file_name);
|
||||
free(path_name);
|
||||
syslog(LOG_ERR, "Can't allocate memory for file name and/or path name");
|
||||
return HV_E_FAIL;
|
||||
}
|
||||
|
||||
wcstoutf8(file_name, (__u16 *)in_file_name, file_size);
|
||||
wcstoutf8(path_name, (__u16 *)in_path_name, path_size);
|
||||
wcstoutf8(file_name, smsg_in->file_name, W_MAX_PATH - 1);
|
||||
wcstoutf8(path_name, smsg_in->path_name, W_MAX_PATH - 1);
|
||||
|
||||
return hv_fcopy_create_file(file_name, path_name, smsg_in->copy_flags);
|
||||
}
|
||||
@@ -406,7 +453,7 @@ int main(int argc, char *argv[])
|
||||
int daemonize = 1, long_index = 0, opt, ret = -EINVAL;
|
||||
struct vmbus_br txbr, rxbr;
|
||||
void *ring;
|
||||
uint32_t len = HV_RING_SIZE;
|
||||
uint32_t ring_size, len;
|
||||
char uio_name[NAME_MAX] = {0};
|
||||
char uio_dev_path[PATH_MAX] = {0};
|
||||
|
||||
@@ -437,7 +484,20 @@ int main(int argc, char *argv[])
|
||||
openlog("HV_UIO_FCOPY", 0, LOG_USER);
|
||||
syslog(LOG_INFO, "starting; pid is:%d", getpid());
|
||||
|
||||
fcopy_get_first_folder(FCOPY_UIO, uio_name);
|
||||
ring_size = get_ring_buffer_size();
|
||||
if (!ring_size) {
|
||||
ret = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
desc = malloc(ring_size * sizeof(unsigned char));
|
||||
if (!desc) {
|
||||
syslog(LOG_ERR, "malloc failed for desc buffer");
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
fcopy_get_first_folder(FCOPY_UIO_PATH, uio_name);
|
||||
snprintf(uio_dev_path, sizeof(uio_dev_path), "/dev/%s", uio_name);
|
||||
fcopy_fd = open(uio_dev_path, O_RDWR);
|
||||
|
||||
@@ -445,17 +505,17 @@ int main(int argc, char *argv[])
|
||||
syslog(LOG_ERR, "open %s failed; error: %d %s",
|
||||
uio_dev_path, errno, strerror(errno));
|
||||
ret = fcopy_fd;
|
||||
goto exit;
|
||||
goto free_desc;
|
||||
}
|
||||
|
||||
ring = vmbus_uio_map(&fcopy_fd, HV_RING_SIZE);
|
||||
ring = vmbus_uio_map(&fcopy_fd, ring_size);
|
||||
if (!ring) {
|
||||
ret = errno;
|
||||
syslog(LOG_ERR, "mmap ringbuffer failed; error: %d %s", ret, strerror(ret));
|
||||
goto close;
|
||||
}
|
||||
vmbus_br_setup(&txbr, ring, HV_RING_SIZE);
|
||||
vmbus_br_setup(&rxbr, (char *)ring + HV_RING_SIZE, HV_RING_SIZE);
|
||||
vmbus_br_setup(&txbr, ring, ring_size);
|
||||
vmbus_br_setup(&rxbr, (char *)ring + ring_size, ring_size);
|
||||
|
||||
rxbr.vbr->imask = 0;
|
||||
|
||||
@@ -472,7 +532,7 @@ int main(int argc, char *argv[])
|
||||
goto close;
|
||||
}
|
||||
|
||||
len = HV_RING_SIZE;
|
||||
len = ring_size;
|
||||
ret = rte_vmbus_chan_recv_raw(&rxbr, desc, &len);
|
||||
if (unlikely(ret <= 0)) {
|
||||
/* This indicates a failure to communicate (or worse) */
|
||||
@@ -492,6 +552,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
close:
|
||||
close(fcopy_fd);
|
||||
free_desc:
|
||||
free(desc);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user