/** * 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(); }
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; }
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); }
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); }
/* 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; }
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); }
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; }
/* 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; }
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); }
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); }
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; }
static void lapic_wait_ready(void) { while ( lapic_read(APIC_ICR) & APIC_ICR_BUSY ) cpu_relax(); }
static uint32_t lapic_errstatus(void){ lapic_write(LAPIC_ESR, 0); return lapic_read(LAPIC_ESR); }
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; }
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; }