~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/staging/gma500/psb_mmu.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**************************************************************************
 
2
 * Copyright (c) 2007, Intel Corporation.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms and conditions of the GNU General Public License,
 
6
 * version 2, as published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope it will be useful, but WITHOUT
 
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
10
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
11
 * more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along with
 
14
 * this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
16
 *
 
17
 **************************************************************************/
 
18
#include <drm/drmP.h>
 
19
#include "psb_drv.h"
 
20
#include "psb_reg.h"
 
21
 
 
22
/*
 
23
 * Code for the SGX MMU:
 
24
 */
 
25
 
 
26
/*
 
27
 * clflush on one processor only:
 
28
 * clflush should apparently flush the cache line on all processors in an
 
29
 * SMP system.
 
30
 */
 
31
 
 
32
/*
 
33
 * kmap atomic:
 
34
 * The usage of the slots must be completely encapsulated within a spinlock, and
 
35
 * no other functions that may be using the locks for other purposed may be
 
36
 * called from within the locked region.
 
37
 * Since the slots are per processor, this will guarantee that we are the only
 
38
 * user.
 
39
 */
 
40
 
 
41
/*
 
42
 * TODO: Inserting ptes from an interrupt handler:
 
43
 * This may be desirable for some SGX functionality where the GPU can fault in
 
44
 * needed pages. For that, we need to make an atomic insert_pages function, that
 
45
 * may fail.
 
46
 * If it fails, the caller need to insert the page using a workqueue function,
 
47
 * but on average it should be fast.
 
48
 */
 
49
 
 
50
struct psb_mmu_driver {
 
51
        /* protects driver- and pd structures. Always take in read mode
 
52
         * before taking the page table spinlock.
 
53
         */
 
54
        struct rw_semaphore sem;
 
55
 
 
56
        /* protects page tables, directory tables and pt tables.
 
57
         * and pt structures.
 
58
         */
 
59
        spinlock_t lock;
 
60
 
 
61
        atomic_t needs_tlbflush;
 
62
 
 
63
        uint8_t __iomem *register_map;
 
64
        struct psb_mmu_pd *default_pd;
 
65
        /*uint32_t bif_ctrl;*/
 
66
        int has_clflush;
 
67
        int clflush_add;
 
68
        unsigned long clflush_mask;
 
69
 
 
70
        struct drm_psb_private *dev_priv;
 
71
};
 
72
 
 
73
struct psb_mmu_pd;
 
74
 
 
75
struct psb_mmu_pt {
 
76
        struct psb_mmu_pd *pd;
 
77
        uint32_t index;
 
78
        uint32_t count;
 
79
        struct page *p;
 
80
        uint32_t *v;
 
81
};
 
82
 
 
83
struct psb_mmu_pd {
 
84
        struct psb_mmu_driver *driver;
 
85
        int hw_context;
 
86
        struct psb_mmu_pt **tables;
 
87
        struct page *p;
 
88
        struct page *dummy_pt;
 
89
        struct page *dummy_page;
 
90
        uint32_t pd_mask;
 
91
        uint32_t invalid_pde;
 
92
        uint32_t invalid_pte;
 
93
};
 
94
 
 
95
static inline uint32_t psb_mmu_pt_index(uint32_t offset)
 
96
{
 
97
        return (offset >> PSB_PTE_SHIFT) & 0x3FF;
 
98
}
 
99
 
 
100
static inline uint32_t psb_mmu_pd_index(uint32_t offset)
 
101
{
 
102
        return offset >> PSB_PDE_SHIFT;
 
103
}
 
104
 
 
105
static inline void psb_clflush(void *addr)
 
106
{
 
107
        __asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory");
 
108
}
 
109
 
 
110
static inline void psb_mmu_clflush(struct psb_mmu_driver *driver,
 
111
                                   void *addr)
 
112
{
 
113
        if (!driver->has_clflush)
 
114
                return;
 
115
 
 
116
        mb();
 
117
        psb_clflush(addr);
 
118
        mb();
 
119
}
 
120
 
 
121
static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page)
 
