Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/hyperv/vmbus/vmbus.c
Context not available. | |||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#if defined(__aarch64__) | |||||
#include <dev/psci/smccc.h> | |||||
#include <dev/hyperv/vmbus/aarch64/hyperv_machdep.h> | |||||
#include <dev/hyperv/vmbus/aarch64/hyperv_reg.h> | |||||
#else | |||||
#include <dev/hyperv/vmbus/x86/hyperv_machdep.h> | |||||
#include <dev/hyperv/vmbus/x86/hyperv_reg.h> | |||||
#include <machine/intr_machdep.h> | #include <machine/intr_machdep.h> | ||||
#include <x86/include/apicvar.h> | |||||
#endif | |||||
#include <machine/metadata.h> | #include <machine/metadata.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <x86/include/apicvar.h> | |||||
#include <contrib/dev/acpica/include/acpi.h> | #include <contrib/dev/acpica/include/acpi.h> | ||||
#include <dev/acpica/acpivar.h> | #include <dev/acpica/acpivar.h> | ||||
#include <dev/hyperv/include/hyperv.h> | #include <dev/hyperv/include/hyperv.h> | ||||
#include <dev/hyperv/include/vmbus_xact.h> | #include <dev/hyperv/include/vmbus_xact.h> | ||||
#include <dev/hyperv/vmbus/hyperv_reg.h> | |||||
#include <dev/hyperv/vmbus/hyperv_var.h> | #include <dev/hyperv/vmbus/hyperv_var.h> | ||||
#include <dev/hyperv/vmbus/vmbus_reg.h> | #include <dev/hyperv/vmbus/vmbus_reg.h> | ||||
#include <dev/hyperv/vmbus/vmbus_var.h> | #include <dev/hyperv/vmbus/vmbus_var.h> | ||||
#include <dev/hyperv/vmbus/vmbus_chanvar.h> | #include <dev/hyperv/vmbus/vmbus_chanvar.h> | ||||
#include "acpi_if.h" | #include "acpi_if.h" | ||||
#include "pcib_if.h" | #include "pcib_if.h" | ||||
#include "vmbus_if.h" | #include "vmbus_if.h" | ||||
Context not available. | |||||
device_t dev, int cpu); | device_t dev, int cpu); | ||||
static struct taskqueue *vmbus_get_eventtq_method(device_t, device_t, | static struct taskqueue *vmbus_get_eventtq_method(device_t, device_t, | ||||
int); | int); | ||||
#ifdef EARLY_AP_STARTUP | #if defined(EARLY_AP_STARTUP) || defined(__aarch64__) | ||||
static void vmbus_intrhook(void *); | static void vmbus_intrhook(void *); | ||||
#endif | #endif | ||||
Context not available. | |||||
static int vmbus_doattach(struct vmbus_softc *); | static int vmbus_doattach(struct vmbus_softc *); | ||||
static void vmbus_event_proc_dummy(struct vmbus_softc *, | static void vmbus_event_proc_dummy(struct vmbus_softc *, | ||||
int); | int); | ||||
static struct vmbus_softc *vmbus_sc; | static struct vmbus_softc *vmbus_sc; | ||||
SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, | SYSCTL_NODE(_hw, OID_AUTO, vmbus, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, | ||||
Context not available. | |||||
static int vmbus_pin_evttask = 1; | static int vmbus_pin_evttask = 1; | ||||
SYSCTL_INT(_hw_vmbus, OID_AUTO, pin_evttask, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_vmbus, OID_AUTO, pin_evttask, CTLFLAG_RDTUN, | ||||
&vmbus_pin_evttask, 0, "Pin event tasks to their respective CPU"); | &vmbus_pin_evttask, 0, "Pin event tasks to their respective CPU"); | ||||
extern inthand_t IDTVEC(vmbus_isr), IDTVEC(vmbus_isr_pti); | |||||
#define VMBUS_ISR_ADDR trunc_page((uintptr_t)IDTVEC(vmbus_isr_pti)) | |||||
uint32_t vmbus_current_version; | uint32_t vmbus_current_version; | ||||
static const uint32_t vmbus_version[] = { | static const uint32_t vmbus_version[] = { | ||||
Context not available. | |||||
}; | }; | ||||
DRIVER_MODULE(vmbus, pcib, vmbus_driver, NULL, NULL); | DRIVER_MODULE(vmbus, pcib, vmbus_driver, NULL, NULL); | ||||
#if !defined(__aarch64__) | |||||
DRIVER_MODULE(vmbus, acpi_syscontainer, vmbus_driver, NULL, NULL); | DRIVER_MODULE(vmbus, acpi_syscontainer, vmbus_driver, NULL, NULL); | ||||
#else | |||||
DRIVER_MODULE(vmbus, vmbus_res, vmbus_driver, NULL, NULL); | |||||
#endif | |||||
MODULE_DEPEND(vmbus, acpi, 1, 1, 1); | MODULE_DEPEND(vmbus, acpi, 1, 1, 1); | ||||
MODULE_DEPEND(vmbus, pci, 1, 1, 1); | MODULE_DEPEND(vmbus, pci, 1, 1, 1); | ||||
Context not available. | |||||
* This will cause message queue rescan to possibly | * This will cause message queue rescan to possibly | ||||
* deliver another msg from the hypervisor | * deliver another msg from the hypervisor | ||||
*/ | */ | ||||
wrmsr(MSR_HV_EOM, 0); | WRMSR(MSR_HV_EOM, 0); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static __inline int | static __inline int | ||||
vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu) | vmbus_handle_intr1(struct vmbus_softc *sc, struct trapframe *frame, int cpu) | ||||
{ | { | ||||
Context not available. | |||||
* | * | ||||
* TODO: move this to independent IDT vector. | * TODO: move this to independent IDT vector. | ||||
*/ | */ | ||||
msg = msg_base + VMBUS_SINT_TIMER; | vmbus_handle_timer_intr1(msg_base, frame); | ||||
if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED) { | |||||
msg->msg_type = HYPERV_MSGTYPE_NONE; | |||||
vmbus_et_intr(frame); | |||||
/* | |||||
* Make sure the write to msg_type (i.e. set to | |||||
* HYPERV_MSGTYPE_NONE) happens before we read the | |||||
* msg_flags and EOMing. Otherwise, the EOMing will | |||||
* not deliver any more messages since there is no | |||||
* empty slot | |||||
* | |||||
* NOTE: | |||||
* mb() is used here, since atomic_thread_fence_seq_cst() | |||||
* will become compiler fence on UP kernel. | |||||
*/ | |||||
mb(); | |||||
if (msg->msg_flags & VMBUS_MSGFLAG_PENDING) { | |||||
/* | |||||
* This will cause message queue rescan to possibly | |||||
* deliver another msg from the hypervisor | |||||
*/ | |||||
wrmsr(MSR_HV_EOM, 0); | |||||
} | |||||
} | |||||
/* | /* | ||||
* Check events. Hot path for network and storage I/O data; high rate. | * Check events. Hot path for network and storage I/O data; high rate. | ||||
* | * | ||||
Context not available. | |||||
critical_enter(); | critical_enter(); | ||||
/* | /* | ||||
* Do a little interrupt counting. | * Do a little interrupt counting. This used x86 specific | ||||
* intrcnt_add function | |||||
*/ | */ | ||||
#if !defined(__aarch64__) | |||||
(*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; | (*VMBUS_PCPU_GET(sc, intr_cnt, cpu))++; | ||||
#endif /* not for aarch64 */ | |||||
vmbus_handle_intr1(sc, trap_frame, cpu); | vmbus_handle_intr1(sc, trap_frame, cpu); | ||||
/* | /* | ||||
Context not available. | |||||
if (hyperv_features & CPUID_HV_MSR_VP_INDEX) { | if (hyperv_features & CPUID_HV_MSR_VP_INDEX) { | ||||
/* Save virtual processor id. */ | /* Save virtual processor id. */ | ||||
VMBUS_PCPU_GET(sc, vcpuid, cpu) = rdmsr(MSR_HV_VP_INDEX); | VMBUS_PCPU_GET(sc, vcpuid, cpu) = RDMSR(MSR_HV_VP_INDEX); | ||||
} else { | } else { | ||||
/* Set virtual processor id to 0 for compatibility. */ | /* Set virtual processor id to 0 for compatibility. */ | ||||
VMBUS_PCPU_GET(sc, vcpuid, cpu) = 0; | VMBUS_PCPU_GET(sc, vcpuid, cpu) = 0; | ||||
Context not available. | |||||
/* | /* | ||||
* Setup the SynIC message. | * Setup the SynIC message. | ||||
*/ | */ | ||||
orig = rdmsr(MSR_HV_SIMP); | orig = RDMSR(MSR_HV_SIMP); | ||||
val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) | | val = MSR_HV_SIMP_ENABLE | (orig & MSR_HV_SIMP_RSVD_MASK) | | ||||
((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) << | ((VMBUS_PCPU_GET(sc, message_dma.hv_paddr, cpu) >> PAGE_SHIFT) | ||||
MSR_HV_SIMP_PGSHIFT); | << MSR_HV_SIMP_PGSHIFT); | ||||
wrmsr(MSR_HV_SIMP, val); | WRMSR(MSR_HV_SIMP, val); | ||||
/* | /* | ||||
* Setup the SynIC event flags. | * Setup the SynIC event flags. | ||||
*/ | */ | ||||
orig = rdmsr(MSR_HV_SIEFP); | orig = RDMSR(MSR_HV_SIEFP); | ||||
val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) | | val = MSR_HV_SIEFP_ENABLE | (orig & MSR_HV_SIEFP_RSVD_MASK) | | ||||
((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu) | ((VMBUS_PCPU_GET(sc, event_flags_dma.hv_paddr, cpu) >> PAGE_SHIFT) | ||||
>> PAGE_SHIFT) << MSR_HV_SIEFP_PGSHIFT); | << MSR_HV_SIEFP_PGSHIFT); | ||||
wrmsr(MSR_HV_SIEFP, val); | WRMSR(MSR_HV_SIEFP, val); | ||||
/* | /* | ||||
* Configure and unmask SINT for message and event flags. | * Configure and unmask SINT for message and event flags. | ||||
*/ | */ | ||||
sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; | sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; | ||||
orig = rdmsr(sint); | orig = RDMSR(sint); | ||||
val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | | val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | | ||||
(orig & MSR_HV_SINT_RSVD_MASK); | (orig & MSR_HV_SINT_RSVD_MASK); | ||||
wrmsr(sint, val); | WRMSR(sint, val); | ||||
/* | /* | ||||
* Configure and unmask SINT for timer. | * Configure and unmask SINT for timer. | ||||
*/ | */ | ||||
sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; | vmbus_synic_setup1(sc); | ||||
orig = rdmsr(sint); | |||||
val = sc->vmbus_idtvec | MSR_HV_SINT_AUTOEOI | | |||||
(orig & MSR_HV_SINT_RSVD_MASK); | |||||
wrmsr(sint, val); | |||||
/* | /* | ||||
* All done; enable SynIC. | * All done; enable SynIC. | ||||
*/ | */ | ||||
orig = rdmsr(MSR_HV_SCONTROL); | orig = RDMSR(MSR_HV_SCONTROL); | ||||
val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK); | val = MSR_HV_SCTRL_ENABLE | (orig & MSR_HV_SCTRL_RSVD_MASK); | ||||
wrmsr(MSR_HV_SCONTROL, val); | WRMSR(MSR_HV_SCONTROL, val); | ||||
} | } | ||||
static void | static void | ||||
Context not available. | |||||
/* | /* | ||||
* Disable SynIC. | * Disable SynIC. | ||||
*/ | */ | ||||
orig = rdmsr(MSR_HV_SCONTROL); | orig = RDMSR(MSR_HV_SCONTROL); | ||||
wrmsr(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK)); | WRMSR(MSR_HV_SCONTROL, (orig & MSR_HV_SCTRL_RSVD_MASK)); | ||||
/* | /* | ||||
* Mask message and event flags SINT. | * Mask message and event flags SINT. | ||||
*/ | */ | ||||
sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; | sint = MSR_HV_SINT0 + VMBUS_SINT_MESSAGE; | ||||
orig = rdmsr(sint); | orig = RDMSR(sint); | ||||
wrmsr(sint, orig | MSR_HV_SINT_MASKED); | WRMSR(sint, orig | MSR_HV_SINT_MASKED); | ||||
/* | /* | ||||
* Mask timer SINT. | * Mask timer SINT. | ||||
*/ | */ | ||||
sint = MSR_HV_SINT0 + VMBUS_SINT_TIMER; | vmbus_synic_teardown1(); | ||||
orig = rdmsr(sint); | |||||
wrmsr(sint, orig | MSR_HV_SINT_MASKED); | |||||
/* | /* | ||||
* Teardown SynIC message. | * Teardown SynIC message. | ||||
*/ | */ | ||||
orig = rdmsr(MSR_HV_SIMP); | orig = RDMSR(MSR_HV_SIMP); | ||||
wrmsr(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK)); | WRMSR(MSR_HV_SIMP, (orig & MSR_HV_SIMP_RSVD_MASK)); | ||||
/* | /* | ||||
* Teardown SynIC event flags. | * Teardown SynIC event flags. | ||||
*/ | */ | ||||
orig = rdmsr(MSR_HV_SIEFP); | orig = RDMSR(MSR_HV_SIEFP); | ||||
wrmsr(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK)); | WRMSR(MSR_HV_SIEFP, (orig & MSR_HV_SIEFP_RSVD_MASK)); | ||||
} | } | ||||
static int | static int | ||||
Context not available. | |||||
/* Allocate an interrupt counter for Hyper-V interrupt */ | /* Allocate an interrupt counter for Hyper-V interrupt */ | ||||
snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); | snprintf(buf, sizeof(buf), "cpu%d:hyperv", cpu); | ||||
#if !defined(__aarch64__) | |||||
intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); | intrcnt_add(buf, VMBUS_PCPU_PTR(sc, intr_cnt, cpu)); | ||||
#endif /* not for aarch64 */ | |||||
/* | /* | ||||
* Setup taskqueue to handle events. Task will be per- | * Setup taskqueue to handle events. Task will be per- | ||||
* channel. | * channel. | ||||
Context not available. | |||||
TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, | TASK_INIT(VMBUS_PCPU_PTR(sc, message_task, cpu), 0, | ||||
vmbus_msg_task, sc); | vmbus_msg_task, sc); | ||||
} | } | ||||
return (vmbus_setup_intr1(sc)); | |||||
#if defined(__amd64__) && defined(KLD_MODULE) | |||||
pmap_pti_add_kva(VMBUS_ISR_ADDR, VMBUS_ISR_ADDR + PAGE_SIZE, true); | |||||
#endif | |||||
/* | |||||
* All Hyper-V ISR required resources are setup, now let's find a | |||||
* free IDT vector for Hyper-V ISR and set it up. | |||||
*/ | |||||
sc->vmbus_idtvec = lapic_ipi_alloc(pti ? IDTVEC(vmbus_isr_pti) : | |||||
IDTVEC(vmbus_isr)); | |||||
if (sc->vmbus_idtvec < 0) { | |||||
#if defined(__amd64__) && defined(KLD_MODULE) | |||||
pmap_pti_remove_kva(VMBUS_ISR_ADDR, VMBUS_ISR_ADDR + PAGE_SIZE); | |||||
#endif | |||||
device_printf(sc->vmbus_dev, "cannot find free IDT vector\n"); | |||||
return ENXIO; | |||||
} | |||||
if (bootverbose) { | |||||
device_printf(sc->vmbus_dev, "vmbus IDT vector %d\n", | |||||
sc->vmbus_idtvec); | |||||
} | |||||
return 0; | |||||
} | } | ||||
static void | static void | ||||
vmbus_intr_teardown(struct vmbus_softc *sc) | vmbus_intr_teardown(struct vmbus_softc *sc) | ||||
{ | { | ||||
int cpu; | vmbus_intr_teardown1(sc); | ||||
if (sc->vmbus_idtvec >= 0) { | |||||
lapic_ipi_free(sc->vmbus_idtvec); | |||||
sc->vmbus_idtvec = -1; | |||||
} | |||||
#if defined(__amd64__) && defined(KLD_MODULE) | |||||
pmap_pti_remove_kva(VMBUS_ISR_ADDR, VMBUS_ISR_ADDR + PAGE_SIZE); | |||||
#endif | |||||
CPU_FOREACH(cpu) { | |||||
if (VMBUS_PCPU_GET(sc, event_tq, cpu) != NULL) { | |||||
taskqueue_free(VMBUS_PCPU_GET(sc, event_tq, cpu)); | |||||
VMBUS_PCPU_GET(sc, event_tq, cpu) = NULL; | |||||
} | |||||
if (VMBUS_PCPU_GET(sc, message_tq, cpu) != NULL) { | |||||
taskqueue_drain(VMBUS_PCPU_GET(sc, message_tq, cpu), | |||||
VMBUS_PCPU_PTR(sc, message_task, cpu)); | |||||
taskqueue_free(VMBUS_PCPU_GET(sc, message_tq, cpu)); | |||||
VMBUS_PCPU_GET(sc, message_tq, cpu) = NULL; | |||||
} | |||||
} | |||||
} | } | ||||
static int | static int | ||||
Context not available. | |||||
vmbus_fb_mmio_res(device_t dev) | vmbus_fb_mmio_res(device_t dev) | ||||
{ | { | ||||
struct efi_fb *efifb; | struct efi_fb *efifb; | ||||
#if !defined(__aarch64__) | |||||
struct vbe_fb *vbefb; | struct vbe_fb *vbefb; | ||||
#endif /* aarch64 */ | |||||
rman_res_t fb_start, fb_end, fb_count; | rman_res_t fb_start, fb_end, fb_count; | ||||
int fb_height, fb_width; | int fb_height, fb_width; | ||||
caddr_t kmdp; | caddr_t kmdp; | ||||
Context not available. | |||||
kmdp = preload_search_by_type("elf64 kernel"); | kmdp = preload_search_by_type("elf64 kernel"); | ||||
efifb = (struct efi_fb *)preload_search_info(kmdp, | efifb = (struct efi_fb *)preload_search_info(kmdp, | ||||
MODINFO_METADATA | MODINFOMD_EFI_FB); | MODINFO_METADATA | MODINFOMD_EFI_FB); | ||||
#if !defined(__aarch64__) | |||||
vbefb = (struct vbe_fb *)preload_search_info(kmdp, | vbefb = (struct vbe_fb *)preload_search_info(kmdp, | ||||
MODINFO_METADATA | MODINFOMD_VBE_FB); | MODINFO_METADATA | MODINFOMD_VBE_FB); | ||||
#endif /* aarch64 */ | |||||
if (efifb != NULL) { | if (efifb != NULL) { | ||||
fb_start = efifb->fb_addr; | fb_start = efifb->fb_addr; | ||||
fb_end = efifb->fb_addr + efifb->fb_size; | fb_end = efifb->fb_addr + efifb->fb_size; | ||||
fb_count = efifb->fb_size; | fb_count = efifb->fb_size; | ||||
fb_height = efifb->fb_height; | fb_height = efifb->fb_height; | ||||
fb_width = efifb->fb_width; | fb_width = efifb->fb_width; | ||||
} else if (vbefb != NULL) { | } | ||||
#if !defined(__aarch64__) | |||||
else if (vbefb != NULL) { | |||||
fb_start = vbefb->fb_addr; | fb_start = vbefb->fb_addr; | ||||
fb_end = vbefb->fb_addr + vbefb->fb_size; | fb_end = vbefb->fb_addr + vbefb->fb_size; | ||||
fb_count = vbefb->fb_size; | fb_count = vbefb->fb_size; | ||||
fb_height = vbefb->fb_height; | fb_height = vbefb->fb_height; | ||||
fb_width = vbefb->fb_width; | fb_width = vbefb->fb_width; | ||||
} else { | } | ||||
#endif /* aarch64 */ | |||||
else { | |||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, | device_printf(dev, | ||||
"no preloaded kernel fb information\n"); | "no preloaded kernel fb information\n"); | ||||
/* We are on Gen1 VM, just return. */ | /* We are on Gen1 VM, just return. */ | ||||
return; | return; | ||||
} | } | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, | device_printf(dev, | ||||
"fb: fb_addr: %#jx, size: %#jx, " | "fb: fb_addr: %#jx, size: %#jx, " | ||||
Context not available. | |||||
{ | { | ||||
} | } | ||||
#ifdef EARLY_AP_STARTUP | #if defined(EARLY_AP_STARTUP) || defined(__aarch64__) | ||||
static void | static void | ||||
vmbus_intrhook(void *xsc) | vmbus_intrhook(void *xsc) | ||||
Context not available. | |||||
config_intrhook_disestablish(&sc->vmbus_intrhook); | config_intrhook_disestablish(&sc->vmbus_intrhook); | ||||
} | } | ||||
#endif /* EARLY_AP_STARTUP */ | #endif /* EARLY_AP_STARTUP aarch64 */ | ||||
static int | static int | ||||
vmbus_attach(device_t dev) | vmbus_attach(device_t dev) | ||||
Context not available. | |||||
*/ | */ | ||||
vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; | vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy; | ||||
#ifdef EARLY_AP_STARTUP | #if defined(EARLY_AP_STARTUP) || defined(__aarch64__) | ||||
/* | /* | ||||
* Defer the real attach until the pause(9) works as expected. | * Defer the real attach until the pause(9) works as expected. | ||||
*/ | */ | ||||
Context not available. | |||||
*/ | */ | ||||
if (!cold) | if (!cold) | ||||
vmbus_doattach(vmbus_sc); | vmbus_doattach(vmbus_sc); | ||||
#endif /* EARLY_AP_STARTUP */ | #endif /* EARLY_AP_STARTUP and aarch64 */ | ||||
return (0); | return (0); | ||||
} | } | ||||
Context not available. | |||||
vmbus_free_mmio_res(dev); | vmbus_free_mmio_res(dev); | ||||
#endif | #endif | ||||
#if defined(__aarch64__) | |||||
bus_release_resource(device_get_parent(dev), SYS_RES_IRQ, sc->vector, | |||||
sc->ires); | |||||
#endif | |||||
return (0); | return (0); | ||||
} | } | ||||
#ifndef EARLY_AP_STARTUP | #if !defined(EARLY_AP_STARTUP) && !defined(__aarch64__) | ||||
static void | static void | ||||
vmbus_sysinit(void *arg __unused) | vmbus_sysinit(void *arg __unused) | ||||
Context not available. | |||||
* global cold set to zero, we just call the driver | * global cold set to zero, we just call the driver | ||||
* initialization directly. | * initialization directly. | ||||
*/ | */ | ||||
if (!cold) | if (!cold) | ||||
vmbus_doattach(sc); | vmbus_doattach(sc); | ||||
} | } | ||||
/* | /* | ||||
Context not available. | |||||
* initialized. | * initialized. | ||||
*/ | */ | ||||
SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); | SYSINIT(vmbus_initialize, SI_SUB_SMP, SI_ORDER_ANY, vmbus_sysinit, NULL); | ||||
#endif /* !EARLY_AP_STARTUP */ | #endif /* !EARLY_AP_STARTUP */ | ||||
Context not available. |