hyperv-next for v7.2-rc1

-----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEIbPD0id6easf0xsudhRwX5BBoF4FAmo41jgTHHdlaS5saXVA
 a2VybmVsLm9yZwAKCRB2FHBfkEGgXjo1CACiN+Ifxj67WZAy1c1tqlHTJbD/OcAh
 KlbZQCVG3QoV9RC8yc9U2DyzSv488YujrqaJhsRg35Cjqs91dFlaXOemArF9dk8f
 ICy3SU48sCGvm6v95ndClUyvncAkqcPR/tyfNs7l5rPh6fZnXEov2SdtOlMMayOA
 HD/s+urd4AiIT3ffj/Ikl/+VrxC7rkYw5oXRF83y4oG79BDtXxgsSlHCudCAM15O
 FvBeUyTT7/7Phz7jk+oNiNBEtJTq6CQo/2Xp5TBpSBl2F/MjfCudAa/XqJakZO27
 UMi5lH8DALYNek4dckyfvt7cVHfeCma0ho77V9AscChFtnAnv74sJyEK
 =ADO8
 -----END PGP SIGNATURE-----

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

Pull hyperv updates from Wei Liu:

 - Use wakeup mailbox to boot APs in Hyper-V VTL2 TDX guests (Yunhong
   Jiang, Ricardo Neri)

 - Move the Hyper-V IOMMU to its own subdirectory (Mukesh Rathor)

 - Cosmetic changes to mshv and balloon driver (Junrui Luo, Markus
   Elfring)

* tag 'hyperv-next-signed-20260621' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  mshv: add bounds check on vp_index in mshv_intercept_isr()
  hv_balloon: Simplify data output in hv_balloon_debug_show()
  x86/hyperv: Cosmetic changes in irqdomain.c for readability
  iommu/hyperv: Create hyperv subdirectory under drivers/iommu
  x86/hyperv/vtl: Use the wakeup mailbox to boot secondary CPUs
  x86/hyperv/vtl: Mark the wakeup mailbox page as private
  x86/acpi: Add a helper to get the address of the wakeup mailbox
  x86/hyperv/vtl: Setup the 64-bit trampoline for TDX guests
  x86/realmode: Make the location of the trampoline configurable
  x86/hyperv/vtl: Set real_mode_header in hv_vtl_init_platform()
  x86/dt: Parse the Wakeup Mailbox for Intel processors
  dt-bindings: reserved-memory: Wakeup Mailbox for Intel processors
  x86/acpi: Add functions to setup and access the wakeup mailbox
  x86/topology: Add missing struct declaration and attribute dependency
This commit is contained in:
Linus Torvalds 2026-06-22 08:06:13 -07:00
commit 6e869de3a1
18 changed files with 290 additions and 122 deletions

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/reserved-memory/intel,wakeup-mailbox.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Wakeup Mailbox for Intel processors
description: |
The Wakeup Mailbox provides a mechanism for the operating system to wake up
secondary CPUs on Intel processors. It is an alternative to the INIT-!INIT-
SIPI sequence used on most x86 systems.
The structure and operation of the mailbox is described in the Multiprocessor
Wakeup Structure of the ACPI specification version 6.6 section 5.2.12.19 [1].
The implementation of the mailbox in platform firmware is described in the
Intel TDX Virtual Firmware Design Guide section 4.3.5 [2].
1: https://uefi.org/specs/ACPI/6.6/05_ACPI_Software_Programming_Model.html#multiprocessor-wakeup-structure
2: https://www.intel.com/content/www/us/en/content-details/733585/intel-tdx-virtual-firmware-design-guide.html
maintainers:
- Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
allOf:
- $ref: reserved-memory.yaml
properties:
compatible:
const: intel,wakeup-mailbox
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
reserved-memory {
#address-cells = <2>;
#size-cells = <1>;
wakeup-mailbox@ffff0000 {
compatible = "intel,wakeup-mailbox";
reg = <0x0 0xffff0000 0x1000>;
};
};

View File

