Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | // SPDX-License-Identifier: GPL-2.0 #include <linux/types.h> #include <linux/vmalloc.h> #include <linux/mm.h> #include <linux/clockchips.h> #include <linux/hyperv.h> #include <linux/slab.h> #include <linux/cpuhotplug.h> #include <linux/minmax.h> #include <asm/hypervisor.h> #include <asm/mshyperv.h> #include <asm/apic.h> #include <asm/trace/hyperv.h> /* * See struct hv_deposit_memory. The first u64 is partition ID, the rest * are GPAs. */ #define HV_DEPOSIT_MAX (HV_HYP_PAGE_SIZE / sizeof(u64) - 1) /* Deposits exact number of pages. Must be called with interrupts enabled. */ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages) { struct page **pages, *page; int *counts; int num_allocations; int i, j, page_count; int order; u64 status; int ret; u64 base_pfn; struct hv_deposit_memory *input_page; unsigned long flags; if (num_pages > HV_DEPOSIT_MAX) return -E2BIG; if (!num_pages) return 0; /* One buffer for page pointers and counts */ page = alloc_page(GFP_KERNEL); if (!page) return -ENOMEM; pages = page_address(page); counts = kcalloc(HV_DEPOSIT_MAX, sizeof(int), GFP_KERNEL); if (!counts) { free_page((unsigned long)pages); return -ENOMEM; } /* Allocate all the pages before disabling interrupts */ i = 0; while (num_pages) { /* Find highest order we can actually allocate */ order = 31 - __builtin_clz(num_pages); while (1) { pages[i] = alloc_pages_node(node, GFP_KERNEL, order); if (pages[i]) break; if (!order) { ret = -ENOMEM; num_allocations = i; goto err_free_allocations; } --order; } split_page(pages[i], order); counts[i] = 1 << order; num_pages -= counts[i]; i++; } num_allocations = i; local_irq_save(flags); input_page = *this_cpu_ptr(hyperv_pcpu_input_arg); input_page->partition_id = partition_id; /* Populate gpa_page_list - these will fit on the input page */ for (i = 0, page_count = 0; i < num_allocations; ++i) { base_pfn = page_to_pfn(pages[i]); for (j = 0; j < counts[i]; ++j, ++page_count) input_page->gpa_page_list[page_count] = base_pfn + j; } status = hv_do_rep_hypercall(HVCALL_DEPOSIT_MEMORY, page_count, 0, input_page, NULL); local_irq_restore(flags); if (!hv_result_success(status)) { pr_err("Failed to deposit pages: %lld\n", status); ret = hv_result(status); goto err_free_allocations; } ret = 0; goto free_buf; err_free_allocations: for (i = 0; i < num_allocations; ++i) { base_pfn = page_to_pfn(pages[i]); for (j = 0; j < counts[i]; ++j) __free_page(pfn_to_page(base_pfn + j)); } free_buf: free_page((unsigned long)pages); kfree(counts); return ret; } int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id) { struct hv_input_add_logical_processor *input; struct hv_output_add_logical_processor *output; u64 status; unsigned long flags; int ret = HV_STATUS_SUCCESS; /* * When adding a logical processor, the hypervisor may return * HV_STATUS_INSUFFICIENT_MEMORY. When that happens, we deposit more * pages and retry. */ do { local_irq_save(flags); input = *this_cpu_ptr(hyperv_pcpu_input_arg); /* We don't do anything with the output right now */ output = *this_cpu_ptr(hyperv_pcpu_output_arg); input->lp_index = lp_index; input->apic_id = apic_id; input->proximity_domain_info = hv_numa_node_to_pxm_info(node); status = hv_do_hypercall(HVCALL_ADD_LOGICAL_PROCESSOR, input, output); local_irq_restore(flags); if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { if (!hv_result_success(status)) { pr_err("%s: cpu %u apic ID %u, %lld\n", __func__, lp_index, apic_id, status); ret = hv_result(status); } break; } ret = hv_call_deposit_pages(node, hv_current_partition_id, 1); } while (!ret); return ret; } int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags) { struct hv_create_vp *input; u64 status; unsigned long irq_flags; int ret = HV_STATUS_SUCCESS; /* Root VPs don't seem to need pages deposited */ if (partition_id != hv_current_partition_id) { /* The value 90 is empirically determined. It may change. */ ret = hv_call_deposit_pages(node, partition_id, 90); if (ret) return ret; } do { local_irq_save(irq_flags); input = *this_cpu_ptr(hyperv_pcpu_input_arg); input->partition_id = partition_id; input->vp_index = vp_index; input->flags = flags; input->subnode_type = HvSubnodeAny; input->proximity_domain_info = hv_numa_node_to_pxm_info(node); status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL); local_irq_restore(irq_flags); if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { if (!hv_result_success(status)) { pr_err("%s: vcpu %u, lp %u, %lld\n", __func__, vp_index, flags, status); ret = hv_result(status); } break; } ret = hv_call_deposit_pages(node, partition_id, 1); } while (!ret); return ret; } |