Beispiel #1
0
void
lapic_setup(int boot)
{
	struct lapic *la;
	u_int32_t maxlvt;
	register_t saveintr;
	char buf[MAXCOMLEN + 1];

	la = &lapics[lapic_id()];
	KASSERT(la->la_present, ("missing APIC structure"));
	saveintr = intr_disable();
	maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;

	/* Initialize the TPR to allow all interrupts. */
	lapic_set_tpr(0);

	/* Setup spurious vector and enable the local APIC. */
	lapic_enable();

	/* Program LINT[01] LVT entries. */
	lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
	lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);

	/* Program the PMC LVT entry if present. */
	if (maxlvt >= LVT_PMC)
		lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);

	/* Program timer LVT and setup handler. */
	la->lvt_timer_cache = lapic->lvt_timer =
	    lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
	if (boot) {
		snprintf(buf, sizeof(buf), "cpu%d:timer", PCPU_GET(cpuid));
		intrcnt_add(buf, &la->la_timer_count);
	}

	/* Setup the timer if configured. */
	if (la->la_timer_mode != 0) {
		KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor",
		    lapic_id()));
		lapic_timer_set_divisor(lapic_timer_divisor);
		if (la->la_timer_mode == 1)
			lapic_timer_periodic(la, la->la_timer_period, 1);
		else
			lapic_timer_oneshot(la, la->la_timer_period, 1);
	}

	/* Program error LVT and clear any existing errors. */
	lapic->lvt_error = lvt_mode(la, LVT_ERROR, lapic->lvt_error);
	lapic->esr = 0;

	/* XXX: Thermal LVT */

	/* Program the CMCI LVT entry if present. */
	if (maxlvt >= LVT_CMCI)
		lapic->lvt_cmci = lvt_mode(la, LVT_CMCI, lapic->lvt_cmci);
	    
	intr_restore(saveintr);
}
Beispiel #2
0
/**
 * @brief Main vmbus driver initialization routine.
 *
 * Here, we
 * - initialize the vmbus driver context
 * - setup various driver entry points
 * - invoke the vmbus hv main init routine
 * - get the irq resource
 * - invoke the vmbus to add the vmbus root device
 * - setup the vmbus root device
 * - retrieve the channel offers
 */
static int
vmbus_bus_init(void)
{
	int i, j, n, ret;
	char buf[MAXCOMLEN + 1];

	if (vmbus_inited)
		return (0);

	vmbus_inited = 1;

	ret = hv_vmbus_init();

	if (ret) {
		if(bootverbose)
			printf("Error VMBUS: Hypervisor Initialization Failed!\n");
		return (ret);
	}

	/*
	 * Find a free IDT slot for vmbus callback.
	 */
	hv_vmbus_g_context.hv_cb_vector = vmbus_vector_alloc();

	if (hv_vmbus_g_context.hv_cb_vector == 0) {
		if(bootverbose)
			printf("Error VMBUS: Cannot find free IDT slot for "
			    "vmbus callback!\n");
		goto cleanup;
	}

	if(bootverbose)
		printf("VMBUS: vmbus callback vector %d\n",
		    hv_vmbus_g_context.hv_cb_vector);

	/*
	 * Notify the hypervisor of our vector.
	 */
	setup_args.vector = hv_vmbus_g_context.hv_cb_vector;

	CPU_FOREACH(j) {
		hv_vmbus_swintr_event_cpu[j] = 0;
		hv_vmbus_g_context.hv_event_intr_event[j] = NULL;
		hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
		hv_vmbus_g_context.event_swintr[j] = NULL;
		hv_vmbus_g_context.msg_swintr[j] = NULL;

		snprintf(buf, sizeof(buf), "cpu%d:hyperv", j);
		intrcnt_add(buf, &hv_vmbus_intr_cpu[j]);

		for (i = 0; i < 2; i++)
			setup_args.page_buffers[2 * j + i] = NULL;
	}

	/*
	 * Per cpu setup.
	 */
	CPU_FOREACH(j) {
		/*
		 * Setup software interrupt thread and handler for msg handling.
		 */
		ret = swi_add(&hv_vmbus_g_context.hv_msg_intr_event[j],
		    "hv_msg", vmbus_msg_swintr, (void *)(long)j, SWI_CLOCK, 0,
		    &hv_vmbus_g_context.msg_swintr[j]);
		if (ret) {
			if(bootverbose)
				printf("VMBUS: failed to setup msg swi for "
				    "cpu %d\n", j);
			goto cleanup1;
		}

		/*
		 * Bind the swi thread to the cpu.
		 */
		ret = intr_event_bind(hv_vmbus_g_context.hv_msg_intr_event[j],
		    j);
	 	if (ret) {
			if(bootverbose)
				printf("VMBUS: failed to bind msg swi thread "
				    "to cpu %d\n", j);
			goto cleanup1;
		}

		/*
		 * Setup software interrupt thread and handler for
		 * event handling.
		 */
		ret = swi_add(&hv_vmbus_g_context.hv_event_intr_event[j],
		    "hv_event", hv_vmbus_on_events, (void *)(long)j,
		    SWI_CLOCK, 0, &hv_vmbus_g_context.event_swintr[j]);
		if (ret) {
			if(bootverbose)
				printf("VMBUS: failed to setup event swi for "
				    "cpu %d\n", j);
			goto cleanup1;
		}

		/*
		 * Prepare the per cpu msg and event pages to be called on each cpu.
		 */
		for(i = 0; i < 2; i++) {
			setup_args.page_buffers[2 * j + i] =
				malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO);
			if (setup_args.page_buffers[2 * j + i] == NULL) {
				KASSERT(setup_args.page_buffers[2 * j + i] != NULL,
					("Error VMBUS: malloc failed!"));
				goto cleanup1;
			}
		}
	}

	if (bootverbose)
		printf("VMBUS: Calling smp_rendezvous, smp_started = %d\n",
		    smp_started);

	smp_rendezvous(NULL, hv_vmbus_synic_init, NULL, &setup_args);

	/*
	 * Connect to VMBus in the root partition
	 */
	ret = hv_vmbus_connect();

	if (ret != 0)
		goto cleanup1;

	hv_vmbus_request_channel_offers();
	return (ret);

	cleanup1:
	/*
	 * Free pages alloc'ed
	 */
	for (n = 0; n < 2 * MAXCPU; n++)
		if (setup_args.page_buffers[n] != NULL)
			free(setup_args.page_buffers[n], M_DEVBUF);

	/*
	 * remove swi and vmbus callback vector;
	 */
	CPU_FOREACH(j) {
		if (hv_vmbus_g_context.msg_swintr[j] != NULL)
			swi_remove(hv_vmbus_g_context.msg_swintr[j]);
		if (hv_vmbus_g_context.event_swintr[j] != NULL)
			swi_remove(hv_vmbus_g_context.event_swintr[j]);
		hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;	
		hv_vmbus_g_context.hv_event_intr_event[j] = NULL;	
	}

	vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);

	cleanup:
	hv_vmbus_cleanup();

	return (ret);
}