@ -12064,7 +12064,7 @@ F: drivers/clocksource/hyperv_timer.c
F: drivers/hid/hid-hyperv.c
F: drivers/hv/
F: drivers/input/serio/hyperv-keyboard.c
F: drivers/iommu/hyperv-iommu.c
F: drivers/iommu/hyperv/
F: drivers/net/ethernet/microsoft/
F: drivers/net/hyperv/
F: drivers/pci/controller/pci-hyperv-intf.c

View File

@ -6,6 +6,9 @@
* Saurabh Sengar <ssengar@microsoft.com>
*/
#include <linux/acpi.h>
#include <asm/acpi.h>
#include <asm/apic.h>
#include <asm/boot.h>
#include <asm/desc.h>
@ -59,6 +62,18 @@ static void __noreturn hv_vtl_restart(char __maybe_unused *cmd)
hv_vtl_emergency_restart();
}
static inline bool within_page(u64 addr, u64 start)
{
return addr >= start && addr < (start + PAGE_SIZE);
}
static bool hv_vtl_is_private_mmio_tdx(u64 addr)
{
u64 mb_addr = acpi_get_mp_wakeup_mailbox_paddr();
return mb_addr && within_page(addr, mb_addr);
}
void __init hv_vtl_init_platform(void)
{
/*
@ -68,8 +83,16 @@ void __init hv_vtl_init_platform(void)
*/
pr_info("Linux runs in Hyper-V Virtual Trust Level %d\n", ms_hyperv.vtl);
x86_platform.realmode_reserve = x86_init_noop;
x86_platform.realmode_init = x86_init_noop;
/* There is no paravisor present if we are here. */
if (hv_isolation_type_tdx()) {
x86_init.resources.realmode_limit = SZ_4G;
x86_platform.hyper.is_private_mmio = hv_vtl_is_private_mmio_tdx;
} else {
x86_platform.realmode_reserve = x86_init_noop;
x86_platform.realmode_init = x86_init_noop;
real_mode_header = &hv_vtl_real_mode_header;
}
x86_init.irqs.pre_vector_init = x86_init_noop;
x86_init.timers.timer_init = x86_init_noop;
x86_init.resources.probe_roms = x86_init_noop;
@ -251,8 +274,15 @@ int __init hv_vtl_early_init(void)
panic("XSAVE has to be disabled as it is not supported by this module.\n"
"Please add 'noxsave' to the kernel command line.\n");
real_mode_header = &hv_vtl_real_mode_header;
apic_update_callback(wakeup_secondary_cpu_64, hv_vtl_wakeup_secondary_cpu);
/*
* TDX confidential VMs do not trust the hypervisor and cannot use it to
* boot secondary CPUs. Instead, they will be booted using the wakeup
* mailbox if detected during boot. See setup_arch().
*
* There is no paravisor present if we are here.
*/
if (!hv_isolation_type_tdx())
apic_update_callback(wakeup_secondary_cpu_64, hv_vtl_wakeup_secondary_cpu);
return 0;
}

View File

