OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [sparc/] [mm/] [sun4c.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1624 jcastillo
/* sun4c.c: Doing in software what should be done in hardware.
2
 *
3
 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
4
 */
5
 
6
#include <linux/kernel.h>
7
#include <linux/mm.h>
8
 
9
#include <asm/page.h>
10
#include <asm/pgtable.h>
11
#include <asm/vaddrs.h>
12
#include <asm/idprom.h>
13
#include <asm/machines.h>
14
#include <asm/memreg.h>
15
#include <asm/processor.h>
16
 
17
extern int num_segmaps, num_contexts;
18
 
19
/* Flushing the cache. */
20
struct sun4c_vac_props sun4c_vacinfo;
21
static int ctxflushes, segflushes, pageflushes;
22
 
23
/* convert a virtual address to a physical address and vice
24
   versa. Easy on the 4c */
25
static unsigned long sun4c_v2p(unsigned long vaddr)
26
{
27
  return(vaddr - PAGE_OFFSET);
28
}
29
 
30
static unsigned long sun4c_p2v(unsigned long vaddr)
31
{
32
  return(vaddr + PAGE_OFFSET);
33
}
34
 
35
 
36
/* Invalidate every sun4c cache line tag. */
37
void sun4c_flush_all(void)
38
{
39
        unsigned long begin, end;
40
 
41
        if(sun4c_vacinfo.on)
42
                panic("SUN4C: AIEEE, trying to invalidate vac while"
43
                      " it is on.");
44
 
45
        /* Clear 'valid' bit in all cache line tags */
46
        begin = AC_CACHETAGS;
47
        end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes);
48
        while(begin < end) {
49
                __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
50
                                     "r" (begin), "i" (ASI_CONTROL));
51
                begin += sun4c_vacinfo.linesize;
52
        }
53
}
54
 
55
/* Blow the entire current context out of the virtual cache. */
56
static inline void sun4c_flush_context(void)
57
{
58
        unsigned long vaddr;
59
 
60
        ctxflushes++;
61
        if(sun4c_vacinfo.do_hwflushes) {
62
                for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=PAGE_SIZE)
63
                        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
64
                                             "r" (vaddr), "i" (ASI_HWFLUSHCONTEXT));
65
        } else {
66
                int incr = sun4c_vacinfo.linesize;
67
                for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=incr)
68
                        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
69
                                             "r" (vaddr), "i" (ASI_FLUSHCTX));
70
        }
71
}
72
 
73
/* Scrape the segment starting at ADDR from the virtual cache. */
74
static inline void sun4c_flush_segment(unsigned long addr)
75
{
76
        unsigned long end;
77
 
78
        segflushes++;
79
        addr &= SUN4C_REAL_PGDIR_MASK;
80
        end = (addr + sun4c_vacinfo.num_bytes);
81
        if(sun4c_vacinfo.do_hwflushes) {
82
                for( ; addr < end; addr += PAGE_SIZE)
83
                        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
84
                                             "r" (addr), "i" (ASI_HWFLUSHSEG));
85
        } else {
86
                int incr = sun4c_vacinfo.linesize;
87
                for( ; addr < end; addr += incr)
88
                        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
89
                                             "r" (addr), "i" (ASI_FLUSHSEG));
90
        }
91
}
92
 
93
/* Bolix one page from the virtual cache. */
94
static inline void sun4c_flush_page(unsigned long addr)
95
{
96
        addr &= PAGE_MASK;
97
 
98
        pageflushes++;
99
        if(sun4c_vacinfo.do_hwflushes) {
100
                __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
101
                                     "r" (addr), "i" (ASI_HWFLUSHPAGE));
102
        } else {
103
                unsigned long end = addr + PAGE_SIZE;
104
                int incr = sun4c_vacinfo.linesize;
105
 
106
                for( ; addr < end; addr += incr)
107
                        __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
108
                                             "r" (addr), "i" (ASI_FLUSHPG));
109
        }
110
}
111
 
112
/* The sun4c's do have an on chip store buffer.  And the way you
113
 * clear them out isn't so obvious.  The only way I can think of
114
 * to accomplish this is to read the current context register,
115
 * store the same value there, then do a bunch of nops for the
116
 * pipeline to clear itself completely.  This is only used for
117
 * dealing with memory errors, so it is not that critical.
118
 */
119
void sun4c_complete_all_stores(void)
120
{
121
        volatile int _unused;
122
 
123
        _unused = sun4c_get_context();
124
        sun4c_set_context(_unused);
125
        nop(); nop(); nop(); nop();
126
        nop(); nop(); nop(); nop();
127
        /* Is that enough? */
128
}
129
 
130
/* Bootup utility functions. */
131
static inline void sun4c_init_clean_segmap(unsigned char pseg)
132
{
133
        unsigned long vaddr;
134
 
135
        sun4c_put_segmap(0, pseg);
136
        for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
137
                sun4c_put_pte(vaddr, 0);
138
        sun4c_put_segmap(0, invalid_segment);
139
}
140
 
141
static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
142
{
143
        unsigned long vaddr;
144
        unsigned char savectx, ctx;
145
 
146
        savectx = sun4c_get_context();
147
        kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
148
        for(ctx = 0; ctx < num_contexts; ctx++) {
149
                sun4c_set_context(ctx);
150
                for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
151
                        sun4c_put_segmap(vaddr, invalid_segment);
152
                for(vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
153
                        sun4c_put_segmap(vaddr, invalid_segment);
154
                for(vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
155
                        sun4c_put_segmap(vaddr, invalid_segment);
156
                for(vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
157
                        sun4c_put_segmap(vaddr, invalid_segment);
158
        }
159
        sun4c_set_context(ctx);
160
}
161
 
162
void sun4c_probe_vac(void)
163
{
164
        int propval;
165
 
166
        sun4c_disable_vac();
167
        sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
168
                                                     "vac-size", 65536);
169
        sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
170
                                                    "vac-linesize", 16);
171
        sun4c_vacinfo.num_lines =
172
                (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
173
        switch(sun4c_vacinfo.linesize) {
174
        case 16:
175
                sun4c_vacinfo.log2lsize = 4;
176
                break;
177
        case 32:
178
                sun4c_vacinfo.log2lsize = 5;
179
                break;
180
        default:
181
                prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
182
                            sun4c_vacinfo.linesize);
183
                prom_halt();
184
        };
185
 
186
        propval = prom_getintdefault(prom_root_node, "vac_hwflush", -1);
187
        sun4c_vacinfo.do_hwflushes = (propval == -1 ?
188
                                      prom_getintdefault(prom_root_node,
189
                                                         "vac-hwflush", 0) :
190
                                      propval);
191
 
192
        if(sun4c_vacinfo.num_bytes != 65536) {
193
                prom_printf("WEIRD Sun4C VAC cache size, tell davem");
194
                prom_halt();
195
        }
196
 
197
        sun4c_flush_all();
198
        sun4c_enable_vac();
199
}
200
 
201
static void sun4c_probe_mmu(void)
202
{
203
        num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
204
        num_contexts = prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
205
}
206
 
207
static inline void sun4c_init_ss2_cache_bug(void)
208
{
209
        extern unsigned long start;
210
 
211
        if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
212
                /* Whee.. */
213
                printk("SS2 cache bug detected, uncaching trap table page\n");
214
                sun4c_flush_page((unsigned int) &start);
215
                sun4c_put_pte(((unsigned long) &start),
216
                        (sun4c_get_pte((unsigned long) &start) | _SUN4C_PAGE_NOCACHE));
217
        }
218
}
219
 
220
static inline unsigned long sun4c_init_alloc_dvma_pages(unsigned long start_mem)
221
{
222
        unsigned long addr, pte;
223
 
224
        for(addr = DVMA_VADDR; addr < DVMA_END; addr += PAGE_SIZE) {
225
                pte = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
226
                pte |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_NOCACHE);
227
                sun4c_put_pte(addr, pte);
228
                start_mem += PAGE_SIZE;
229
        }