122
{
 
123
        uint32_t clflush_add = driver->clflush_add >> PAGE_SHIFT;
 
124
        uint32_t clflush_count = PAGE_SIZE / clflush_add;
 
125
        int i;
 
126
        uint8_t *clf;
 
127
 
 
128
        clf = kmap_atomic(page, KM_USER0);
 
129
        mb();
 
130
        for (i = 0; i < clflush_count; ++i) {
 
131
                psb_clflush(clf);
 
132
                clf += clflush_add;
 
133
        }
 
134
        mb();
 
135
        kunmap_atomic(clf, KM_USER0);
 
136
}
 
137
 
 
138
static void psb_pages_clflush(struct psb_mmu_driver *driver,
 
139
                                struct page *page[], unsigned long num_pages)
 
140
{
 
141
        int i;
 
142
 
 
143
        if (!driver->has_clflush)
 
144
                return ;
 
145
 
 
146
        for (i = 0; i < num_pages; i++)
 
147
                psb_page_clflush(driver, *page++);
 
148
}
 
149
 
 
150
static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver,
 
151
                                    int force)
 
152
{
 
153
        atomic_set(&driver->needs_tlbflush, 0);
 
154
}
 
155
 
 
156
static void psb_mmu_flush_pd(struct psb_mmu_driver *driver, int force)
 
157
{
 
158
        down_write(&driver->sem);
 
159
        psb_mmu_flush_pd_locked(driver, force);
 
160
        up_write(&driver->sem);
 
161
}
 
162
 
 
163
void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot)
 
164
{
 
165
        if (rc_prot)
 
166
                down_write(&driver->sem);
 
167
        if (rc_prot)
 
168
                up_write(&driver->sem);
 
169
}
 
170
 
 
171
void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context)
 
172
{
 
173
        /*ttm_tt_cache_flush(&pd->p, 1);*/
 
174
        psb_pages_clflush(pd->driver, &pd->p, 1);
 
175
        down_write(&pd->driver->sem);
 
176
        wmb();
 
177
        psb_mmu_flush_pd_locked(pd->driver, 1);
 
178
        pd->hw_context = hw_context;
 
179
        up_write(&pd->driver->sem);
 
180
 
 
181
}
 
182
 
 
183
static inline unsigned long psb_pd_addr_end(unsigned long addr,
 
184
                                            unsigned long end)
 
185
{
 
186
 
 
187
        addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK;
 
188
        return (addr < end) ? addr : end;
 
189
}
 
190
 
 
191
static inline uint32_t psb_mmu_mask_pte(uint32_t pfn, int type)
 
192
{
 
193
        uint32_t mask = PSB_PTE_VALID;
 
194
 
 
195
        if (type & PSB_MMU_CACHED_MEMORY)
 
196
                mask |= PSB_PTE_CACHED;
 
197
        if (type & PSB_MMU_RO_MEMORY)
 
198
                mask |= PSB_PTE_RO;
 
199
        if (type & PSB_MMU_WO_MEMORY)
 
200
                mask |= PSB_PTE_WO;
 
201
 
 
202
        return (pfn << PAGE_SHIFT) | mask;
 
203
}
 
204
 
 
205
struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver,
 
206
                                    int trap_pagefaults, int invalid_type)
 
207
{
 
208
        struct psb_mmu_pd *pd = kmalloc(sizeof(*pd), GFP_KERNEL);
 
209
        uint32_t *v;
 
210
        int i;
 
211
 
 
212
        if (!pd)
 
213
                return NULL;
 
214
 
 
215
        pd->p = alloc_page(GFP_DMA32);
 
216
        if (!pd->p)
 
217
                goto out_err1;
 
218
        pd->dummy_pt = alloc_page(GFP_DMA32);
 
219
        if (!pd->dummy_pt)
 
220
                goto out_err2;
 
221
        pd->dummy_page = alloc_page(GFP_DMA32);
 
222
        if (!pd->dummy_page)
 
223
                goto out_err3;
 
224
 
 
225
        if (!trap_pagefaults) {
 
226
                pd->invalid_pde =
 
227
                    psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt),
 
228
                                     invalid_type);
 
229
                pd->invalid_pte =
 