@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Irqdomain for Linux to run as the root partition on Microsoft Hypervisor.
*
@ -14,8 +13,8 @@
#include <linux/irqchip/irq-msi-lib.h>
#include <asm/mshyperv.h>
static int hv_map_interrupt(union hv_device_id device_id, bool level,
int cpu, int vector, struct hv_interrupt_entry *entry)
static int hv_map_interrupt(union hv_device_id hv_devid, bool level,
int cpu, int vector, struct hv_interrupt_entry *ret_entry)
{
struct hv_input_map_device_interrupt *input;
struct hv_output_map_device_interrupt *output;
@ -32,7 +31,7 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level,
intr_desc = &input->interrupt_descriptor;
memset(input, 0, sizeof(*input));
input->partition_id = hv_current_partition_id;
input->device_id = device_id.as_uint64;
input->device_id = hv_devid.as_uint64;
intr_desc->interrupt_type = HV_X64_INTERRUPT_TYPE_FIXED;
intr_desc->vector_count = 1;
intr_desc->target.vector = vector;
@ -44,7 +43,7 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level,
intr_desc->target.vp_set.valid_bank_mask = 0;
intr_desc->target.vp_set.format = HV_GENERIC_SET_SPARSE_4K;
nr_bank = cpumask_to_vpset(&(intr_desc->target.vp_set), cpumask_of(cpu));
nr_bank = cpumask_to_vpset(&intr_desc->target.vp_set, cpumask_of(cpu));
if (nr_bank < 0) {
local_irq_restore(flags);
pr_err("%s: unable to generate VP set\n", __func__);
@ -61,7 +60,7 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level,
status = hv_do_rep_hypercall(HVCALL_MAP_DEVICE_INTERRUPT, 0, var_size,
input, output);
*entry = output->interrupt_entry;
*ret_entry = output->interrupt_entry;
local_irq_restore(flags);
@ -71,21 +70,19 @@ static int hv_map_interrupt(union hv_device_id device_id, bool level,
return hv_result_to_errno(status);
}
static int hv_unmap_interrupt(u64 id, struct hv_interrupt_entry *old_entry)
static int hv_unmap_interrupt(u64 id, struct hv_interrupt_entry *irq_entry)
{
unsigned long flags;
struct hv_input_unmap_device_interrupt *input;
struct hv_interrupt_entry *intr_entry;
u64 status;
local_irq_save(flags);
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
memset(input, 0, sizeof(*input));
intr_entry = &input->interrupt_entry;
input->partition_id = hv_current_partition_id;
input->device_id = id;
*intr_entry = *old_entry;
input->interrupt_entry = *irq_entry;
status = hv_do_hypercall(HVCALL_UNMAP_DEVICE_INTERRUPT, input, NULL);
local_irq_restore(flags);
@ -115,67 +112,71 @@ static int get_rid_cb(struct pci_dev *pdev, u16 alias, void *data)
return 0;
}
static union hv_device_id hv_build_pci_dev_id(struct pci_dev *dev)
static union hv_device_id hv_build_devid_type_pci(struct pci_dev *pdev)
{
union hv_device_id dev_id;
int pos;
union hv_device_id hv_devid;
struct rid_data data = {
.bridge = NULL,
.rid = PCI_DEVID(dev->bus->number, dev->devfn)
.rid = PCI_DEVID(pdev->bus->number, pdev->devfn)
};
pci_for_each_dma_alias(dev, get_rid_cb, &data);
pci_for_each_dma_alias(pdev, get_rid_cb, &data);
dev_id.as_uint64 = 0;
dev_id.device_type = HV_DEVICE_TYPE_PCI;
dev_id.pci.segment = pci_domain_nr(dev->bus);
hv_devid.as_uint64 = 0;
hv_devid.device_type = HV_DEVICE_TYPE_PCI;
hv_devid.pci.segment = pci_domain_nr(pdev->bus);
dev_id.pci.bdf.bus = PCI_BUS_NUM(data.rid);
dev_id.pci.bdf.device = PCI_SLOT(data.rid);
dev_id.pci.bdf.function = PCI_FUNC(data.rid);
dev_id.pci.source_shadow = HV_SOURCE_SHADOW_NONE;
hv_devid.pci.bdf.bus = PCI_BUS_NUM(data.rid);
hv_devid.pci.bdf.device = PCI_SLOT(data.rid);
hv_devid.pci.bdf.function = PCI_FUNC(data.rid);
hv_devid.pci.source_shadow = HV_SOURCE_SHADOW_NONE;
if (data.bridge) {
int pos;
if (data.bridge == NULL)
goto out;
/*
* Microsoft Hypervisor requires a bus range when the bridge is
* running in PCI-X mode.
*
* To distinguish conventional vs PCI-X bridge, we can check
* the bridge's PCI-X Secondary Status Register, Secondary Bus
* Mode and Frequency bits. See PCI Express to PCI/PCI-X Bridge
* Specification Revision 1.0 5.2.2.1.3.
*
* Value zero means it is in conventional mode, otherwise it is
* in PCI-X mode.
*/
/*
* Microsoft Hypervisor requires a bus range when the bridge is
* running in PCI-X mode.
*
* To distinguish conventional vs PCI-X bridge, we can check
* the bridge's PCI-X Secondary Status Register, Secondary Bus
* Mode and Frequency bits. See PCI Express to PCI/PCI-X Bridge
* Specification Revision 1.0 5.2.2.1.3.
*
* Value zero means it is in conventional mode, otherwise it is
* in PCI-X mode.
*/
pos = pci_find_capability(data.bridge, PCI_CAP_ID_PCIX);
if (pos) {
u16 status;
pos = pci_find_capability(data.bridge, PCI_CAP_ID_PCIX);
if (pos) {
u16 status;
pci_read_config_word(data.bridge, pos +
PCI_X_BRIDGE_SSTATUS, &status);
pci_read_config_word(data.bridge, pos + PCI_X_BRIDGE_SSTATUS,
&status);
if (status & PCI_X_SSTATUS_FREQ) {
/* Non-zero, PCI-X mode */
u8 sec_bus, sub_bus;
if (status & PCI_X_SSTATUS_FREQ) {
/* Non-zero, PCI-X mode */
u8 sec_bus, sub_bus;
dev_id.pci.source_shadow = HV_SOURCE_SHADOW_BRIDGE_BUS_RANGE;
hv_devid.pci.source_shadow =
HV_SOURCE_SHADOW_BRIDGE_BUS_RANGE;
pci_read_config_byte(data.bridge, PCI_SECONDARY_BUS, &sec_bus);
dev_id.pci.shadow_bus_range.secondary_bus = sec_bus;
pci_read_config_byte(data.bridge, PCI_SUBORDINATE_BUS, &sub_bus);
dev_id.pci.shadow_bus_range.subordinate_bus = sub_bus;
}
pci_read_config_byte(data.bridge, PCI_SECONDARY_BUS,
&sec_bus);
hv_devid.pci.shadow_bus_range.secondary_bus = sec_bus;
pci_read_config_byte(data.bridge, PCI_SUBORDINATE_BUS,
&sub_bus);
hv_devid.pci.shadow_bus_range.subordinate_bus = sub_bus;
}
}
return dev_id;
out:
return hv_devid;
}
/**
* hv_map_msi_interrupt() - "Map" the MSI IRQ in the hypervisor.
/*
* hv_map_msi_interrupt() - Map the MSI IRQ in the hypervisor.
* @data: Describes the IRQ
* @out_entry: Hypervisor (MSI) interrupt entry (can be NULL)
*
@ -188,22 +189,23 @@ int hv_map_msi_interrupt(struct irq_data *data,
{
struct irq_cfg *cfg = irqd_cfg(data);
struct hv_interrupt_entry dummy;
union hv_device_id device_id;
union hv_device_id hv_devid;
struct msi_desc *msidesc;
struct pci_dev *dev;
struct pci_dev *pdev;
int cpu;
msidesc = irq_data_get_msi_desc(data);
dev = msi_desc_to_pci_dev(msidesc);
device_id = hv_build_pci_dev_id(dev);
pdev = msi_desc_to_pci_dev(msidesc);
hv_devid = hv_build_devid_type_pci(pdev);
cpu = cpumask_first(irq_data_get_effective_affinity_mask(data));
return hv_map_interrupt(device_id, false, cpu, cfg->vector,
return hv_map_interrupt(hv_devid, 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)
static void entry_to_msi_msg(struct hv_interrupt_entry *entry,
struct msi_msg *msg)
{
/* High address is always 0 */
msg->address_hi = 0;
@ -211,17 +213,19 @@ static inline void entry_to_msi_msg(struct hv_interrupt_entry *entry, struct msi
msg->data = entry->msi_entry.data.as_uint32;
}
static int hv_unmap_msi_interrupt(struct pci_dev *dev, struct hv_interrupt_entry *old_entry);
static int hv_unmap_msi_interrupt(struct pci_dev *pdev,
struct hv_interrupt_entry *irq_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 pci_dev *pdev;
int ret;
msidesc = irq_data_get_msi_desc(data);
dev = msi_desc_to_pci_dev(msidesc);
pdev = msi_desc_to_pci_dev(msidesc);
if (!cfg) {
pr_debug("%s: cfg is NULL", __func__);
@ -240,7 +244,7 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
stored_entry = data->chip_data;
data->chip_data = NULL;
ret = hv_unmap_msi_interrupt(dev, stored_entry);
ret = hv_unmap_msi_interrupt(pdev, stored_entry);
kfree(stored_entry);
@ -249,10 +253,8 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
}
stored_entry = kzalloc_obj(*stored_entry, GFP_ATOMIC);
if (!stored_entry) {
pr_debug("%s: failed to allocate chip data\n", __func__);
if (!stored_entry)
return;
}
ret = hv_map_msi_interrupt(data, stored_entry);
if (ret) {
@ -262,18 +264,21 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
data->chip_data = stored_entry;
entry_to_msi_msg(data->chip_data, msg);
return;
}
static int hv_unmap_msi_interrupt(struct pci_dev *dev, struct hv_interrupt_entry *old_entry)
static int hv_unmap_msi_interrupt(struct pci_dev *pdev,
struct hv_interrupt_entry *irq_entry)
{
return hv_unmap_interrupt(hv_build_pci_dev_id(dev).as_uint64, old_entry);
union hv_device_id hv_devid;
hv_devid = hv_build_devid_type_pci(pdev);
return hv_unmap_interrupt(hv_devid.as_uint64, irq_entry);
}
static void hv_teardown_msi_irq(struct pci_dev *dev, struct irq_data *irqd)
/* NB: during map, hv_interrupt_entry is saved via data->chip_data */
static void hv_teardown_msi_irq(struct pci_dev *pdev, struct irq_data *irqd)
{
struct hv_interrupt_entry old_entry;
struct hv_interrupt_entry irq_entry;
struct msi_msg msg;
if (!irqd->chip_data) {
@ -281,13 +286,13 @@ static void hv_teardown_msi_irq(struct pci_dev *dev, struct irq_data *irqd)
return;
}
old_entry = *(struct hv_interrupt_entry *)irqd->chip_data;
entry_to_msi_msg(&old_entry, &msg);
irq_entry = *(struct hv_interrupt_entry *)irqd->chip_data;
entry_to_msi_msg(&irq_entry, &msg);
kfree(irqd->chip_data);
irqd->chip_data = NULL;
(void)hv_unmap_msi_interrupt(dev, &old_entry);
(void)hv_unmap_msi_interrupt(pdev, &irq_entry);
}
/*
@ -302,7 +307,8 @@ static struct irq_chip hv_pci_msi_controller = {
};
static bool hv_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
struct irq_domain *real_parent, struct msi_domain_info *info)
struct irq_domain *real_parent,
struct msi_domain_info *info)
{
struct irq_chip *chip = info->chip;
@ -317,7 +323,8 @@ static bool hv_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
}
#define HV_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | MSI_FLAG_PCI_MSIX)
#define HV_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS)
#define HV_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
MSI_FLAG_USE_DEF_CHIP_OPS)
static struct msi_parent_ops hv_msi_parent_ops = {
.supported_flags = HV_MSI_FLAGS_SUPPORTED,
@ -329,14 +336,14 @@ static struct msi_parent_ops hv_msi_parent_ops = {
.init_dev_msi_info = hv_init_dev_msi_info,
};
static int hv_msi_domain_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs,
void *arg)
/* Allocate nr_irqs IRQs for the given irq domain */
static int hv_msi_domain_alloc(struct irq_domain *d, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
/*
* TODO: The allocation bits of hv_irq_compose_msi_msg(), i.e. everything except
* entry_to_msi_msg() should be in here.
* TODO: The allocation bits of hv_irq_compose_msi_msg(), i.e.
* everything except entry_to_msi_msg() should be in here.
*/
int ret;
ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, arg);
@ -344,13 +351,15 @@ static int hv_msi_domain_alloc(struct irq_domain *d, unsigned int virq, unsigned
return ret;
for (int i = 0; i < nr_irqs; ++i) {
irq_domain_set_info(d, virq + i, 0, &hv_pci_msi_controller, NULL,
handle_edge_irq, NULL, "edge");
irq_domain_set_info(d, virq + i, 0, &hv_pci_msi_controller,
NULL, handle_edge_irq, NULL, "edge");
}
return 0;
}
static void hv_msi_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs)
static void hv_msi_domain_free(struct irq_domain *d, unsigned int virq,
unsigned int nr_irqs)
{
for (int i = 0; i < nr_irqs; ++i) {
struct irq_data *irqd = irq_domain_get_irq_data(d, virq);
@ -362,6 +371,7 @@ static void hv_msi_domain_free(struct irq_domain *d, unsigned int virq, unsigned
hv_teardown_msi_irq(to_pci_dev(desc->dev), irqd);
}
irq_domain_free_irqs_top(d, virq, nr_irqs);
}
@ -394,25 +404,25 @@ struct irq_domain * __init hv_create_pci_msi_domain(void)
int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry)
{
union hv_device_id device_id;
union hv_device_id hv_devid;
device_id.as_uint64 = 0;
device_id.device_type = HV_DEVICE_TYPE_IOAPIC;
device_id.ioapic.ioapic_id = (u8)ioapic_id;
hv_devid.as_uint64 = 0;
hv_devid.device_type = HV_DEVICE_TYPE_IOAPIC;
hv_devid.ioapic.ioapic_id = (u8)ioapic_id;
return hv_unmap_interrupt(device_id.as_uint64, entry);
return hv_unmap_interrupt(hv_devid.as_uint64, entry);
}
EXPORT_SYMBOL_GPL(hv_unmap_ioapic_interrupt);
int hv_map_ioapic_interrupt(int ioapic_id, bool level, int cpu, int vector,
struct hv_interrupt_entry *entry)
{
union hv_device_id device_id;
union hv_device_id hv_devid;
device_id.as_uint64 = 0;
device_id.device_type = HV_DEVICE_TYPE_IOAPIC;
device_id.ioapic.ioapic_id = (u8)ioapic_id;
hv_devid.as_uint64 = 0;
hv_devid.device_type = HV_DEVICE_TYPE_IOAPIC;
hv_devid.ioapic.ioapic_id = (u8)ioapic_id;
return hv_map_interrupt(device_id, level, cpu, vector, entry);
return hv_map_interrupt(hv_devid, level, cpu, vector, entry);
}
EXPORT_SYMBOL_GPL(hv_map_ioapic_interrupt);

View File

@ -182,6 +182,10 @@ void __iomem *x86_acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
#define acpi_os_ioremap acpi_os_ioremap
#endif
void acpi_setup_mp_wakeup_mailbox(u64 addr);
struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void);
u64 acpi_get_mp_wakeup_mailbox_paddr(void);
#else /* !CONFIG_ACPI */
#define acpi_lapic 0
@ -200,6 +204,18 @@ static inline u64 x86_default_get_root_pointer(void)
return 0;
}
static inline void acpi_setup_mp_wakeup_mailbox(u64 addr) { }
static inline struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void)
{
return NULL;
}
static inline u64 acpi_get_mp_wakeup_mailbox_paddr(void)
{
return 0;
}
#endif /* !CONFIG_ACPI */
#define ARCH_HAS_POWER_INIT 1

View File

@ -157,6 +157,8 @@ extern unsigned int __num_threads_per_package;
extern unsigned int __num_cores_per_package;
extern unsigned int __num_nodes_per_package;
struct cpuinfo_x86;
const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c);
enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c);
@ -265,6 +267,7 @@ extern bool x86_topology_update;
#ifdef CONFIG_SCHED_MC_PRIO
#include <asm/percpu.h>
#include <linux/cache.h>
DECLARE_PER_CPU_READ_MOSTLY(int, sched_core_priority);
extern bool __read_mostly sysctl_sched_itmt_enabled;

