Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Drivers: hv: Functions for setting up and tearing down the paravisor SynIC

The confidential VMBus runs with the paravisor SynIC and requires
configuring it with the paravisor.

Add the functions for configuring the paravisor SynIC. Update
overall SynIC initialization logic to initialize the SynIC if it
is present. Finally, break out SynIC interrupt enable/disable
code into separate functions so that SynIC interrupts can be
enabled or disabled via the paravisor instead of the hypervisor
if the paravisor SynIC is present.

Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Roman Kisel and committed by
Wei Liu
e096fe2b 74fa5d7e

+126 -12
+126 -12
drivers/hv/hv.c
··· 278 278 union hv_synic_simp simp; 279 279 union hv_synic_siefp siefp; 280 280 union hv_synic_sint shared_sint; 281 - union hv_synic_scontrol sctrl; 282 281 283 - /* Setup the Synic's message page */ 282 + /* Setup the Synic's message page with the hypervisor. */ 284 283 simp.as_uint64 = hv_get_msr(HV_MSR_SIMP); 285 284 simp.simp_enabled = 1; 286 285 ··· 298 299 299 300 hv_set_msr(HV_MSR_SIMP, simp.as_uint64); 300 301 301 - /* Setup the Synic's event page */ 302 + /* Setup the Synic's event page with the hypervisor. */ 302 303 siefp.as_uint64 = hv_get_msr(HV_MSR_SIEFP); 303 304 siefp.siefp_enabled = 1; 304 305 ··· 327 328 shared_sint.masked = false; 328 329 shared_sint.auto_eoi = hv_recommend_using_aeoi(); 329 330 hv_set_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); 331 + } 332 + 333 + static void hv_hyp_synic_enable_interrupts(void) 334 + { 335 + union hv_synic_scontrol sctrl; 330 336 331 337 /* Enable the global synic bit */ 332 338 sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL); ··· 340 336 hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64); 341 337 } 342 338 339 + static void hv_para_synic_enable_regs(unsigned int cpu) 340 + { 341 + union hv_synic_simp simp; 342 + union hv_synic_siefp siefp; 343 + struct hv_per_cpu_context *hv_cpu 344 + = per_cpu_ptr(hv_context.cpu_context, cpu); 345 + 346 + /* Setup the Synic's message page with the paravisor. */ 347 + simp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIMP); 348 + simp.simp_enabled = 1; 349 + simp.base_simp_gpa = virt_to_phys(hv_cpu->para_synic_message_page) 350 + >> HV_HYP_PAGE_SHIFT; 351 + hv_para_set_synic_register(HV_MSR_SIMP, simp.as_uint64); 352 + 353 + /* Setup the Synic's event page with the paravisor. */ 354 + siefp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIEFP); 355 + siefp.siefp_enabled = 1; 356 + siefp.base_siefp_gpa = virt_to_phys(hv_cpu->para_synic_event_page) 357 + >> HV_HYP_PAGE_SHIFT; 358 + hv_para_set_synic_register(HV_MSR_SIEFP, siefp.as_uint64); 359 + } 360 + 361 + static void hv_para_synic_enable_interrupts(void) 362 + { 363 + union hv_synic_scontrol sctrl; 364 + 365 + /* Enable the global synic bit */ 366 + sctrl.as_uint64 = hv_para_get_synic_register(HV_MSR_SCONTROL); 367 + sctrl.enable = 1; 368 + hv_para_set_synic_register(HV_MSR_SCONTROL, sctrl.as_uint64); 369 + } 370 + 343 371 int hv_synic_init(unsigned int cpu) 344 372 { 373 + if (vmbus_is_confidential()) 374 + hv_para_synic_enable_regs(cpu); 375 + 376 + /* 377 + * The SINT is set in hv_hyp_synic_enable_regs() by calling 378 + * hv_set_msr(). hv_set_msr() in turn has special case code for the 379 + * SINT MSRs that write to the hypervisor version of the MSR *and* 380 + * the paravisor version of the MSR (but *without* the proxy bit when 381 + * VMBus is confidential). 382 + * 383 + * Then enable interrupts via the paravisor if VMBus is confidential, 384 + * and otherwise via the hypervisor. 385 + */ 386 + 345 387 hv_hyp_synic_enable_regs(cpu); 388 + if (vmbus_is_confidential()) 389 + hv_para_synic_enable_interrupts(); 390 + else 391 + hv_hyp_synic_enable_interrupts(); 346 392 347 393 hv_stimer_legacy_init(cpu, VMBUS_MESSAGE_SINT); 348 394 ··· 406 352 union hv_synic_sint shared_sint; 407 353 union hv_synic_simp simp; 408 354 union hv_synic_siefp siefp; 409 - union hv_synic_scontrol sctrl; 410 355 411 356 shared_sint.as_uint64 = hv_get_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT); 412 357 ··· 418 365 419 366 simp.as_uint64 = hv_get_msr(HV_MSR_SIMP); 420 367 /* 421 - * In Isolation VM, sim and sief pages are allocated by 368 + * In Isolation VM, simp and sief pages are allocated by 422 369 * paravisor. These pages also will be used by kdump 423 370 * kernel. So just reset enable bit here and keep page 424 371 * addresses. ··· 448 395 } 449 396 450 397 hv_set_msr(HV_MSR_SIEFP, siefp.as_uint64); 398 + } 399 + 400 + static void hv_hyp_synic_disable_interrupts(void) 401 + { 402 + union hv_synic_scontrol sctrl; 451 403 452 404 /* Disable the global synic bit */ 453 405 sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL); 454 406 sctrl.enable = 0; 455 407 hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64); 408 + } 456 409 457 - if (vmbus_irq != -1) 458 - disable_percpu_irq(vmbus_irq); 410 + static void hv_para_synic_disable_regs(unsigned int cpu) 411 + { 412 + union hv_synic_simp simp; 413 + union hv_synic_siefp siefp; 414 + 415 + /* Disable SynIC's message page in the paravisor. */ 416 + simp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIMP); 417 + simp.simp_enabled = 0; 418 + hv_para_set_synic_register(HV_MSR_SIMP, simp.as_uint64); 419 + 420 + /* Disable SynIC's event page in the paravisor. */ 421 + siefp.as_uint64 = hv_para_get_synic_register(HV_MSR_SIEFP); 422 + siefp.siefp_enabled = 0; 423 + hv_para_set_synic_register(HV_MSR_SIEFP, siefp.as_uint64); 424 + } 425 + 426 + static void hv_para_synic_disable_interrupts(void) 427 + { 428 + union hv_synic_scontrol sctrl; 429 + 430 + /* Disable the global synic bit */ 431 + sctrl.as_uint64 = hv_para_get_synic_register(HV_MSR_SCONTROL); 432 + sctrl.enable = 0; 433 + hv_para_set_synic_register(HV_MSR_SCONTROL, sctrl.as_uint64); 459 434 } 460 435 461 436 #define HV_MAX_TRIES 3 ··· 496 415 * that the normal interrupt handling mechanism will find and process the channel interrupt 497 416 * "very soon", and in the process clear the bit. 498 417 */ 499 - static bool hv_synic_event_pending(void) 418 + static bool __hv_synic_event_pending(union hv_synic_event_flags *event, int sint) 500 419 { 501 - struct hv_per_cpu_context *hv_cpu = this_cpu_ptr(hv_context.cpu_context); 502 - union hv_synic_event_flags *event = 503 - (union hv_synic_event_flags *)hv_cpu->hyp_synic_event_page + VMBUS_MESSAGE_SINT; 504 - unsigned long *recv_int_page = event->flags; /* assumes VMBus version >= VERSION_WIN8 */ 420 + unsigned long *recv_int_page; 505 421 bool pending; 506 422 u32 relid; 507 423 int tries = 0; 508 424 425 + if (!event) 426 + return false; 427 + 428 + event += sint; 429 + recv_int_page = event->flags; /* assumes VMBus version >= VERSION_WIN8 */ 509 430 retry: 510 431 pending = false; 511 432 for_each_set_bit(relid, recv_int_page, HV_EVENT_FLAGS_COUNT) { ··· 522 439 goto retry; 523 440 } 524 441 return pending; 442 + } 443 + 444 + static bool hv_synic_event_pending(void) 445 + { 446 + struct hv_per_cpu_context *hv_cpu = this_cpu_ptr(hv_context.cpu_context); 447 + union hv_synic_event_flags *hyp_synic_event_page = hv_cpu->hyp_synic_event_page; 448 + union hv_synic_event_flags *para_synic_event_page = hv_cpu->para_synic_event_page; 449 + 450 + return 451 + __hv_synic_event_pending(hyp_synic_event_page, VMBUS_MESSAGE_SINT) || 452 + __hv_synic_event_pending(para_synic_event_page, VMBUS_MESSAGE_SINT); 525 453 } 526 454 527 455 static int hv_pick_new_cpu(struct vmbus_channel *channel) ··· 627 533 always_cleanup: 628 534 hv_stimer_legacy_cleanup(cpu); 629 535 536 + /* 537 + * First, disable the event and message pages 538 + * used for communicating with the host, and then 539 + * disable the host interrupts if VMBus is not 540 + * confidential. 541 + */ 630 542 hv_hyp_synic_disable_regs(cpu); 543 + if (!vmbus_is_confidential()) 544 + hv_hyp_synic_disable_interrupts(); 545 + 546 + /* 547 + * Perform the same steps for the Confidential VMBus. 548 + * The sequencing provides the guarantee that no data 549 + * may be posted for processing before disabling interrupts. 550 + */ 551 + if (vmbus_is_confidential()) { 552 + hv_para_synic_disable_regs(cpu); 553 + hv_para_synic_disable_interrupts(); 554 + } 555 + if (vmbus_irq != -1) 556 + disable_percpu_irq(vmbus_irq); 631 557 632 558 return ret; 633 559 }