Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Drivers: hv: vmbus: Propagate VMbus coherence to each VMbus device

VMbus synthetic devices are not represented in the ACPI DSDT -- only
the top level VMbus device is represented. As a result, on ARM64
coherence information in the _CCA method is not specified for
synthetic devices, so they default to not hardware coherent.
Drivers for some of these synthetic devices have been recently
updated to use the standard DMA APIs, and they are incurring extra
overhead of unneeded software coherence management.

Fix this by propagating coherence information from the VMbus node
in ACPI to the individual synthetic devices. There's no effect on
x86/x64 where devices are always hardware coherent.

Signed-off-by: Michael Kelley <mikelley@microsoft.com>
Acked-by: Robin Murphy <robin.murphy@arm.com>
Link: https://lore.kernel.org/r/1648138492-2191-2-git-send-email-mikelley@microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Michael Kelley and committed by
Wei Liu
37200078 792f232d

+43
+11
drivers/hv/hv_common.c
··· 20 20 #include <linux/panic_notifier.h> 21 21 #include <linux/ptrace.h> 22 22 #include <linux/slab.h> 23 + #include <linux/dma-map-ops.h> 23 24 #include <asm/hyperv-tlfs.h> 24 25 #include <asm/mshyperv.h> 25 26 ··· 216 215 return hv_extended_cap & cap_query; 217 216 } 218 217 EXPORT_SYMBOL_GPL(hv_query_ext_cap); 218 + 219 + void hv_setup_dma_ops(struct device *dev, bool coherent) 220 + { 221 + /* 222 + * Hyper-V does not offer a vIOMMU in the guest 223 + * VM, so pass 0/NULL for the IOMMU settings 224 + */ 225 + arch_setup_dma_ops(dev, 0, 0, NULL, coherent); 226 + } 227 + EXPORT_SYMBOL_GPL(hv_setup_dma_ops); 219 228 220 229 bool hv_is_hibernation_supported(void) 221 230 {
+31
drivers/hv/vmbus_drv.c
··· 921 921 } 922 922 923 923 /* 924 + * vmbus_dma_configure -- Configure DMA coherence for VMbus device 925 + */ 926 + static int vmbus_dma_configure(struct device *child_device) 927 + { 928 + /* 929 + * On ARM64, propagate the DMA coherence setting from the top level 930 + * VMbus ACPI device to the child VMbus device being added here. 931 + * On x86/x64 coherence is assumed and these calls have no effect. 932 + */ 933 + hv_setup_dma_ops(child_device, 934 + device_get_dma_attr(&hv_acpi_dev->dev) == DEV_DMA_COHERENT); 935 + return 0; 936 + } 937 + 938 + /* 924 939 * vmbus_remove - Remove a vmbus device 925 940 */ 926 941 static void vmbus_remove(struct device *child_device) ··· 1055 1040 .remove = vmbus_remove, 1056 1041 .probe = vmbus_probe, 1057 1042 .uevent = vmbus_uevent, 1043 + .dma_configure = vmbus_dma_configure, 1058 1044 .dev_groups = vmbus_dev_groups, 1059 1045 .drv_groups = vmbus_drv_groups, 1060 1046 .bus_groups = vmbus_bus_groups, ··· 2450 2434 struct acpi_device *ancestor; 2451 2435 2452 2436 hv_acpi_dev = device; 2437 + 2438 + /* 2439 + * Older versions of Hyper-V for ARM64 fail to include the _CCA 2440 + * method on the top level VMbus device in the DSDT. But devices 2441 + * are hardware coherent in all current Hyper-V use cases, so fix 2442 + * up the ACPI device to behave as if _CCA is present and indicates 2443 + * hardware coherence. 2444 + */ 2445 + ACPI_COMPANION_SET(&device->dev, device); 2446 + if (IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED) && 2447 + device_get_dma_attr(&device->dev) == DEV_DMA_NOT_SUPPORTED) { 2448 + pr_info("No ACPI _CCA found; assuming coherent device I/O\n"); 2449 + device->flags.cca_seen = true; 2450 + device->flags.coherent_dma = true; 2451 + } 2453 2452 2454 2453 result = acpi_walk_resources(device->handle, METHOD_NAME__CRS, 2455 2454 vmbus_walk_resources, NULL);
+1
include/asm-generic/mshyperv.h
··· 269 269 u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); 270 270 void hyperv_cleanup(void); 271 271 bool hv_query_ext_cap(u64 cap_query); 272 + void hv_setup_dma_ops(struct device *dev, bool coherent); 272 273 void *hv_map_memory(void *addr, unsigned long size); 273 274 void hv_unmap_memory(void *addr); 274 275 #else /* CONFIG_HYPERV */