View File

@ -31,12 +31,15 @@ struct x86_init_mpparse {
* platform
* @memory_setup: platform specific memory setup
* @dmi_setup: platform specific DMI setup
* @realmode_limit: platform specific address limit for the real mode trampoline
* (default 1M)
*/
struct x86_init_resources {
void (*probe_roms)(void);
void (*reserve_resources)(void);
char *(*memory_setup)(void);
void (*dmi_setup)(void);
unsigned long realmode_limit;
};
/**

View File

@ -247,3 +247,19 @@ int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
return 0;
}
void __init acpi_setup_mp_wakeup_mailbox(u64 mailbox_paddr)
{
acpi_mp_wake_mailbox_paddr = mailbox_paddr;
apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
}
struct acpi_madt_multiproc_wakeup_mailbox *acpi_get_mp_wakeup_mailbox(void)
{
return acpi_mp_wake_mailbox;
}
u64 acpi_get_mp_wakeup_mailbox_paddr(void)
{
return acpi_mp_wake_mailbox_paddr;
}

View File

@ -18,6 +18,7 @@
#include <linux/of_pci.h>
#include <linux/initrd.h>
#include <asm/acpi.h>
#include <asm/irqdomain.h>
#include <asm/hpet.h>
#include <asm/apic.h>
@ -125,6 +126,51 @@ static void __init dtb_setup_hpet(void)
#endif
}
#if defined(CONFIG_X86_64) && defined(CONFIG_SMP)
#define WAKEUP_MAILBOX_SIZE 0x1000
#define WAKEUP_MAILBOX_ALIGN 0x1000
/** dtb_wakeup_mailbox_setup() - Parse the wakeup mailbox from the device tree
*
* Look for the presence of a wakeup mailbox in the DeviceTree. The mailbox is
* expected to follow the structure and operation described in the Multiprocessor
* Wakeup Structure of the ACPI specification.
*/
static void __init dtb_wakeup_mailbox_setup(void)
{
struct device_node *node;
struct resource res;
node = of_find_compatible_node(NULL, NULL, "intel,wakeup-mailbox");
if (!node)
return;
if (of_address_to_resource(node, 0, &res))
goto done;
/* The mailbox is a 4KB-aligned region.*/
if (res.start & (WAKEUP_MAILBOX_ALIGN - 1))
goto done;
/* The mailbox has a size of 4KB. */
if (res.end - res.start + 1 != WAKEUP_MAILBOX_SIZE)
goto done;
/* Not supported when the mailbox is used. */
cpu_hotplug_disable_offlining();
acpi_setup_mp_wakeup_mailbox(res.start);
done:
of_node_put(node);
}
#else /* !CONFIG_X86_64 || !CONFIG_SMP */
static inline int dtb_wakeup_mailbox_setup(void)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_X86_64 && CONFIG_SMP */
#ifdef CONFIG_X86_LOCAL_APIC
static void __init dtb_cpu_setup(void)
@ -287,6 +333,7 @@ static void __init x86_dtb_parse_smp_config(void)
dtb_setup_hpet();
dtb_apic_setup();
dtb_wakeup_mailbox_setup();
}
void __init x86_flattree_get_config(void)