230
        return start_mem;
231
}
232
 
233
/* TLB management. */
234
struct sun4c_mmu_entry {
235
        struct sun4c_mmu_entry *next;
236
        struct sun4c_mmu_entry *prev;
237
        unsigned long vaddr;
238
        unsigned char pseg;
239
        unsigned char locked;
240
};
241
static struct sun4c_mmu_entry mmu_entry_pool[256];
242
 
243
static void sun4c_init_mmu_entry_pool(void)
244
{
245
        int i;
246
 
247
        for(i=0; i < 256; i++) {
248
                mmu_entry_pool[i].pseg = i;
249
                mmu_entry_pool[i].next = 0;
250
                mmu_entry_pool[i].prev = 0;
251
                mmu_entry_pool[i].vaddr = 0;
252
                mmu_entry_pool[i].locked = 0;
253
        }
254
        mmu_entry_pool[invalid_segment].locked = 1;
255
}
256
 
257
static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
258
                                   unsigned long bits_off)
259
{
260
        unsigned long start, end;
261
 
262
        end = vaddr + SUN4C_REAL_PGDIR_SIZE;
263
        for(start = vaddr; start < end; start += PAGE_SIZE)
264
                if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
265
                        sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
266
                                      ~bits_off);
267
}
268
 
269
static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
270
{
271
        unsigned long vaddr;
272
        unsigned char pseg, ctx;
273
 
274
        for(vaddr = KADB_DEBUGGER_BEGVM;
275
            vaddr < LINUX_OPPROM_ENDVM;
276
            vaddr += SUN4C_REAL_PGDIR_SIZE) {
277
                pseg = sun4c_get_segmap(vaddr);
278
                if(pseg != invalid_segment) {
279
                        mmu_entry_pool[pseg].locked = 1;
280
                        for(ctx = 0; ctx < num_contexts; ctx++)
281
                                prom_putsegment(ctx, vaddr, pseg);
282
                        fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
283
                }
284
        }
285
        for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
286
                pseg = sun4c_get_segmap(vaddr);
287
                mmu_entry_pool[pseg].locked = 1;
288
                for(ctx = 0; ctx < num_contexts; ctx++)
289
                        prom_putsegment(ctx, vaddr, pseg);
290
                fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
291
        }
292
}
293
 
294
static void sun4c_init_lock_area(unsigned long start, unsigned long end)
295
{
296
        int i, ctx;
297
 
298
        while(start < end) {
299
                for(i=0; i < invalid_segment; i++)
300
                        if(!mmu_entry_pool[i].locked)
301
                                break;
302
                mmu_entry_pool[i].locked = 1;
303
                sun4c_init_clean_segmap(i);
304
                for(ctx = 0; ctx < num_contexts; ctx++)
305
                        prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
306
                start += SUN4C_REAL_PGDIR_SIZE;
307
        }
308
}
309
 
310
struct sun4c_mmu_ring {
311
        struct sun4c_mmu_entry ringhd;
312
        int num_entries;
313
};
314
static struct sun4c_mmu_ring sun4c_context_ring[16]; /* used user entries */
315
static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
316
static struct sun4c_mmu_ring sun4c_kernel_ring;      /* used kernel entries */
317
static struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
318
 
319
static inline void sun4c_init_rings(void)
320
{
321
        int i;
322
        for(i=0; i<16; i++) {
323
                sun4c_context_ring[i].ringhd.next =
324
                        sun4c_context_ring[i].ringhd.prev =
325
                        &sun4c_context_ring[i].ringhd;
326
                sun4c_context_ring[i].num_entries = 0;
327
        }
328
        sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
329
                &sun4c_ufree_ring.ringhd;
330
        sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
331
                &sun4c_kernel_ring.ringhd;
332
        sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev =
333
                &sun4c_kfree_ring.ringhd;
334
        sun4c_ufree_ring.num_entries = sun4c_kernel_ring.num_entries =
335
                sun4c_kfree_ring.num_entries = 0;
336
}
337
 
338
static inline void add_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
339
{
340
        struct sun4c_mmu_entry *head = &ring->ringhd;
341
 
342
        entry->prev = head;
343
        (entry->next = head->next)->prev = entry;
344
        head->next = entry;
345
        ring->num_entries++;
346
}
347
 
348
static inline void remove_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
349
{
350
        struct sun4c_mmu_entry *next = entry->next;
351
 
352
        (next->prev = entry->prev)->next = next;
353
        ring->num_entries--;
354
}
355
 
356
static inline void recycle_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
357
{
358
        struct sun4c_mmu_entry *head = &ring->ringhd;
359
        struct sun4c_mmu_entry *next = entry->next;
360
 
361
        (next->prev = entry->prev)->next = next;
362
        entry->prev = head; (entry->next = head->next)->prev = entry;
363
        head->next = entry;
364
        /* num_entries stays the same */
365
}
366
 
367
static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
368
{
369
        remove_ring(sun4c_context_ring+ctx, entry);
370
        add_ring(&sun4c_ufree_ring, entry);
371
}
372
 
373
static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry)
374
{
375
        remove_ring(&sun4c_ufree_ring, entry);
376
        add_ring(sun4c_context_ring+ctx, entry);
377
}
378
 
379
static inline void free_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring)
380
{
381
        remove_ring(ring, entry);
382
        add_ring(&sun4c_kfree_ring, entry);
383
}
384
 
385
static inline void assign_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring)
386
{
387
        remove_ring(ring, entry);
388
        add_ring(&sun4c_kernel_ring, entry);
389
}
390
 
391
static inline void reassign_kernel_entry(struct sun4c_mmu_entry *entry)
392
{
393
        recycle_ring(&sun4c_kernel_ring, entry);
394
}
395
 
396
static void sun4c_init_fill_kernel_ring(int howmany)
397
{
398
        int i;
399
 
400
        while(howmany) {
401
                for(i=0; i < invalid_segment; i++)
402
                        if(!mmu_entry_pool[i].locked)
403
                                break;
404
                mmu_entry_pool[i].locked = 1;
405
                sun4c_init_clean_segmap(i);
406
                add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]);
407
                howmany--;
408
        }
409
}
410
 
411
static void sun4c_init_fill_user_ring(void)
412
{
413
        int i;
414
 
415
        for(i=0; i < invalid_segment; i++) {
416
                if(mmu_entry_pool[i].locked)
417
                        continue;
418
                sun4c_init_clean_segmap(i);
419
                add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
420
        }
421
}
422
 
423
static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
424
{
425
        int savectx, ctx;
426
 
427
        savectx = sun4c_get_context();
428
        flush_user_windows();
429
        sun4c_flush_segment(kentry->vaddr);
430
        for(ctx = 0; ctx < num_contexts; ctx++) {
431
                sun4c_set_context(ctx);
432
                sun4c_put_segmap(kentry->vaddr, invalid_segment);
433
        }
434
        sun4c_set_context(savectx);
435
}
436
 
437
static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
438
{
439
        int savectx, ctx;
440
 
441
        savectx = sun4c_get_context();
442
        flush_user_windows();
443
        for(ctx = 0; ctx < num_contexts; ctx++) {
444
                sun4c_set_context(ctx);
445
                sun4c_put_segmap(kentry->vaddr, kentry->pseg);
446
        }
447
        sun4c_set_context(savectx);
448
}
449
 
450
static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
451
{
452
        sun4c_flush_segment(uentry->vaddr);
453
        sun4c_put_segmap(uentry->vaddr, invalid_segment);
454
}
455
 
456
static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
457
{
458
        unsigned long start = uentry->vaddr;
459
        unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
460
 
461
        sun4c_put_segmap(uentry->vaddr, uentry->pseg);
462
        while(start < end) {
463
                sun4c_put_pte(start, 0);
464
                start += PAGE_SIZE;
465
        }
466
}
467
 
