From 3135f8e83f5a5810cb0a998669b9bb564061422c Mon Sep 17 00:00:00 2001 From: Li-Ta Lo Date: Thu, 3 Jan 2002 03:53:22 +0000 Subject: [PATCH] use P5 TSC for timer function --- src/etherboot/netboot.c | 60 ++++++-------------- src/etherboot/timer.c | 119 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 43 deletions(-) create mode 100644 src/etherboot/timer.c diff --git a/src/etherboot/netboot.c b/src/etherboot/netboot.c index e12418098d..24e8067a4d 100644 --- a/src/etherboot/netboot.c +++ b/src/etherboot/netboot.c @@ -13,35 +13,6 @@ struct nic nic; unsigned char eth_addr[6]; -int acpi_base; - -void init_HR_TIMER(void) -{ - int j; - - outl(0x80000840, 0x0cf8); - acpi_base = inb(0x0cfc) | 0x80; - outb(acpi_base, 0x0cfc); - - outl(0x80000874, 0x0cf8); - acpi_base = inw(0x0cfc); - - printk_info("init_HR_TIMER: acpi_base = %04x\n", acpi_base); - - j = inw(acpi_base + 0x56) | 0x02; // HR_TMR control - outw(j, acpi_base + 0x56); // activate HR_TMR -} - -inline unsigned long currticks(void) -{ - unsigned long int j=0; - - j = inl(acpi_base + 0x4c); - j /= 55555; // HR_TMR runs at 1MHz, etherboot drivers expect 18.2Hz, but this will be close enough. - - return(j); -} - int test_display_tftp_callback(char *data, int block, int length, int eof) { int i; @@ -49,13 +20,13 @@ int test_display_tftp_callback(char *data, int block, int length, int eof) #ifdef DEBUG printk_info("RECD block %u, length = %u:\n",block, length); #endif - for(i=0; ibase_address[0] & PCI_BASE_ADDRESS_IO_MASK; result = sis900_probe(&nic, &iobase, pcidev); @@ -91,13 +62,16 @@ void netboot_init() printk_info("doing rarp:\n"); rarp(); - printk_info("My IP address is: %04x\n",arptable[ARP_CLIENT].ipaddr.s_addr); - printk_info("My server's IP address is: %04x\n",arptable[ARP_SERVER].ipaddr.s_addr); + //printk_info("doing DHCP:\n"); + //bootp(); + + printk_info("My IP address is: %04x\n", arptable[ARP_CLIENT].ipaddr.s_addr); + printk_info("My server's IP address is: %04x\n", arptable[ARP_SERVER].ipaddr.s_addr); #ifdef DEBUG printk_info("Now testing tftp, transferring cmdline\n"); -// tftp("cmdline", test_display_tftp_callback); + //tftp("cmdline", test_display_tftp_callback); tftp_init("cmdline"); while(rc == 512) { rc = tftp_fetchone(buffer); diff --git a/src/etherboot/timer.c b/src/etherboot/timer.c new file mode 100644 index 0000000000..3e5fd6427c --- /dev/null +++ b/src/etherboot/timer.c @@ -0,0 +1,119 @@ +/* A couple of routines to implement a low-overhead timer for drivers */ + + /* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + */ +#include +#include +#include "etherboot.h" +#include "timer.h" + +void load_timer2(unsigned int ticks) +{ + /* Set up the timer gate, turn off the speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); + outb(ticks & 0xFF, TIMER2_PORT); + outb(ticks >> 8, TIMER2_PORT); +} + +#define HZ TICKS_PER_SEC +#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */ +/* LATCH is used in the interval timer and ftape setup. */ +#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ + + +/* ------ Calibrate the TSC ------- + * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). + * Too much 64-bit arithmetic here to do this cleanly in C, and for + * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) + * output busy loop as low as possible. We avoid reading the CTC registers + * directly because of the awkward 8-bit access mechanism of the 82C54 + * device. + */ + +#define CALIBRATE_LATCH (5 * LATCH) + +static unsigned long long calibrate_tsc(void) +{ + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + /* + * Now let's take care of CTC channel 2 + * + * Set the Gate high, program CTC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + */ + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ + outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ + outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ + + { + unsigned long startlow, starthigh; + unsigned long endlow, endhigh; + unsigned long count; + + rdtsc(startlow,starthigh); + count = 0; + do { + count++; + } while ((inb(0x61) & 0x20) == 0); + rdtsc(endlow,endhigh); + + /* Error: ECTCNEVERSET */ + if (count <= 1) + goto bad_ctc; + + /* 64-bit subtract - gcc just messes up with long longs */ + __asm__("subl %2,%0\n\t" + "sbbl %3,%1" + :"=a" (endlow), "=d" (endhigh) + :"g" (startlow), "g" (starthigh), + "0" (endlow), "1" (endhigh)); + + /* Error: ECPUTOOFAST */ + if (endhigh) + goto bad_ctc; + + endlow /= 5; + return endlow; + } + + /* + * The CTC wasn't reliable: we got a hit on the very first read, + * or the CPU was so fast/slow that the quotient wouldn't fit in + * 32 bits.. + */ +bad_ctc: + printk_err("bad_ctc\n"); + return 0; +} + + +unsigned long currticks(void) +{ + static unsigned long clocks_per_tick; + unsigned long clocks_high, clocks_low; + unsigned long currticks; + + if (!clocks_per_tick) { + clocks_per_tick = calibrate_tsc(); + printk_info("clocks_per_tick = %d\n", clocks_per_tick); + } + + /* Read the Time Stamp Counter */ + rdtsc(clocks_low, clocks_high); + + /* currticks = clocks / clocks_per_tick; */ + __asm__("divl %1" + :"=a" (currticks) + :"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high)); + + + return currticks; +}