View File

@ -9,6 +9,7 @@
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/sizes.h>
#include <asm/acpi.h>
#include <asm/bios_ebda.h>
@ -69,6 +70,8 @@ struct x86_init_ops x86_init __initdata = {
.reserve_resources = reserve_standard_io_resources,
.memory_setup = e820__memory_setup_default,
.dmi_setup = dmi_setup,
/* Has to be under 1M so we can execute real-mode AP code. */
.realmode_limit = SZ_1M,
},
.mpparse = {

View File

@ -46,7 +46,7 @@ void load_trampoline_pgtable(void)
void __init reserve_real_mode(void)
{
phys_addr_t mem;
phys_addr_t mem, limit = x86_init.resources.realmode_limit;
size_t size = real_mode_size_needed();
if (!size)
@ -54,10 +54,9 @@ void __init reserve_real_mode(void)
WARN_ON(slab_is_available());
/* Has to be under 1M so we can execute real-mode AP code. */
mem = memblock_phys_alloc_range(size, PAGE_SIZE, 0, 1<<20);
mem = memblock_phys_alloc_range(size, PAGE_SIZE, 0, limit);
if (!mem)
pr_info("No sub-1M memory is available for the trampoline\n");
pr_info("No memory below %pa for the real-mode trampoline\n", &limit);
else
set_real_mode_mem(mem);

View File

@ -1862,9 +1862,7 @@ static int hv_balloon_debug_show(struct seq_file *f, void *offset)
if (hot_add_enabled())
seq_puts(f, " hot_add");
seq_puts(f, "\n");
seq_printf(f, "%-22s: %u", "state", dm->state);
seq_printf(f, "\n%-22s: %u", "state", dm->state);
switch (dm->state) {
case DM_INITIALIZING:
sname = "Initializing";

View File

@ -384,6 +384,11 @@ mshv_intercept_isr(struct hv_message *msg)
*/
vp_index =
((struct hv_opaque_intercept_message *)msg->u.payload)->vp_index;
/* This shouldn't happen, but just in case. */
if (unlikely(vp_index >= MSHV_MAX_VPS)) {
pr_debug("VP index %u out of bounds\n", vp_index);
goto unlock_out;
}
vp = partition->pt_vp_array[vp_index];
if (unlikely(!vp)) {
pr_debug("failed to find VP %u\n", vp_index);

View File

@ -351,15 +351,6 @@ config MTK_IOMMU_V1
if unsure, say N here.
config HYPERV_IOMMU
bool "Hyper-V IRQ Handling"
depends on HYPERV && X86
select IOMMU_API
default HYPERV
help
Stub IOMMU driver to handle IRQs to support Hyper-V Linux
guest and root partitions.
config VIRTIO_IOMMU
tristate "Virtio IOMMU driver"
depends on VIRTIO

View File

@ -4,6 +4,7 @@ obj-$(CONFIG_AMD_IOMMU) += amd/
obj-$(CONFIG_INTEL_IOMMU) += intel/
obj-$(CONFIG_RISCV_IOMMU) += riscv/
obj-$(CONFIG_GENERIC_PT) += generic_pt/fmt/
obj-$(CONFIG_HYPERV) += hyperv/
obj-$(CONFIG_IOMMU_API) += iommu.o
obj-$(CONFIG_IOMMU_SUPPORT) += iommu-pages.o
obj-$(CONFIG_IOMMU_API) += iommu-traces.o
@ -30,7 +31,6 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o
obj-$(CONFIG_IOMMU_IOPF) += io-pgfault.o

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_IRQ_REMAP) += hv-irq-remap-x86.o

View File

@ -22,9 +22,7 @@
#include <asm/hypervisor.h>
#include <asm/mshyperv.h>
#include "irq_remapping.h"
#ifdef CONFIG_IRQ_REMAP
#include "../irq_remapping.h"
/*
* According 82093AA IO-APIC spec , IO APIC has a 24-entry Interrupt
@ -330,5 +328,3 @@ static const struct irq_domain_ops hyperv_root_ir_domain_ops = {
.alloc = hyperv_root_irq_remapping_alloc,
.free = hyperv_root_irq_remapping_free,
};
#endif

View File

@ -108,7 +108,7 @@ int __init irq_remapping_prepare(void)
else if (IS_ENABLED(CONFIG_AMD_IOMMU) &&
amd_iommu_irq_ops.prepare() == 0)
remap_ops = &amd_iommu_irq_ops;
else if (IS_ENABLED(CONFIG_HYPERV_IOMMU) &&
else if (IS_ENABLED(CONFIG_HYPERV) &&
hyperv_irq_remap_ops.prepare() == 0)
remap_ops = &hyperv_irq_remap_ops;
else