Commit 42e7a03d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hyperv-fixes-signed-20220407' of...

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

Pull hyperv fixes from Wei Liu:

 - Correctly propagate coherence information for VMbus devices (Michael
   Kelley)

 - Disable balloon and memory hot-add on ARM64 temporarily (Boqun Feng)

 - Use barrier to prevent reording when reading ring buffer (Michael
   Kelley)

 - Use virt_store_mb in favour of smp_store_mb (Andrea Parri)

 - Fix VMbus device object initialization (Andrea Parri)

 - Deactivate sysctl_record_panic_msg on isolated guest (Andrea Parri)

 - Fix a crash when unloading VMbus module (Guilherme G. Piccoli)

* tag 'hyperv-fixes-signed-20220407' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  Drivers: hv: vmbus: Replace smp_store_mb() with virt_store_mb()
  Drivers: hv: balloon: Disable balloon and hot-add accordingly
  Drivers: hv: balloon: Support status report for larger page sizes
  Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer
  PCI: hv: Propagate coherence from VMbus device to PCI device
  Drivers: hv: vmbus: Propagate VMbus coherence to each VMbus device
  Drivers: hv: vmbus: Fix potential crash on module unload
  Drivers: hv: vmbus: Fix initialization of device object in vmbus_device_register()
  Drivers: hv: vmbus: Deactivate sysctl_record_panic_msg by default in isolated guests
