Beispiel #1
0
/**
 * Normally this function is defined in lapic.h as an always inline function
 * that just keeps the CPU in a hlt() loop. This does not work on all CPUs.
 * I think all hyperthreading CPUs might need this version, but I could only
 * verify this on the Intel Core Duo
 */
void stop_this_cpu(void)
{
	int timeout;
	unsigned long send_status;
	unsigned long id;

	id = lapicid();

	printk(BIOS_DEBUG, "CPU %ld going down...\n", id);

	/* send an LAPIC INIT to myself */
	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id));
	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG |
				LAPIC_INT_ASSERT | LAPIC_DM_INIT);

	/* wait for the ipi send to finish */
#if DEBUG_HALT_SELF
	printk(BIOS_SPEW, "Waiting for send to finish...\n");
#endif
	timeout = 0;
	do {
#if DEBUG_HALT_SELF
		printk(BIOS_SPEW, "+");
#endif
		udelay(100);
		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
	} while (send_status && (timeout++ < 1000));
	if (timeout >= 1000) {
#if DEBUG_HALT_SELF
		printk(BIOS_ERR, "timed out\n");
#endif
	}
	mdelay(10);

#if DEBUG_HALT_SELF
	printk(BIOS_SPEW, "Deasserting INIT.\n");
#endif
	/* Deassert the LAPIC INIT */
	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id));
	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);

#if DEBUG_HALT_SELF
	printk(BIOS_SPEW, "Waiting for send to finish...\n");
