Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

#include "mp.h"

_MP_ *_mp_;

static void
mpresetothers(void)
{
        /*
         * INIT all excluding self.
         */
        lapicicrw(0, 0x000C0000|ApicINIT);
}

static int identify(void);

PCArch archmp = {
.id=            "_MP_", 
.ident=         identify,
.reset=         mpshutdown,
.intrinit=      mpinit,
.intrenable=    mpintrenable,
.intron=        lapicintron,
.introff=       lapicintroff,
.fastclock=     i8253read,
.timerset=      lapictimerset,
.resetothers=   mpresetothers,
};

static int
identify(void)
{
        char *cp;
        PCMP *pcmp;
        uchar *p, sum;
        ulong length;

        if((cp = getconf("*nomp")) != nil && strtol(cp, 0, 0) != 0)
                return 1;

        /*
         * Search for an MP configuration table. For now,
         * don't accept the default configurations (physaddr == 0).
         * Check for correct signature, calculate the checksum and,
         * if correct, check the version.
         * To do: check extended table checksum.
         */
        if((_mp_ = sigsearch("_MP_")) == 0 || _mp_->physaddr == 0) {
                /*
                 * we can easily get processor info from acpi, but
                 * interrupt routing, etc. would require interpreting aml.
                 */
                print("archmp: no mp table found, assuming uniprocessor\n");
                return 1;
        }

        if (0)
                iprint("mp physaddr %#lux\n", _mp_->physaddr);
        pcmp = KADDR(_mp_->physaddr);
        if(memcmp(pcmp, "PCMP", 4) != 0) {
                print("archmp: mp table has bad magic");
                return 1;
        }

        length = pcmp->length;
        sum = 0;
        for(p = (uchar*)pcmp; length; length--)
                sum += *p++;

        if(sum || (pcmp->version != 1 && pcmp->version != 4))
                return 1;

        if(cpuserver && m->havetsc)
                archmp.fastclock = tscticks;
        return 0;
}

Lock mpsynclock;

void
syncclock(void)
{
        uvlong x;

        if(arch->fastclock != tscticks)
                return;

        if(m->machno == 0){
                wrmsr(0x10, 0);
                m->tscticks = 0;
        } else {
                x = MACHP(0)->tscticks;
                while(x == MACHP(0)->tscticks)
                        ;
                wrmsr(0x10, MACHP(0)->tscticks);
                cycles(&m->tscticks);
        }
}

uvlong
tscticks(uvlong *hz)
{
        if(hz != nil)
                *hz = m->cpuhz;

        cycles(&m->tscticks);   /* Uses the rdtsc instruction */
        return m->tscticks;
}