1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2009, Microsoft Corporation. 4 * 5 * Authors: 6 * Haiyang Zhang <haiyangz@microsoft.com> 7 * Hank Janssen <hjanssen@microsoft.com> 8 */ 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11 #include <linux/kernel.h> 12 #include <linux/mm.h> 13 #include <linux/slab.h> 14 #include <linux/vmalloc.h> 15 #include <linux/hyperv.h> 16 #include <linux/version.h> 17 #include <linux/random.h> 18 #include <linux/clockchips.h> 19 #include <clocksource/hyperv_timer.h> 20 #include <asm/mshyperv.h> 21 #include "hyperv_vmbus.h" 22 23 /* The one and only */ 24 struct hv_context hv_context; 25 26 /* 27 * hv_init - Main initialization routine. 28 * 29 * This routine must be called before any other routines in here are called 30 */ 31 int hv_init(void) 32 { 33 hv_context.cpu_context = alloc_percpu(struct hv_per_cpu_context); 34 if (!hv_context.cpu_context) 35 return -ENOMEM; 36 return 0; 37 } 38 39 /* 40 * hv_post_message - Post a message using the hypervisor message IPC. 41 * 42 * This involves a hypercall. 43 */ 44 int hv_post_message(union hv_connection_id connection_id, 45 enum hv_message_type message_type, 46 void *payload, size_t payload_size) 47 { 48 struct hv_input_post_message *aligned_msg; 49 struct hv_per_cpu_context *hv_cpu; 50 u64 status; 51 52 if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) 53 return -EMSGSIZE; 54 55 hv_cpu = get_cpu_ptr(hv_context.cpu_context); 56 aligned_msg = hv_cpu->post_msg_page; 57 aligned_msg->connectionid = connection_id; 58 aligned_msg->reserved = 0; 59 aligned_msg->message_type = message_type; 60 aligned_msg->payload_size = payload_size; 61 memcpy((void *)aligned_msg->payload, payload, payload_size); 62 63 status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); 64 65 /* Preemption must remain disabled until after the hypercall 66 * so some other thread can't get scheduled onto this cpu and 67 * corrupt the per-cpu post_msg_page 68 */ 69 put_cpu_ptr(hv_cpu); 70 71 return status & 0xFFFF; 72 } 73 74 int hv_synic_alloc(void) 75 { 76 int cpu; 77 struct hv_per_cpu_context *hv_cpu; 78 79 /* 80 * First, zero all per-cpu memory areas so hv_synic_free() can 81 * detect what memory has been allocated and cleanup properly 82 * after any failures. 83 */ 84 for_each_present_cpu(cpu) { 85 hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); 86 memset(hv_cpu, 0, sizeof(*hv_cpu)); 87 } 88 89 hv_context.hv_numa_map = kcalloc(nr_node_ids, sizeof(struct cpumask), 90 GFP_KERNEL); 91 if (hv_context.hv_numa_map == NULL) { 92 pr_err("Unable to allocate NUMA map\n"); 93 goto err; 94 } 95 96 for_each_present_cpu(cpu) { 97 hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); 98 99 tasklet_init(&hv_cpu->msg_dpc, 100 vmbus_on_msg_dpc, (unsigned long) hv_cpu); 101 102 hv_cpu->synic_message_page = 103 (void *)get_zeroed_page(GFP_ATOMIC); 104 if (hv_cpu->synic_message_page == NULL) { 105 pr_err("Unable to allocate SYNIC message page\n"); 106 goto err; 107 } 108 109 hv_cpu->synic_event_page = (void *)get_zeroed_page(GFP_ATOMIC); 110 if (hv_cpu->synic_event_page == NULL) { 111 pr_err("Unable to allocate SYNIC event page\n"); 112 goto err; 113 } 114 115 hv_cpu->post_msg_page = (void *)get_zeroed_page(GFP_ATOMIC); 116 if (hv_cpu->post_msg_page == NULL) { 117 pr_err("Unable to allocate post msg page\n"); 118 goto err; 119 } 120 121 INIT_LIST_HEAD(&hv_cpu->chan_list); 122 } 123 124 return 0; 125 err: 126 /* 127 * Any memory allocations that succeeded will be freed when 128 * the caller cleans up by calling hv_synic_free() 129 */ 130 return -ENOMEM; 131 } 132 133 134 void hv_synic_free(void) 135 { 136 int cpu; 137 138 for_each_present_cpu(cpu) { 139 struct hv_per_cpu_context *hv_cpu 140 = per_cpu_ptr(hv_context.cpu_context, cpu); 141 142 free_page((unsigned long)hv_cpu->synic_event_page); 143 free_page((unsigned long)hv_cpu->synic_message_page); 144 free_page((unsigned long)hv_cpu->post_msg_page); 145 } 146 147 kfree(hv_context.hv_numa_map); 148 } 149 150 /* 151 * hv_synic_init - Initialize the Synthetic Interrupt Controller. 152 * 153 * If it is already initialized by another entity (ie x2v shim), we need to 154 * retrieve the initialized message and event pages. Otherwise, we create and 155 * initialize the message and event pages. 156 */ 157 int hv_synic_init(unsigned int cpu) 158 { 159 struct hv_per_cpu_context *hv_cpu 160 = per_cpu_ptr(hv_context.cpu_context, cpu); 161 union hv_synic_simp simp; 162 union hv_synic_siefp siefp; 163 union hv_synic_sint shared_sint; 164 union hv_synic_scontrol sctrl; 165 166 /* Setup the Synic's message page */ 167 hv_get_simp(simp.as_uint64); 168 simp.simp_enabled = 1; 169 simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) 170 >> PAGE_SHIFT; 171 172 hv_set_simp(simp.as_uint64); 173 174 /* Setup the Synic's event page */ 175 hv_get_siefp(siefp.as_uint64); 176 siefp.siefp_enabled = 1; 177 siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) 178 >> PAGE_SHIFT; 179 180 hv_set_siefp(siefp.as_uint64); 181 182 /* Setup the shared SINT. */ 183 hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); 184 185 shared_sint.vector = HYPERVISOR_CALLBACK_VECTOR; 186 shared_sint.masked = false; 187 if (ms_hyperv.hints & HV_DEPRECATING_AEOI_RECOMMENDED) 188 shared_sint.auto_eoi = false; 189 else 190 shared_sint.auto_eoi = true; 191 192 hv_set_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); 193 194 /* Enable the global synic bit */ 195 hv_get_synic_state(sctrl.as_uint64); 196 sctrl.enable = 1; 197 198 hv_set_synic_state(sctrl.as_uint64); 199 200 hv_stimer_init(cpu); 201 202 return 0; 203 } 204 205 /* 206 * hv_synic_cleanup - Cleanup routine for hv_synic_init(). 207 */ 208 int hv_synic_cleanup(unsigned int cpu) 209 { 210 union hv_synic_sint shared_sint; 211 union hv_synic_simp simp; 212 union hv_synic_siefp siefp; 213 union hv_synic_scontrol sctrl; 214 struct vmbus_channel *channel, *sc; 215 bool channel_found = false; 216 unsigned long flags; 217 218 hv_get_synic_state(sctrl.as_uint64); 219 if (sctrl.enable != 1) 220 return -EFAULT; 221 222 /* 223 * Search for channels which are bound to the CPU we're about to 224 * cleanup. In case we find one and vmbus is still connected we need to 225 * fail, this will effectively prevent CPU offlining. There is no way 226 * we can re-bind channels to different CPUs for now. 227 */ 228 mutex_lock(&vmbus_connection.channel_mutex); 229 list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { 230 if (channel->target_cpu == cpu) { 231 channel_found = true; 232 break; 233 } 234 spin_lock_irqsave(&channel->lock, flags); 235 list_for_each_entry(sc, &channel->sc_list, sc_list) { 236 if (sc->target_cpu == cpu) { 237 channel_found = true; 238 break; 239 } 240 } 241 spin_unlock_irqrestore(&channel->lock, flags); 242 if (channel_found) 243 break; 244 } 245 mutex_unlock(&vmbus_connection.channel_mutex); 246 247 if (channel_found && vmbus_connection.conn_state == CONNECTED) 248 return -EBUSY; 249 250 hv_stimer_cleanup(cpu); 251 252 hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); 253 254 shared_sint.masked = 1; 255 256 /* Need to correctly cleanup in the case of SMP!!! */ 257 /* Disable the interrupt */ 258 hv_set_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); 259 260 hv_get_simp(simp.as_uint64); 261 simp.simp_enabled = 0; 262 simp.base_simp_gpa = 0; 263 264 hv_set_simp(simp.as_uint64); 265 266 hv_get_siefp(siefp.as_uint64); 267 siefp.siefp_enabled = 0; 268 siefp.base_siefp_gpa = 0; 269 270 hv_set_siefp(siefp.as_uint64); 271 272 /* Disable the global synic bit */ 273 sctrl.enable = 0; 274 hv_set_synic_state(sctrl.as_uint64); 275 276 return 0; 277 } 278