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