parents 3638bd90 eaa03d34
......@@ -380,7 +380,7 @@ void vmbus_channel_map_relid(struct vmbus_channel *channel)
* execute:
*
* (a) In the "normal (i.e., not resuming from hibernation)" path,
* the full barrier in smp_store_mb() guarantees that the store
* the full barrier in virt_store_mb() guarantees that the store
* is propagated to all CPUs before the add_channel_work work
* is queued. In turn, add_channel_work is queued before the
* channel's ring buffer is allocated/initialized and the
......@@ -392,14 +392,14 @@ void vmbus_channel_map_relid(struct vmbus_channel *channel)
* recv_int_page before retrieving the channel pointer from the
* array of channels.
*
* (b) In the "resuming from hibernation" path, the smp_store_mb()
* (b) In the "resuming from hibernation" path, the virt_store_mb()
* guarantees that the store is propagated to all CPUs before
* the VMBus connection is marked as ready for the resume event
* (cf. check_ready_for_resume_event()). The interrupt handler
* of the VMBus driver and vmbus_chan_sched() can not run before
* vmbus_bus_resume() has completed execution (cf. resume_noirq).
*/
smp_store_mb(
virt_store_mb(
vmbus_connection.channels[channel->offermsg.child_relid],
channel);
}
......
......@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/completion.h>
#include <linux/count_zeros.h>
#include <linux/memory_hotplug.h>
#include <linux/memory.h>
#include <linux/notifier.h>
......@@ -1130,6 +1131,7 @@ static void post_status(struct hv_dynmem_device *dm)
struct dm_status status;
unsigned long now = jiffies;
unsigned long last_post = last_post_time;
unsigned long num_pages_avail, num_pages_committed;
if (pressure_report_delay > 0) {
--pressure_report_delay;
......@@ -1154,16 +1156,21 @@ static void post_status(struct hv_dynmem_device *dm)
* num_pages_onlined) as committed to the host, otherwise it can try
* asking us to balloon them out.
*/
status.num_avail = si_mem_available();
status.num_committed = vm_memory_committed() +
num_pages_avail = si_mem_available();
num_pages_committed = vm_memory_committed() +
dm->num_pages_ballooned +
(dm->num_pages_added > dm->num_pages_onlined ?
dm->num_pages_added - dm->num_pages_onlined : 0) +
compute_balloon_floor();
trace_balloon_status(status.num_avail, status.num_committed,
trace_balloon_status(num_pages_avail, num_pages_committed,
vm_memory_committed(), dm->num_pages_ballooned,
dm->num_pages_added, dm->num_pages_onlined);
/* Convert numbers of pages into numbers of HV_HYP_PAGEs. */
status.num_avail = num_pages_avail * NR_HV_HYP_PAGES_IN_PAGE;
status.num_committed = num_pages_committed * NR_HV_HYP_PAGES_IN_PAGE;
/*
* If our transaction ID is no longer current, just don't
* send the status. This can happen if we were interrupted
......@@ -1653,6 +1660,38 @@ static void disable_page_reporting(void)
}
}
static int ballooning_enabled(void)
{
/*
* Disable ballooning if the page size is not 4k (HV_HYP_PAGE_SIZE),
* since currently it's unclear to us whether an unballoon request can
* make sure all page ranges are guest page size aligned.
*/
if (PAGE_SIZE != HV_HYP_PAGE_SIZE) {
pr_info("Ballooning disabled because page size is not 4096 bytes\n");
return 0;
}
return 1;
}
static int hot_add_enabled(void)
{
/*
* Disable hot add on ARM64, because we currently rely on
* memory_add_physaddr_to_nid() to get a node id of a hot add range,
* however ARM64's memory_add_physaddr_to_nid() always return 0 and
* DM_MEM_HOT_ADD_REQUEST doesn't have the NUMA node information for
* add_memory().
*/
if (IS_ENABLED(CONFIG_ARM64)) {
pr_info("Memory hot add disabled on ARM64\n");
return 0;
}
return 1;
}
static int balloon_connect_vsp(struct hv_device *dev)
{
struct dm_version_request version_req;
......@@ -1724,8 +1763,8 @@ static int balloon_connect_vsp(struct hv_device *dev)
* currently still requires the bits to be set, so we have to add code
* to fail the host's hot-add and balloon up/down requests, if any.
*/
cap_msg.caps.cap_bits.balloon = 1;
cap_msg.caps.cap_bits.hot_add = 1;
cap_msg.caps.cap_bits.balloon = ballooning_enabled();
cap_msg.caps.cap_bits.hot_add = hot_add_enabled();
/*
* Specify our alignment requirements as it relates
......
......@@ -20,6 +20,7 @@
#include <linux/panic_notifier.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/dma-map-ops.h>
#include <asm/hyperv-tlfs.h>
#include <asm/mshyperv.h>
......@@ -218,6 +219,16 @@ bool hv_query_ext_cap(u64 cap_query)
}
EXPORT_SYMBOL_GPL(hv_query_ext_cap);
void hv_setup_dma_ops(struct device *dev, bool coherent)
{
/*
* Hyper-V does not offer a vIOMMU in the guest
* VM, so pass 0/NULL for the IOMMU settings
*/
arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
}
EXPORT_SYMBOL_GPL(hv_setup_dma_ops);
bool hv_is_hibernation_supported(void)
{
return !hv_root_partition && acpi_sleep_state_supported(ACPI_STATE_S4);
......
......@@ -439,7 +439,16 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
{
u32 priv_read_loc = rbi->priv_read_index;
u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index);
u32 write_loc;
/*
* The Hyper-V host writes the packet data, then uses
* store_release() to update the write_index. Use load_acquire()
* here to prevent loads of the packet data from being re-ordered
* before the read of the write_index and potentially getting
* stale data.
*/
write_loc = virt_load_acquire(&rbi->ring_buffer->write_index);
if (write_loc >= priv_read_loc)
return write_loc - priv_read_loc;
......
......@@ -77,8 +77,8 @@ static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
/*
* Hyper-V should be notified only once about a panic. If we will be
* doing hyperv_report_panic_msg() later with kmsg data, don't do
* the notification here.
* doing hv_kmsg_dump() with kmsg data later, don't do the notification
* here.
*/
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
&& hyperv_report_reg()) {
......@@ -100,8 +100,8 @@ static int hyperv_die_event(struct notifier_block *nb, unsigned long val,
/*
* Hyper-V should be notified only once about a panic. If we will be
* doing hyperv_report_panic_msg() later with kmsg data, don't do
* the notification here.
* doing hv_kmsg_dump() with kmsg data later, don't do the notification
* here.
*/
if (hyperv_report_reg())
hyperv_report_panic(regs, val, true);
......@@ -920,6 +920,21 @@ static int vmbus_probe(struct device *child_device)
return ret;
}
/*
* vmbus_dma_configure -- Configure DMA coherence for VMbus device
*/
static int vmbus_dma_configure(struct device *child_device)
{
/*
* On ARM64, propagate the DMA coherence setting from the top level
* VMbus ACPI device to the child VMbus device being added here.
* On x86/x64 coherence is assumed and these calls have no effect.
*/
hv_setup_dma_ops(child_device,
device_get_dma_attr(&hv_acpi_dev->dev) == DEV_DMA_COHERENT);
return 0;
}
/*
* vmbus_remove - Remove a vmbus device
*/
......@@ -1040,6 +1055,7 @@ static struct bus_type hv_bus = {
.remove = vmbus_remove,
.probe = vmbus_probe,
.uevent = vmbus_uevent,
.dma_configure = vmbus_dma_configure,
.dev_groups = vmbus_dev_groups,
.drv_groups = vmbus_drv_groups,
.bus_groups = vmbus_bus_groups,
......@@ -1546,14 +1562,20 @@ static int vmbus_bus_init(void)
if (ret)
goto err_connect;
if (hv_is_isolation_supported())
sysctl_record_panic_msg = 0;
/*
* Only register if the crash MSRs are available
*/
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
u64 hyperv_crash_ctl;
/*
* Sysctl registration is not fatal, since by default
* reporting is enabled.
* Panic message recording (sysctl_record_panic_msg)
* is enabled by default in non-isolated guests and
* disabled by default in isolated guests; the panic
* message recording won't be available in isolated
* guests should the following registration fail.
*/
hv_ctl_table_hdr = register_sysctl_table(hv_root_table);
if (!hv_ctl_table_hdr)
......@@ -2097,6 +2119,10 @@ int vmbus_device_register(struct hv_device *child_device_obj)
child_device_obj->device.parent = &hv_acpi_dev->dev;
child_device_obj->device.release = vmbus_device_release;
child_device_obj->device.dma_parms = &child_device_obj->dma_parms;
child_device_obj->device.dma_mask = &child_device_obj->dma_mask;
dma_set_mask(&child_device_obj->device, DMA_BIT_MASK(64));
/*
* Register with the LDM. This will kick off the driver/device
* binding...which will eventually call vmbus_match() and vmbus_probe()
......@@ -2122,9 +2148,6 @@ int vmbus_device_register(struct hv_device *child_device_obj)
}
hv_debug_add_dev_dir(child_device_obj);
child_device_obj->device.dma_parms = &child_device_obj->dma_parms;
child_device_obj->device.dma_mask = &child_device_obj->dma_mask;
dma_set_mask(&child_device_obj->device, DMA_BIT_MASK(64));
return 0;
err_kset_unregister:
......@@ -2428,6 +2451,21 @@ static int vmbus_acpi_add(struct acpi_device *device)
hv_acpi_dev = device;
/*
* Older versions of Hyper-V for ARM64 fail to include the _CCA
* method on the top level VMbus device in the DSDT. But devices
* are hardware coherent in all current Hyper-V use cases, so fix
* up the ACPI device to behave as if _CCA is present and indicates
* hardware coherence.
*/
ACPI_COMPANION_SET(&device->dev, device);
if (IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED) &&
device_get_dma_attr(&device->dev) == DEV_DMA_NOT_SUPPORTED) {
pr_info("No ACPI _CCA found; assuming coherent device I/O\n");
device->flags.cca_seen = true;
device->flags.coherent_dma = true;
}
result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
vmbus_walk_resources, NULL);
......@@ -2780,10 +2818,15 @@ static void __exit vmbus_exit(void)
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
kmsg_dump_unregister(&hv_kmsg_dumper);
unregister_die_notifier(&hyperv_die_block);
atomic_notifier_chain_unregister(&panic_notifier_list,
&hyperv_panic_block);
}
/*
* The panic notifier is always registered, hence we should
* also unconditionally unregister it here as well.
*/
atomic_notifier_chain_unregister(&panic_notifier_list,
&hyperv_panic_block);
free_page((unsigned long)hv_panic_page);
unregister_sysctl_table(hv_ctl_table_hdr);
hv_ctl_table_hdr = NULL;
......
......@@ -3407,6 +3407,15 @@ static int hv_pci_probe(struct hv_device *hdev,
hbus->bridge->domain_nr = dom;
#ifdef CONFIG_X86
hbus->sysdata.domain = dom;
#elif defined(CONFIG_ARM64)
/*
* Set the PCI bus parent to be the corresponding VMbus
* device. Then the VMbus device will be assigned as the
* ACPI companion in pcibios_root_bridge_prepare() and
* pci_dma_configure() will propagate device coherence
* information to devices created on the bus.
*/
hbus->sysdata.parent = hdev->device.parent;
#endif
hbus->hdev = hdev;
......
......@@ -269,6 +269,7 @@ bool hv_isolation_type_snp(void);
u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size);
void hyperv_cleanup(void);
bool hv_query_ext_cap(u64 cap_query);
void hv_setup_dma_ops(struct device *dev, bool coherent);
void *hv_map_memory(void *addr, unsigned long size);
void hv_unmap_memory(void *addr);
#else /* CONFIG_HYPERV */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment