Staging: hv: fix smp problems in the hyperv core code

This fixes a number of SMP problems that were in the hyperv core code.

Patch originally written by K. Y. Srinivasan <ksrinivasan@novell.com>
but forward ported to the latest in-kernel code and tweaked slightly by
me.

Novell, Inc. hereby disclaims all copyright in any derivative work
copyright associated with this patch.

Signed-off-by: K. Y. Srinivasan <ksrinivasan@novell.com>
Cc: Hank Janssen <hjanssen@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>.
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

+35 -33
+25 -25
drivers/staging/hv/Hv.c
··· 386 386 * retrieve the initialized message and event pages. Otherwise, we create and 387 387 * initialize the message and event pages. 388 388 */ 389 - int HvSynicInit(u32 irqVector) 389 + void HvSynicInit(void *irqarg) 390 390 { 391 391 u64 version; 392 392 union hv_synic_simp simp; ··· 394 394 union hv_synic_sint sharedSint; 395 395 union hv_synic_scontrol sctrl; 396 396 u64 guestID; 397 - int ret = 0; 397 + u32 irqVector = *((u32 *)(irqarg)); 398 + int cpu = smp_processor_id(); 398 399 399 400 DPRINT_ENTER(VMBUS); 400 401 401 402 if (!gHvContext.HypercallPage) { 402 403 DPRINT_EXIT(VMBUS); 403 - return ret; 404 + return; 404 405 } 405 406 406 407 /* Check the version */ ··· 426 425 */ 427 426 rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID); 428 427 if (guestID == HV_LINUX_GUEST_ID) { 429 - gHvContext.synICMessagePage[0] = 428 + gHvContext.synICMessagePage[cpu] = 430 429 phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT); 431 - gHvContext.synICEventPage[0] = 430 + gHvContext.synICEventPage[cpu] = 432 431 phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT); 433 432 } else { 434 433 DPRINT_ERR(VMBUS, "unknown guest id!!"); 435 434 goto Cleanup; 436 435 } 437 436 DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", 438 - gHvContext.synICMessagePage[0], 439 - gHvContext.synICEventPage[0]); 437 + gHvContext.synICMessagePage[cpu], 438 + gHvContext.synICEventPage[cpu]); 440 439 } else { 441 - gHvContext.synICMessagePage[0] = osd_PageAlloc(1); 442 - if (gHvContext.synICMessagePage[0] == NULL) { 440 + gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); 441 + if (gHvContext.synICMessagePage[cpu] == NULL) { 443 442 DPRINT_ERR(VMBUS, 444 443 "unable to allocate SYNIC message page!!"); 445 444 goto Cleanup; 446 445 } 447 446 448 - gHvContext.synICEventPage[0] = osd_PageAlloc(1); 449 - if (gHvContext.synICEventPage[0] == NULL) { 447 + gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); 448 + if (gHvContext.synICEventPage[cpu] == NULL) { 450 449 DPRINT_ERR(VMBUS, 451 450 "unable to allocate SYNIC event page!!"); 452 451 goto Cleanup; ··· 455 454 /* Setup the Synic's message page */ 456 455 rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); 457 456 simp.SimpEnabled = 1; 458 - simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0]) 457 + simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu]) 459 458 >> PAGE_SHIFT; 460 459 461 460 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", ··· 466 465 /* Setup the Synic's event page */ 467 466 rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); 468 467 siefp.SiefpEnabled = 1; 469 - siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0]) 468 + siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu]) 470 469 >> PAGE_SHIFT; 471 470 472 471 DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", ··· 502 501 503 502 DPRINT_EXIT(VMBUS); 504 503 505 - return ret; 504 + return; 506 505 507 506 Cleanup: 508 - ret = -1; 509 - 510 507 if (gHvContext.GuestId == HV_LINUX_GUEST_ID) { 511 - if (gHvContext.synICEventPage[0]) 512 - osd_PageFree(gHvContext.synICEventPage[0], 1); 508 + if (gHvContext.synICEventPage[cpu]) 509 + osd_PageFree(gHvContext.synICEventPage[cpu], 1); 513 510 514 - if (gHvContext.synICMessagePage[0]) 515 - osd_PageFree(gHvContext.synICMessagePage[0], 1); 511 + if (gHvContext.synICMessagePage[cpu]) 512 + osd_PageFree(gHvContext.synICMessagePage[cpu], 1); 516 513 } 517 514 518 515 DPRINT_EXIT(VMBUS); 519 - 520 - return ret; 516 + return; 521 517 } 522 518 523 519 /** 524 520 * HvSynicCleanup - Cleanup routine for HvSynicInit(). 525 521 */ 526 - void HvSynicCleanup(void) 522 + void HvSynicCleanup(void *arg) 527 523 { 528 524 union hv_synic_sint sharedSint; 529 525 union hv_synic_simp simp; 530 526 union hv_synic_siefp siefp; 527 + int cpu = smp_processor_id(); 531 528 532 529 DPRINT_ENTER(VMBUS); 533 530 ··· 538 539 539 540 sharedSint.Masked = 1; 540 541 542 + /* Need to correctly cleanup in the case of SMP!!! */ 541 543 /* Disable the interrupt */ 542 544 wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); 543 545 ··· 560 560 561 561 wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); 562 562 563 - osd_PageFree(gHvContext.synICMessagePage[0], 1); 564 - osd_PageFree(gHvContext.synICEventPage[0], 1); 563 + osd_PageFree(gHvContext.synICMessagePage[cpu], 1); 564 + osd_PageFree(gHvContext.synICEventPage[cpu], 1); 565 565 } 566 566 567 567 DPRINT_EXIT(VMBUS);
+3 -3
drivers/staging/hv/Hv.h
··· 93 93 }, 94 94 }; 95 95 96 - #define MAX_NUM_CPUS 1 96 + #define MAX_NUM_CPUS 32 97 97 98 98 99 99 struct hv_input_signal_event_buffer { ··· 137 137 138 138 extern u16 HvSignalEvent(void); 139 139 140 - extern int HvSynicInit(u32 irqVector); 140 + extern void HvSynicInit(void *irqarg); 141 141 142 - extern void HvSynicCleanup(void); 142 + extern void HvSynicCleanup(void *arg); 143 143 144 144 #endif /* __HV_H__ */
+7 -5
drivers/staging/hv/Vmbus.c
··· 129 129 130 130 /* strcpy(dev->name, "vmbus"); */ 131 131 /* SynIC setup... */ 132 - ret = HvSynicInit(*irqvector); 132 + on_each_cpu(HvSynicInit, (void *)irqvector, 1); 133 133 134 134 /* Connect to VMBus in the root partition */ 135 135 ret = VmbusConnect(); ··· 150 150 DPRINT_ENTER(VMBUS); 151 151 VmbusChannelReleaseUnattachedChannels(); 152 152 VmbusDisconnect(); 153 - HvSynicCleanup(); 153 + on_each_cpu(HvSynicCleanup, NULL, 1); 154 154 DPRINT_EXIT(VMBUS); 155 155 156 156 return ret; ··· 173 173 */ 174 174 static void VmbusOnMsgDPC(struct hv_driver *drv) 175 175 { 176 - void *page_addr = gHvContext.synICMessagePage[0]; 176 + int cpu = smp_processor_id(); 177 + void *page_addr = gHvContext.synICMessagePage[cpu]; 177 178 struct hv_message *msg = (struct hv_message *)page_addr + 178 179 VMBUS_MESSAGE_SINT; 179 180 struct hv_message *copied; ··· 231 230 static int VmbusOnISR(struct hv_driver *drv) 232 231 { 233 232 int ret = 0; 233 + int cpu = smp_processor_id(); 234 234 void *page_addr; 235 235 struct hv_message *msg; 236 236 union hv_synic_event_flags *event; 237 237 238 - page_addr = gHvContext.synICMessagePage[0]; 238 + page_addr = gHvContext.synICMessagePage[cpu]; 239 239 msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; 240 240 241 241 DPRINT_ENTER(VMBUS); ··· 250 248 } 251 249 252 250 /* TODO: Check if there are events to be process */ 253 - page_addr = gHvContext.synICEventPage[0]; 251 + page_addr = gHvContext.synICEventPage[cpu]; 254 252 event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; 255 253 256 254 /* Since we are a child, we only need to check bit 0 */