Pull hyperv updates from Wei Liu: - More patches for Hyper-V isolation VM support (Tianyu Lan) - Bug fixes and clean-up patches from various people * tag 'hyperv-next-signed-20220114' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: scsi: storvsc: Fix storvsc_queuecommand() memory leak x86/hyperv: Properly deal with empty cpumasks in hyperv_flush_tlb_multi() Drivers: hv: vmbus: Initialize request offers message for Isolation VM scsi: storvsc: Fix unsigned comparison to zero swiotlb: Add CONFIG_HAS_IOMEM check around swiotlb_mem_remap() x86/hyperv: Fix definition of hv_ghcb_pg variable Drivers: hv: Fix definition of hypercall input & output arg variables net: netvsc: Add Isolation VM support for netvsc driver scsi: storvsc: Add Isolation VM support for storvsc driver hyper-v: Enable swiotlb bounce buffer for Isolation VM x86/hyper-v: Add hyperv Isolation VM check in the cc_platform_has() swiotlb: Add swiotlb bounce buffer remap function for HV IVM
Unified · Split
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <linux/syscore_ops.h> |
| 29 | 29 | #include <clocksource/hyperv_timer.h> |
| 30 | 30 | #include <linux/highmem.h> |
| 31 | +#include <linux/swiotlb.h> | |
| 31 | 32 | |
| 32 | 33 | int hyperv_init_cpuhp; |
| 33 | 34 | u64 hv_current_partition_id = ~0ull; |
| @@ -36,7 +37,7 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id); · 2 unmodified lines | ||
| 36 | 37 | void *hv_hypercall_pg; |
| 37 | 38 | EXPORT_SYMBOL_GPL(hv_hypercall_pg); |
| 38 | 39 | |
| 39 | −union hv_ghcb __percpu **hv_ghcb_pg; | |
| 40 | +union hv_ghcb * __percpu *hv_ghcb_pg; | |
| 40 | 41 | |
| 41 | 42 | /* Storage to save the hypercall page temporarily for hibernation */ |
| 42 | 43 | static void *hv_hypercall_pg_saved; |
| @@ -498,6 +499,17 @@ void __init hyperv_init(void) · 455 unmodified lines | ||
| 498 | 499 | |
| 499 | 500 | /* Query the VMs extended capability once, so that it can be cached. */ |
| 500 | 501 | hv_query_ext_cap(0); |
| 502 | + | |
| 503 | +#ifdef CONFIG_SWIOTLB | |
| 504 | + /* | |
| 505 | + * Swiotlb bounce buffer needs to be mapped in extra address | |
| 506 | + * space. Map function doesn't work in the early place and so | |
| 507 | + * call swiotlb_update_mem_attributes() here. | |
| 508 | + */ | |
| 509 | + if (hv_is_isolation_supported()) | |
| 510 | + swiotlb_update_mem_attributes(); | |
| 511 | +#endif | |
| 512 | + | |
| 501 | 513 | return; |
| 502 | 514 | |
| 503 | 515 | clean_guest_os_id: |
| @@ -287,3 +287,31 @@ int hv_set_mem_host_visibility(unsigned long kbuffer, int pagecount, bool visibl · 286 unmodified lines | ||
| 287 | 287 | kfree(pfn_array); |
| 288 | 288 | return ret; |
| 289 | 289 | } |
| 290 | + | |
| 291 | +/* | |
| 292 | + * hv_map_memory - map memory to extra space in the AMD SEV-SNP Isolation VM. | |
| 293 | + */ | |
| 294 | +void *hv_map_memory(void *addr, unsigned long size) | |
| 295 | +{ | |
| 296 | + unsigned long *pfns = kcalloc(size / PAGE_SIZE, | |
| 297 | + sizeof(unsigned long), GFP_KERNEL); | |
| 298 | + void *vaddr; | |
| 299 | + int i; | |
| 300 | + | |
| 301 | + if (!pfns) | |
| 302 | + return NULL; | |
| 303 | + | |
| 304 | + for (i = 0; i < size / PAGE_SIZE; i++) | |
| 305 | + pfns[i] = vmalloc_to_pfn(addr + i * PAGE_SIZE) + | |
| 306 | + (ms_hyperv.shared_gpa_boundary >> PAGE_SHIFT); | |
| 307 | + | |
| 308 | + vaddr = vmap_pfn(pfns, size / PAGE_SIZE, PAGE_KERNEL_IO); | |
| 309 | + kfree(pfns); | |
| 310 | + | |
| 311 | + return vaddr; | |
| 312 | +} | |
| 313 | + | |
| 314 | +void hv_unmap_memory(void *addr) | |
| 315 | +{ | |
| 316 | + vunmap(addr); | |
| 317 | +} | |
| @@ -68,15 +68,6 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, · 67 unmodified lines | ||
| 68 | 68 | |
| 69 | 69 | local_irq_save(flags); |
| 70 | 70 | |
| 71 | − /* | |
| 72 | − * Only check the mask _after_ interrupt has been disabled to avoid the | |
| 73 | − * mask changing under our feet. | |
| 74 | − */ | |
| 75 | − if (cpumask_empty(cpus)) { | |
| 76 | − local_irq_restore(flags); | |
| 77 | − return; | |
| 78 | − } | |
| 79 | − | |
| 80 | 71 | flush_pcpu = (struct hv_tlb_flush **) |
| 81 | 72 | this_cpu_ptr(hyperv_pcpu_input_arg); |
| 82 | 73 | |
| @@ -115,7 +106,9 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, · 32 unmodified lines | ||
| 115 | 106 | * must. We will also check all VP numbers when walking the |
| 116 | 107 | * supplied CPU set to remain correct in all cases. |
| 117 | 108 | */ |
| 118 | − if (hv_cpu_number_to_vp_number(cpumask_last(cpus)) >= 64) | |
| 109 | + cpu = cpumask_last(cpus); | |
| 110 | + | |
| 111 | + if (cpu < nr_cpumask_bits && hv_cpu_number_to_vp_number(cpu) >= 64) | |
| 119 | 112 | goto do_ex_hypercall; |
| 120 | 113 | |
| 121 | 114 | for_each_cpu(cpu, cpus) { |
| @@ -131,6 +124,12 @@ static void hyperv_flush_tlb_multi(const struct cpumask *cpus, · 9 unmodified lines | ||
| 131 | 124 | __set_bit(vcpu, (unsigned long *) |
| 132 | 125 | &flush->processor_mask); |
| 133 | 126 | } |
| 127 | + | |
| 128 | + /* nothing to flush if 'processor_mask' ends up being empty */ | |
| 129 | + if (!flush->processor_mask) { | |
| 130 | + local_irq_restore(flags); | |
| 131 | + return; | |
| 132 | + } | |
| 134 | 133 | } |
| 135 | 134 | |
| 136 | 135 | /* |
| @@ -30,7 +30,7 @@ extern void *hv_hypercall_pg; · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | extern u64 hv_current_partition_id; |
| 32 | 32 | |
| 33 | −extern union hv_ghcb __percpu **hv_ghcb_pg; | |
| 33 | +extern union hv_ghcb * __percpu *hv_ghcb_pg; | |
| 34 | 34 | |
| 35 | 35 | int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); |
| 36 | 36 | int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/cc_platform.h> |
| 12 | 12 | #include <linux/mem_encrypt.h> |
| 13 | 13 | |
| 14 | +#include <asm/mshyperv.h> | |
| 14 | 15 | #include <asm/processor.h> |
| 15 | 16 | |
| 16 | 17 | static bool __maybe_unused intel_cc_platform_has(enum cc_attr attr) |
| @@ -66,12 +67,19 @@ static bool amd_cc_platform_has(enum cc_attr attr) · 49 unmodified lines | ||
| 66 | 67 | #endif |
| 67 | 68 | } |
| 68 | 69 | |
| 70 | +static bool hyperv_cc_platform_has(enum cc_attr attr) | |
| 71 | +{ | |
| 72 | + return attr == CC_ATTR_GUEST_MEM_ENCRYPT; | |
| 73 | +} | |
| 69 | 74 | |
| 70 | 75 | bool cc_platform_has(enum cc_attr attr) |
| 71 | 76 | { |
| 72 | 77 | if (sme_me_mask) |
| 73 | 78 | return amd_cc_platform_has(attr); |
| 74 | 79 | |
| 80 | + if (hv_is_isolation_supported()) | |
| 81 | + return hyperv_cc_platform_has(attr); | |
| 82 | + | |
| 75 | 83 | return false; |
| 76 | 84 | } |
| 77 | 85 | EXPORT_SYMBOL_GPL(cc_platform_has); |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/kexec.h> |
| 19 | 19 | #include <linux/i8253.h> |
| 20 | 20 | #include <linux/random.h> |
| 21 | +#include <linux/swiotlb.h> | |
| 21 | 22 | #include <asm/processor.h> |
| 22 | 23 | #include <asm/hypervisor.h> |
| 23 | 24 | #include <asm/hyperv-tlfs.h> |
| @@ -329,8 +330,20 @@ static void __init ms_hyperv_init_platform(void) · 305 unmodified lines | ||
| 329 | 330 | pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n", |
| 330 | 331 | ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b); |
| 331 | 332 | |
| 332 | − if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) | |
| 333 | + if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) { | |
| 333 | 334 | static_branch_enable(&isolation_type_snp); |
| 335 | +#ifdef CONFIG_SWIOTLB | |
| 336 | + swiotlb_unencrypted_base = ms_hyperv.shared_gpa_boundary; | |
| 337 | +#endif | |
| 338 | + } | |
| 339 | + | |
| 340 | +#ifdef CONFIG_SWIOTLB | |
| 341 | + /* | |
| 342 | + * Enable swiotlb force mode in Isolation VM to | |
| 343 | + * use swiotlb bounce buffer for dma transaction. | |
| 344 | + */ | |
| 345 | + swiotlb_force = SWIOTLB_FORCE; | |
| 346 | +#endif | |
| 334 | 347 | } |
| 335 | 348 | |
| 336 | 349 | if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { |
| @@ -1554,7 +1554,7 @@ int vmbus_request_offers(void) · 1553 unmodified lines | ||
| 1554 | 1554 | struct vmbus_channel_msginfo *msginfo; |
| 1555 | 1555 | int ret; |
| 1556 | 1556 | |
| 1557 | − msginfo = kmalloc(sizeof(*msginfo) + | |
| 1557 | + msginfo = kzalloc(sizeof(*msginfo) + | |
| 1558 | 1558 | sizeof(struct vmbus_channel_message_header), |
| 1559 | 1559 | GFP_KERNEL); |
| 1560 | 1560 | if (!msginfo) |
| @@ -44,10 +44,10 @@ EXPORT_SYMBOL_GPL(hv_vp_index); · 43 unmodified lines | ||
| 44 | 44 | u32 hv_max_vp_index; |
| 45 | 45 | EXPORT_SYMBOL_GPL(hv_max_vp_index); |
| 46 | 46 | |
| 47 | −void __percpu **hyperv_pcpu_input_arg; | |
| 47 | +void * __percpu *hyperv_pcpu_input_arg; | |
| 48 | 48 | EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg); |
| 49 | 49 | |
| 50 | −void __percpu **hyperv_pcpu_output_arg; | |
| 50 | +void * __percpu *hyperv_pcpu_output_arg; | |
| 51 | 51 | EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg); |
| 52 | 52 | |
| 53 | 53 | /* |
| @@ -295,3 +295,14 @@ u64 __weak hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_s · 241 unmodified lines | ||
| 295 | 295 | return HV_STATUS_INVALID_PARAMETER; |
| 296 | 296 | } |
| 297 | 297 | EXPORT_SYMBOL_GPL(hv_ghcb_hypercall); |
| 298 | + | |
| 299 | +void __weak *hv_map_memory(void *addr, unsigned long size) | |
| 300 | +{ | |
| 301 | + return NULL; | |
| 302 | +} | |
| 303 | +EXPORT_SYMBOL_GPL(hv_map_memory); | |
| 304 | + | |
| 305 | +void __weak hv_unmap_memory(void *addr) | |
| 306 | +{ | |
| 307 | +} | |
| 308 | +EXPORT_SYMBOL_GPL(hv_unmap_memory); | |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #include <linux/random.h> |
| 34 | 34 | #include <linux/kernel.h> |
| 35 | 35 | #include <linux/syscore_ops.h> |
| 36 | +#include <linux/dma-map-ops.h> | |
| 36 | 37 | #include <clocksource/hyperv_timer.h> |
| 37 | 38 | #include "hyperv_vmbus.h" |
| 38 | 39 | |
| @@ -2078,6 +2079,7 @@ struct hv_device *vmbus_device_create(const guid_t *type, · 2039 unmodified lines | ||
| 2078 | 2079 | return child_device_obj; |
| 2079 | 2080 | } |
| 2080 | 2081 | |
| 2082 | +static u64 vmbus_dma_mask = DMA_BIT_MASK(64); | |
| 2081 | 2083 | /* |
| 2082 | 2084 | * vmbus_device_register - Register the child device |
| 2083 | 2085 | */ |
| @@ -2118,6 +2120,8 @@ int vmbus_device_register(struct hv_device *child_device_obj) · 34 unmodified lines | ||
| 2118 | 2120 | } |
| 2119 | 2121 | hv_debug_add_dev_dir(child_device_obj); |
| 2120 | 2122 | |
| 2123 | + child_device_obj->device.dma_mask = &vmbus_dma_mask; | |
| 2124 | + child_device_obj->device.dma_parms = &child_device_obj->dma_parms; | |
| 2121 | 2125 | return 0; |
| 2122 | 2126 | |
| 2123 | 2127 | err_kset_unregister: |
| @@ -164,6 +164,7 @@ struct hv_netvsc_packet { · 163 unmodified lines | ||
| 164 | 164 | u32 total_bytes; |
| 165 | 165 | u32 send_buf_index; |
| 166 | 166 | u32 total_data_buflen; |
| 167 | + struct hv_dma_range *dma_range; | |
| 167 | 168 | }; |
| 168 | 169 | |
| 169 | 170 | #define NETVSC_HASH_KEYLEN 40 |
| @@ -1074,6 +1075,7 @@ struct netvsc_device { · 904 unmodified lines | ||
| 1074 | 1075 | |
| 1075 | 1076 | /* Receive buffer allocated by us but manages by NetVSP */ |
| 1076 | 1077 | void *recv_buf; |
| 1078 | + void *recv_original_buf; | |
| 1077 | 1079 | u32 recv_buf_size; /* allocated bytes */ |
| 1078 | 1080 | struct vmbus_gpadl recv_buf_gpadl_handle; |
| 1079 | 1081 | u32 recv_section_cnt; |
| @@ -1082,6 +1084,7 @@ struct netvsc_device { · 2 unmodified lines | ||
| 1082 | 1084 | |
| 1083 | 1085 | /* Send buffer allocated by us */ |
| 1084 | 1086 | void *send_buf; |
| 1087 | + void *send_original_buf; | |
| 1085 | 1088 | u32 send_buf_size; |
| 1086 | 1089 | struct vmbus_gpadl send_buf_gpadl_handle; |
| 1087 | 1090 | u32 send_section_cnt; |
| @@ -1731,4 +1734,6 @@ struct rndis_message { · 643 unmodified lines | ||
| 1731 | 1734 | #define RETRY_US_HI 10000 |
| 1732 | 1735 | #define RETRY_MAX 2000 /* >10 sec */ |
| 1733 | 1736 | |
| 1737 | +void netvsc_dma_unmap(struct hv_device *hv_dev, | |
| 1738 | + struct hv_netvsc_packet *packet); | |
| 1734 | 1739 | #endif /* _HYPERV_NET_H */ |
| @@ -153,8 +153,21 @@ static void free_netvsc_device(struct rcu_head *head) · 152 unmodified lines | ||
| 153 | 153 | int i; |
| 154 | 154 | |
| 155 | 155 | kfree(nvdev->extension); |
| 156 | − vfree(nvdev->recv_buf); | |
| 157 | − vfree(nvdev->send_buf); | |
| 156 | + | |
| 157 | + if (nvdev->recv_original_buf) { | |
| 158 | + hv_unmap_memory(nvdev->recv_buf); | |
| 159 | + vfree(nvdev->recv_original_buf); | |
| 160 | + } else { | |
| 161 | + vfree(nvdev->recv_buf); | |
| 162 | + } | |
| 163 | + | |
| 164 | + if (nvdev->send_original_buf) { | |
| 165 | + hv_unmap_memory(nvdev->send_buf); | |
| 166 | + vfree(nvdev->send_original_buf); | |
| 167 | + } else { | |
| 168 | + vfree(nvdev->send_buf); | |
| 169 | + } | |
| 170 | + | |
| 158 | 171 | bitmap_free(nvdev->send_section_map); |
| 159 | 172 | |
| 160 | 173 | for (i = 0; i < VRSS_CHANNEL_MAX; i++) { |
| @@ -337,6 +350,7 @@ static int netvsc_init_buf(struct hv_device *device, · 176 unmodified lines | ||
| 337 | 350 | struct nvsp_message *init_packet; |
| 338 | 351 | unsigned int buf_size; |
| 339 | 352 | int i, ret = 0; |
| 353 | + void *vaddr; | |
| 340 | 354 | |
| 341 | 355 | /* Get receive buffer area. */ |
| 342 | 356 | buf_size = device_info->recv_sections * device_info->recv_section_size; |
| @@ -372,6 +386,17 @@ static int netvsc_init_buf(struct hv_device *device, · 29 unmodified lines | ||
| 372 | 386 | goto cleanup; |
| 373 | 387 | } |
| 374 | 388 | |
| 389 | + if (hv_isolation_type_snp()) { | |
| 390 | + vaddr = hv_map_memory(net_device->recv_buf, buf_size); | |
| 391 | + if (!vaddr) { | |
| 392 | + ret = -ENOMEM; | |
| 393 | + goto cleanup; | |
| 394 | + } | |
| 395 | + | |
| 396 | + net_device->recv_original_buf = net_device->recv_buf; | |
| 397 | + net_device->recv_buf = vaddr; | |
| 398 | + } | |
| 399 | + | |
| 375 | 400 | /* Notify the NetVsp of the gpadl handle */ |
| 376 | 401 | init_packet = &net_device->channel_init_pkt; |
| 377 | 402 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
| @@ -475,6 +500,17 @@ static int netvsc_init_buf(struct hv_device *device, · 97 unmodified lines | ||
| 475 | 500 | goto cleanup; |
| 476 | 501 | } |
| 477 | 502 | |
| 503 | + if (hv_isolation_type_snp()) { | |
| 504 | + vaddr = hv_map_memory(net_device->send_buf, buf_size); | |
| 505 | + if (!vaddr) { | |
| 506 | + ret = -ENOMEM; | |
| 507 | + goto cleanup; | |
| 508 | + } | |
| 509 | + | |
| 510 | + net_device->send_original_buf = net_device->send_buf; | |
| 511 | + net_device->send_buf = vaddr; | |
| 512 | + } | |
| 513 | + | |
| 478 | 514 | /* Notify the NetVsp of the gpadl handle */ |
| 479 | 515 | init_packet = &net_device->channel_init_pkt; |
| 480 | 516 | memset(init_packet, 0, sizeof(struct nvsp_message)); |
| @@ -764,7 +800,7 @@ static void netvsc_send_tx_complete(struct net_device *ndev, · 283 unmodified lines | ||
| 764 | 800 | |
| 765 | 801 | /* Notify the layer above us */ |
| 766 | 802 | if (likely(skb)) { |
| 767 | − const struct hv_netvsc_packet *packet | |
| 803 | + struct hv_netvsc_packet *packet | |
| 768 | 804 | = (struct hv_netvsc_packet *)skb->cb; |
| 769 | 805 | u32 send_index = packet->send_buf_index; |
| 770 | 806 | struct netvsc_stats *tx_stats; |
| @@ -780,6 +816,7 @@ static void netvsc_send_tx_complete(struct net_device *ndev, · 9 unmodified lines | ||
| 780 | 816 | tx_stats->bytes += packet->total_bytes; |
| 781 | 817 | u64_stats_update_end(&tx_stats->syncp); |
| 782 | 818 | |
| 819 | + netvsc_dma_unmap(ndev_ctx->device_ctx, packet); | |
| 783 | 820 | napi_consume_skb(skb, budget); |
| 784 | 821 | } |
| 785 | 822 | |
| @@ -944,6 +981,88 @@ static void netvsc_copy_to_send_buf(struct netvsc_device *net_device, · 158 unmodified lines | ||
| 944 | 981 | memset(dest, 0, padding); |
| 945 | 982 | } |
| 946 | 983 | |
| 984 | +void netvsc_dma_unmap(struct hv_device *hv_dev, | |
| 985 | + struct hv_netvsc_packet *packet) | |
| 986 | +{ | |
| 987 | + u32 page_count = packet->cp_partial ? | |
| 988 | + packet->page_buf_cnt - packet->rmsg_pgcnt : | |
| 989 | + packet->page_buf_cnt; | |
| 990 | + int i; | |
| 991 | + | |
| 992 | + if (!hv_is_isolation_supported()) | |
| 993 | + return; | |
| 994 | + | |
| 995 | + if (!packet->dma_range) | |
| 996 | + return; | |
| 997 | + | |
| 998 | + for (i = 0; i < page_count; i++) | |
| 999 | + dma_unmap_single(&hv_dev->device, packet->dma_range[i].dma, | |
| 1000 | + packet->dma_range[i].mapping_size, | |
| 1001 | + DMA_TO_DEVICE); | |
| 1002 | + | |
| 1003 | + kfree(packet->dma_range); | |
| 1004 | +} | |
| 1005 | + | |
| 1006 | +/* netvsc_dma_map - Map swiotlb bounce buffer with data page of | |
| 1007 | + * packet sent by vmbus_sendpacket_pagebuffer() in the Isolation | |
| 1008 | + * VM. | |
| 1009 | + * | |
| 1010 | + * In isolation VM, netvsc send buffer has been marked visible to | |
| 1011 | + * host and so the data copied to send buffer doesn't need to use | |
| 1012 | + * bounce buffer. The data pages handled by vmbus_sendpacket_pagebuffer() | |
| 1013 | + * may not be copied to send buffer and so these pages need to be | |
| 1014 | + * mapped with swiotlb bounce buffer. netvsc_dma_map() is to do | |
| 1015 | + * that. The pfns in the struct hv_page_buffer need to be converted | |
| 1016 | + * to bounce buffer's pfn. The loop here is necessary because the | |
| 1017 | + * entries in the page buffer array are not necessarily full | |
| 1018 | + * pages of data. Each entry in the array has a separate offset and | |
| 1019 | + * len that may be non-zero, even for entries in the middle of the | |
| 1020 | + * array. And the entries are not physically contiguous. So each | |
| 1021 | + * entry must be individually mapped rather than as a contiguous unit. | |
| 1022 | + * So not use dma_map_sg() here. | |
| 1023 | + */ | |
| 1024 | +static int netvsc_dma_map(struct hv_device *hv_dev, | |
| 1025 | + struct hv_netvsc_packet *packet, | |
| 1026 | + struct hv_page_buffer *pb) | |
| 1027 | +{ | |
| 1028 | + u32 page_count = packet->cp_partial ? | |
| 1029 | + packet->page_buf_cnt - packet->rmsg_pgcnt : | |
| 1030 | + packet->page_buf_cnt; | |
| 1031 | + dma_addr_t dma; | |
| 1032 | + int i; | |
| 1033 | + | |
| 1034 | + if (!hv_is_isolation_supported()) | |
| 1035 | + return 0; | |
| 1036 | + | |
| 1037 | + packet->dma_range = kcalloc(page_count, | |
| 1038 | + sizeof(*packet->dma_range), | |
| 1039 | + GFP_KERNEL); | |
| 1040 | + if (!packet->dma_range) | |
| 1041 | + return -ENOMEM; | |
| 1042 | + | |
| 1043 | + for (i = 0; i < page_count; i++) { | |
| 1044 | + char *src = phys_to_virt((pb[i].pfn << HV_HYP_PAGE_SHIFT) | |
| 1045 | + + pb[i].offset); | |
| 1046 | + u32 len = pb[i].len; | |
| 1047 | + | |
| 1048 | + dma = dma_map_single(&hv_dev->device, src, len, | |
| 1049 | + DMA_TO_DEVICE); | |
| 1050 | + if (dma_mapping_error(&hv_dev->device, dma)) { | |
| 1051 | + kfree(packet->dma_range); | |
| 1052 | + return -ENOMEM; | |
| 1053 | + } | |
| 1054 | + | |
| 1055 | + /* pb[].offset and pb[].len are not changed during dma mapping | |
| 1056 | + * and so not reassign. | |
| 1057 | + */ | |
| 1058 | + packet->dma_range[i].dma = dma; | |
| 1059 | + packet->dma_range[i].mapping_size = len; | |
| 1060 | + pb[i].pfn = dma >> HV_HYP_PAGE_SHIFT; | |
| 1061 | + } | |
| 1062 | + | |
| 1063 | + return 0; | |
| 1064 | +} | |
| 1065 | + | |
| 947 | 1066 | static inline int netvsc_send_pkt( |
| 948 | 1067 | struct hv_device *device, |
| 949 | 1068 | struct hv_netvsc_packet *packet, |
| @@ -984,14 +1103,24 @@ static inline int netvsc_send_pkt( · 34 unmodified lines | ||
| 984 | 1103 | |
| 985 | 1104 | trace_nvsp_send_pkt(ndev, out_channel, rpkt); |
| 986 | 1105 | |
| 1106 | + packet->dma_range = NULL; | |
| 987 | 1107 | if (packet->page_buf_cnt) { |
| 988 | 1108 | if (packet->cp_partial) |
| 989 | 1109 | pb += packet->rmsg_pgcnt; |
| 990 | 1110 | |
| 1111 | + ret = netvsc_dma_map(ndev_ctx->device_ctx, packet, pb); | |
| 1112 | + if (ret) { | |
| 1113 | + ret = -EAGAIN; | |
| 1114 | + goto exit; | |
| 1115 | + } | |
| 1116 | + | |
| 991 | 1117 | ret = vmbus_sendpacket_pagebuffer(out_channel, |
| 992 | 1118 | pb, packet->page_buf_cnt, |
| 993 | 1119 | &nvmsg, sizeof(nvmsg), |
| 994 | 1120 | req_id); |
| 1121 | + | |
| 1122 | + if (ret) | |
| 1123 | + netvsc_dma_unmap(ndev_ctx->device_ctx, packet); | |
| 995 | 1124 | } else { |
| 996 | 1125 | ret = vmbus_sendpacket(out_channel, |
| 997 | 1126 | &nvmsg, sizeof(nvmsg), |
| @@ -999,6 +1128,7 @@ static inline int netvsc_send_pkt( · 1 unmodified line | ||
| 999 | 1128 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
| 1000 | 1129 | } |
| 1001 | 1130 | |
| 1131 | +exit: | |
| 1002 | 1132 | if (ret == 0) { |
| 1003 | 1133 | atomic_inc_return(&nvchan->queue_sends); |
| 1004 | 1134 | |
| @@ -2516,6 +2516,7 @@ static int netvsc_probe(struct hv_device *dev, · 2515 unmodified lines | ||
| 2516 | 2516 | net->netdev_ops = &device_ops; |
| 2517 | 2517 | net->ethtool_ops = ðtool_ops; |
| 2518 | 2518 | SET_NETDEV_DEV(net, &dev->device); |
| 2519 | + dma_set_min_align_mask(&dev->device, HV_HYP_PAGE_SIZE - 1); | |
| 2519 | 2520 | |
| 2520 | 2521 | /* We always need headroom for rndis header */ |
| 2521 | 2522 | net->needed_headroom = RNDIS_AND_PPI_SIZE; |
| @@ -361,6 +361,8 @@ static void rndis_filter_receive_response(struct net_device *ndev, · 360 unmodified lines | ||
| 361 | 361 | } |
| 362 | 362 | } |
| 363 | 363 | |
| 364 | + netvsc_dma_unmap(((struct net_device_context *) | |
| 365 | + netdev_priv(ndev))->device_ctx, &request->pkt); | |
| 364 | 366 | complete(&request->wait_event); |
| 365 | 367 | } else { |
| 366 | 368 | netdev_err(ndev, |
| @@ -21,6 +21,8 @@ · 20 unmodified lines | ||
| 21 | 21 | #include <linux/device.h> |
| 22 | 22 | #include <linux/hyperv.h> |
| 23 | 23 | #include <linux/blkdev.h> |
| 24 | +#include <linux/dma-mapping.h> | |
| 25 | + | |
| 24 | 26 | #include <scsi/scsi.h> |
| 25 | 27 | #include <scsi/scsi_cmnd.h> |
| 26 | 28 | #include <scsi/scsi_host.h> |
| @@ -1336,6 +1338,7 @@ static void storvsc_on_channel_callback(void *context) · 1309 unmodified lines | ||
| 1336 | 1338 | continue; |
| 1337 | 1339 | } |
| 1338 | 1340 | request = (struct storvsc_cmd_request *)scsi_cmd_priv(scmnd); |
| 1341 | + scsi_dma_unmap(scmnd); | |
| 1339 | 1342 | } |
| 1340 | 1343 | |
| 1341 | 1344 | storvsc_on_receive(stor_device, packet, request); |
| @@ -1749,9 +1752,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) · 407 unmodified lines | ||
| 1749 | 1752 | struct hv_host_device *host_dev = shost_priv(host); |
| 1750 | 1753 | struct hv_device *dev = host_dev->dev; |
| 1751 | 1754 | struct storvsc_cmd_request *cmd_request = scsi_cmd_priv(scmnd); |
| 1752 | − int i; | |
| 1753 | 1755 | struct scatterlist *sgl; |
| 1754 | − unsigned int sg_count; | |
| 1755 | 1756 | struct vmscsi_request *vm_srb; |
| 1756 | 1757 | struct vmbus_packet_mpb_array *payload; |
| 1757 | 1758 | u32 payload_sz; |
| @@ -1824,17 +1825,17 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) · 66 unmodified lines | ||
| 1824 | 1825 | memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length); |
| 1825 | 1826 | |
| 1826 | 1827 | sgl = (struct scatterlist *)scsi_sglist(scmnd); |
| 1827 | − sg_count = scsi_sg_count(scmnd); | |
| 1828 | 1828 | |
| 1829 | 1829 | length = scsi_bufflen(scmnd); |
| 1830 | 1830 | payload = (struct vmbus_packet_mpb_array *)&cmd_request->mpb; |
| 1831 | 1831 | payload_sz = sizeof(cmd_request->mpb); |
| 1832 | 1832 | |
| 1833 | − if (sg_count) { | |
| 1834 | − unsigned int hvpgoff, hvpfns_to_add; | |
| 1833 | + if (scsi_sg_count(scmnd)) { | |
| 1835 | 1834 | unsigned long offset_in_hvpg = offset_in_hvpage(sgl->offset); |
| 1836 | 1835 | unsigned int hvpg_count = HVPFN_UP(offset_in_hvpg + length); |
| 1837 | − u64 hvpfn; | |
| 1836 | + struct scatterlist *sg; | |
| 1837 | + unsigned long hvpfn, hvpfns_to_add; | |
| 1838 | + int j, i = 0, sg_count; | |
| 1838 | 1839 | |
| 1839 | 1840 | if (hvpg_count > MAX_PAGE_BUFFER_COUNT) { |
| 1840 | 1841 | |
| @@ -1848,21 +1849,24 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) · 7 unmodified lines | ||
| 1848 | 1849 | payload->range.len = length; |
| 1849 | 1850 | payload->range.offset = offset_in_hvpg; |
| 1850 | 1851 | |
| 1852 | + sg_count = scsi_dma_map(scmnd); | |
| 1853 | + if (sg_count < 0) { | |
| 1854 | + ret = SCSI_MLQUEUE_DEVICE_BUSY; | |
| 1855 | + goto err_free_payload; | |
| 1856 | + } | |
| 1851 | 1857 | |
| 1852 | − for (i = 0; sgl != NULL; sgl = sg_next(sgl)) { | |
| 1858 | + for_each_sg(sgl, sg, sg_count, j) { | |
| 1853 | 1859 | /* |
| 1854 | − * Init values for the current sgl entry. hvpgoff | |
| 1855 | − * and hvpfns_to_add are in units of Hyper-V size | |
| 1856 | − * pages. Handling the PAGE_SIZE != HV_HYP_PAGE_SIZE | |
| 1857 | − * case also handles values of sgl->offset that are | |
| 1858 | − * larger than PAGE_SIZE. Such offsets are handled | |
| 1859 | − * even on other than the first sgl entry, provided | |
| 1860 | − * they are a multiple of PAGE_SIZE. | |
| 1860 | + * Init values for the current sgl entry. hvpfns_to_add | |
| 1861 | + * is in units of Hyper-V size pages. Handling the | |
| 1862 | + * PAGE_SIZE != HV_HYP_PAGE_SIZE case also handles | |
| 1863 | + * values of sgl->offset that are larger than PAGE_SIZE. | |
| 1864 | + * Such offsets are handled even on other than the first | |
| 1865 | + * sgl entry, provided they are a multiple of PAGE_SIZE. | |
| 1861 | 1866 | */ |
| 1862 | − hvpgoff = HVPFN_DOWN(sgl->offset); | |
| 1863 | − hvpfn = page_to_hvpfn(sg_page(sgl)) + hvpgoff; | |
| 1864 | − hvpfns_to_add = HVPFN_UP(sgl->offset + sgl->length) - | |
| 1865 | − hvpgoff; | |
| 1867 | + hvpfn = HVPFN_DOWN(sg_dma_address(sg)); | |
| 1868 | + hvpfns_to_add = HVPFN_UP(sg_dma_address(sg) + | |
| 1869 | + sg_dma_len(sg)) - hvpfn; | |
| 1866 | 1870 | |
| 1867 | 1871 | /* |
| 1868 | 1872 | * Fill the next portion of the PFN array with |
| @@ -1872,7 +1876,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) · 3 unmodified lines | ||
| 1872 | 1876 | * the PFN array is filled. |
| 1873 | 1877 | */ |
| 1874 | 1878 | while (hvpfns_to_add--) |
| 1875 | − payload->range.pfn_array[i++] = hvpfn++; | |
| 1879 | + payload->range.pfn_array[i++] = hvpfn++; | |
| 1876 | 1880 | } |
| 1877 | 1881 | } |
| 1878 | 1882 | |
| @@ -1884,13 +1888,18 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) · 5 unmodified lines | ||
| 1884 | 1888 | put_cpu(); |
| 1885 | 1889 | |
| 1886 | 1890 | if (ret == -EAGAIN) { |
| 1887 | − if (payload_sz > sizeof(cmd_request->mpb)) | |
| 1888 | − kfree(payload); | |
| 1889 | 1891 | /* no more space */ |
| 1890 | − return SCSI_MLQUEUE_DEVICE_BUSY; | |
| 1892 | + ret = SCSI_MLQUEUE_DEVICE_BUSY; | |
| 1893 | + goto err_free_payload; | |
| 1891 | 1894 | } |
| 1892 | 1895 | |
| 1893 | 1896 | return 0; |
| 1897 | + | |
| 1898 | +err_free_payload: | |
| 1899 | + if (payload_sz > sizeof(cmd_request->mpb)) | |
| 1900 | + kfree(payload); | |
| 1901 | + | |
| 1902 | + return ret; | |
| 1894 | 1903 | } |
| 1895 | 1904 | |
| 1896 | 1905 | static struct scsi_host_template scsi_driver = { |
| @@ -2016,6 +2025,7 @@ static int storvsc_probe(struct hv_device *device, · 119 unmodified lines | ||
| 2016 | 2025 | stor_device->vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); |
| 2017 | 2026 | spin_lock_init(&stor_device->lock); |
| 2018 | 2027 | hv_set_drvdata(device, stor_device); |
| 2028 | + dma_set_min_align_mask(&device->device, HV_HYP_PAGE_SIZE - 1); | |
| 2019 | 2029 | |
| 2020 | 2030 | stor_device->port_number = host->host_no; |
| 2021 | 2031 | ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc); |
| @@ -49,8 +49,8 @@ struct ms_hyperv_info { · 48 unmodified lines | ||
| 49 | 49 | }; |
| 50 | 50 | extern struct ms_hyperv_info ms_hyperv; |
| 51 | 51 | |
| 52 | −extern void __percpu **hyperv_pcpu_input_arg; | |
| 53 | −extern void __percpu **hyperv_pcpu_output_arg; | |
| 52 | +extern void * __percpu *hyperv_pcpu_input_arg; | |
| 53 | +extern void * __percpu *hyperv_pcpu_output_arg; | |
| 54 | 54 | |
| 55 | 55 | extern u64 hv_do_hypercall(u64 control, void *inputaddr, void *outputaddr); |
| 56 | 56 | extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); |
| @@ -269,6 +269,8 @@ bool hv_isolation_type_snp(void); · 212 unmodified lines | ||
| 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_map_memory(void *addr, unsigned long size); | |
| 273 | +void hv_unmap_memory(void *addr); | |
| 272 | 274 | #else /* CONFIG_HYPERV */ |
| 273 | 275 | static inline bool hv_is_hyperv_initialized(void) { return false; } |
| 274 | 276 | static inline bool hv_is_hibernation_supported(void) { return false; } |
| @@ -1261,6 +1261,7 @@ struct hv_device { · 1260 unmodified lines | ||
| 1261 | 1261 | |
| 1262 | 1262 | struct vmbus_channel *channel; |
| 1263 | 1263 | struct kset *channels_kset; |
| 1264 | + struct device_dma_parameters dma_parms; | |
| 1264 | 1265 | |
| 1265 | 1266 | /* place holder to keep track of the dir for hv device in debugfs */ |
| 1266 | 1267 | struct dentry *debug_dir; |
| @@ -1583,6 +1584,11 @@ struct hyperv_service_callback { · 316 unmodified lines | ||
| 1583 | 1584 | void (*callback)(void *context); |
| 1584 | 1585 | }; |
| 1585 | 1586 | |
| 1587 | +struct hv_dma_range { | |
| 1588 | + dma_addr_t dma; | |
| 1589 | + u32 mapping_size; | |
| 1590 | +}; | |
| 1591 | + | |
| 1586 | 1592 | #define MAX_SRV_VER 0x7ffffff |
| 1587 | 1593 | extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf, u32 buflen, |
| 1588 | 1594 | const int *fw_version, int fw_vercnt, |
| @@ -73,6 +73,9 @@ extern enum swiotlb_force swiotlb_force; · 72 unmodified lines | ||
| 73 | 73 | * @end: The end address of the swiotlb memory pool. Used to do a quick |
| 74 | 74 | * range check to see if the memory was in fact allocated by this |
| 75 | 75 | * API. |
| 76 | + * @vaddr: The vaddr of the swiotlb memory pool. The swiotlb memory pool | |
| 77 | + * may be remapped in the memory encrypted case and store virtual | |
| 78 | + * address for bounce buffer operation. | |
| 76 | 79 | * @nslabs: The number of IO TLB blocks (in groups of 64) between @start and |
| 77 | 80 | * @end. For default swiotlb, this is command line adjustable via |
| 78 | 81 | * setup_io_tlb_npages. |
| @@ -92,6 +95,7 @@ extern enum swiotlb_force swiotlb_force; · 13 unmodified lines | ||
| 92 | 95 | struct io_tlb_mem { |
| 93 | 96 | phys_addr_t start; |
| 94 | 97 | phys_addr_t end; |
| 98 | + void *vaddr; | |
| 95 | 99 | unsigned long nslabs; |
| 96 | 100 | unsigned long used; |
| 97 | 101 | unsigned int index; |
| @@ -186,4 +190,6 @@ static inline bool is_swiotlb_for_alloc(struct device *dev) · 88 unmodified lines | ||
| 186 | 190 | } |
| 187 | 191 | #endif /* CONFIG_DMA_RESTRICTED_POOL */ |
| 188 | 192 | |
| 193 | +extern phys_addr_t swiotlb_unencrypted_base; | |
| 194 | + | |
| 189 | 195 | #endif /* __LINUX_SWIOTLB_H */ |
| @@ -50,6 +50,7 @@ · 49 unmodified lines | ||
| 50 | 50 | #include <asm/io.h> |
| 51 | 51 | #include <asm/dma.h> |
| 52 | 52 | |
| 53 | +#include <linux/io.h> | |
| 53 | 54 | #include <linux/init.h> |
| 54 | 55 | #include <linux/memblock.h> |
| 55 | 56 | #include <linux/iommu-helper.h> |
| @@ -72,6 +73,8 @@ enum swiotlb_force swiotlb_force; · 16 unmodified lines | ||
| 72 | 73 | |
| 73 | 74 | struct io_tlb_mem io_tlb_default_mem; |
| 74 | 75 | |
| 76 | +phys_addr_t swiotlb_unencrypted_base; | |
| 77 | + | |
| 75 | 78 | /* |
| 76 | 79 | * Max segment that we can provide which (if pages are contingous) will |
| 77 | 80 | * not be bounced (unless SWIOTLB_FORCE is set). |
| @@ -155,6 +158,34 @@ static inline unsigned long nr_slots(u64 val) · 77 unmodified lines | ||
| 155 | 158 | return DIV_ROUND_UP(val, IO_TLB_SIZE); |
| 156 | 159 | } |
| 157 | 160 | |
| 161 | +/* | |
| 162 | + * Remap swioltb memory in the unencrypted physical address space | |
| 163 | + * when swiotlb_unencrypted_base is set. (e.g. for Hyper-V AMD SEV-SNP | |
| 164 | + * Isolation VMs). | |
| 165 | + */ | |
| 166 | +#ifdef CONFIG_HAS_IOMEM | |
| 167 | +static void *swiotlb_mem_remap(struct io_tlb_mem *mem, unsigned long bytes) | |
| 168 | +{ | |
| 169 | + void *vaddr = NULL; | |
| 170 | + | |
| 171 | + if (swiotlb_unencrypted_base) { | |
| 172 | + phys_addr_t paddr = mem->start + swiotlb_unencrypted_base; | |
| 173 | + | |
| 174 | + vaddr = memremap(paddr, bytes, MEMREMAP_WB); | |
| 175 | + if (!vaddr) | |
| 176 | + pr_err("Failed to map the unencrypted memory %pa size %lx.\n", | |
| 177 | + &paddr, bytes); | |
| 178 | + } | |
| 179 | + | |
| 180 | + return vaddr; | |
| 181 | +} | |
| 182 | +#else | |
| 183 | +static void *swiotlb_mem_remap(struct io_tlb_mem *mem, unsigned long bytes) | |
| 184 | +{ | |
| 185 | + return NULL; | |
| 186 | +} | |
| 187 | +#endif | |
| 188 | + | |
| 158 | 189 | /* |
| 159 | 190 | * Early SWIOTLB allocation may be too early to allow an architecture to |
| 160 | 191 | * perform the desired operations. This function allows the architecture to |
| @@ -172,7 +203,12 @@ void __init swiotlb_update_mem_attributes(void) · 11 unmodified lines | ||
| 172 | 203 | vaddr = phys_to_virt(mem->start); |
| 173 | 204 | bytes = PAGE_ALIGN(mem->nslabs << IO_TLB_SHIFT); |
| 174 | 205 | set_memory_decrypted((unsigned long)vaddr, bytes >> PAGE_SHIFT); |
| 175 | − memset(vaddr, 0, bytes); | |
| 206 | + | |
| 207 | + mem->vaddr = swiotlb_mem_remap(mem, bytes); | |
| 208 | + if (!mem->vaddr) | |
| 209 | + mem->vaddr = vaddr; | |
| 210 | + | |
| 211 | + memset(mem->vaddr, 0, bytes); | |
| 176 | 212 | } |
| 177 | 213 | |
| 178 | 214 | static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, |
| @@ -196,7 +232,17 @@ static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, · 17 unmodified lines | ||
| 196 | 232 | mem->slots[i].orig_addr = INVALID_PHYS_ADDR; |
| 197 | 233 | mem->slots[i].alloc_size = 0; |
| 198 | 234 | } |
| 235 | + | |
| 236 | + /* | |
| 237 | + * If swiotlb_unencrypted_base is set, the bounce buffer memory will | |
| 238 | + * be remapped and cleared in swiotlb_update_mem_attributes. | |
| 239 | + */ | |
| 240 | + if (swiotlb_unencrypted_base) | |
| 241 | + return; | |
| 242 | + | |
| 199 | 243 | memset(vaddr, 0, bytes); |
| 244 | + mem->vaddr = vaddr; | |
| 245 | + return; | |
| 200 | 246 | } |
| 201 | 247 | |
| 202 | 248 | int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) |
| @@ -371,7 +417,7 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size · 168 unmodified lines | ||
| 371 | 417 | phys_addr_t orig_addr = mem->slots[index].orig_addr; |
| 372 | 418 | size_t alloc_size = mem->slots[index].alloc_size; |
| 373 | 419 | unsigned long pfn = PFN_DOWN(orig_addr); |
| 374 | − unsigned char *vaddr = phys_to_virt(tlb_addr); | |
| 420 | + unsigned char *vaddr = mem->vaddr + tlb_addr - mem->start; | |
| 375 | 421 | unsigned int tlb_offset, orig_addr_offset; |
| 376 | 422 | |
| 377 | 423 | if (orig_addr == INVALID_PHYS_ADDR) |