#endif
	timeout = 0;
	do {
#if DEBUG_HALT_SELF
		printk(BIOS_SPEW, "+");
#endif
		udelay(100);
		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
	} while (send_status && (timeout++ < 1000));
	if (timeout >= 1000) {
#if DEBUG_HALT_SELF
		printk(BIOS_ERR, "timed out\n");
#endif
	}

	halt();
}
Beispiel #2
0
void timer_monotonic_get(struct mono_time *mt)
{
	uint32_t current_tick;
	uint32_t usecs_elapsed;
	uint32_t timer_fsb;

	if (!mono_counter.initialized) {
		init_timer();
		timer_fsb = get_timer_fsb();
		/* An FSB frequency of 200Mhz provides a 20 second polling
		 * interval between timer_monotonic_get() calls before wrap
		 * around occurs. */
		if (timer_fsb > 200)
			printk(BIOS_WARNING,
			       "apic timer freq (%d) may be too fast.\n",
			       timer_fsb);
		mono_counter.last_value = lapic_read(LAPIC_TMCCT);
		mono_counter.initialized = 1;
	}

	timer_fsb = get_timer_fsb();
	current_tick = lapic_read(LAPIC_TMCCT);
	/* Note that the APIC timer counts down. */
	usecs_elapsed = (mono_counter.last_value - current_tick) / timer_fsb;

	/* Update current time and tick values only if a full tick occurred. */
	if (usecs_elapsed) {
		mono_time_add_usecs(&mono_counter.time, usecs_elapsed);
		mono_counter.last_value = current_tick;
	}

	/* Save result. */
	*mt = mono_counter.time;
}
Beispiel #3
0
void udelay(unsigned usecs)
{
	uint32_t start, value, ticks;
	/* Calculate the number of ticks to run, our FSB runs a 200Mhz */
	ticks = usecs * 200;
	start = lapic_read(LAPIC_TMCCT);
	do {
		value = lapic_read(LAPIC_TMCCT);
	} while((start - value) < ticks);

}
Beispiel #4
0
void udelay(u32 usecs)
{
	u32 start, value, ticks;

	if (!timer_fsb || (lapic_read(LAPIC_LVTT) &
		(LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)) !=
		(LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED))
		init_timer();

	/* Calculate the number of ticks to run, our FSB runs at timer_fsb Mhz */
	ticks = usecs * timer_fsb;
	start = lapic_read(LAPIC_TMCCT);
	do {
		value = lapic_read(LAPIC_TMCCT);
	} while((start - value) < ticks);
}
Beispiel #5
0
/* Returns 1 for timeout. 0 on success */
static int apic_wait_timeout(int total_delay, const char *msg)
{
	int total = 0;

	if (!(lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY))
		return 0;

	debug("Waiting for %s...", msg);
	while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY) {
		udelay(50);
		total += 50;
		if (total >= total_delay) {
			debug("timed out: aborting\n");
			return -ETIMEDOUT;
		}
	}
	debug("done\n");

	return 0;
}
Beispiel #6
0
void udelay(u32 usecs)
{
	u32 start, value, ticks, timer_fsb;

	if (!thread_yield_microseconds(usecs))
		return;

	timer_fsb = get_timer_fsb();
	if (!timer_fsb || (lapic_read(LAPIC_LVTT) &
		(LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)) !=
		(LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)) {
		init_timer();
		timer_fsb = get_timer_fsb();
	}

	/* Calculate the number of ticks to run, our FSB runs at timer_fsb Mhz */
	ticks = usecs * timer_fsb;
	start = lapic_read(LAPIC_TMCCT);
	do {
		value = lapic_read(LAPIC_TMCCT);
	} while((start - value) < ticks);
}
Beispiel #7
0
static int
lapic_icr_wait()
{
    uint32_t i = 100000;
    while ((lapic_read(ICRLO) & DLSTAT_BUSY) != 0) {
	nop_pause();
	i--;
	if (i == 0) {
	    cprintf("apic_icr_wait: wedged?\n");
	    return -E_INVAL;
	}
    }
    return 0;
}
Beispiel #8
0
/* Returns 1 for timeout. 0 on success */
static int apic_wait_timeout(int total_delay, int delay_step)
{
	int total = 0;
	int timeout = 0;

	while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY) {
		udelay(delay_step);
		total += delay_step;
		if (total >= total_delay) {
			timeout = 1;
			break;
		}
	}

	return timeout;
}
Beispiel #9
0
Datei: apic.c Projekt: glguida/mh
void lapic_configure(void)
{
	unsigned i, physid = lapic_getcurrent();
	struct lapic_desc *d = NULL;

	for (i = 0; i < lapics_no; i++) {
		if (lapics[i].physid == physid)
			d = lapics + i;
	}
	if (d == NULL) {
		printf("Warning: Current CPU not in Platform Tables!\n");
		/* Try to continue, ignore the NMI configuration */
	} else {
		lapic_write(L_LVT_LINT(0), d->lint[0]);
		lapic_write(L_LVT_LINT(1), d->lint[1]);
	}
	/* Enable LAPIC */
	lapic_write(L_MISC, lapic_read(L_MISC) | 0x100);
}
Beispiel #10
0
static void *smp_write_config_table(void *v)
{
    struct mp_config_table *mc;
    int bus_isa;
    int boot_apic_id;
    unsigned apic_version;
    unsigned cpu_features;
    unsigned cpu_feature_flags;
    struct cpuid_result result;
    unsigned long cpu_flag;

    mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);

    mptable_init(mc, LAPIC_ADDR);
    memcpy(mc->mpc_oem, "AMD     ", 8);

    /*Inagua used dure core cpu with one die */
    boot_apic_id = lapicid();
    apic_version = lapic_read(LAPIC_LVR) & 0xff;
    result = cpuid(1);
    cpu_features = result.eax;
    cpu_feature_flags = result.edx;
    cpu_flag = MPC_CPU_ENABLED | MPC_CPU_BOOTPROCESSOR;
    smp_write_processor(mc,
                        0, apic_version,
                        cpu_flag, cpu_features, cpu_feature_flags
                       );

    cpu_flag = MPC_CPU_ENABLED;
    smp_write_processor(mc,
                        1, apic_version,
                        cpu_flag, cpu_features, cpu_feature_flags
                       );

    get_bus_conf();

    //mptable_write_buses(mc, NULL, &bus_isa);
    my_smp_write_bus(mc, 0, "PCI   ");
    my_smp_write_bus(mc, 1, "PCI   ");
    bus_isa = 0x02;
    my_smp_write_bus(mc, bus_isa, "ISA   ");

    /* I/O APICs:   APIC ID Version State   Address */

    device_t dev;
    u32 dword;
    u8 byte;

    dword = 0;
    dword = pm_ioread(0x34) & 0xF0;
    dword |= (pm_ioread(0x35) & 0xFF) << 8;
    dword |= (pm_ioread(0x36) & 0xFF) << 16;
    dword |= (pm_ioread(0x37) & 0xFF) << 24;
    /* Set IO APIC ID onto IO_APIC_ID */
    write32 (dword, 0x00);
    write32 (dword + 0x10, IO_APIC_ID << 24);
    apicid_sb900 = IO_APIC_ID;
    smp_write_ioapic(mc, apicid_sb900, 0x21, dword);

    /* PIC IRQ routine */
    for (byte = 0x0; byte < sizeof(picr_data); byte ++) {
        outb(byte, 0xC00);
        outb(picr_data[byte], 0xC01);
    }

    /* APIC IRQ routine */
    for (byte = 0x0; byte < sizeof(intr_data); byte ++) {
        outb(byte | 0x80, 0xC00);
        outb(intr_data[byte], 0xC01);
    }

    /* I/O Ints:    Type    Polarity    Trigger     Bus ID   IRQ    APIC ID PIN# */