468
static inline void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
469
{
470
        struct sun4c_mmu_entry *this_entry, *next_entry;
471
        int savectx = sun4c_get_context();
472
 
473
        this_entry = crp->ringhd.next;
474
        flush_user_windows();
475
        sun4c_set_context(ctx);
476
        while(crp->num_entries) {
477
                next_entry = this_entry->next;
478
                sun4c_user_unmap(this_entry);
479
                free_user_entry(ctx, this_entry);
480
                this_entry = next_entry;
481
        }
482
        sun4c_set_context(savectx);
483
}
484
 
485
static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
486
{
487
        struct sun4c_mmu_entry *entry = crp->ringhd.next;
488
        int savectx = sun4c_get_context();
489
 
490
        flush_user_windows();
491
        sun4c_set_context(ctx);
492
        sun4c_user_unmap(entry);
493
        free_user_entry(ctx, entry);
494
        sun4c_set_context(savectx);
495
}
496
 
497
/* Using this method to free up mmu entries eliminates a lot of
498
 * potential races since we have a kernel that incurs tlb
499
 * replacement faults.  There may be performance penalties.
500
 */
501
static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
502
{
503
        struct sun4c_mmu_ring *rp = 0;
504
        unsigned char mmuhog, i, ctx = 0;
505
 
506
        /* If some are free, return first one. */
507
        if(sun4c_ufree_ring.num_entries)
508
                return sun4c_ufree_ring.ringhd.next;
509
 
510
        /* Else free one up. */
511
        mmuhog = 0;
512
        for(i=0; i < num_contexts; i++) {
513
                if(sun4c_context_ring[i].num_entries > mmuhog) {
514
                        rp = &sun4c_context_ring[i];
515
                        mmuhog = rp->num_entries;
516
                        ctx = i;
517
                }
518
        }
519
        sun4c_demap_one(rp, ctx);
520
        return sun4c_ufree_ring.ringhd.next;
521
}
522
 
523
static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
524
{
525
        struct sun4c_mmu_entry *this_entry;
526
 
527
        /* If some are free, return first one. */
528
        if(sun4c_kfree_ring.num_entries)
529
                return sun4c_kfree_ring.ringhd.next;
530
 
531
        /* Else free one up. */
532
        this_entry = sun4c_kernel_ring.ringhd.prev;
533
        sun4c_kernel_unmap(this_entry);
534
        free_kernel_entry(this_entry, &sun4c_kernel_ring);
535
        return sun4c_kfree_ring.ringhd.next;
536
}
537
 
538
static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
539
{
540
        struct sun4c_mmu_entry *entry;
541
 
542
        address &= SUN4C_REAL_PGDIR_MASK;
543
        entry = sun4c_user_strategy();
544
        assign_user_entry(ctx, entry);
545
        entry->vaddr = address;
546
        sun4c_user_map(entry);
547
}
548
 
549
static inline void alloc_kernel_segment(unsigned long address)
550
{
551
        struct sun4c_mmu_entry *entry;
552
 
553
        address &= SUN4C_REAL_PGDIR_MASK;
554
        entry = sun4c_kernel_strategy();
555
 
556
        assign_kernel_entry(entry, &sun4c_kfree_ring);
557
        entry->vaddr = address;
558
        sun4c_kernel_map(entry);
559
}
560
 
561
/* XXX Just like kernel tlb replacement we'd like to have a low level
562
 * XXX equivalent for user faults which need not go through the mm
563
 * XXX subsystem just to load a mmu entry.  But this might not be as
564
 * XXX feasible since we need to go through the kernel page tables
565
 * XXX for this process, which we currently don't lock into the mmu
566
 * XXX so we would fault with traps off... must think about this...
567
 */
568
static void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
569
{
570
        unsigned long flags;
571
 
572
        save_flags(flags); cli();
573
        address &= PAGE_MASK;
574
        if(sun4c_get_segmap(address) == invalid_segment)
575
                alloc_user_segment(address, sun4c_get_context());
576
        sun4c_put_pte(address, pte_val(pte));
577
        restore_flags(flags);
578
}
579
 
580
/* READ THIS:  If you put any diagnostic printing code in any of the kernel
581
 *             fault handling code you will lose badly.  This is the most
582
 *             delicate piece of code in the entire kernel, atomicity of
583
 *             kernel tlb replacement must be guaranteed.  This is why we
584
 *             have separate user and kernel allocation rings to alleviate
585
 *             as many bad interactions as possible.
586
 *
587
 * XXX Someday make this into a fast in-window trap handler to avoid
588
 * XXX any and all races.  *High* priority, also for performance.
589
 */
590
static void sun4c_quick_kernel_fault(unsigned long address)
591
{
592
        unsigned long end, flags;
593
 
594
        save_flags(flags); cli();
595
        address &= SUN4C_REAL_PGDIR_MASK;
596
        end = address + SUN4C_REAL_PGDIR_SIZE;
597
        if(sun4c_get_segmap(address) == invalid_segment)
598
                alloc_kernel_segment(address);
599
 
600
        if(address < SUN4C_VMALLOC_START) {
601
                unsigned long pte;
602
                pte = (address - PAGE_OFFSET) >> PAGE_SHIFT;
603
                pte |= pgprot_val(SUN4C_PAGE_KERNEL);
604
                /* Stupid pte tricks... */
605
                while(address < end) {
606
                        sun4c_put_pte(address, pte++);
607
                        address += PAGE_SIZE;
608
                }
609
        } else {
610
                pte_t *ptep;
611
 
612
                ptep = (pte_t *) (PAGE_MASK & pgd_val(swapper_pg_dir[address>>SUN4C_PGDIR_SHIFT]));
613
                ptep = (ptep + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)));
614
                while(address < end) {
615
                        sun4c_put_pte(address, pte_val(*ptep++));
616
                        address += PAGE_SIZE;
617
                }
618
        }
619
        restore_flags(flags);
620
}
621
 
622
/*
623
 * 4 page buckets for task struct and kernel stack allocation.
624
 *
625
 * TASK_STACK_BEGIN
626
 * bucket[0]
627
 * bucket[1]
628
 *   [ ... ]
629
 * bucket[NR_TASKS-1]
630
 * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASKS)
631
 *
632
 * Each slot looks like:
633
 *
634
 *  page 1   --  task struct
635
 *  page 2   --  unmapped, for stack redzone (maybe use for pgd)
636
 *  page 3/4 --  kernel stack
637
 */
638
 
639
struct task_bucket {
640
        struct task_struct task;
641
        char _unused1[PAGE_SIZE - sizeof(struct task_struct)];
642
        char kstack[(PAGE_SIZE*3)];
643
};
644
 
645
struct task_bucket *sun4c_bucket[NR_TASKS];
646
 
647
#define BUCKET_EMPTY     ((struct task_bucket *) 0)
648
#define BUCKET_SIZE      (PAGE_SIZE << 2)
649
#define BUCKET_SHIFT     14        /* log2(sizeof(struct task_bucket)) */
650
#define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
651
#define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
652
#define BUCKET_PTE(page)       \
653
        ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL))
654
#define BUCKET_PTE_PAGE(pte)   \
655
        (PAGE_OFFSET + (((pte) & 0xffff) << PAGE_SHIFT))
656
 
657
static inline void get_task_segment(unsigned long addr)
658
{
659
        struct sun4c_mmu_entry *stolen;
660
        unsigned long flags;
661
 
662
        save_flags(flags); cli();
663
        addr &= SUN4C_REAL_PGDIR_MASK;
664
        stolen = sun4c_user_strategy();
665
        remove_ring(&sun4c_ufree_ring, stolen);
666
        stolen->vaddr = addr;
667
        sun4c_kernel_map(stolen);
668
        restore_flags(flags);
669
}
670
 
