1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2023, Microsoft Corporation. 4 * 5 * mshv_root module's main interrupt handler and associated functionality. 6 * 7 * Authors: Microsoft Linux virtualization team 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/slab.h> 12 #include <linux/mm.h> 13 #include <linux/interrupt.h> 14 #include <linux/io.h> 15 #include <linux/random.h> 16 #include <linux/cpuhotplug.h> 17 #include <linux/reboot.h> 18 #include <asm/mshyperv.h> 19 #include <linux/acpi.h> 20 21 #include "mshv_eventfd.h" 22 #include "mshv.h" 23 24 static int synic_cpuhp_online; 25 static struct hv_synic_pages __percpu *synic_pages; 26 static int mshv_sint_vector = -1; /* hwirq for the SynIC SINTs */ 27 static int mshv_sint_irq = -1; /* Linux IRQ for mshv_sint_vector */ 28 29 static u32 synic_event_ring_get_queued_port(u32 sint_index) 30 { 31 struct hv_synic_event_ring_page **event_ring_page; 32 volatile struct hv_synic_event_ring *ring; 33 struct hv_synic_pages *spages; 34 u8 **synic_eventring_tail; 35 u32 message; 36 u8 tail; 37 38 spages = this_cpu_ptr(synic_pages); 39 event_ring_page = &spages->synic_event_ring_page; 40 synic_eventring_tail = (u8 **)this_cpu_ptr(hv_synic_eventring_tail); 41 42 if (unlikely(!*synic_eventring_tail)) { 43 pr_debug("Missing synic event ring tail!\n"); 44 return 0; 45 } 46 tail = (*synic_eventring_tail)[sint_index]; 47 48 if (unlikely(!*event_ring_page)) { 49 pr_debug("Missing synic event ring page!\n"); 50 return 0; 51 } 52 53 ring = &(*event_ring_page)->sint_event_ring[sint_index]; 54 55 /* 56 * Get the message. 57 */ 58 message = ring->data[tail]; 59 60 if (!message) { 61 if (ring->ring_full) { 62 /* 63 * Ring is marked full, but we would have consumed all 64 * the messages. Notify the hypervisor that ring is now 65 * empty and check again. 66 */ 67 ring->ring_full = 0; 68 hv_call_notify_port_ring_empty(sint_index); 69 message = ring->data[tail]; 70 } 71 72 if (!message) { 73 ring->signal_masked = 0; 74 /* 75 * Unmask the signal and sync with hypervisor 76 * before one last check for any message. 77 */ 78 mb(); 79 message = ring->data[tail]; 80 81 /* 82 * Ok, lets bail out. 83 */ 84 if (!message) 85 return 0; 86 } 87 88 ring->signal_masked = 1; 89 } 90 91 /* 92 * Clear the message in the ring buffer. 93 */ 94 ring->data[tail] = 0; 95 96 if (++tail == HV_SYNIC_EVENT_RING_MESSAGE_COUNT) 97 tail = 0; 98 99 (*synic_eventring_tail)[sint_index] = tail; 100 101 return message; 102 } 103 104 static bool 105 mshv_doorbell_isr(struct hv_message *msg) 106 { 107 struct hv_notification_message_payload *notification; 108 u32 port; 109 110 if (msg->header.message_type != HVMSG_SYNIC_SINT_INTERCEPT) 111 return false; 112 113 notification = (struct hv_notification_message_payload *)msg->u.payload; 114 if (notification->sint_index != HV_SYNIC_DOORBELL_SINT_INDEX) 115 return false; 116 117 while ((port = synic_event_ring_get_queued_port(HV_SYNIC_DOORBELL_SINT_INDEX))) { 118 struct port_table_info ptinfo = { 0 }; 119 120 if (mshv_portid_lookup(port, &ptinfo)) { 121 pr_debug("Failed to get port info from port_table!\n"); 122 continue; 123 } 124 125 if (ptinfo.hv_port_type != HV_PORT_TYPE_DOORBELL) { 126 pr_debug("Not a doorbell port!, port: %d, port_type: %d\n", 127 port, ptinfo.hv_port_type); 128 continue; 129 } 130 131 /* Invoke the callback */ 132 ptinfo.hv_port_doorbell.doorbell_cb(port, 133 ptinfo.hv_port_doorbell.data); 134 } 135 136 return true; 137 } 138 139 static bool mshv_async_call_completion_isr(struct hv_message *msg) 140 { 141 bool handled = false; 142 struct hv_async_completion_message_payload *async_msg; 143 struct mshv_partition *partition; 144 u64 partition_id; 145 146 if (msg->header.message_type != HVMSG_ASYNC_CALL_COMPLETION) 147 goto out; 148 149 async_msg = 150 (struct hv_async_completion_message_payload *)msg->u.payload; 151 152 partition_id = async_msg->partition_id; 153 154 /* 155 * Hold this lock for the rest of the isr, because the partition could 156 * be released anytime. 157 * e.g. the MSHV_RUN_VP thread could wake on another cpu; it could 158 * release the partition unless we hold this! 159 */ 160 rcu_read_lock(); 161 162 partition = mshv_partition_find(partition_id); 163 164 if (unlikely(!partition)) { 165 pr_debug("failed to find partition %llu\n", partition_id); 166 goto unlock_out; 167 } 168 169 partition->async_hypercall_status = async_msg->status; 170 complete(&partition->async_hypercall); 171 172 handled = true; 173 174 unlock_out: 175 rcu_read_unlock(); 176 out: 177 return handled; 178 } 179 180 static void kick_vp(struct mshv_vp *vp) 181 { 182 atomic64_inc(&vp->run.vp_signaled_count); 183 vp->run.kicked_by_hv = 1; 184 wake_up(&vp->run.vp_suspend_queue); 185 } 186 187 static void 188 handle_bitset_message(const struct hv_vp_signal_bitset_scheduler_message *msg) 189 { 190 int bank_idx, vps_signaled = 0, bank_mask_size; 191 struct mshv_partition *partition; 192 const struct hv_vpset *vpset; 193 const u64 *bank_contents; 194 u64 partition_id = msg->partition_id; 195 196 if (msg->vp_bitset.bitset.format != HV_GENERIC_SET_SPARSE_4K) { 197 pr_debug("scheduler message format is not HV_GENERIC_SET_SPARSE_4K"); 198 return; 199 } 200 201 if (msg->vp_count == 0) { 202 pr_debug("scheduler message with no VP specified"); 203 return; 204 } 205 206 rcu_read_lock(); 207 208 partition = mshv_partition_find(partition_id); 209 if (unlikely(!partition)) { 210 pr_debug("failed to find partition %llu\n", partition_id); 211 goto unlock_out; 212 } 213 214 vpset = &msg->vp_bitset.bitset; 215 216 bank_idx = -1; 217 bank_contents = vpset->bank_contents; 218 bank_mask_size = sizeof(vpset->valid_bank_mask) * BITS_PER_BYTE; 219 220 while (true) { 221 int vp_bank_idx = -1; 222 int vp_bank_size = sizeof(*bank_contents) * BITS_PER_BYTE; 223 int vp_index; 224 225 bank_idx = find_next_bit((unsigned long *)&vpset->valid_bank_mask, 226 bank_mask_size, bank_idx + 1); 227 if (bank_idx == bank_mask_size) 228 break; 229 230 while (true) { 231 struct mshv_vp *vp; 232 233 vp_bank_idx = find_next_bit((unsigned long *)bank_contents, 234 vp_bank_size, vp_bank_idx + 1); 235 if (vp_bank_idx == vp_bank_size) 236 break; 237 238 vp_index = (bank_idx * vp_bank_size) + vp_bank_idx; 239 240 /* This shouldn't happen, but just in case. */ 241 if (unlikely(vp_index >= MSHV_MAX_VPS)) { 242 pr_debug("VP index %u out of bounds\n", 243 vp_index); 244 goto unlock_out; 245 } 246 247 vp = partition->pt_vp_array[vp_index]; 248 if (unlikely(!vp)) { 249 pr_debug("failed to find VP %u\n", vp_index); 250 goto unlock_out; 251 } 252 253 kick_vp(vp); 254 vps_signaled++; 255 } 256 257 bank_contents++; 258 } 259 260 unlock_out: 261 rcu_read_unlock(); 262 263 if (vps_signaled != msg->vp_count) 264 pr_debug("asked to signal %u VPs but only did %u\n", 265 msg->vp_count, vps_signaled); 266 } 267 268 static void 269 handle_pair_message(const struct hv_vp_signal_pair_scheduler_message *msg) 270 { 271 struct mshv_partition *partition = NULL; 272 struct mshv_vp *vp; 273 int idx; 274 275 rcu_read_lock(); 276 277 for (idx = 0; idx < msg->vp_count; idx++) { 278 u64 partition_id = msg->partition_ids[idx]; 279 u32 vp_index = msg->vp_indexes[idx]; 280 281 if (idx == 0 || partition->pt_id != partition_id) { 282 partition = mshv_partition_find(partition_id); 283 if (unlikely(!partition)) { 284 pr_debug("failed to find partition %llu\n", 285 partition_id); 286 break; 287 } 288 } 289 290 /* This shouldn't happen, but just in case. */ 291 if (unlikely(vp_index >= MSHV_MAX_VPS)) { 292 pr_debug("VP index %u out of bounds\n", vp_index); 293 break; 294 } 295 296 vp = partition->pt_vp_array[vp_index]; 297 if (!vp) { 298 pr_debug("failed to find VP %u\n", vp_index); 299 break; 300 } 301 302 kick_vp(vp); 303 } 304 305 rcu_read_unlock(); 306 } 307 308 static bool 309 mshv_scheduler_isr(struct hv_message *msg) 310 { 311 if (msg->header.message_type != HVMSG_SCHEDULER_VP_SIGNAL_BITSET && 312 msg->header.message_type != HVMSG_SCHEDULER_VP_SIGNAL_PAIR) 313 return false; 314 315 if (msg->header.message_type == HVMSG_SCHEDULER_VP_SIGNAL_BITSET) 316 handle_bitset_message((struct hv_vp_signal_bitset_scheduler_message *) 317 msg->u.payload); 318 else 319 handle_pair_message((struct hv_vp_signal_pair_scheduler_message *) 320 msg->u.payload); 321 322 return true; 323 } 324 325 static bool 326 mshv_intercept_isr(struct hv_message *msg) 327 { 328 struct mshv_partition *partition; 329 bool handled = false; 330 struct mshv_vp *vp; 331 u64 partition_id; 332 u32 vp_index; 333 334 partition_id = msg->header.sender; 335 336 rcu_read_lock(); 337 338 partition = mshv_partition_find(partition_id); 339 if (unlikely(!partition)) { 340 pr_debug("failed to find partition %llu\n", 341 partition_id); 342 goto unlock_out; 343 } 344 345 if (msg->header.message_type == HVMSG_X64_APIC_EOI) { 346 /* 347 * Check if this gsi is registered in the 348 * ack_notifier list and invoke the callback 349 * if registered. 350 */ 351 352 /* 353 * If there is a notifier, the ack callback is supposed 354 * to handle the VMEXIT. So we need not pass this message 355 * to vcpu thread. 356 */ 357 struct hv_x64_apic_eoi_message *eoi_msg = 358 (struct hv_x64_apic_eoi_message *)&msg->u.payload[0]; 359 360 if (mshv_notify_acked_gsi(partition, eoi_msg->interrupt_vector)) { 361 handled = true; 362 goto unlock_out; 363 } 364 } 365 366 /* 367 * We should get an opaque intercept message here for all intercept 368 * messages, since we're using the mapped VP intercept message page. 369 * 370 * The intercept message will have been placed in intercept message 371 * page at this point. 372 * 373 * Make sure the message type matches our expectation. 374 */ 375 if (msg->header.message_type != HVMSG_OPAQUE_INTERCEPT) { 376 pr_debug("wrong message type %d", msg->header.message_type); 377 goto unlock_out; 378 } 379 380 /* 381 * Since we directly index the vp, and it has to exist for us to be here 382 * (because the vp is only deleted when the partition is), no additional 383 * locking is needed here 384 */ 385 vp_index = 386 ((struct hv_opaque_intercept_message *)msg->u.payload)->vp_index; 387 vp = partition->pt_vp_array[vp_index]; 388 if (unlikely(!vp)) { 389 pr_debug("failed to find VP %u\n", vp_index); 390 goto unlock_out; 391 } 392 393 kick_vp(vp); 394 395 handled = true; 396 397 unlock_out: 398 rcu_read_unlock(); 399 400 return handled; 401 } 402 403 void mshv_isr(void) 404 { 405 struct hv_synic_pages *spages = this_cpu_ptr(synic_pages); 406 struct hv_message_page **msg_page = &spages->hyp_synic_message_page; 407 struct hv_message *msg; 408 bool handled; 409 410 if (unlikely(!(*msg_page))) { 411 pr_debug("Missing synic page!\n"); 412 return; 413 } 414 415 msg = &((*msg_page)->sint_message[HV_SYNIC_INTERCEPTION_SINT_INDEX]); 416 417 /* 418 * If the type isn't set, there isn't really a message; 419 * it may be some other hyperv interrupt 420 */ 421 if (msg->header.message_type == HVMSG_NONE) 422 return; 423 424 handled = mshv_doorbell_isr(msg); 425 426 if (!handled) 427 handled = mshv_scheduler_isr(msg); 428 429 if (!handled) 430 handled = mshv_async_call_completion_isr(msg); 431 432 if (!handled) 433 handled = mshv_intercept_isr(msg); 434 435 if (handled) { 436 /* 437 * Acknowledge message with hypervisor if another message is 438 * pending. 439 */ 440 msg->header.message_type = HVMSG_NONE; 441 /* 442 * Ensure the write is complete so the hypervisor will deliver 443 * the next message if available. 444 */ 445 mb(); 446 if (msg->header.message_flags.msg_pending) 447 hv_set_non_nested_msr(HV_MSR_EOM, 0); 448 449 add_interrupt_randomness(mshv_sint_vector); 450 } else { 451 pr_warn_once("%s: unknown message type 0x%x\n", __func__, 452 msg->header.message_type); 453 } 454 } 455 456 static int mshv_synic_cpu_init(unsigned int cpu) 457 { 458 union hv_synic_simp simp; 459 union hv_synic_siefp siefp; 460 union hv_synic_sirbp sirbp; 461 union hv_synic_sint sint; 462 union hv_synic_scontrol sctrl; 463 struct hv_synic_pages *spages = this_cpu_ptr(synic_pages); 464 struct hv_message_page **msg_page = &spages->hyp_synic_message_page; 465 struct hv_synic_event_flags_page **event_flags_page = 466 &spages->synic_event_flags_page; 467 struct hv_synic_event_ring_page **event_ring_page = 468 &spages->synic_event_ring_page; 469 470 /* Setup the Synic's message page */ 471 simp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIMP); 472 simp.simp_enabled = true; 473 *msg_page = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT, 474 HV_HYP_PAGE_SIZE, 475 MEMREMAP_WB); 476 477 if (!(*msg_page)) 478 return -EFAULT; 479 480 hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64); 481 482 /* Setup the Synic's event flags page */ 483 siefp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIEFP); 484 siefp.siefp_enabled = true; 485 *event_flags_page = memremap(siefp.base_siefp_gpa << PAGE_SHIFT, 486 PAGE_SIZE, MEMREMAP_WB); 487 488 if (!(*event_flags_page)) 489 goto cleanup; 490 491 hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64); 492 493 /* Setup the Synic's event ring page */ 494 sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP); 495 sirbp.sirbp_enabled = true; 496 *event_ring_page = memremap(sirbp.base_sirbp_gpa << PAGE_SHIFT, 497 PAGE_SIZE, MEMREMAP_WB); 498 499 if (!(*event_ring_page)) 500 goto cleanup; 501 502 hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64); 503 504 if (mshv_sint_irq != -1) 505 enable_percpu_irq(mshv_sint_irq, 0); 506 507 /* Enable intercepts */ 508 sint.as_uint64 = 0; 509 sint.vector = mshv_sint_vector; 510 sint.masked = false; 511 sint.auto_eoi = hv_recommend_using_aeoi(); 512 hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX, 513 sint.as_uint64); 514 515 /* Doorbell SINT */ 516 sint.as_uint64 = 0; 517 sint.vector = mshv_sint_vector; 518 sint.masked = false; 519 sint.as_intercept = 1; 520 sint.auto_eoi = hv_recommend_using_aeoi(); 521 hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX, 522 sint.as_uint64); 523 524 /* Enable global synic bit */ 525 sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL); 526 sctrl.enable = 1; 527 hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64); 528 529 return 0; 530 531 cleanup: 532 if (*event_ring_page) { 533 sirbp.sirbp_enabled = false; 534 hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64); 535 memunmap(*event_ring_page); 536 } 537 if (*event_flags_page) { 538 siefp.siefp_enabled = false; 539 hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64); 540 memunmap(*event_flags_page); 541 } 542 if (*msg_page) { 543 simp.simp_enabled = false; 544 hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64); 545 memunmap(*msg_page); 546 } 547 548 return -EFAULT; 549 } 550 551 static int mshv_synic_cpu_exit(unsigned int cpu) 552 { 553 union hv_synic_sint sint; 554 union hv_synic_simp simp; 555 union hv_synic_siefp siefp; 556 union hv_synic_sirbp sirbp; 557 union hv_synic_scontrol sctrl; 558 struct hv_synic_pages *spages = this_cpu_ptr(synic_pages); 559 struct hv_message_page **msg_page = &spages->hyp_synic_message_page; 560 struct hv_synic_event_flags_page **event_flags_page = 561 &spages->synic_event_flags_page; 562 struct hv_synic_event_ring_page **event_ring_page = 563 &spages->synic_event_ring_page; 564 565 /* Disable the interrupt */ 566 sint.as_uint64 = hv_get_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX); 567 sint.masked = true; 568 hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX, 569 sint.as_uint64); 570 571 /* Disable Doorbell SINT */ 572 sint.as_uint64 = hv_get_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX); 573 sint.masked = true; 574 hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX, 575 sint.as_uint64); 576 577 if (mshv_sint_irq != -1) 578 disable_percpu_irq(mshv_sint_irq); 579 580 /* Disable Synic's event ring page */ 581 sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP); 582 sirbp.sirbp_enabled = false; 583 hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64); 584 memunmap(*event_ring_page); 585 586 /* Disable Synic's event flags page */ 587 siefp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIEFP); 588 siefp.siefp_enabled = false; 589 hv_set_non_nested_msr(HV_MSR_SIEFP, siefp.as_uint64); 590 memunmap(*event_flags_page); 591 592 /* Disable Synic's message page */ 593 simp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIMP); 594 simp.simp_enabled = false; 595 hv_set_non_nested_msr(HV_MSR_SIMP, simp.as_uint64); 596 memunmap(*msg_page); 597 598 /* Disable global synic bit */ 599 sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL); 600 sctrl.enable = 0; 601 hv_set_non_nested_msr(HV_MSR_SCONTROL, sctrl.as_uint64); 602 603 return 0; 604 } 605 606 int 607 mshv_register_doorbell(u64 partition_id, doorbell_cb_t doorbell_cb, void *data, 608 u64 gpa, u64 val, u64 flags) 609 { 610 struct hv_connection_info connection_info = { 0 }; 611 union hv_connection_id connection_id = { 0 }; 612 struct port_table_info *port_table_info; 613 struct hv_port_info port_info = { 0 }; 614 union hv_port_id port_id = { 0 }; 615 int ret; 616 617 port_table_info = kmalloc_obj(*port_table_info); 618 if (!port_table_info) 619 return -ENOMEM; 620 621 port_table_info->hv_port_type = HV_PORT_TYPE_DOORBELL; 622 port_table_info->hv_port_doorbell.doorbell_cb = doorbell_cb; 623 port_table_info->hv_port_doorbell.data = data; 624 ret = mshv_portid_alloc(port_table_info); 625 if (ret < 0) { 626 kfree(port_table_info); 627 return ret; 628 } 629 630 port_id.u.id = ret; 631 port_info.port_type = HV_PORT_TYPE_DOORBELL; 632 port_info.doorbell_port_info.target_sint = HV_SYNIC_DOORBELL_SINT_INDEX; 633 port_info.doorbell_port_info.target_vp = HV_ANY_VP; 634 ret = hv_call_create_port(hv_current_partition_id, port_id, partition_id, 635 &port_info, 636 0, 0, NUMA_NO_NODE); 637 638 if (ret < 0) { 639 mshv_portid_free(port_id.u.id); 640 return ret; 641 } 642 643 connection_id.u.id = port_id.u.id; 644 connection_info.port_type = HV_PORT_TYPE_DOORBELL; 645 connection_info.doorbell_connection_info.gpa = gpa; 646 connection_info.doorbell_connection_info.trigger_value = val; 647 connection_info.doorbell_connection_info.flags = flags; 648 649 ret = hv_call_connect_port(hv_current_partition_id, port_id, partition_id, 650 connection_id, &connection_info, 0, NUMA_NO_NODE); 651 if (ret < 0) { 652 hv_call_delete_port(hv_current_partition_id, port_id); 653 mshv_portid_free(port_id.u.id); 654 return ret; 655 } 656 657 // lets use the port_id as the doorbell_id 658 return port_id.u.id; 659 } 660 661 void 662 mshv_unregister_doorbell(u64 partition_id, int doorbell_portid) 663 { 664 union hv_port_id port_id = { 0 }; 665 union hv_connection_id connection_id = { 0 }; 666 667 connection_id.u.id = doorbell_portid; 668 hv_call_disconnect_port(partition_id, connection_id); 669 670 port_id.u.id = doorbell_portid; 671 hv_call_delete_port(hv_current_partition_id, port_id); 672 673 mshv_portid_free(doorbell_portid); 674 } 675 676 static int mshv_synic_reboot_notify(struct notifier_block *nb, 677 unsigned long code, void *unused) 678 { 679 if (!hv_root_partition()) 680 return 0; 681 682 cpuhp_remove_state(synic_cpuhp_online); 683 return 0; 684 } 685 686 static struct notifier_block mshv_synic_reboot_nb = { 687 .notifier_call = mshv_synic_reboot_notify, 688 }; 689 690 #ifndef HYPERVISOR_CALLBACK_VECTOR 691 static DEFINE_PER_CPU(long, mshv_evt); 692 693 static irqreturn_t mshv_percpu_isr(int irq, void *dev_id) 694 { 695 mshv_isr(); 696 return IRQ_HANDLED; 697 } 698 699 #ifdef CONFIG_ACPI 700 static int __init mshv_acpi_setup_sint_irq(void) 701 { 702 return acpi_register_gsi(NULL, mshv_sint_vector, ACPI_EDGE_SENSITIVE, 703 ACPI_ACTIVE_HIGH); 704 } 705 706 static void mshv_acpi_cleanup_sint_irq(void) 707 { 708 acpi_unregister_gsi(mshv_sint_vector); 709 } 710 #else 711 static int __init mshv_acpi_setup_sint_irq(void) 712 { 713 return -ENODEV; 714 } 715 716 static void mshv_acpi_cleanup_sint_irq(void) 717 { 718 } 719 #endif 720 721 static int __init mshv_sint_vector_setup(void) 722 { 723 int ret; 724 struct hv_register_assoc reg = { 725 .name = HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID, 726 }; 727 union hv_input_vtl input_vtl = { 0 }; 728 729 if (acpi_disabled) 730 return -ENODEV; 731 732 ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF, 733 1, input_vtl, ®); 734 if (ret || !reg.value.reg64) 735 return -ENODEV; 736 737 mshv_sint_vector = reg.value.reg64; 738 ret = mshv_acpi_setup_sint_irq(); 739 if (ret < 0) { 740 pr_err("Failed to setup IRQ for MSHV SINT vector %d: %d\n", 741 mshv_sint_vector, ret); 742 goto out_fail; 743 } 744 745 mshv_sint_irq = ret; 746 747 ret = request_percpu_irq(mshv_sint_irq, mshv_percpu_isr, "MSHV", 748 &mshv_evt); 749 if (ret) 750 goto out_unregister; 751 752 return 0; 753 754 out_unregister: 755 mshv_acpi_cleanup_sint_irq(); 756 out_fail: 757 return ret; 758 } 759 760 static void mshv_sint_vector_cleanup(void) 761 { 762 free_percpu_irq(mshv_sint_irq, &mshv_evt); 763 mshv_acpi_cleanup_sint_irq(); 764 } 765 #else /* !HYPERVISOR_CALLBACK_VECTOR */ 766 static int __init mshv_sint_vector_setup(void) 767 { 768 mshv_sint_vector = HYPERVISOR_CALLBACK_VECTOR; 769 return 0; 770 } 771 772 static void mshv_sint_vector_cleanup(void) 773 { 774 } 775 #endif /* HYPERVISOR_CALLBACK_VECTOR */ 776 777 int __init mshv_synic_init(struct device *dev) 778 { 779 int ret = 0; 780 781 ret = mshv_sint_vector_setup(); 782 if (ret) 783 return ret; 784 785 synic_pages = alloc_percpu(struct hv_synic_pages); 786 if (!synic_pages) { 787 dev_err(dev, "Failed to allocate percpu synic page\n"); 788 ret = -ENOMEM; 789 goto sint_vector_cleanup; 790 } 791 792 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic", 793 mshv_synic_cpu_init, 794 mshv_synic_cpu_exit); 795 if (ret < 0) { 796 dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret); 797 goto free_synic_pages; 798 } 799 800 synic_cpuhp_online = ret; 801 802 ret = register_reboot_notifier(&mshv_synic_reboot_nb); 803 if (ret) 804 goto remove_cpuhp_state; 805 806 return 0; 807 808 remove_cpuhp_state: 809 cpuhp_remove_state(synic_cpuhp_online); 810 free_synic_pages: 811 free_percpu(synic_pages); 812 sint_vector_cleanup: 813 mshv_sint_vector_cleanup(); 814 return ret; 815 } 816 817 void mshv_synic_exit(void) 818 { 819 unregister_reboot_notifier(&mshv_synic_reboot_nb); 820 cpuhp_remove_state(synic_cpuhp_online); 821 free_percpu(synic_pages); 822 mshv_sint_vector_cleanup(); 823 } 824