#define IO_LOCAL_INT(type, intr, apicid, pin) \
  smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin));

    //mptable_add_isa_interrupts(mc, bus_isa, apicid_sb900, 0);
    /*I/O Ints:          Type    Trigger             Polarity               Bus ID   IRQ  APIC ID       PIN# */
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x0, apicid_sb900, 0x0);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x1, apicid_sb900, 0x1);
    smp_write_intsrc(mc, mp_ExtINT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x2, apicid_sb900, 0x2);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x3, apicid_sb900, 0x3);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x4, apicid_sb900, 0x4);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,  0, 0x49, apicid_sb900, 0x11);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x6, apicid_sb900, 0x6);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x7, apicid_sb900, 0x7);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x8, apicid_sb900, 0x8);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0x9, apicid_sb900, 0x9);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,  bus_isa, 0xa, apicid_sb900, 0xa);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,  bus_isa, 0x1c, apicid_sb900, 0x13);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xc, apicid_sb900, 0xc);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xd, apicid_sb900, 0xd);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xe, apicid_sb900, 0xe);
    smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH,  bus_isa, 0xf, apicid_sb900, 0xf);

    /* PCI interrupts are level triggered, and are
     * associated with a specific bus/device/function tuple.
     */
#define PCI_INT(bus, dev, int_sign, pin) \
        smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(int_sign)), apicid_sb900, (pin))

    /* Internal VGA */
    PCI_INT(0x0, 0x01, 0x0, intr_data[0x02]);
    PCI_INT(0x0, 0x01, 0x1, intr_data[0x03]);

    /* SMBUS */
    PCI_INT(0x0, 0x14, 0x0, 0x10);

    /* HD Audio */
    PCI_INT(0x0, 0x14, 0x0, intr_data[0x13]);

    /* USB */
    PCI_INT(0x0, 0x12, 0x0, intr_data[0x30]);
    PCI_INT(0x0, 0x12, 0x1, intr_data[0x31]);
    PCI_INT(0x0, 0x13, 0x0, intr_data[0x32]);
    PCI_INT(0x0, 0x13, 0x1, intr_data[0x33]);
    PCI_INT(0x0, 0x16, 0x0, intr_data[0x34]);
    PCI_INT(0x0, 0x16, 0x1, intr_data[0x35]);
    PCI_INT(0x0, 0x14, 0x2, intr_data[0x36]);

    /* sata */
    PCI_INT(0x0, 0x11, 0x0, intr_data[0x40]);
    PCI_INT(0x0, 0x11, 0x0, intr_data[0x41]);


    /* on board NIC & Slot PCIE.  */

    /* PCI slots */
    /* PCI_SLOT 0. */
    PCI_INT(bus_sb900[1], 0x5, 0x0, 0x14);
    PCI_INT(bus_sb900[1], 0x5, 0x1, 0x15);
    PCI_INT(bus_sb900[1], 0x5, 0x2, 0x16);
    PCI_INT(bus_sb900[1], 0x5, 0x3, 0x17);

    /* PCI_SLOT 1. */
    PCI_INT(bus_sb900[1], 0x6, 0x0, 0x15);
    PCI_INT(bus_sb900[1], 0x6, 0x1, 0x16);
    PCI_INT(bus_sb900[1], 0x6, 0x2, 0x17);
    PCI_INT(bus_sb900[1], 0x6, 0x3, 0x14);

    /* PCI_SLOT 2. */
    PCI_INT(bus_sb900[1], 0x7, 0x0, 0x16);
    PCI_INT(bus_sb900[1], 0x7, 0x1, 0x17);
    PCI_INT(bus_sb900[1], 0x7, 0x2, 0x14);
    PCI_INT(bus_sb900[1], 0x7, 0x3, 0x15);

    PCI_INT(bus_sb900[2], 0x0, 0x0, 0x12);
    PCI_INT(bus_sb900[2], 0x0, 0x1, 0x13);
    PCI_INT(bus_sb900[2], 0x0, 0x2, 0x14);

    /* PCIe Lan*/
    PCI_INT(0x0, 0x06, 0x0, 0x13);

    /* FCH PCIe PortA */
    PCI_INT(0x0, 0x15, 0x0, 0x10);
    /* FCH PCIe PortB */
    PCI_INT(0x0, 0x15, 0x1, 0x11);
    /* FCH PCIe PortC */
    PCI_INT(0x0, 0x15, 0x2, 0x12);
    /* FCH PCIe PortD */
    PCI_INT(0x0, 0x15, 0x3, 0x13);

    /*Local Ints:   Type    Polarity    Trigger     Bus ID   IRQ    APIC ID PIN# */
    IO_LOCAL_INT(mp_ExtINT, 0, MP_APIC_ALL, 0x0);
    IO_LOCAL_INT(mp_NMI, 0, MP_APIC_ALL, 0x1);
    /* There is no extension information... */

    /* Compute the checksums */
    mc->mpe_checksum =
        smp_compute_checksum(smp_next_mpc_entry(mc), mc->mpe_length);
    mc->mpc_checksum = smp_compute_checksum(mc, mc->mpc_length);
    printk(BIOS_DEBUG, "Wrote the mp table end at: %p - %p\n",
           mc, smp_next_mpe_entry(mc));
    return smp_next_mpe_entry(mc);
}
Beispiel #11
0
static int start_aps(int ap_count, atomic_t *num_aps)
{
	int sipi_vector;
	/* Max location is 4KiB below 1MiB */
	const int max_vector_loc = ((1 << 20) - (1 << 12)) >> 12;

	if (ap_count == 0)
		return 0;

	/* The vector is sent as a 4k aligned address in one byte */
	sipi_vector = AP_DEFAULT_BASE >> 12;

	if (sipi_vector > max_vector_loc) {
		printf("SIPI vector too large! 0x%08x\n",
		       sipi_vector);
		return -1;
	}

	debug("Attempting to start %d APs\n", ap_count);

	if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) {
		debug("Waiting for ICR not to be busy...");
		if (apic_wait_timeout(1000, 50)) {
			debug("timed out. Aborting.\n");
			return -1;
		} else {
			debug("done.\n");
		}
	}

	/* Send INIT IPI to all but self */
	lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
	lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
		    LAPIC_DM_INIT);
	debug("Waiting for 10ms after sending INIT.\n");
	mdelay(10);

	/* Send 1st SIPI */
	if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) {
		debug("Waiting for ICR not to be busy...");
		if (apic_wait_timeout(1000, 50)) {
			debug("timed out. Aborting.\n");
			return -1;
		} else {
			debug("done.\n");
		}
	}

	lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
	lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
		    LAPIC_DM_STARTUP | sipi_vector);
	debug("Waiting for 1st SIPI to complete...");
	if (apic_wait_timeout(10000, 50)) {
		debug("timed out.\n");
		return -1;
	} else {
		debug("done.\n");
	}

	/* Wait for CPUs to check in up to 200 us */
	wait_for_aps(num_aps, ap_count, 200, 15);

	/* Send 2nd SIPI */
	if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) {
		debug("Waiting for ICR not to be busy...");
		if (apic_wait_timeout(1000, 50)) {
			debug("timed out. Aborting.\n");
			return -1;
		} else {
			debug("done.\n");
		}
	}

	lapic_write(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0));
	lapic_write(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT |
		    LAPIC_DM_STARTUP | sipi_vector);
	debug("Waiting for 2nd SIPI to complete...");
	if (apic_wait_timeout(10000, 50)) {
		debug("timed out.\n");
		return -1;
	} else {
		debug("done.\n");
	}

	/* Wait for CPUs to check in */
	if (wait_for_aps(num_aps, ap_count, 10000, 50)) {
		debug("Not all APs checked in: %d/%d.\n",
		      atomic_read(num_aps), ap_count);
		return -1;
	}

	return 0;
}
Beispiel #12
0
Datei: smp.c Projekt: 0day-ci/xen
static void lapic_wait_ready(void)
{
    while ( lapic_read(APIC_ICR) & APIC_ICR_BUSY )
        cpu_relax();
}
Beispiel #13
0
static  uint32_t
lapic_errstatus(void){

	lapic_write(LAPIC_ESR, 0);
	return lapic_read(LAPIC_ESR);
}
Beispiel #14
0
static int lapic_start_cpu(unsigned long apicid)
{
	int timeout;
	unsigned long send_status, accept_status;
	int j, maxlvt;

	/*
	 * Starting actual IPI sequence...
	 */

	printk(BIOS_SPEW, "Asserting INIT.\n");

	/*
	 * Turn INIT on target chip
	 */
	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));

	/*
	 * Send IPI
	 */

	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT
				| LAPIC_DM_INIT);

	printk(BIOS_SPEW, "Waiting for send to finish...\n");
	timeout = 0;
	do {
		printk(BIOS_SPEW, "+");
		udelay(100);
		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
	} while (send_status && (timeout++ < 1000));
	if (timeout >= 1000) {
		printk(BIOS_ERR, "CPU %ld: First APIC write timed out. "
			"Disabling\n", apicid);
		// too bad.
		printk(BIOS_ERR, "ESR is 0x%lx\n", lapic_read(LAPIC_ESR));
		if (lapic_read(LAPIC_ESR)) {
			printk(BIOS_ERR, "Try to reset ESR\n");
			lapic_write_around(LAPIC_ESR, 0);
			printk(BIOS_ERR, "ESR is 0x%lx\n",
				lapic_read(LAPIC_ESR));
		}
		return 0;
	}