671
static inline void free_task_segment(unsigned long addr)
672
{
673
        struct sun4c_mmu_entry *entry;
674
        unsigned long flags;
675
        unsigned char pseg;
676
 
677
        save_flags(flags); cli();
678
        addr &= SUN4C_REAL_PGDIR_MASK;
679
        pseg = sun4c_get_segmap(addr);
680
        entry = &mmu_entry_pool[pseg];
681
        sun4c_flush_segment(addr);
682
        sun4c_kernel_unmap(entry);
683
        add_ring(&sun4c_ufree_ring, entry);
684
        restore_flags(flags);
685
}
686
 
687
static inline void garbage_collect(int entry)
688
{
689
        int start, end;
690
 
691
        /* 16 buckets per segment... */
692
        entry &= ~15;
693
        start = entry;
694
        for(end = (start + 16); start < end; start++)
695
                if(sun4c_bucket[start] != BUCKET_EMPTY)
696
                        return;
697
        /* Entire segment empty, release it. */
698
        free_task_segment(BUCKET_ADDR(entry));
699
}
700
 
701
static struct task_struct *sun4c_alloc_task_struct(void)
702
{
703
        unsigned long addr, page;
704
        int entry;
705
 
706
        page = get_free_page(GFP_KERNEL);
707
        if(!page)
708
                return (struct task_struct *) 0;
709
        /* XXX Bahh, linear search too slow, use hash
710
         * XXX table in final implementation.  Or
711
         * XXX keep track of first free when we free
712
         * XXX a bucket... anything but this.
713
         */
714
        for(entry = 0; entry < NR_TASKS; entry++)
715
                if(sun4c_bucket[entry] == BUCKET_EMPTY)
716
                        break;
717
        if(entry == NR_TASKS) {
718
                free_page(page);
719
                return (struct task_struct *) 0;
720
        }
721
        addr = BUCKET_ADDR(entry);
722
        sun4c_bucket[entry] = (struct task_bucket *) addr;
723
        if(sun4c_get_segmap(addr) == invalid_segment)
724
                get_task_segment(addr);
725
        sun4c_put_pte(addr, BUCKET_PTE(page));
726
        return (struct task_struct *) addr;
727
}
728
 
729
static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
730
{
731
        unsigned long saddr = (unsigned long) tsk;
732
        unsigned long page[3];
733
 
734
        if(!saddr)
735
                return 0;
736
        page[0] = get_free_page(GFP_KERNEL);
737
        if(!page[0])
738
                return 0;
739
        page[1] = get_free_page(GFP_KERNEL);
740
        if(!page[1]) {
741
                free_page(page[0]);
742
                return 0;
743
        }
744
        page[2] = get_free_page(GFP_KERNEL);
745
        if(!page[2]) {
746
                free_page(page[0]);
747
                free_page(page[1]);
748
                return 0;
749
        }
750
        saddr += PAGE_SIZE;
751
        sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
752
        sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
753
        sun4c_put_pte(saddr + (PAGE_SIZE<<1), BUCKET_PTE(page[2]));
754
        return saddr;
755
}
756
 
757
static void sun4c_free_kernel_stack(unsigned long stack)
758
{
759
        unsigned long page[3];
760
 
761
        page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
762
        page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
763
        page[2] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+(PAGE_SIZE<<1)));
764
        sun4c_flush_segment(stack & SUN4C_REAL_PGDIR_MASK);
765
        sun4c_put_pte(stack, 0);
766
        sun4c_put_pte(stack + PAGE_SIZE, 0);
767
        sun4c_put_pte(stack + (PAGE_SIZE<<1), 0);
768
        free_page(page[0]);
769
        free_page(page[1]);
770
        free_page(page[2]);
771
}
772
 
773
static void sun4c_free_task_struct(struct task_struct *tsk)
774
{
775
        unsigned long tsaddr = (unsigned long) tsk;
776
        unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
777
        int entry = BUCKET_NUM(tsaddr);
778
 
779
        sun4c_flush_segment(tsaddr & SUN4C_REAL_PGDIR_MASK);
780
        sun4c_put_pte(tsaddr, 0);
781
        sun4c_bucket[entry] = BUCKET_EMPTY;
782
        free_page(page);
783
        garbage_collect(entry);
784
}
785
 
786
static void sun4c_init_buckets(void)
787
{
788
        int entry;
789
 
790
        if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) {
791
                prom_printf("task bucket not 4 pages!\n");
792
                prom_halt();
793
        }
794
        for(entry = 0; entry < NR_TASKS; entry++)
795
                sun4c_bucket[entry] = BUCKET_EMPTY;
796
}
797
 
798
static unsigned long sun4c_iobuffer_start;
799
static unsigned long sun4c_iobuffer_end;
800
static unsigned long *sun4c_iobuffer_map;
801
static int iobuffer_map_size;
802
 
803
/*
804
 * Alias our pages so they do not cause a trap.
805
 * Also one page may be aliased into several I/O areas and we may
806
 * finish these I/O separately.
807
 */
808
static char *sun4c_lockarea(char *vaddr, unsigned long size)
809
{
810
        unsigned long base, scan;
811
        unsigned long npages;
812
        unsigned long vpage;
813
        unsigned long pte;
814
        unsigned long apage;
815
 
816
        npages = (((unsigned long)vaddr & ~PAGE_MASK) +
817
                  size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
818
 
819
        scan = 0;
820
        for (;;) {
821
                scan = find_next_zero_bit(sun4c_iobuffer_map,
822
                                          iobuffer_map_size, scan);
823
                if ((base = scan) + npages > iobuffer_map_size) goto abend;
824
                for (;;) {
825
                        if (scan >= base + npages) goto found;
826
                        if (test_bit(scan, sun4c_iobuffer_map)) break;
827
                        scan++;
828
                }
829
        }
830
 
831
found:
832
        vpage = ((unsigned long) vaddr) & PAGE_MASK;
833
        for (scan = base; scan < base+npages; scan++) {
834
                pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT);
835
                pte |= pgprot_val(SUN4C_PAGE_KERNEL);
836
                pte |= _SUN4C_PAGE_NOCACHE;
837
                set_bit(scan, sun4c_iobuffer_map);
838
                apage = (scan << PAGE_SHIFT) + sun4c_iobuffer_start;
839
                sun4c_flush_page(vpage);
840
                sun4c_put_pte(apage, pte);
841
                vpage += PAGE_SIZE;
842
        }
843
        return (char *) ((base << PAGE_SHIFT) + sun4c_iobuffer_start +
844
                         (((unsigned long) vaddr) & ~PAGE_MASK));
845
 
846
abend:
847
        printk("DMA vaddr=0x%p size=%08lx\n", vaddr, size);
848
        panic("Out of iobuffer table");
849
        return 0;
850
}
851
 
852
static void sun4c_unlockarea(char *vaddr, unsigned long size)
853
{
854
        unsigned long vpage, npages;
855
 
856
        vpage = (unsigned long)vaddr & PAGE_MASK;
857
        npages = (((unsigned long)vaddr & ~PAGE_MASK) +
858
                  size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
859
        while (npages != 0) {
860
                --npages;
861
                sun4c_put_pte(vpage, 0);
862
                clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT,
863
                          sun4c_iobuffer_map);
864
                vpage += PAGE_SIZE;
865
        }
866
}
867
 
868
/* Note the scsi code at init time passes to here buffers
869
 * which sit on the kernel stack, those are already locked
870
 * by implication and fool the page locking code above
871
 * if passed to by mistake.
872
 */
873
static char *sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
874
{
875
        unsigned long page;
876
 
877
        page = ((unsigned long) bufptr) & PAGE_MASK;
878
        if(page > high_memory)
879
                return bufptr; /* already locked */
880
        return sun4c_lockarea(bufptr, len);
881
}
882
 
