linux-bk/arch/mips64/mm/andes.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org)
   7 * Copyright (C) 1999 Silicon Graphics, Inc.
   8 * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com)
   9 */
  10#include <linux/init.h>
  11#include <linux/kernel.h>
  12#include <linux/sched.h>
  13#include <linux/mm.h>
  14#include <asm/page.h>
  15#include <asm/pgtable.h>
  16#include <asm/r10kcache.h>
  17#include <asm/system.h>
  18#include <asm/sgialib.h>
  19#include <asm/mmu_context.h>
  20
  21static int scache_lsz64;
  22
  23/*
  24 * This version has been tuned on an Origin.  For other machines the arguments
  25 * of the pref instructin may have to be tuned differently.
  26 */
  27static void andes_clear_page(void * page)
  28{
  29        __asm__ __volatile__(
  30                ".set\tnoreorder\n\t"
  31                ".set\tnoat\n\t"
  32                "daddiu\t$1,%0,%2\n"
  33                "1:\tpref 7,512(%0)\n\t"
  34                "sd\t$0,(%0)\n\t"
  35                "sd\t$0,8(%0)\n\t"
  36                "sd\t$0,16(%0)\n\t"
  37                "sd\t$0,24(%0)\n\t"
  38                "daddiu\t%0,64\n\t"
  39                "sd\t$0,-32(%0)\n\t"
  40                "sd\t$0,-24(%0)\n\t"
  41                "sd\t$0,-16(%0)\n\t"
  42                "bne\t$1,%0,1b\n\t"
  43                "sd\t$0,-8(%0)\n\t"
  44                ".set\tat\n\t"
  45                ".set\treorder"
  46                :"=r" (page)
  47                :"0" (page), "I" (PAGE_SIZE)
  48                :"$1", "memory");
  49}
  50
  51/* R10000 has no Create_Dirty type cacheops.  */
  52static void andes_copy_page(void * to, void * from)
  53{
  54        unsigned long dummy1, dummy2, reg1, reg2, reg3, reg4;
  55
  56        __asm__ __volatile__(
  57                ".set\tnoreorder\n\t"
  58                ".set\tnoat\n\t"
  59                "daddiu\t$1,%0,%8\n"
  60                "1:\tpref\t0,2*128(%1)\n\t"
  61                "pref\t1,2*128(%0)\n\t"
  62                "ld\t%2,(%1)\n\t"
  63                "ld\t%3,8(%1)\n\t"
  64                "ld\t%4,16(%1)\n\t"
  65                "ld\t%5,24(%1)\n\t"
  66                "sd\t%2,(%0)\n\t"
  67                "sd\t%3,8(%0)\n\t"
  68                "sd\t%4,16(%0)\n\t"
  69                "sd\t%5,24(%0)\n\t"
  70                "daddiu\t%0,64\n\t"
  71                "daddiu\t%1,64\n\t"
  72                "ld\t%2,-32(%1)\n\t"
  73                "ld\t%3,-24(%1)\n\t"
  74                "ld\t%4,-16(%1)\n\t"
  75                "ld\t%5,-8(%1)\n\t"
  76                "sd\t%2,-32(%0)\n\t"
  77                "sd\t%3,-24(%0)\n\t"
  78                "sd\t%4,-16(%0)\n\t"
  79                "bne\t$1,%0,1b\n\t"
  80                " sd\t%5,-8(%0)\n\t"
  81                ".set\tat\n\t"
  82                ".set\treorder"
  83                :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2),
  84                 "=&r" (reg3), "=&r" (reg4)
  85                :"0" (to), "1" (from), "I" (PAGE_SIZE));
  86}
  87
  88/* Cache operations.  These are only used with the virtual memory system,
  89   not for non-coherent I/O so it's ok to ignore the secondary caches.  */
  90static void
  91andes_flush_cache_l1(void)
  92{
  93        blast_dcache32(); blast_icache64();
  94}
  95
  96/*
  97 * This is only used during initialization time. vmalloc() also calls
  98 * this, but that will be changed pretty soon.
  99 */
 100static void
 101andes_flush_cache_l2(void)
 102{
 103        switch (sc_lsize()) {
 104                case 64:
 105                        blast_scache64();
 106                        break;
 107                case 128:
 108                        blast_scache128();
 109                        break;
 110                default:
 111                        printk("Unknown L2 line size\n");
 112                        while(1);
 113        }
 114}
 115
 116void
 117andes_flush_icache_page(unsigned long page)
 118{
 119        if (scache_lsz64)
 120                blast_scache64_page(page);
 121        else
 122                blast_scache128_page(page);
 123}
 124
 125static void
 126andes_flush_cache_sigtramp(unsigned long addr)
 127{
 128        protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
 129        protected_flush_icache_line(addr & ~(ic_lsize - 1));
 130}
 131
 132#define NTLB_ENTRIES       64
 133#define NTLB_ENTRIES_HALF  32
 134
 135static inline void
 136andes_flush_tlb_all(void)
 137{
 138        unsigned long flags;
 139        unsigned long old_ctx;
 140        unsigned long entry;
 141
 142#ifdef DEBUG_TLB
 143        printk("[tlball]");
 144#endif
 145
 146        local_irq_save(flags);
 147        /* Save old context and create impossible VPN2 value */
 148        old_ctx = get_entryhi() & 0xff;
 149        set_entryhi(CKSEG0);
 150        set_entrylo0(0);
 151        set_entrylo1(0);
 152
 153        entry = get_wired();
 154
 155        /* Blast 'em all away. */
 156        while(entry < NTLB_ENTRIES) {
 157                set_index(entry);
 158                tlb_write_indexed();
 159                entry++;
 160        }
 161        set_entryhi(old_ctx);
 162        local_irq_restore(flags);
 163}
 164
 165static void andes_flush_tlb_mm(struct mm_struct *mm)
 166{
 167        if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 168                unsigned long flags;
 169
 170#ifdef DEBUG_TLB
 171                printk("[tlbmm<%d>]", mm->context);
 172#endif
 173                local_irq_save(flags);
 174                get_new_cpu_mmu_context(mm, smp_processor_id());
 175                if(mm == current->mm)
 176                        set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff);
 177                local_irq_restore(flags);
 178        }
 179}
 180
 181static void
 182andes_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 183                      unsigned long end)
 184{
 185        struct mm_struct *mm = vma->vm_mm;
 186
 187        if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
 188                unsigned long flags;
 189                int size;
 190
 191#ifdef DEBUG_TLB
 192                printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
 193                       start, end);
 194#endif
 195                local_irq_save(flags);
 196                size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 197                size = (size + 1) >> 1;
 198                if(size <= NTLB_ENTRIES_HALF) {
 199                        int oldpid = (get_entryhi() & 0xff);
 200                        int newpid = (CPU_CONTEXT(smp_processor_id(), mm) & 0xff);
 201
 202                        start &= (PAGE_MASK << 1);
 203                        end += ((PAGE_SIZE << 1) - 1);
 204                        end &= (PAGE_MASK << 1);
 205                        while(start < end) {
 206                                int idx;
 207
 208                                set_entryhi(start | newpid);
 209                                start += (PAGE_SIZE << 1);
 210                                tlb_probe();
 211                                idx = get_index();
 212                                set_entrylo0(0);
 213                                set_entrylo1(0);
 214                                set_entryhi(KSEG0);
 215                                if(idx < 0)
 216                                        continue;
 217                                tlb_write_indexed();
 218                        }
 219                        set_entryhi(oldpid);
 220                } else {
 221                        get_new_cpu_mmu_context(mm, smp_processor_id());
 222                        if(mm == current->mm)
 223                                set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 
 224                                                                        0xff);
 225                }
 226                local_irq_restore(flags);
 227        }
 228}
 229
 230static void
 231andes_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 232{
 233        if (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) != 0) {
 234                unsigned long flags;
 235                int oldpid, newpid, idx;
 236
 237#ifdef DEBUG_TLB
 238                printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
 239#endif
 240                newpid = (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff);
 241                page &= (PAGE_MASK << 1);
 242                local_irq_save(flags);
 243                oldpid = (get_entryhi() & 0xff);
 244                set_entryhi(page | newpid);
 245                tlb_probe();
 246                idx = get_index();
 247                set_entrylo0(0);
 248                set_entrylo1(0);
 249                set_entryhi(KSEG0);
 250                if(idx < 0)
 251                        goto finish;
 252                tlb_write_indexed();
 253
 254        finish:
 255                set_entryhi(oldpid);
 256                local_irq_restore(flags);
 257        }
 258}
 259
 260/* XXX Simplify this.  On the R10000 writing a TLB entry for an virtual
 261   address that already exists will overwrite the old entry and not result
 262   in TLB malfunction or TLB shutdown.  */
 263static void andes_update_mmu_cache(struct vm_area_struct * vma,
 264                                   unsigned long address, pte_t pte)
 265{
 266        unsigned long flags;
 267        pgd_t *pgdp;
 268        pmd_t *pmdp;
 269        pte_t *ptep;
 270        int idx, pid;
 271
 272        /*
 273         * Handle debugger faulting in for debugee.
 274         */
 275        if (current->active_mm != vma->vm_mm)
 276                return;
 277
 278        local_irq_save(flags);
 279        pid = get_entryhi() & 0xff;
 280
 281        if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) ||
 282           (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) == 0)) {
 283                printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d "
 284                        "tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(),
 285                        vma->vm_mm) & 0xff), pid);
 286        }
 287
 288        address &= (PAGE_MASK << 1);
 289        set_entryhi(address | (pid));
 290        pgdp = pgd_offset(vma->vm_mm, address);
 291        tlb_probe();
 292        pmdp = pmd_offset(pgdp, address);
 293        idx = get_index();
 294        ptep = pte_offset(pmdp, address);
 295        set_entrylo0(pte_val(*ptep++) >> 6);
 296        set_entrylo1(pte_val(*ptep) >> 6);
 297        set_entryhi(address | (pid));
 298        if(idx < 0) {
 299                tlb_write_random();
 300        } else {
 301                tlb_write_indexed();
 302        }
 303        set_entryhi(pid);
 304        local_irq_restore(flags);
 305}
 306
 307static void andes_show_regs(struct pt_regs *regs)
 308{
 309        printk("Cpu %d\n", smp_processor_id());
 310        /* Saved main processor registers. */
 311        printk("$0      : %016lx %016lx %016lx %016lx\n",
 312               0UL, regs->regs[1], regs->regs[2], regs->regs[3]);
 313        printk("$4      : %016lx %016lx %016lx %016lx\n",
 314               regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
 315        printk("$8      : %016lx %016lx %016lx %016lx\n",
 316               regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]);
 317        printk("$12     : %016lx %016lx %016lx %016lx\n",
 318               regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
 319        printk("$16     : %016lx %016lx %016lx %016lx\n",
 320               regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
 321        printk("$20     : %016lx %016lx %016lx %016lx\n",
 322               regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
 323        printk("$24     : %016lx %016lx\n",
 324               regs->regs[24], regs->regs[25]);
 325        printk("$28     : %016lx %016lx %016lx %016lx\n",
 326               regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
 327        printk("Hi      : %016lx\n", regs->hi);
 328        printk("Lo      : %016lx\n", regs->lo);
 329
 330        /* Saved cp0 registers. */
 331        printk("epc     : %016lx    %s\nbadvaddr: %016lx\n",
 332               regs->cp0_epc, print_tainted(), regs->cp0_badvaddr);
 333        printk("Status  : %08x\nCause   : %08x\n",
 334               (unsigned int) regs->cp0_status, (unsigned int) regs->cp0_cause);
 335}
 336
 337void __init ld_mmu_andes(void)
 338{
 339        printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
 340
 341        printk("Primary instruction cache %dkb, linesize %d bytes\n",
 342               icache_size >> 10, ic_lsize);
 343        printk("Primary data cache %dkb, linesize %d bytes\n",
 344               dcache_size >> 10, dc_lsize);
 345        printk("Secondary cache sized at %ldK, linesize %ld\n",
 346               scache_size() >> 10, sc_lsize());
 347
 348        _clear_page = andes_clear_page;
 349        _copy_page = andes_copy_page;
 350
 351        _flush_cache_l1 = andes_flush_cache_l1;
 352        _flush_cache_l2 = andes_flush_cache_l2;
 353        _flush_cache_sigtramp = andes_flush_cache_sigtramp;
 354
 355        _flush_tlb_all = andes_flush_tlb_all;
 356        _flush_tlb_mm = andes_flush_tlb_mm;
 357        _flush_tlb_range = andes_flush_tlb_range;
 358        _flush_tlb_page = andes_flush_tlb_page;
 359
 360        switch (sc_lsize()) {
 361                case 64:
 362                        scache_lsz64 = 1;
 363                        break;
 364                case 128:
 365                        scache_lsz64 = 0;
 366                        break;
 367                default:
 368                        printk("Unknown L2 line size\n");
 369                        while(1);
 370        }
 371    
 372        update_mmu_cache = andes_update_mmu_cache;
 373
 374        _show_regs = andes_show_regs;
 375
 376        flush_cache_l1();
 377
 378        /*
 379         * You should never change this register:
 380         *   - On R4600 1.7 the tlbp never hits for pages smaller than
 381         *     the value in the c0_pagemask register.
 382         *   - The entire mm handling assumes the c0_pagemask register to
 383         *     be set for 4kb pages.
 384         */
 385        write_32bit_cp0_register(CP0_PAGEMASK, PM_4K);
 386
 387        /* From this point on the ARC firmware is dead.  */
 388        _flush_tlb_all();
 389
 390        /* Did I tell you that ARC SUCKS?  */
 391}
 392
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.