#if !IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX) \
	&& !IS_ENABLED(CONFIG_CPU_INTEL_MODEL_206AX) \
	&& !IS_ENABLED(CONFIG_CPU_INTEL_MODEL_2065X)
	mdelay(10);
#endif

	printk(BIOS_SPEW, "Deasserting INIT.\n");

	/* Target chip */
	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));

	/* Send IPI */
	lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);

	printk(BIOS_SPEW, "Waiting for send to finish...\n");
	timeout = 0;
	do {
		printk(BIOS_SPEW, "+");
		udelay(100);
		send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
	} while (send_status && (timeout++ < 1000));
	if (timeout >= 1000) {
		printk(BIOS_ERR, "CPU %ld: Second APIC write timed out. "
			"Disabling\n", apicid);
		// too bad.
		return 0;
	}

	/*
	 * Run STARTUP IPI loop.
	 */
	printk(BIOS_SPEW, "#startup loops: %d.\n", CONFIG_NUM_IPI_STARTS);

	maxlvt = 4;

	for (j = 1; j <= CONFIG_NUM_IPI_STARTS; j++) {
		printk(BIOS_SPEW, "Sending STARTUP #%d to %lu.\n", j, apicid);
		lapic_read_around(LAPIC_SPIV);
		lapic_write(LAPIC_ESR, 0);
		lapic_read(LAPIC_ESR);
		printk(BIOS_SPEW, "After apic_write.\n");

		/*
		 * STARTUP IPI
		 */

		/* Target chip */
		lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));

		/* Boot on the stack */
		/* Kick the second */
		lapic_write_around(LAPIC_ICR, LAPIC_DM_STARTUP
					| (AP_SIPI_VECTOR >> 12));

		/*
		 * Give the other CPU some time to accept the IPI.
		 */
		udelay(300);

		printk(BIOS_SPEW, "Startup point 1.\n");

		printk(BIOS_SPEW, "Waiting for send to finish...\n");
		timeout = 0;
		do {
			printk(BIOS_SPEW, "+");
			udelay(100);
			send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
		} while (send_status && (timeout++ < 1000));

		/*
		 * Give the other CPU some time to accept the IPI.
		 */
		udelay(200);
		/*
		 * Due to the Pentium erratum 3AP.
		 */
		if (maxlvt > 3) {
			lapic_read_around(LAPIC_SPIV);
			lapic_write(LAPIC_ESR, 0);
		}
		accept_status = (lapic_read(LAPIC_ESR) & 0xEF);
		if (send_status || accept_status)
			break;
	}
	printk(BIOS_SPEW, "After Startup.\n");
	if (send_status)
		printk(BIOS_WARNING, "APIC never delivered???\n");
	if (accept_status)
		printk(BIOS_WARNING, "APIC delivery error (%lx).\n",
			accept_status);
	if (send_status || accept_status)
		return 0;
	return 1;
}
Beispiel #15
0
int lapic_clock_setup(struct time_dev_conf *conf) {
	static int initialized = 0;
	uint32_t ticks, cpubusfreq, counter;
	uint8_t tmp;

	if (initialized) {
		return ENOERR;
	}
	initialized = 1;

	/*
	 * Map APIC timer to an interrupt, and by that enable it in
	 * one-shot mode.
	 */
	lapic_write(LAPIC_LVT_TR, 32);

	/* Set up divide value to 16 */
	lapic_write(LAPIC_TIMER_DCR, 0x03);

	/*
	 * Initialize PIT Ch 2 in one-shot mode.
	 * Waiting 1/100 sec.
	 */
	outb((inb(0x61) & 0xFD) | 1, 0x61);
	outb(0xB2, 0x43);

	/* 1193180/100 Hz = 11931 = 2e9bh */
	outb(0x9B, 0x42);	/* LSB */
	inb(0x60);	/* short delay */
	outb(0x2E, 0x42);	/* MSB */

	/* Reset PIT one-shot counter (start counting) */
	tmp = inb(0x61) & 0xFE;
	outb((uint8_t) tmp, 0x61);     /* Gate low */
	outb((uint8_t) tmp | 1, 0x61); /* Gate high */

	/* Reset APIC timer (set counter to -1) */
	lapic_write(LAPIC_TIMER_ICR, 0xFFFFFFFF);

	/* Now wait until PIT counter reaches zero */
	while(!(inb(0x61) & 0x20));

	/* Stop APIC timer */
	lapic_write(LAPIC_LVT_TR, 0x10000);

	/* Now do the math... */
	ticks = (0xFFFFFFFF - lapic_read(LAPIC_TIMER_CCR)) + 1;
	cpubusfreq = ticks * 16 * 100;
	counter = cpubusfreq / LAPIC_HZ / 16;

	/* Set APIC timer counter initializer */
	lapic_write(LAPIC_TIMER_ICR, counter < 16 ? 16 : counter);

	/* Finally re-enable timer in periodic mode. */
	lapic_write(LAPIC_LVT_TR, 32 | 0x20000);

#if 0
	/*
	 * Setting divide value register again not needed by the manuals
	 * although I have found buggy hardware that required it
	 */
	lapic_write(LAPIC_TIMER_DCR, 0x03);
#endif

	return ENOERR;
}