AMD K6 WriteBack Optimisations

This source code uses GCC inline assembler (AT&T syntax).

I wrote and tested this on my own K6 (k6-200) and it works ok, but I was unable to find anyone with a K6-2 (CXT core) or K6-3 since there is two different methods for enabling writeback mode. It _should_ work fine on k6-2 CXT and K6-3 processors.

With some tweaking, can be put into anyone's OS.

You call AMD_K6_writeback with the CPUID results family, model and stepping, only when you are sure you have an AMD cpu.

void AMD_K6_writeback(int family, int model, int stepping)
{
    /* mem_end == top of memory in bytes */
    int mem=(mem_end>>20)/4; /* turn into 4mb aligned pages */
    int c;
    union REGS regs;

    if(family==5)
    {
        c=model;

        /* model 8 stepping 0-7 use old style, 8-F use new style */
        if(model==8)
        {
            if(stepping<8)
                c=7;
            else
                c=9;
        }

        switch(c)
        {
        /* old style write back */
        case 6:
        case 7:
            AMD_K6_read_msr(0xC0000082, &regs);
            if(((regs.x.eax>>1)&0x7F)==0)
                kprintf("AMD K6 : WriteBack currently disabled\n");
            else
                kprintf("AMD K6 : WriteBack currently enabled (%luMB)\n",
                    ((regs.x.eax>>1)&0x7F)*4);

            kprintf("AMD K6 : Enabling WriteBack to %luMB\n", mem*4);
            AMD_K6_write_msr(0xC0000082, ((mem<<1)&0x7F), 0, &regs);
            break;

        /* new style write back */
        case 9:
            AMD_K6_read_msr(0xC0000082, &regs);
            if(((regs.x.eax>>22)&0x3FF)==0)
                kprintf("AMD K6 : WriteBack Disabled\n");
            else
                kprintf("AMD K6 : WriteBack Enabled (%luMB)\n",
                    ((regs.x.eax>>22)&0x3FF)*4);

            kprintf("AMD K6 : Enabled WriteBack (%luMB)\n", mem*4);
            AMD_K6_write_msr(0xC0000082, ((mem<<22)&0x3FF), 0, &regs);
            break;
        default:    /* dont set it on Unknowns + k5's */
            break;
        }
    }
}

void AMD_K6_write_msr(ULONG msr, ULONG v1, ULONG v2, union REGS *regs)
{
    asm __volatile__ (
        "pushfl\n"
        "cli\n"
        "wbinvd\n"
        "wrmsr\n"
        "popfl\n"
        : "=a" (regs->x.eax),
          "=b" (regs->x.ebx),
          "=c" (regs->x.ecx),
          "=d" (regs->x.edx)
        : "a" (v1),
          "d" (v2),
          "c" (msr)
        : "eax",
          "ecx",
          "edx",
          "ebx",
          "memory");
}

void AMD_K6_read_msr(ULONG msr, union REGS *regs)
{
    asm __volatile__ (
        "pushfl\n"
        "cli\n"
        "wbinvd\n"
        "xorl %%eax, %%eax\n"
        "xorl %%edx, %%edx\n"
        "rdmsr\n"
        "popfl\n"
        : "=a" (regs->x.eax),
          "=b" (regs->x.ebx),
          "=c" (regs->x.ecx),
          "=d" (regs->x.edx)
        : "c" (msr)
        : "eax",
          "ecx",
          "edx",
          "ebx",
          "memory");
}