883
static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
884
{
885
        while(sz >= 0) {
886
                sg[sz].alt_addr = sun4c_lockarea(sg[sz].addr, sg[sz].len);
887
                sz--;
888
        }
889
}
890
 
891
static void sun4c_release_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
892
{
893
        unsigned long page = (unsigned long) bufptr;
894
 
895
        if(page < sun4c_iobuffer_start)
896
                return; /* On kernel stack or similar, see above */
897
        sun4c_unlockarea(bufptr, len);
898
}
899
 
900
static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
901
{
902
        while(sz >= 0) {
903
                sun4c_unlockarea(sg[sz].alt_addr, sg[sz].len);
904
                sg[sz].alt_addr = 0;
905
                sz--;
906
        }
907
}
908
 
909
#define TASK_ENTRY_SIZE    BUCKET_SIZE /* see above */
910
#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
911
 
912
struct vm_area_struct sun4c_kstack_vma;
913
 
914
static unsigned long sun4c_init_lock_areas(unsigned long start_mem)
915
{
916
        unsigned long sun4c_taskstack_start;
917
        unsigned long sun4c_taskstack_end;
918
        int bitmap_size;
919
 
920
        sun4c_init_buckets();
921
        sun4c_taskstack_start = SUN4C_LOCK_VADDR;
922
        sun4c_taskstack_end = (sun4c_taskstack_start +
923
                               (TASK_ENTRY_SIZE * NR_TASKS));
924
        if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
925
                prom_printf("Too many tasks, decrease NR_TASKS please.\n");
926
                prom_halt();
927
        }
928
 
929
        sun4c_iobuffer_start = SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end);
930
        sun4c_iobuffer_end = SUN4C_LOCK_END;
931
        bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT;
932
        bitmap_size = (bitmap_size + 7) >> 3;
933
        bitmap_size = LONG_ALIGN(bitmap_size);
934
        iobuffer_map_size = bitmap_size << 3;
935
        sun4c_iobuffer_map = (unsigned long *) start_mem;
936
        memset((void *) start_mem, 0, bitmap_size);
937
        start_mem += bitmap_size;
938
 
939
        /* Now get us some mmu entries for I/O maps. */
940
        sun4c_init_lock_area(sun4c_iobuffer_start, sun4c_iobuffer_end);
941
        sun4c_kstack_vma.vm_mm = init_task.mm;
942
        sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
943
        sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
944
        sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
945
        sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC;
946
        insert_vm_struct(&init_task, &sun4c_kstack_vma);
947
        return start_mem;
948
}
949
 
950
/* Cache flushing on the sun4c. */
951
static void sun4c_flush_cache_all(void)
952
{
953
        unsigned long start, end;
954
 
955
        /* Clear all tags in the sun4c cache.
956
         * The cache is write through so this is safe.
957
         */
958
        start = AC_CACHETAGS;
959
        end = start + sun4c_vacinfo.num_bytes;
960
        flush_user_windows();
961
        while(start < end) {
962
                __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
963
                                     "r" (start), "i" (ASI_CONTROL));
964
                start += sun4c_vacinfo.linesize;
965
        }
966
}
967
 
968
static void sun4c_flush_cache_mm(struct mm_struct *mm)
969
{
970
        unsigned long flags;
971
        int octx;
972
 
973
#ifndef __SMP__
974
        if(mm->context != NO_CONTEXT) {
975
#endif
976
                octx = sun4c_get_context();
977
                save_flags(flags); cli();
978
                flush_user_windows();
979
                sun4c_set_context(mm->context);
980
                sun4c_flush_context();
981
                sun4c_set_context(octx);
982
                restore_flags(flags);
983
#ifndef __SMP__
984
        }
985
#endif
986
}
987
 
988
static void sun4c_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
989
{
990
        unsigned long flags;
991
        int size, octx;
992
 
993
#ifndef __SMP__
994
        if(mm->context != NO_CONTEXT) {
995
#endif
996
                size = start - end;
997
 
998
                flush_user_windows();
999
 
1000
                if(size >= sun4c_vacinfo.num_bytes)
1001
                        goto flush_it_all;
1002
 
1003
                save_flags(flags); cli();
1004
                octx = sun4c_get_context();
1005
                sun4c_set_context(mm->context);
1006
 
1007
                if(size <= (PAGE_SIZE << 1)) {
1008
                        start &= PAGE_MASK;
1009
                        while(start < end) {
1010
                                sun4c_flush_page(start);
1011
                                start += PAGE_SIZE;
1012
                        };
1013
                } else {
1014
                        start &= SUN4C_REAL_PGDIR_MASK;
1015
                        while(start < end) {
1016
                                sun4c_flush_segment(start);
1017
                                start += SUN4C_REAL_PGDIR_SIZE;
1018
                        }
1019
                }
1020
                sun4c_set_context(octx);
1021
                restore_flags(flags);
1022
#ifndef __SMP__
1023
        }
1024
#endif
1025
        return;
1026
 
1027
flush_it_all:
1028
        /* Cache size bounded flushing, thank you. */
1029
        sun4c_flush_cache_all();
1030
}
1031
 
1032
static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
1033
{
1034
        unsigned long flags;
1035
        int octx;
1036
        struct mm_struct *mm = vma->vm_mm;
1037
 
1038
        /* Sun4c has no separate I/D caches so cannot optimize for non
1039
         * text page flushes.
1040
         */
1041
#ifndef __SMP__
1042
        if(mm->context != NO_CONTEXT) {
1043
#endif
1044
                octx = sun4c_get_context();
1045
                save_flags(flags); cli();
1046
                flush_user_windows();
1047
                sun4c_set_context(mm->context);
1048
                sun4c_flush_page(page);
1049
                sun4c_set_context(octx);
1050
                restore_flags(flags);
1051
#ifndef __SMP__
1052
        }
1053
#endif
1054
}
1055
 
1056
/* Sun4c cache is write-through, so no need to validate main memory
1057
 * during a page copy in kernel space.
1058
 */
1059
static void sun4c_flush_page_to_ram(unsigned long page)
1060
{
1061
}
1062
 
1063
/* TLB flushing on the sun4c.  These routines count on the cache
1064
 * flushing code to flush the user register windows so that we need
1065
 * not do so when we get here.
1066
 */
1067
 
1068
static void sun4c_flush_tlb_all(void)
1069
{
1070
        struct sun4c_mmu_entry *this_entry, *next_entry;
1071
        unsigned long flags;
1072
        int savectx, ctx;
1073
 
1074
        save_flags(flags); cli();
1075
        this_entry = sun4c_kernel_ring.ringhd.next;
1076
        savectx = sun4c_get_context();
1077
        while(sun4c_kernel_ring.num_entries) {
1078
                next_entry = this_entry->next;
1079
                for(ctx = 0; ctx < num_contexts; ctx++) {
1080
                        sun4c_set_context(ctx);
1081
                        sun4c_put_segmap(this_entry->vaddr, invalid_segment);
1082
                }
1083
                free_kernel_entry(this_entry, &sun4c_kernel_ring);
1084
                this_entry = next_entry;
1085
        }
1086
        sun4c_set_context(savectx);
1087
        restore_flags(flags);
1088
}
1089
 
1090
static void sun4c_flush_tlb_mm(struct mm_struct *mm)
1091
{
1092
        struct sun4c_mmu_entry *this_entry, *next_entry;
1093
        struct sun4c_mmu_ring *crp;
1094
        int savectx, ctx;
1095
 
1096
#ifndef __SMP__
1097
        if(mm->context != NO_CONTEXT) {
1098
#endif
1099
                crp = &sun4c_context_ring[mm->context];
1100
                savectx = sun4c_get_context();
1101
                ctx = mm->context;
1102
                this_entry = crp->ringhd.next;
1103
                sun4c_set_context(mm->context);
1104
                while(crp->num_entries) {
1105
                        next_entry = this_entry->next;
1106
                        sun4c_user_unmap(this_entry);
1107
                        free_user_entry(ctx, this_entry);
1108
                        this_entry = next_entry;
1109
                }
1110
                sun4c_set_context(savectx);
1111
#ifndef __SMP__
1112
        }
1113
#endif
1114
}
1115
 