230
                    psb_mmu_mask_pte(page_to_pfn(pd->dummy_page),
 
231
                                     invalid_type);
 
232
        } else {
 
233
                pd->invalid_pde = 0;
 
234
                pd->invalid_pte = 0;
 
235
        }
 
236
 
 
237
        v = kmap(pd->dummy_pt);
 
238
        for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i)
 
239
                v[i] = pd->invalid_pte;
 
240
 
 
241
        kunmap(pd->dummy_pt);
 
242
 
 
243
        v = kmap(pd->p);
 
244
        for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i)
 
245
                v[i] = pd->invalid_pde;
 
246
 
 
247
        kunmap(pd->p);
 
248
 
 
249
        clear_page(kmap(pd->dummy_page));
 
250
        kunmap(pd->dummy_page);
 
251
 
 
252
        pd->tables = vmalloc_user(sizeof(struct psb_mmu_pt *) * 1024);
 
253
        if (!pd->tables)
 
254
                goto out_err4;
 
255
 
 
256
        pd->hw_context = -1;
 
257
        pd->pd_mask = PSB_PTE_VALID;
 
258
        pd->driver = driver;
 
259
 
 
260
        return pd;
 
261
 
 
262
out_err4:
 
263
        __free_page(pd->dummy_page);
 
264
out_err3:
 
265
        __free_page(pd->dummy_pt);
 
266
out_err2:
 
267
        __free_page(pd->p);
 
268
out_err1:
 
269
        kfree(pd);
 
270
        return NULL;
 
271
}
 
272
 
 
273
void psb_mmu_free_pt(struct psb_mmu_pt *pt)
 
274
{
 
275
        __free_page(pt->p);
 
276
        kfree(pt);
 
277
}
 
278
 
 
279
void psb_mmu_free_pagedir(struct psb_mmu_pd *pd)
 
280
{
 
281
        struct psb_mmu_driver *driver = pd->driver;
 
282
        struct psb_mmu_pt *pt;
 
283
        int i;
 
284
 
 
285
        down_write(&driver->sem);
 
286
        if (pd->hw_context != -1)
 
287
                psb_mmu_flush_pd_locked(driver, 1);
 
288
 
 
289
        /* Should take the spinlock here, but we don't need to do that
 
290
           since we have the semaphore in write mode. */
 
291
 
 
292
        for (i = 0; i < 1024; ++i) {
 
293
                pt = pd->tables[i];
 
294
                if (pt)
 
295
                        psb_mmu_free_pt(pt);
 
296
        }
 
297
 
 
298
        vfree(pd->tables);
 
299
        __free_page(pd->dummy_page);
 
300
        __free_page(pd->dummy_pt);
 
301
        __free_page(pd->p);
 
302
        kfree(pd);
 
303
        up_write(&driver->sem);
 
304
}
 
305
 
 
306
static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
 
307
{
 
308
        struct psb_mmu_pt *pt = kmalloc(sizeof(*pt), GFP_KERNEL);
 
309
        void *v;
 
310
        uint32_t clflush_add = pd->driver->clflush_add >> PAGE_SHIFT;
 
311
        uint32_t clflush_count = PAGE_SIZE / clflush_add;
 
312
        spinlock_t *lock = &pd->driver->lock;
 
313
        uint8_t *clf;
 
314
        uint32_t *ptes;
 
315
        int i;
 
316
 
 
317
        if (!pt)
 
318
                return NULL;
 
319
 
 
320
        pt->p = alloc_page(GFP_DMA32);
 
321
        if (!pt->p) {
 
322
                kfree(pt);
 
323
                return NULL;
 
324
        }
 
325
 
 
326
        spin_lock(lock);
 
327
 
 
328
        v = kmap_atomic(pt->p, KM_USER0);
 
329
        clf = (uint8_t *) v;
 
330
        ptes = (uint32_t *) v;
 
331
        for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i)
 
332
                *ptes++ = pd->invalid_pte;
 
333
 
 
334
 
 
335
        if (pd->driver->has_clflush && pd->hw_context != -1) {
 
336
                mb();
 
337
                for (i = 0; i < clflush_count; ++i) {
 
338
                        psb_clflush(clf);
 
339
                        clf += clflush_add;
 
340
                }
 
341
                mb();
 
342
        }
 
343
 
 
344
        kunmap_atomic(v, KM_USER0);
 
345
        spin_unlock(lock);
 
346
 
 
347
        pt->count = 0;
 
348
        pt->pd = pd;
 
349
        pt->index = 0;
 
350
 
 
351
        return pt;
 
352
}
 
353
 
 
354
struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
 
355
                                             unsigned long addr)
 
356
{
 
357
        uint32_t index = psb_mmu_pd_index(addr);
 
358
        struct psb_mmu_pt *pt;
 
359
        uint32_t *v;
 
360
        spinlock_t *lock = &pd->driver->lock;
 
361
 
 
362
        spin_lock(lock);
 
363
        pt = pd->tables[index];
 
364
        while (!pt) {
 
365
                spin_unlock(lock);
 
366
                pt = psb_mmu_alloc_pt(pd);
 
367
                if (!pt)
 
368
                        return NULL;
 
369
                spin_lock(lock);
 
370
 
 
371
                if (pd->tables[index]) {
 
372
                        spin_unlock(lock);
 
373
                        psb_mmu_free_pt(pt);
 
374
                        spin_lock(lock);
 
375
                        pt = pd->tables[index];
 
376
                        continue;
 
377
                }
 
378
 
 
379
                v = kmap_atomic(pd->p, KM_USER0);
 
380
                pd->tables[index] = pt;
 
381
                v[index] = (page_to_pfn(pt->p) << 12) | pd->pd_mask;
 
382
                pt->index = index;
 
383
                kunmap_atomic((void *) v, KM_USER0);
 
384
 
 
385
                if (pd->hw_context != -1) {
 
386
                        psb_mmu_clflush(pd->driver, (void *) &v[index]);
 
387
                        atomic_set(&pd->driver->needs_tlbflush, 1);
 
388
                }
 
389
        }
 
390
        pt->v = kmap_atomic(pt->p, KM_USER0);
 
391
        return pt;
 
392
}
 
393
 
 
394
static struct psb_mmu_pt *psb_mmu_pt_map_lock(struct psb_mmu_pd *pd,
 
395
                                              unsigned long addr)
 
396
{
 
397
        uint32_t index = psb_mmu_pd_index(addr);
 
398
        struct psb_mmu_pt *pt;
 
399
        spinlock_t *lock = &pd->driver->lock;
 
400
 
 
401
        spin_lock(lock);
 
402
        pt = pd->tables[index];
 
403
        if (!pt) {
 
404
                spin_unlock(lock);
 
405
                return NULL;
 
406
        }
 
407
        pt->v = kmap_atomic(pt->p, KM_USER0);
 
408
        return pt;
 
409
}
 
410
 
 
411
static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt)
 
412
{
 
413
        struct psb_mmu_pd *pd = pt->pd;
 
414
        uint32_t *v;
 
415
 
 
416
        kunmap_atomic(pt->v, KM_USER0);
 
417
        if (pt->count == 0) {
 
418
                v = kmap_atomic(pd->p, KM_USER0);
 
419
                v[pt->index] = pd->invalid_pde;
 
420
                pd->tables[pt->index] = NULL;
 
421
 
 
422
                if (pd->hw_context != -1) {
 
423
                        psb_mmu_clflush(pd->driver,
 
424
                                        (void *) &v[pt->index]);
 
425
                        atomic_set(&pd->driver->needs_tlbflush, 1);
 
426
                }
 
427
                kunmap_atomic(pt->v, KM_USER0);
 
428
                spin_unlock(&pd->driver->lock);
 
429
                psb_mmu_free_pt(pt);
 
430
                return;
 
431
        }
 
432
        spin_unlock(&pd->driver->lock);
 
433
}
 
434
 
 
435
static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt,
 
436
                                   unsigned long addr, uint32_t pte)
 
437
{
 
438
        pt->v[psb_mmu_pt_index(addr)] = pte;
 
439
}
 
440
 
 
441
static inline void psb_mmu_invalidate_pte(struct psb_mmu_pt *pt,
 
442
                                          unsigned long addr)
 
443
{
 
444
        pt->v[psb_mmu_pt_index(addr)] = pt->pd->invalid_pte;
 
445
}
 
446
 
 
447
 
 
448
void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd,
 
449
                        uint32_t mmu_offset, uint32_t gtt_start,
 
450
                        uint32_t gtt_pages)
 
451
{
 
452
        uint32_t *v;
 
453
        uint32_t start = psb_mmu_pd_index(mmu_offset);
 
454
        struct psb_mmu_driver *driver = pd->driver;
 
455
        int num_pages = gtt_pages;
 
456
 
 
457
        down_read(&driver->sem);
 
458
        spin_lock(&driver->lock);
 
459
 
 
460
        v = kmap_atomic(pd->p, KM_USER0);
 
461
        v += start;
 
462
 
 
463
        while (gtt_pages--) {
 
464
                *v++ = gtt_start | pd->pd_mask;
 
465
                gtt_start += PAGE_SIZE;
 
466
        }
 
467
 
 
468
        /*ttm_tt_cache_flush(&pd->p, num_pages);*/
 
469
        psb_pages_clflush(pd->driver, &pd->p, num_pages);
 
470
        kunmap_atomic(v, KM_USER0);
 
471
        spin_unlock(&driver->lock);
 
472
 
 
473
        if (pd->hw_context != -1)
 
474
                atomic_set(&pd->driver->needs_tlbflush, 1);
 
475
 
 
476
        up_read(&pd->driver->sem);
 
477
        psb_mmu_flush_pd(pd->driver, 0);
 
478
}
 
479
 
 
480
struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver)
 
481
{
 
482
        struct psb_mmu_pd *pd;
 
483
 
 
484
        /* down_read(&driver->sem); */
 
485
        pd = driver->default_pd;
 
486
        /* up_read(&driver->sem); */
 
487
 
 
488
        return pd;
 
489
}
 
490
 
 
491
/* Returns the physical address of the PD shared by sgx/msvdx */
 
492
uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver)
 
493
{
 
494
        struct psb_mmu_pd *pd;
 
495
 
 
496
        pd = psb_mmu_get_default_pd(driver);
 
497
        return page_to_pfn(pd->p) << PAGE_SHIFT;
 
498
}
 
499
 
 
500
void psb_mmu_driver_takedown(struct psb_mmu_driver *driver)
 
501
{
 
502
        psb_mmu_free_pagedir(driver->default_pd);
 
503
        kfree(driver);
 
504
}
 
505
 
 
506
struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
 
507
                                        int trap_pagefaults,
 
508
                                        int invalid_type,
 
509
                                        struct drm_psb_private *dev_priv)
 
510
{
 
511
        struct psb_mmu_driver *driver;
 
512
 
 
513
        driver = kmalloc(sizeof(*driver), GFP_KERNEL);
 
514
 
 
515
        if (!driver)
 
516
                return NULL;
 
517
        driver->dev_priv = dev_priv;
 
518
 
 
519
        driver->default_pd = psb_mmu_alloc_pd(driver, trap_pagefaults,
 
520
                                              invalid_type);
 
521
        if (!driver->default_pd)
 
522
                goto out_err1;
 
523
 
 
524
        spin_lock_init(&driver->lock);
 
525
        init_rwsem(&driver->sem);
 
526
        down_write(&driver->sem);
 
527
        driver->register_map = registers;
 
528
        atomic_set(&driver->needs_tlbflush, 1);
 
529
 
 
530
        driver->has_clflush = 0;
 
531
 
 
532
        if (boot_cpu_has(X86_FEATURE_CLFLSH)) {
 
533
                uint32_t tfms, misc, cap0, cap4, clflush_size;
 
534
 
 
535
                /*
 
536
                 * clflush size is determined at kernel setup for x86_64
 
537
                 *  but not for i386. We have to do it here.
 
538
                 */
 
539
 
 
540
                cpuid(0x00000001, &tfms, &misc, &cap0, &cap4);
 
541
                clflush_size = ((misc >> 8) & 0xff) * 8;
 
542
                driver->has_clflush = 1;
 
543
                driver->clflush_add =
 
544
                    PAGE_SIZE * clflush_size / sizeof(uint32_t);
 
545
                driver->clflush_mask = driver->clflush_add - 1;
 
546
                driver->clflush_mask = ~driver->clflush_mask;
 
547
        }
 
548
 
 
549
        up_write(&driver->sem);
 
550
        return driver;
 
551
 
 
552
out_err1:
 
553
        kfree(driver);
 
554
        return NULL;
 
555
}
 
556
 
 
557
static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd,
 
558
                               unsigned long address, uint32_t num_pages,
 
559
                               uint32_t desired_tile_stride,
 
560
                               uint32_t hw_tile_stride)
 
561
{
 
562
        struct psb_mmu_pt *pt;
 
563
        uint32_t rows = 1;
 
564
        uint32_t i;
 
565
        unsigned long addr;
 
566
        unsigned long end;
 
567
        unsigned long next;
 
568
        unsigned long add;
 
569
        unsigned long row_add;
 
570
        unsigned long clflush_add = pd->driver->clflush_add;
 
571
        unsigned long clflush_mask = pd->driver->clflush_mask;
 
572
 
 
573
        if (!pd->driver->has_clflush) {
 
574
                /*ttm_tt_cache_flush(&pd->p, num_pages);*/
 
575
                psb_pages_clflush(pd->driver, &pd->p, num_pages);
 
576
                return;
 
577
        }
 
578
 
 
579
        if (hw_tile_stride)
 
580
                rows = num_pages / desired_tile_stride;
 
581
        else
 
582
                desired_tile_stride = num_pages;
 
583
 
 
584
        add = desired_tile_stride << PAGE_SHIFT;
 
585
        row_add = hw_tile_stride << PAGE_SHIFT;
 
586
        mb();
 
587
        for (i = 0; i < rows; ++i) {
 
588
 
 
589
                addr = address;
 
590
                end = addr + add;
 
591
 
 
592
                do {
 
593
                        next = psb_pd_addr_end(addr, end);
 
594
                        pt = psb_mmu_pt_map_lock(pd, addr);
 
595
                        if (!pt)
 
596
                                continue;
 
597
                        do {
 
598
                                psb_clflush(&pt->v
 
599
                                            [psb_mmu_pt_index(addr)]);
 
600
                        } while (addr +=
 
601
                                 clflush_add,
 
602
                                 (addr & clflush_mask) < next);
 
603
 
 
604
                        psb_mmu_pt_unmap_unlock(pt);
 
605
                } while (addr = next, next != end);
 
606
                address += row_add;
 
607
        }
 
608
        mb();
 
609
}
 
610
 
 
611
void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd,
 
612
                                 unsigned long address, uint32_t num_pages)
 
613
{
 
614
        struct psb_mmu_pt *pt;
 
615
        unsigned long addr;
 
616
        unsigned long end;
 
617
        unsigned long next;
 
618
        unsigned long f_address = address;
 
619
 
 
620
        down_read(&pd->driver->sem);
 
621
 
 
622
        addr = address;
 
623
        end = addr + (num_pages << PAGE_SHIFT);
 
624
 
 
625
        do {
 
626
                next = psb_pd_addr_end(addr, end);
 
627
                pt = psb_mmu_pt_alloc_map_lock(pd, addr);
 
628
                if (!pt)
 
629
                        goto out;
 
630
                do {
 
631
                        psb_mmu_invalidate_pte(pt, addr);
 
632
                        --pt->count;
 
633
                } while (addr += PAGE_SIZE, addr < next);
 
634
                psb_mmu_pt_unmap_unlock(pt);
 
635
 
 
636
        } while (addr = next, next != end);
 
637
 
 
638
out:
 
639
        if (pd->hw_context != -1)
 
640
                psb_mmu_flush_ptes(pd, f_address, num_pages, 1, 1);
 
641
 
 
642
        up_read(&pd->driver->sem);
 
643
 
 
644
        if (pd->hw_context != -1)
 
645
                psb_mmu_flush(pd->driver, 0);
 
646
 
 
647
        return;
 
648
}
 
649
 
 
650
void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address,
 
651
                          uint32_t num_pages, uint32_t desired_tile_stride,
 
652
                          uint32_t hw_tile_stride)
 
653
{
 
654
        struct psb_mmu_pt *pt;
 
655
        uint32_t rows = 1;
 
656
        uint32_t i;
 
657
        unsigned long addr;
 
658
        unsigned long end;
 
659
        unsigned long next;
 
660
        unsigned long add;
 
661
        unsigned long row_add;
 
662
        unsigned long f_address = address;
 
663
 
 
664
        if (hw_tile_stride)
 
665
                rows = num_pages / desired_tile_stride;
 
666
        else
 
667
                desired_tile_stride = num_pages;
 
668
 
 
669
        add = desired_tile_stride << PAGE_SHIFT;
 
670
        row_add = hw_tile_stride << PAGE_SHIFT;
 
671
 
 
672
        /* down_read(&pd->driver->sem); */
 
673
 
 
674
        /* Make sure we only need to flush this processor's cache */
 
675
 
 
676
        for (i = 0; i < rows; ++i) {
 
677
 
 
678
                addr = address;
 
679
                end = addr + add;
 
680
 
 
681
                do {
 
682
                        next = psb_pd_addr_end(addr, end);
 
683
                        pt = psb_mmu_pt_map_lock(pd, addr);
 
684
                        if (!pt)
 
685
                                continue;
 
686
                        do {
 
687
                                psb_mmu_invalidate_pte(pt, addr);
 
688
                                --pt->count;
 
689
 
 
690
                        } while (addr += PAGE_SIZE, addr < next);
 
691
                        psb_mmu_pt_unmap_unlock(pt);
 
692
 
 
693
                } while (addr = next, next != end);
 
694
                address += row_add;
 
695
        }
 
696
        if (pd->hw_context != -1)
 
697
                psb_mmu_flush_ptes(pd, f_address, num_pages,
 
698
                                   desired_tile_stride, hw_tile_stride);
 
699
 
 
700
        /* up_read(&pd->driver->sem); */
 
701
 
 
702
        if (pd->hw_context != -1)
 
703
                psb_mmu_flush(pd->driver, 0);
 
704
}
 
705
 
 
706
int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn,
 
707
                                unsigned long address, uint32_t num_pages,
 
708
                                int type)
 
709
{
 
710
        struct psb_mmu_pt *pt;
 
711
        uint32_t pte;
 
712
        unsigned long addr;
 
713
        unsigned long end;
 
714
        unsigned long next;
 
715
        unsigned long f_address = address;
 
716
        int ret = 0;
 
717
 
 
718
        down_read(&pd->driver->sem);
 
719
 
 
720
        addr = address;
 
721
        end = addr + (num_pages << PAGE_SHIFT);
 
722
 
 
723
        do {
 
724
                next = psb_pd_addr_end(addr, end);
 
725
                pt = psb_mmu_pt_alloc_map_lock(pd, addr);
 
726
                if (!pt) {
 
727
                        ret = -ENOMEM;
 
728
                        goto out;
 
729
                }
 
730
                do {
 
731
                        pte = psb_mmu_mask_pte(start_pfn++, type);
 
732
                        psb_mmu_set_pte(pt, addr, pte);
 
733
                        pt->count++;
 
734
                } while (addr += PAGE_SIZE, addr < next);
 
735
                psb_mmu_pt_unmap_unlock(pt);
 
736
 
 
737
        } while (addr = next, next != end);
 
738
 
 
739
out:
 
740
        if (pd->hw_context != -1)
 
741
                psb_mmu_flush_ptes(pd, f_address, num_pages, 1, 1);
 
742
 
 
743
        up_read(&pd->driver->sem);
 
744
 
 
745
        if (pd->hw_context != -1)
 
746
                psb_mmu_flush(pd->driver, 1);
 
747
 
 
748
        return ret;
 
749
}
 
750
 
 
751
int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
 
752
                         unsigned long address, uint32_t num_pages,
 
753
                         uint32_t desired_tile_stride,
 
754
                         uint32_t hw_tile_stride, int type)
 
755
{
 
756
        struct psb_mmu_pt *pt;
 
757
        uint32_t rows = 1;
 
758
        uint32_t i;
 
759
        uint32_t pte;
 
760
        unsigned long addr;
 
761
        unsigned long end;
 
762
        unsigned long next;
 
763
        unsigned long add;
 
764
        unsigned long row_add;
 
765
        unsigned long f_address = address;
 
766
        int ret = 0;
 
767
 
 
768
        if (hw_tile_stride) {
 
769
                if (num_pages % desired_tile_stride != 0)
 
770
                        return -EINVAL;
 
771
                rows = num_pages / desired_tile_stride;
 
772
        } else {
 
773
                desired_tile_stride = num_pages;
 
774
        }
 
775
 
 
776
        add = desired_tile_stride << PAGE_SHIFT;
 
777
        row_add = hw_tile_stride << PAGE_SHIFT;
 
778
 
 
779
        down_read(&pd->driver->sem);
 
780
 
 
781
        for (i = 0; i < rows; ++i) {
 
782
 
 
783
                addr = address;
 
784
                end = addr + add;
 
785
 
 
786
                do {
 
787
                        next = psb_pd_addr_end(addr, end);
 
788
                        pt = psb_mmu_pt_alloc_map_lock(pd, addr);
 
789
                        if (!pt) {
 
790
                                ret = -ENOMEM;
 
791
                                goto out;
 
792
                        }
 
793
                        do {
 
794
                                pte =
 
795
                                    psb_mmu_mask_pte(page_to_pfn(*pages++),
 
796
                                                     type);
 
797
                                psb_mmu_set_pte(pt, addr, pte);
 
798
                                pt->count++;
 
799
                        } while (addr += PAGE_SIZE, addr < next);
 
800
                        psb_mmu_pt_unmap_unlock(pt);
 
801
 
 
802
                } while (addr = next, next != end);
 
803
 
 
804
                address += row_add;
 
805
        }
 
806
out:
 
807
        if (pd->hw_context != -1)
 
808
                psb_mmu_flush_ptes(pd, f_address, num_pages,
 
809
                                   desired_tile_stride, hw_tile_stride);
 
810
 
 
811
        up_read(&pd->driver->sem);
 
812
 
 
813
        if (pd->hw_context != -1)
 
814
                psb_mmu_flush(pd->driver, 1);
 
815
 
 
816
        return ret;
 
817
}
 
818
 
 
819
int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual,
 
820
                           unsigned long *pfn)
 
821
{
 
822
        int ret;
 
823
        struct psb_mmu_pt *pt;
 
824
        uint32_t tmp;
 
825
        spinlock_t *lock = &pd->driver->lock;
 
826
 
 
827
        down_read(&pd->driver->sem);
 
828
        pt = psb_mmu_pt_map_lock(pd, virtual);
 
829
        if (!pt) {
 
830
                uint32_t *v;
 
831
 
 
832
                spin_lock(lock);
 
833
                v = kmap_atomic(pd->p, KM_USER0);
 
834
                tmp = v[psb_mmu_pd_index(virtual)];
 
835
                kunmap_atomic(v, KM_USER0);
 
836
                spin_unlock(lock);
 
837
 
 
838
                if (tmp != pd->invalid_pde || !(tmp & PSB_PTE_VALID) ||
 
839
                    !(pd->invalid_pte & PSB_PTE_VALID)) {
 
840
                        ret = -EINVAL;
 
841
                        goto out;
 
842
                }
 
843
                ret = 0;
 
844
                *pfn = pd->invalid_pte >> PAGE_SHIFT;
 
845
                goto out;
 
846
        }
 
847
        tmp = pt->v[psb_mmu_pt_index(virtual)];
 
848
        if (!(tmp & PSB_PTE_VALID)) {
 
849
                ret = -EINVAL;
 
850
        } else {
 
851
                ret = 0;
 
852
                *pfn = tmp >> PAGE_SHIFT;
 
853
        }
 
854
        psb_mmu_pt_unmap_unlock(pt);
 
855
out:
 
856
        up_read(&pd->driver->sem);
 
857
        return ret;
 
858
}