[PATCH 3/3] Staging: hv: fix smp problems in the hyperv core code

Greg Kroah-Hartman gregkh at suse.de
Wed Jan 20 23:50:37 UTC 2010


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

Patch originally written by K. Y. Srinivasan <ksrinivasan at 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 at novell.com>
Cc: Hank Janssen <hjanssen at microsoft.com>
Cc: Haiyang Zhang <haiyangz at microsoft.com>.
Cc: stable <stable at kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
---
 drivers/staging/hv/Hv.c    |   50 ++++++++++++++++++++++----------------------
 drivers/staging/hv/Hv.h    |    6 ++--
 drivers/staging/hv/Vmbus.c |   12 ++++++----
 3 files changed, 35 insertions(+), 33 deletions(-)

diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c
index c5b6613..c2809f2 100644
--- a/drivers/staging/hv/Hv.c
+++ b/drivers/staging/hv/Hv.c
@@ -386,7 +386,7 @@ u16 HvSignalEvent(void)
  * retrieve the initialized message and event pages.  Otherwise, we create and
  * initialize the message and event pages.
  */
-int HvSynicInit(u32 irqVector)
+void HvSynicInit(void *irqarg)
 {
 	u64 version;
 	union hv_synic_simp simp;
@@ -394,13 +394,14 @@ int HvSynicInit(u32 irqVector)
 	union hv_synic_sint sharedSint;
 	union hv_synic_scontrol sctrl;
 	u64 guestID;
-	int ret = 0;
+	u32 irqVector = *((u32 *)(irqarg));
+	int cpu = smp_processor_id();
 
 	DPRINT_ENTER(VMBUS);
 
 	if (!gHvContext.HypercallPage) {
 		DPRINT_EXIT(VMBUS);
-		return ret;
+		return;
 	}
 
 	/* Check the version */
@@ -425,27 +426,27 @@ int HvSynicInit(u32 irqVector)
 		 */
 		rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID);
 		if (guestID == HV_LINUX_GUEST_ID) {
-			gHvContext.synICMessagePage[0] =
+			gHvContext.synICMessagePage[cpu] =
 				phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT);
-			gHvContext.synICEventPage[0] =
+			gHvContext.synICEventPage[cpu] =
 				phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT);
 		} else {
 			DPRINT_ERR(VMBUS, "unknown guest id!!");
 			goto Cleanup;
 		}
 		DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p",
-			   gHvContext.synICMessagePage[0],
-			   gHvContext.synICEventPage[0]);
+			   gHvContext.synICMessagePage[cpu],
+			   gHvContext.synICEventPage[cpu]);
 	} else {
-		gHvContext.synICMessagePage[0] = osd_PageAlloc(1);
-		if (gHvContext.synICMessagePage[0] == NULL) {
+		gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
+		if (gHvContext.synICMessagePage[cpu] == NULL) {
 			DPRINT_ERR(VMBUS,
 				   "unable to allocate SYNIC message page!!");
 			goto Cleanup;
 		}
 
-		gHvContext.synICEventPage[0] = osd_PageAlloc(1);
-		if (gHvContext.synICEventPage[0] == NULL) {
+		gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC);
+		if (gHvContext.synICEventPage[cpu] == NULL) {
 			DPRINT_ERR(VMBUS,
 				   "unable to allocate SYNIC event page!!");
 			goto Cleanup;
@@ -454,7 +455,7 @@ int HvSynicInit(u32 irqVector)
 		/* Setup the Synic's message page */
 		rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64);
 		simp.SimpEnabled = 1;
-		simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0])
+		simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu])
 					>> PAGE_SHIFT;
 
 		DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx",
@@ -465,7 +466,7 @@ int HvSynicInit(u32 irqVector)
 		/* Setup the Synic's event page */
 		rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
 		siefp.SiefpEnabled = 1;
-		siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0])
+		siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu])
 					>> PAGE_SHIFT;
 
 		DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx",
@@ -501,32 +502,30 @@ int HvSynicInit(u32 irqVector)
 
 	DPRINT_EXIT(VMBUS);
 
-	return ret;
+	return;
 
 Cleanup:
-	ret = -1;
-
 	if (gHvContext.GuestId == HV_LINUX_GUEST_ID) {
-		if (gHvContext.synICEventPage[0])
-			osd_PageFree(gHvContext.synICEventPage[0], 1);
+		if (gHvContext.synICEventPage[cpu])
+			osd_PageFree(gHvContext.synICEventPage[cpu], 1);
 
-		if (gHvContext.synICMessagePage[0])
-			osd_PageFree(gHvContext.synICMessagePage[0], 1);
+		if (gHvContext.synICMessagePage[cpu])
+			osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
 	}
 
 	DPRINT_EXIT(VMBUS);
-
-	return ret;
+	return;
 }
 
 /**
  * HvSynicCleanup - Cleanup routine for HvSynicInit().
  */
-void HvSynicCleanup(void)
+void HvSynicCleanup(void *arg)
 {
 	union hv_synic_sint sharedSint;
 	union hv_synic_simp simp;
 	union hv_synic_siefp siefp;
+	int cpu = smp_processor_id();
 
 	DPRINT_ENTER(VMBUS);
 
@@ -539,6 +538,7 @@ void HvSynicCleanup(void)
 
 	sharedSint.Masked = 1;
 
+	/* Need to correctly cleanup in the case of SMP!!! */
 	/* Disable the interrupt */
 	wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
 
@@ -560,8 +560,8 @@ void HvSynicCleanup(void)
 
 		wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64);
 
-		osd_PageFree(gHvContext.synICMessagePage[0], 1);
-		osd_PageFree(gHvContext.synICEventPage[0], 1);
+		osd_PageFree(gHvContext.synICMessagePage[cpu], 1);
+		osd_PageFree(gHvContext.synICEventPage[cpu], 1);
 	}
 
 	DPRINT_EXIT(VMBUS);
diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/Hv.h
index 5379e4b..fce4b5c 100644
--- a/drivers/staging/hv/Hv.h
+++ b/drivers/staging/hv/Hv.h
@@ -93,7 +93,7 @@ static const struct hv_guid VMBUS_SERVICE_ID = {
 	},
 };
 
-#define MAX_NUM_CPUS	1
+#define MAX_NUM_CPUS	32
 
 
 struct hv_input_signal_event_buffer {
@@ -137,8 +137,8 @@ extern u16 HvPostMessage(union hv_connection_id connectionId,
 
 extern u16 HvSignalEvent(void);
 
-extern int HvSynicInit(u32 irqVector);
+extern void HvSynicInit(void *irqarg);
 
-extern void HvSynicCleanup(void);
+extern void HvSynicCleanup(void *arg);
 
 #endif /* __HV_H__ */
diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/Vmbus.c
index a4dd06f..35a023e 100644
--- a/drivers/staging/hv/Vmbus.c
+++ b/drivers/staging/hv/Vmbus.c
@@ -129,7 +129,7 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo)
 
 	/* strcpy(dev->name, "vmbus"); */
 	/* SynIC setup... */
-	ret = HvSynicInit(*irqvector);
+	on_each_cpu(HvSynicInit, (void *)irqvector, 1);
 
 	/* Connect to VMBus in the root partition */
 	ret = VmbusConnect();
@@ -150,7 +150,7 @@ static int VmbusOnDeviceRemove(struct hv_device *dev)
 	DPRINT_ENTER(VMBUS);
 	VmbusChannelReleaseUnattachedChannels();
 	VmbusDisconnect();
-	HvSynicCleanup();
+	on_each_cpu(HvSynicCleanup, NULL, 1);
 	DPRINT_EXIT(VMBUS);
 
 	return ret;
@@ -173,7 +173,8 @@ static void VmbusOnCleanup(struct hv_driver *drv)
  */
 static void VmbusOnMsgDPC(struct hv_driver *drv)
 {
-	void *page_addr = gHvContext.synICMessagePage[0];
+	int cpu = smp_processor_id();
+	void *page_addr = gHvContext.synICMessagePage[cpu];
 	struct hv_message *msg = (struct hv_message *)page_addr +
 				  VMBUS_MESSAGE_SINT;
 	struct hv_message *copied;
@@ -230,11 +231,12 @@ static void VmbusOnEventDPC(struct hv_driver *drv)
 static int VmbusOnISR(struct hv_driver *drv)
 {
 	int ret = 0;
+	int cpu = smp_processor_id();
 	void *page_addr;
 	struct hv_message *msg;
 	union hv_synic_event_flags *event;
 
-	page_addr = gHvContext.synICMessagePage[0];
+	page_addr = gHvContext.synICMessagePage[cpu];
 	msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
 
 	DPRINT_ENTER(VMBUS);
@@ -248,7 +250,7 @@ static int VmbusOnISR(struct hv_driver *drv)
 	}
 
 	/* TODO: Check if there are events to be process */
-	page_addr = gHvContext.synICEventPage[0];
+	page_addr = gHvContext.synICEventPage[cpu];
 	event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
 
 	/* Since we are a child, we only need to check bit 0 */
-- 
1.6.5.7




More information about the devel mailing list