1116
static void sun4c_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
1117
{
1118
        struct sun4c_mmu_entry *this_entry;
1119
        unsigned char pseg, savectx;
1120
 
1121
#ifndef __SMP__
1122
        if(mm->context == NO_CONTEXT)
1123
                return;
1124
#endif
1125
        flush_user_windows();
1126
        savectx = sun4c_get_context();
1127
        sun4c_set_context(mm->context);
1128
        start &= SUN4C_REAL_PGDIR_MASK;
1129
        while(start < end) {
1130
                pseg = sun4c_get_segmap(start);
1131
                if(pseg == invalid_segment)
1132
                        goto next_one;
1133
                this_entry = &mmu_entry_pool[pseg];
1134
                sun4c_put_segmap(this_entry->vaddr, invalid_segment);
1135
                free_user_entry(mm->context, this_entry);
1136
        next_one:
1137
                start += SUN4C_REAL_PGDIR_SIZE;
1138
        }
1139
        sun4c_set_context(savectx);
1140
}
1141
 
1142
static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
1143
{
1144
        struct mm_struct *mm = vma->vm_mm;
1145
        int savectx;
1146
 
1147
#ifndef __SMP__
1148
        if(mm->context != NO_CONTEXT) {
1149
#endif
1150
                savectx = sun4c_get_context();
1151
                sun4c_set_context(mm->context);
1152
                page &= PAGE_MASK;
1153
                if(sun4c_get_pte(page) & _SUN4C_PAGE_VALID)
1154
                        sun4c_put_pte(page, 0);
1155
                sun4c_set_context(savectx);
1156
#ifndef __SMP__
1157
        }
1158
#endif
1159
}
1160
 
1161
/* Sun4c mmu hardware doesn't update the dirty bit in the pte's
1162
 * for us, so we do it in software.
1163
 */
1164
static void sun4c_set_pte(pte_t *ptep, pte_t pte)
1165
{
1166
 
1167
        if((pte_val(pte) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_DIRTY)) ==
1168
           _SUN4C_PAGE_WRITE)
1169
                pte_val(pte) |= _SUN4C_PAGE_DIRTY;
1170
 
1171
        *ptep = pte;
1172
}
1173
 
1174
/* static */ void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
1175
                     int bus_type, int rdonly)
1176
{
1177
        unsigned long page_entry;
1178
 
1179
        page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
1180
        page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
1181
                       _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
1182
        if(rdonly)
1183
                page_entry &= (~_SUN4C_PAGE_WRITE);
1184
        sun4c_flush_page(virt_addr);
1185
        sun4c_put_pte(virt_addr, page_entry);
1186
}
1187
 
1188
static inline void sun4c_alloc_context(struct mm_struct *mm)
1189
{
1190
        struct ctx_list *ctxp;
1191
 
1192
        ctxp = ctx_free.next;
1193
        if(ctxp != &ctx_free) {
1194
                remove_from_ctx_list(ctxp);
1195
                add_to_used_ctxlist(ctxp);
1196
                mm->context = ctxp->ctx_number;
1197
                ctxp->ctx_mm = mm;
1198
                return;
1199
        }
1200
        ctxp = ctx_used.next;
1201
        if(ctxp->ctx_mm == current->mm)
1202
                ctxp = ctxp->next;
1203
        if(ctxp == &ctx_used)
1204
                panic("out of mmu contexts");
1205
        remove_from_ctx_list(ctxp);
1206
        add_to_used_ctxlist(ctxp);
1207
        ctxp->ctx_mm->context = NO_CONTEXT;
1208
        ctxp->ctx_mm = mm;
1209
        mm->context = ctxp->ctx_number;
1210
        sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number], ctxp->ctx_number);
1211
}
1212
 
1213
#if some_day_soon /* We need some tweaking to start using this */
1214
extern void force_user_fault(unsigned long, int);
1215
 
1216
void sun4c_switch_heuristic(struct pt_regs *regs)
1217
{
1218
        unsigned long sp = regs->u_regs[UREG_FP];
1219
        unsigned long sp2 = sp + REGWIN_SZ - 0x8;
1220
 
1221
        force_user_fault(regs->pc, 0);
1222
        force_user_fault(sp, 0);
1223
        if((sp&PAGE_MASK) != (sp2&PAGE_MASK))
1224
                force_user_fault(sp2, 0);
1225
}
1226
#endif
1227
 
1228
static void sun4c_switch_to_context(struct task_struct *tsk)
1229
{
1230
        /* Kernel threads can execute in any context and so can tasks
1231
         * sleeping in the middle of exiting. If this task has already
1232
         * been allocated a piece of the mmu realestate, just jump to
1233
         * it.
1234
         */
1235
        if((tsk->tss.flags & SPARC_FLAG_KTHREAD) ||
1236
           (tsk->flags & PF_EXITING))
1237
                return;
1238
        if(tsk->mm->context == NO_CONTEXT)
1239
                sun4c_alloc_context(tsk->mm);
1240
 
1241
        sun4c_set_context(tsk->mm->context);
1242
}
1243
 
1244
static void sun4c_flush_hook(void)
1245
{
1246
        if(current->tss.flags & SPARC_FLAG_KTHREAD) {
1247
                sun4c_alloc_context(current->mm);
1248
                sun4c_set_context(current->mm->context);
1249
        }
1250
}
1251
 
1252
static void sun4c_exit_hook(void)
1253
{
1254
        struct ctx_list *ctx_old;
1255
        struct mm_struct *mm = current->mm;
1256
 
1257
        if(mm->context != NO_CONTEXT) {
1258
                sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
1259
                ctx_old = ctx_list_pool + mm->context;
1260
                remove_from_ctx_list(ctx_old);
1261
                add_to_free_ctxlist(ctx_old);
1262
                mm->context = NO_CONTEXT;
1263
        }
1264
}
1265
 
1266
static char s4cinfo[512];
1267
 
