10222eb30SNuno Das Neves // SPDX-License-Identifier: GPL-2.0 20222eb30SNuno Das Neves #include <linux/types.h> 30222eb30SNuno Das Neves #include <linux/vmalloc.h> 40222eb30SNuno Das Neves #include <linux/mm.h> 50222eb30SNuno Das Neves #include <linux/clockchips.h> 60222eb30SNuno Das Neves #include <linux/slab.h> 70222eb30SNuno Das Neves #include <linux/cpuhotplug.h> 80222eb30SNuno Das Neves #include <linux/minmax.h> 90222eb30SNuno Das Neves #include <asm/mshyperv.h> 100222eb30SNuno Das Neves 110222eb30SNuno Das Neves /* 120222eb30SNuno Das Neves * See struct hv_deposit_memory. The first u64 is partition ID, the rest 130222eb30SNuno Das Neves * are GPAs. 140222eb30SNuno Das Neves */ 150222eb30SNuno Das Neves #define HV_DEPOSIT_MAX (HV_HYP_PAGE_SIZE / sizeof(u64) - 1) 160222eb30SNuno Das Neves 170222eb30SNuno Das Neves /* Deposits exact number of pages. Must be called with interrupts enabled. */ 180222eb30SNuno Das Neves int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages) 190222eb30SNuno Das Neves { 200222eb30SNuno Das Neves struct page **pages, *page; 210222eb30SNuno Das Neves int *counts; 220222eb30SNuno Das Neves int num_allocations; 230222eb30SNuno Das Neves int i, j, page_count; 240222eb30SNuno Das Neves int order; 250222eb30SNuno Das Neves u64 status; 260222eb30SNuno Das Neves int ret; 270222eb30SNuno Das Neves u64 base_pfn; 280222eb30SNuno Das Neves struct hv_deposit_memory *input_page; 290222eb30SNuno Das Neves unsigned long flags; 300222eb30SNuno Das Neves 310222eb30SNuno Das Neves if (num_pages > HV_DEPOSIT_MAX) 320222eb30SNuno Das Neves return -E2BIG; 330222eb30SNuno Das Neves if (!num_pages) 340222eb30SNuno Das Neves return 0; 350222eb30SNuno Das Neves 360222eb30SNuno Das Neves /* One buffer for page pointers and counts */ 370222eb30SNuno Das Neves page = alloc_page(GFP_KERNEL); 380222eb30SNuno Das Neves if (!page) 390222eb30SNuno Das Neves return -ENOMEM; 400222eb30SNuno Das Neves pages = page_address(page); 410222eb30SNuno Das Neves 420222eb30SNuno Das Neves counts = kcalloc(HV_DEPOSIT_MAX, sizeof(int), GFP_KERNEL); 430222eb30SNuno Das Neves if (!counts) { 440222eb30SNuno Das Neves free_page((unsigned long)pages); 450222eb30SNuno Das Neves return -ENOMEM; 460222eb30SNuno Das Neves } 470222eb30SNuno Das Neves 480222eb30SNuno Das Neves /* Allocate all the pages before disabling interrupts */ 490222eb30SNuno Das Neves i = 0; 500222eb30SNuno Das Neves 510222eb30SNuno Das Neves while (num_pages) { 520222eb30SNuno Das Neves /* Find highest order we can actually allocate */ 530222eb30SNuno Das Neves order = 31 - __builtin_clz(num_pages); 540222eb30SNuno Das Neves 550222eb30SNuno Das Neves while (1) { 560222eb30SNuno Das Neves pages[i] = alloc_pages_node(node, GFP_KERNEL, order); 570222eb30SNuno Das Neves if (pages[i]) 580222eb30SNuno Das Neves break; 590222eb30SNuno Das Neves if (!order) { 600222eb30SNuno Das Neves ret = -ENOMEM; 610222eb30SNuno Das Neves num_allocations = i; 620222eb30SNuno Das Neves goto err_free_allocations; 630222eb30SNuno Das Neves } 640222eb30SNuno Das Neves --order; 650222eb30SNuno Das Neves } 660222eb30SNuno Das Neves 670222eb30SNuno Das Neves split_page(pages[i], order); 680222eb30SNuno Das Neves counts[i] = 1 << order; 690222eb30SNuno Das Neves num_pages -= counts[i]; 700222eb30SNuno Das Neves i++; 710222eb30SNuno Das Neves } 720222eb30SNuno Das Neves num_allocations = i; 730222eb30SNuno Das Neves 740222eb30SNuno Das Neves local_irq_save(flags); 750222eb30SNuno Das Neves 760222eb30SNuno Das Neves input_page = *this_cpu_ptr(hyperv_pcpu_input_arg); 770222eb30SNuno Das Neves 780222eb30SNuno Das Neves input_page->partition_id = partition_id; 790222eb30SNuno Das Neves 800222eb30SNuno Das Neves /* Populate gpa_page_list - these will fit on the input page */ 810222eb30SNuno Das Neves for (i = 0, page_count = 0; i < num_allocations; ++i) { 820222eb30SNuno Das Neves base_pfn = page_to_pfn(pages[i]); 830222eb30SNuno Das Neves for (j = 0; j < counts[i]; ++j, ++page_count) 840222eb30SNuno Das Neves input_page->gpa_page_list[page_count] = base_pfn + j; 850222eb30SNuno Das Neves } 860222eb30SNuno Das Neves status = hv_do_rep_hypercall(HVCALL_DEPOSIT_MEMORY, 870222eb30SNuno Das Neves page_count, 0, input_page, NULL); 880222eb30SNuno Das Neves local_irq_restore(flags); 890222eb30SNuno Das Neves if (!hv_result_success(status)) { 903817854bSNuno Das Neves hv_status_err(status, "\n"); 919d8731a1SNuno Das Neves ret = hv_result_to_errno(status); 920222eb30SNuno Das Neves goto err_free_allocations; 930222eb30SNuno Das Neves } 940222eb30SNuno Das Neves 950222eb30SNuno Das Neves ret = 0; 960222eb30SNuno Das Neves goto free_buf; 970222eb30SNuno Das Neves 980222eb30SNuno Das Neves err_free_allocations: 990222eb30SNuno Das Neves for (i = 0; i < num_allocations; ++i) { 1000222eb30SNuno Das Neves base_pfn = page_to_pfn(pages[i]); 1010222eb30SNuno Das Neves for (j = 0; j < counts[i]; ++j) 1020222eb30SNuno Das Neves __free_page(pfn_to_page(base_pfn + j)); 1030222eb30SNuno Das Neves } 1040222eb30SNuno Das Neves 1050222eb30SNuno Das Neves free_buf: 1060222eb30SNuno Das Neves free_page((unsigned long)pages); 1070222eb30SNuno Das Neves kfree(counts); 1080222eb30SNuno Das Neves return ret; 1090222eb30SNuno Das Neves } 110*21050f61SNuno Das Neves EXPORT_SYMBOL_GPL(hv_call_deposit_pages); 1110222eb30SNuno Das Neves 1120222eb30SNuno Das Neves int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id) 1130222eb30SNuno Das Neves { 1140222eb30SNuno Das Neves struct hv_input_add_logical_processor *input; 1150222eb30SNuno Das Neves struct hv_output_add_logical_processor *output; 1160222eb30SNuno Das Neves u64 status; 1170222eb30SNuno Das Neves unsigned long flags; 1189d8731a1SNuno Das Neves int ret = 0; 1190222eb30SNuno Das Neves 1200222eb30SNuno Das Neves /* 1210222eb30SNuno Das Neves * When adding a logical processor, the hypervisor may return 1220222eb30SNuno Das Neves * HV_STATUS_INSUFFICIENT_MEMORY. When that happens, we deposit more 1230222eb30SNuno Das Neves * pages and retry. 1240222eb30SNuno Das Neves */ 1250222eb30SNuno Das Neves do { 1260222eb30SNuno Das Neves local_irq_save(flags); 1270222eb30SNuno Das Neves 1280222eb30SNuno Das Neves input = *this_cpu_ptr(hyperv_pcpu_input_arg); 1290222eb30SNuno Das Neves /* We don't do anything with the output right now */ 1300222eb30SNuno Das Neves output = *this_cpu_ptr(hyperv_pcpu_output_arg); 1310222eb30SNuno Das Neves 1320222eb30SNuno Das Neves input->lp_index = lp_index; 1330222eb30SNuno Das Neves input->apic_id = apic_id; 1340222eb30SNuno Das Neves input->proximity_domain_info = hv_numa_node_to_pxm_info(node); 1350222eb30SNuno Das Neves status = hv_do_hypercall(HVCALL_ADD_LOGICAL_PROCESSOR, 1360222eb30SNuno Das Neves input, output); 1370222eb30SNuno Das Neves local_irq_restore(flags); 1380222eb30SNuno Das Neves 1390222eb30SNuno Das Neves if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { 1400222eb30SNuno Das Neves if (!hv_result_success(status)) { 1413817854bSNuno Das Neves hv_status_err(status, "cpu %u apic ID: %u\n", 1423817854bSNuno Das Neves lp_index, apic_id); 1439d8731a1SNuno Das Neves ret = hv_result_to_errno(status); 1440222eb30SNuno Das Neves } 1450222eb30SNuno Das Neves break; 1460222eb30SNuno Das Neves } 1470222eb30SNuno Das Neves ret = hv_call_deposit_pages(node, hv_current_partition_id, 1); 1480222eb30SNuno Das Neves } while (!ret); 1490222eb30SNuno Das Neves 1500222eb30SNuno Das Neves return ret; 1510222eb30SNuno Das Neves } 1520222eb30SNuno Das Neves 1530222eb30SNuno Das Neves int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags) 1540222eb30SNuno Das Neves { 1550222eb30SNuno Das Neves struct hv_create_vp *input; 1560222eb30SNuno Das Neves u64 status; 1570222eb30SNuno Das Neves unsigned long irq_flags; 1589d8731a1SNuno Das Neves int ret = 0; 1590222eb30SNuno Das Neves 1600222eb30SNuno Das Neves /* Root VPs don't seem to need pages deposited */ 1610222eb30SNuno Das Neves if (partition_id != hv_current_partition_id) { 1620222eb30SNuno Das Neves /* The value 90 is empirically determined. It may change. */ 1630222eb30SNuno Das Neves ret = hv_call_deposit_pages(node, partition_id, 90); 1640222eb30SNuno Das Neves if (ret) 1650222eb30SNuno Das Neves return ret; 1660222eb30SNuno Das Neves } 1670222eb30SNuno Das Neves 1680222eb30SNuno Das Neves do { 1690222eb30SNuno Das Neves local_irq_save(irq_flags); 1700222eb30SNuno Das Neves 1710222eb30SNuno Das Neves input = *this_cpu_ptr(hyperv_pcpu_input_arg); 1720222eb30SNuno Das Neves 1730222eb30SNuno Das Neves input->partition_id = partition_id; 1740222eb30SNuno Das Neves input->vp_index = vp_index; 1750222eb30SNuno Das Neves input->flags = flags; 1760222eb30SNuno Das Neves input->subnode_type = HV_SUBNODE_ANY; 1770222eb30SNuno Das Neves input->proximity_domain_info = hv_numa_node_to_pxm_info(node); 1780222eb30SNuno Das Neves status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL); 1790222eb30SNuno Das Neves local_irq_restore(irq_flags); 1800222eb30SNuno Das Neves 1810222eb30SNuno Das Neves if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { 1820222eb30SNuno Das Neves if (!hv_result_success(status)) { 1833817854bSNuno Das Neves hv_status_err(status, "vcpu: %u, lp: %u\n", 1843817854bSNuno Das Neves vp_index, flags); 1859d8731a1SNuno Das Neves ret = hv_result_to_errno(status); 1860222eb30SNuno Das Neves } 1870222eb30SNuno Das Neves break; 1880222eb30SNuno Das Neves } 1890222eb30SNuno Das Neves ret = hv_call_deposit_pages(node, partition_id, 1); 1900222eb30SNuno Das Neves 1910222eb30SNuno Das Neves } while (!ret); 1920222eb30SNuno Das Neves 1930222eb30SNuno Das Neves return ret; 1940222eb30SNuno Das Neves } 195*21050f61SNuno Das Neves EXPORT_SYMBOL_GPL(hv_call_create_vp); 196