diff options
Diffstat (limited to 'drivers/staging/hv/Hv.c')
-rw-r--r-- | drivers/staging/hv/Hv.c | 223 |
1 files changed, 90 insertions, 133 deletions
diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c index c5b6613f2f2f..51149e69f3e8 100644 --- a/drivers/staging/hv/Hv.c +++ b/drivers/staging/hv/Hv.c @@ -208,50 +208,51 @@ int HvInit(void) /* HvQueryHypervisorFeatures(maxLeaf); */ /* - * Determine if we are running on xenlinux (ie x2v shim) or native - * linux + * We only support running on top of Hyper-V */ rdmsrl(HV_X64_MSR_GUEST_OS_ID, gHvContext.GuestId); - if (gHvContext.GuestId == 0) { - /* Write our OS info */ - wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); - gHvContext.GuestId = HV_LINUX_GUEST_ID; + + if (gHvContext.GuestId != 0) { + DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", + gHvContext.GuestId); + goto Cleanup; } + /* Write our OS info */ + wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); + gHvContext.GuestId = HV_LINUX_GUEST_ID; + /* See if the hypercall page is already set */ rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); - if (gHvContext.GuestId == HV_LINUX_GUEST_ID) { - /* Allocate the hypercall page memory */ - /* virtAddr = osd_PageAlloc(1); */ - virtAddr = osd_VirtualAllocExec(PAGE_SIZE); - - if (!virtAddr) { - DPRINT_ERR(VMBUS, - "unable to allocate hypercall page!!"); - goto Cleanup; - } - hypercallMsr.Enable = 1; - /* hypercallMsr.GuestPhysicalAddress = - * virt_to_phys(virtAddr) >> PAGE_SHIFT; */ - hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr); - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + /* + * Allocate the hypercall page memory + * virtAddr = osd_PageAlloc(1); + */ + virtAddr = osd_VirtualAllocExec(PAGE_SIZE); - /* Confirm that hypercall page did get setup. */ - hypercallMsr.AsUINT64 = 0; - rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); - if (!hypercallMsr.Enable) { - DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); - goto Cleanup; - } + if (!virtAddr) { + DPRINT_ERR(VMBUS, + "unable to allocate hypercall page!!"); + goto Cleanup; + } - gHvContext.HypercallPage = virtAddr; - } else { - DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", - gHvContext.GuestId); + hypercallMsr.Enable = 1; + + hypercallMsr.GuestPhysicalAddress = vmalloc_to_pfn(virtAddr); + wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + + /* Confirm that hypercall page did get setup. */ + hypercallMsr.AsUINT64 = 0; + rdmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + + if (!hypercallMsr.Enable) { + DPRINT_ERR(VMBUS, "unable to set hypercall page!!"); goto Cleanup; } + gHvContext.HypercallPage = virtAddr; + DPRINT_INFO(VMBUS, "Hypercall page VA=%p, PA=0x%0llx", gHvContext.HypercallPage, (u64)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT); @@ -273,8 +274,6 @@ int HvInit(void) gHvContext.SignalEventParam->FlagNumber = 0; gHvContext.SignalEventParam->RsvdZ = 0; - /* DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId()); */ - DPRINT_EXIT(VMBUS); return ret; @@ -311,17 +310,14 @@ void HvCleanup(void) kfree(gHvContext.SignalEventBuffer); } - if (gHvContext.GuestId == HV_LINUX_GUEST_ID) { - if (gHvContext.HypercallPage) { - hypercallMsr.AsUINT64 = 0; - wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); - vfree(gHvContext.HypercallPage); - gHvContext.HypercallPage = NULL; - } + if (gHvContext.HypercallPage) { + hypercallMsr.AsUINT64 = 0; + wrmsrl(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64); + vfree(gHvContext.HypercallPage); + gHvContext.HypercallPage = NULL; } DPRINT_EXIT(VMBUS); - } /** @@ -386,21 +382,22 @@ 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; union hv_synic_siefp siefp; 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 */ @@ -408,71 +405,41 @@ int HvSynicInit(u32 irqVector) DPRINT_INFO(VMBUS, "SynIC version: %llx", version); - /* TODO: Handle SMP */ - if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID) { - DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since " - "it is already set."); - - rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - - DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", - simp.AsUINT64, siefp.AsUINT64); - - /* - * Determine if we are running on xenlinux (ie x2v shim) or - * native linux - */ - rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID); - if (guestID == HV_LINUX_GUEST_ID) { - gHvContext.synICMessagePage[0] = - phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT); - gHvContext.synICEventPage[0] = - 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]); - } else { - gHvContext.synICMessagePage[0] = osd_PageAlloc(1); - if (gHvContext.synICMessagePage[0] == NULL) { - DPRINT_ERR(VMBUS, - "unable to allocate SYNIC message page!!"); - goto Cleanup; - } + gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); - gHvContext.synICEventPage[0] = osd_PageAlloc(1); - if (gHvContext.synICEventPage[0] == NULL) { - DPRINT_ERR(VMBUS, - "unable to allocate SYNIC event page!!"); - goto Cleanup; - } + if (gHvContext.synICMessagePage[cpu] == NULL) { + DPRINT_ERR(VMBUS, + "unable to allocate SYNIC message page!!"); + goto Cleanup; + } + + 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; + } - /* Setup the Synic's message page */ - rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - simp.SimpEnabled = 1; - simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0]) - >> PAGE_SHIFT; + /* Setup the Synic's message page */ + rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); + simp.SimpEnabled = 1; + simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu]) + >> PAGE_SHIFT; - DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", - simp.AsUINT64); + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64); - wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); + wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - /* Setup the Synic's event page */ - rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - siefp.SiefpEnabled = 1; - siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0]) - >> PAGE_SHIFT; + /* Setup the Synic's event page */ + rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); + siefp.SiefpEnabled = 1; + siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu]) + >> PAGE_SHIFT; - DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", - siefp.AsUINT64); + DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64); - wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - } + wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); /* Setup the interception SINT. */ /* wrmsrl((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX), */ @@ -501,32 +468,28 @@ 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,30 +502,24 @@ 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); - /* - * Disable and free the resources only if we are running as - * native linux since in xenlinux, we are sharing the - * resources with the x2v shim - */ - if (gHvContext.GuestId == HV_LINUX_GUEST_ID) { - rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - simp.SimpEnabled = 0; - simp.BaseSimpGpa = 0; + rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); + simp.SimpEnabled = 0; + simp.BaseSimpGpa = 0; - wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); + wrmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); - rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - siefp.SiefpEnabled = 0; - siefp.BaseSiefpGpa = 0; + rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); + siefp.SiefpEnabled = 0; + siefp.BaseSiefpGpa = 0; - wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); + 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); } |