1268
static char *sun4c_mmu_info(void)
1269
{
1270
        int used_user_entries, i;
1271
 
1272
        used_user_entries = 0;
1273
        for(i=0; i < num_contexts; i++)
1274
                used_user_entries += sun4c_context_ring[i].num_entries;
1275
 
1276
        sprintf(s4cinfo, "vacsize\t\t: %d bytes\n"
1277
                "vachwflush\t: %s\n"
1278
                "vaclinesize\t: %d bytes\n"
1279
                "mmuctxs\t\t: %d\n"
1280
                "mmupsegs\t: %d\n"
1281
                "usedpsegs\t: %d\n"
1282
                "ufreepsegs\t: %d\n"
1283
                "context\t\t: %d flushes\n"
1284
                "segment\t\t: %d flushes\n"
1285
                "page\t\t: %d flushes\n",
1286
                sun4c_vacinfo.num_bytes,
1287
                (sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
1288
                sun4c_vacinfo.linesize,
1289
                num_contexts,
1290
                (invalid_segment + 1),
1291
                used_user_entries,
1292
                sun4c_ufree_ring.num_entries,
1293
                ctxflushes, segflushes, pageflushes);
1294
 
1295
        return s4cinfo;
1296
}
1297
 
1298
/* Nothing below here should touch the mmu hardware nor the mmu_entry
1299
 * data structures.
1300
 */
1301
 
1302
static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
1303
static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
1304
 
1305
/* First the functions which the mid-level code uses to directly
1306
 * manipulate the software page tables.  Some defines since we are
1307
 * emulating the i386 page directory layout.
1308
 */
1309
#define PGD_PRESENT  0x001
1310
#define PGD_RW       0x002
1311
#define PGD_USER     0x004
1312
#define PGD_ACCESSED 0x020
1313
#define PGD_DIRTY    0x040
1314
#define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
1315
 
1316
static unsigned long sun4c_vmalloc_start(void)
1317
{
1318
        return SUN4C_VMALLOC_START;
1319
}
1320
 
1321
static int sun4c_pte_none(pte_t pte)            { return !pte_val(pte); }
1322
static int sun4c_pte_present(pte_t pte)         { return pte_val(pte) & _SUN4C_PAGE_VALID; }
1323
static void sun4c_pte_clear(pte_t *ptep)        { pte_val(*ptep) = 0; }
1324
 
1325
static int sun4c_pmd_none(pmd_t pmd)            { return !pmd_val(pmd); }
1326
static int sun4c_pmd_bad(pmd_t pmd)
1327
{
1328
        return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
1329
}
1330
 
1331
static int sun4c_pmd_present(pmd_t pmd)         { return pmd_val(pmd) & PGD_PRESENT; }
1332
static void sun4c_pmd_clear(pmd_t *pmdp)        { pmd_val(*pmdp) = 0; }
1333
 
1334
static int sun4c_pgd_none(pgd_t pgd)            { return 0; }
1335
static int sun4c_pgd_bad(pgd_t pgd)             { return 0; }
1336
static int sun4c_pgd_present(pgd_t pgd)         { return 1; }
1337
static void sun4c_pgd_clear(pgd_t * pgdp)       { }
1338
 
1339
/*
1340
 * The following only work if pte_present() is true.
1341
 * Undefined behaviour if not..
1342
 */
1343
static int sun4c_pte_write(pte_t pte)           { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
1344
static int sun4c_pte_dirty(pte_t pte)           { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
1345
static int sun4c_pte_young(pte_t pte)           { return pte_val(pte) & _SUN4C_PAGE_REF; }
1346
 
1347
static pte_t sun4c_pte_wrprotect(pte_t pte)     { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
1348
static pte_t sun4c_pte_mkclean(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
1349
static pte_t sun4c_pte_mkold(pte_t pte)         { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
1350
static pte_t sun4c_pte_mkwrite(pte_t pte)       { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
1351
static pte_t sun4c_pte_mkdirty(pte_t pte)       { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
1352
static pte_t sun4c_pte_mkyoung(pte_t pte)       { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
1353
 
1354
/*
1355
 * Conversion functions: convert a page and protection to a page entry,
1356
 * and a page entry and page directory to the page they refer to.
1357
 */
1358
static pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
1359
{
1360
        return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
1361
}
1362
 
1363
static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
1364
{
1365
        return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
1366
}
1367
 
1368
static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
1369
{
1370
        return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
1371
}
1372
 
1373
static unsigned long sun4c_pte_page(pte_t pte)
1374
{
1375
        return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
1376
}
1377
 
1378
static unsigned long sun4c_pmd_page(pmd_t pmd)
1379
{
1380
        return (pmd_val(pmd) & PAGE_MASK);
1381
}
1382
 
1383
/* to find an entry in a page-table-directory */
1384
static pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
1385
{
1386
        return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
1387
}
1388
 
1389
/* Find an entry in the second-level page table.. */
1390
static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
1391
{
1392
        return (pmd_t *) dir;
1393
}
1394
 
1395
/* Find an entry in the third-level page table.. */
1396
static pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
1397
{
1398
        return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
1399
}
1400
 
1401
/* Update the root mmu directory. */
1402
static void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
1403
{
1404
}
1405
 
1406
/* Allocate and free page tables. The xxx_kernel() versions are
1407
 * used to allocate a kernel page table - this turns on ASN bits
1408
 * if any, and marks the page tables reserved.
1409
 */
1410
static void sun4c_pte_free_kernel(pte_t *pte)
1411
{
1412
        free_page((unsigned long) pte);
1413
}
1414
 
1415
static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
1416
{
1417
        address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
1418
        if (sun4c_pmd_none(*pmd)) {
1419
                pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
1420
                if (sun4c_pmd_none(*pmd)) {
1421
                        if (page) {
1422
                                pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
1423
                                return page + address;
1424
                        }
1425
                        pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1426
                        return NULL;
1427
                }
1428
                free_page((unsigned long) page);
1429
        }
1430
        if (sun4c_pmd_bad(*pmd)) {
1431
                printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
1432
                pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1433
                return NULL;
1434
        }
1435
        return (pte_t *) sun4c_pmd_page(*pmd) + address;
1436
}
1437
 
1438
/*
1439
 * allocating and freeing a pmd is trivial: the 1-entry pmd is
1440
 * inside the pgd, so has no extra memory associated with it.
1441
 */
1442
static void sun4c_pmd_free_kernel(pmd_t *pmd)
1443
{
1444
        pmd_val(*pmd) = 0;
1445
}
1446
 
1447
static pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
1448
{
1449
        return (pmd_t *) pgd;
1450
}
1451
 
1452
static void sun4c_pte_free(pte_t *pte)
1453
{
1454
        free_page((unsigned long) pte);
1455
}
1456
 
1457
static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
1458
{
1459
        address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
1460
        if (sun4c_pmd_none(*pmd)) {
1461
                pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
1462
                if (sun4c_pmd_none(*pmd)) {
1463
                        if (page) {
1464
                                pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
1465
                                return page + address;
1466
                        }
1467
                        pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1468
                        return NULL;
1469
                }
1470
                free_page((unsigned long) page);
1471
        }
1472
        if (sun4c_pmd_bad(*pmd)) {
1473
                printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
1474
                pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
1475
                return NULL;
1476
        }
1477
        return (pte_t *) sun4c_pmd_page(*pmd) + address;
1478
}
1479
 
1480
/*
1481
 * allocating and freeing a pmd is trivial: the 1-entry pmd is
1482
 * inside the pgd, so has no extra memory associated with it.
1483
 */
1484
static void sun4c_pmd_free(pmd_t * pmd)
1485
{
1486
        pmd_val(*pmd) = 0;
1487
}
1488
 
1489
static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
1490
{
1491
        return (pmd_t *) pgd;
1492
}
1493
 
1494
static void sun4c_pgd_free(pgd_t *pgd)
1495
{
1496
        free_page((unsigned long) pgd);
1497
}
1498
 
1499
static pgd_t *sun4c_pgd_alloc(void)
1500
{
1501
        return (pgd_t *) get_free_page(GFP_KERNEL);
1502
}
1503
 
1504
#define SUN4C_KERNEL_BUCKETS   16
1505
extern unsigned long free_area_init(unsigned long, unsigned long);
1506
extern unsigned long sparc_context_init(unsigned long, int);
1507
extern unsigned long end;
1508
 
1509
unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
1510
{
1511
        int i, cnt;
1512
        unsigned long kernel_end;
1513
 
1514
        kernel_end = (unsigned long) &end;
1515
        kernel_end += (SUN4C_REAL_PGDIR_SIZE * 3);
1516
        kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
1517
        sun4c_probe_mmu();
1518
        invalid_segment = (num_segmaps - 1);
1519
        sun4c_init_mmu_entry_pool();
1520
        sun4c_init_rings();
1521
        sun4c_init_map_kernelprom(kernel_end);
1522
        sun4c_init_clean_mmu(kernel_end);
1523
        sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS);
1524
        sun4c_init_lock_area(IOBASE_VADDR, IOBASE_END);
1525
        sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
1526
        start_mem = sun4c_init_lock_areas(start_mem);
1527
        sun4c_init_fill_user_ring();
1528
 
1529
        sun4c_set_context(0);
1530
        memset(swapper_pg_dir, 0, PAGE_SIZE);
1531
        memset(pg0, 0, PAGE_SIZE);
1532
        /* Save work later. */
1533
        pgd_val(swapper_pg_dir[SUN4C_VMALLOC_START>>SUN4C_PGDIR_SHIFT]) =
1534
                PGD_TABLE | (unsigned long) pg0;
1535
        sun4c_init_ss2_cache_bug();
1536
        start_mem = PAGE_ALIGN(start_mem);
1537
        start_mem = sun4c_init_alloc_dvma_pages(start_mem);
1538
        start_mem = sparc_context_init(start_mem, num_contexts);
1539
        start_mem = free_area_init(start_mem, end_mem);
1540
        cnt = 0;
1541
        for(i = 0; i < num_segmaps; i++)
1542
                if(mmu_entry_pool[i].locked)
1543
                        cnt++;
1544
        printk("SUN4C: %d mmu entries for the kernel\n", cnt);
1545
        return start_mem;
1546
}
1547
 
1548
/* Load up routines and constants for sun4c mmu */
1549
void ld_mmu_sun4c(void)
1550
{
1551
        printk("Loading sun4c MMU routines\n");
1552
 
1553
        /* First the constants */
1554
        pmd_shift = SUN4C_PMD_SHIFT;
1555
        pmd_size = SUN4C_PMD_SIZE;
1556
        pmd_mask = SUN4C_PMD_MASK;
1557
        pgdir_shift = SUN4C_PGDIR_SHIFT;
1558
        pgdir_size = SUN4C_PGDIR_SIZE;
1559
        pgdir_mask = SUN4C_PGDIR_MASK;
1560
 
1561
        ptrs_per_pte = SUN4C_PTRS_PER_PTE;
1562
        ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
1563
        ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
1564
 
1565
        page_none = SUN4C_PAGE_NONE;
1566
        page_shared = SUN4C_PAGE_SHARED;
1567
        page_copy = SUN4C_PAGE_COPY;
1568
        page_readonly = SUN4C_PAGE_READONLY;
1569
        page_kernel = SUN4C_PAGE_KERNEL;
1570
        pg_iobits = _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO | _SUN4C_PAGE_VALID
1571
            | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_DIRTY;
1572
 
1573
        /* Functions */
1574
#ifndef __SMP__
1575
        flush_cache_all = sun4c_flush_cache_all;
1576
        flush_cache_mm = sun4c_flush_cache_mm;
1577
        flush_cache_range = sun4c_flush_cache_range;
1578
        flush_cache_page = sun4c_flush_cache_page;
1579
 
1580
        flush_tlb_all = sun4c_flush_tlb_all;
1581
        flush_tlb_mm = sun4c_flush_tlb_mm;
1582
        flush_tlb_range = sun4c_flush_tlb_range;
1583
        flush_tlb_page = sun4c_flush_tlb_page;
1584
#else
1585
        local_flush_cache_all = sun4c_flush_cache_all;
1586
        local_flush_cache_mm = sun4c_flush_cache_mm;
1587
        local_flush_cache_range = sun4c_flush_cache_range;
1588
        local_flush_cache_page = sun4c_flush_cache_page;
1589
 
1590
        local_flush_tlb_all = sun4c_flush_tlb_all;
1591
        local_flush_tlb_mm = sun4c_flush_tlb_mm;
1592
        local_flush_tlb_range = sun4c_flush_tlb_range;
1593
        local_flush_tlb_page = sun4c_flush_tlb_page;
1594
 
1595
        flush_cache_all = smp_flush_cache_all;
1596
        flush_cache_mm = smp_flush_cache_mm;
1597
        flush_cache_range = smp_flush_cache_range;
1598
        flush_cache_page = smp_flush_cache_page;
1599
 
1600
        flush_tlb_all = smp_flush_tlb_all;
1601
        flush_tlb_mm = smp_flush_tlb_mm;
1602
        flush_tlb_range = smp_flush_tlb_range;
1603
        flush_tlb_page = smp_flush_tlb_page;
1604
#endif
1605
 
1606
        flush_page_to_ram = sun4c_flush_page_to_ram;
1607
 
1608
        set_pte = sun4c_set_pte;
1609
        switch_to_context = sun4c_switch_to_context;
1610
        pmd_align = sun4c_pmd_align;
1611
        pgdir_align = sun4c_pgdir_align;
1612
        vmalloc_start = sun4c_vmalloc_start;
1613
 
1614
        pte_page = sun4c_pte_page;
1615
        pmd_page = sun4c_pmd_page;
1616
 
1617
        sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
1618
 
1619
        pte_none = sun4c_pte_none;
1620
        pte_present = sun4c_pte_present;
1621
        pte_clear = sun4c_pte_clear;
1622
 
1623
        pmd_none = sun4c_pmd_none;
1624
        pmd_bad = sun4c_pmd_bad;
1625
        pmd_present = sun4c_pmd_present;
1626
        pmd_clear = sun4c_pmd_clear;
1627
 
1628
        pgd_none = sun4c_pgd_none;
1629
        pgd_bad = sun4c_pgd_bad;
1630
        pgd_present = sun4c_pgd_present;
1631
        pgd_clear = sun4c_pgd_clear;
1632
 
1633
        mk_pte = sun4c_mk_pte;
1634
        mk_pte_io = sun4c_mk_pte_io;
1635
        pte_modify = sun4c_pte_modify;
1636
        pgd_offset = sun4c_pgd_offset;
1637
        pmd_offset = sun4c_pmd_offset;
1638
        pte_offset = sun4c_pte_offset;
1639
        pte_free_kernel = sun4c_pte_free_kernel;
1640
        pmd_free_kernel = sun4c_pmd_free_kernel;
1641
        pte_alloc_kernel = sun4c_pte_alloc_kernel;
1642
        pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
1643
        pte_free = sun4c_pte_free;
1644
        pte_alloc = sun4c_pte_alloc;
1645
        pmd_free = sun4c_pmd_free;
1646
        pmd_alloc = sun4c_pmd_alloc;
1647
        pgd_free = sun4c_pgd_free;
1648
        pgd_alloc = sun4c_pgd_alloc;
1649
 
1650
        pte_write = sun4c_pte_write;
1651
        pte_dirty = sun4c_pte_dirty;
1652
        pte_young = sun4c_pte_young;
1653
        pte_wrprotect = sun4c_pte_wrprotect;
1654
        pte_mkclean = sun4c_pte_mkclean;
1655
        pte_mkold = sun4c_pte_mkold;
1656
        pte_mkwrite = sun4c_pte_mkwrite;
1657
        pte_mkdirty = sun4c_pte_mkdirty;
1658
        pte_mkyoung = sun4c_pte_mkyoung;
1659
        update_mmu_cache = sun4c_update_mmu_cache;
1660
        mmu_exit_hook = sun4c_exit_hook;
1661
        mmu_flush_hook = sun4c_flush_hook;
1662
        mmu_lockarea = sun4c_lockarea;
1663
        mmu_unlockarea = sun4c_unlockarea;
1664
 
1665
        mmu_get_scsi_one = sun4c_get_scsi_one;
1666
        mmu_get_scsi_sgl = sun4c_get_scsi_sgl;
1667
        mmu_release_scsi_one = sun4c_release_scsi_one;
1668
        mmu_release_scsi_sgl = sun4c_release_scsi_sgl;
1669
 
1670
        mmu_v2p = sun4c_v2p;
1671
        mmu_p2v = sun4c_p2v;
1672
 
1673
        /* Task struct and kernel stack allocating/freeing. */
1674
        alloc_kernel_stack = sun4c_alloc_kernel_stack;
1675
        alloc_task_struct = sun4c_alloc_task_struct;
1676
        free_kernel_stack = sun4c_free_kernel_stack;
1677
        free_task_struct = sun4c_free_task_struct;
1678
 
1679
        quick_kernel_fault = sun4c_quick_kernel_fault;
1680
        mmu_info = sun4c_mmu_info;
1681
 
1682
        /* These should _never_ get called with two level tables. */
1683
        pgd_set = 0;
1684
        pgd_page = 0;
1685
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.