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>
This commit is contained in:
Родитель
d31a2ff03f
Коммит
7692fd4d44
|
@ -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);
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче