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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [sparc/] [mm/] [io-unit.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/* $Id: io-unit.c,v 1.24 2001/12/17 07:05:09 davem Exp $
2
 * io-unit.c:  IO-UNIT specific routines for memory management.
3
 *
4
 * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
5
 */
6
 
7
#include <linux/kernel.h>
8
#include <linux/init.h>
9
#include <linux/slab.h>
10
#include <linux/spinlock.h>
11
#include <linux/mm.h>
12
#include <linux/highmem.h>      /* pte_offset_map => kmap_atomic */
13
#include <linux/bitops.h>
14
#include <linux/scatterlist.h>
15
 
16
#include <asm/pgalloc.h>
17
#include <asm/pgtable.h>
18
#include <asm/sbus.h>
19
#include <asm/io.h>
20
#include <asm/io-unit.h>
21
#include <asm/mxcc.h>
22
#include <asm/cacheflush.h>
23
#include <asm/tlbflush.h>
24
#include <asm/dma.h>
25
#include <asm/oplib.h>
26
 
27
/* #define IOUNIT_DEBUG */
28
#ifdef IOUNIT_DEBUG
29
#define IOD(x) printk(x)
30
#else
31
#define IOD(x) do { } while (0)
32
#endif
33
 
34
#define IOPERM        (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
35
#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
36
 
37
void __init
38
iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
39
{
40
        iopte_t *xpt, *xptend;
41
        struct iounit_struct *iounit;
42
        struct linux_prom_registers iommu_promregs[PROMREG_MAX];
43
        struct resource r;
44
 
45
        iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
46
        if (!iounit) {
47
                prom_printf("SUN4D: Cannot alloc iounit, halting.\n");
48
                prom_halt();
49
        }
50
 
51
        iounit->limit[0] = IOUNIT_BMAP1_START;
52
        iounit->limit[1] = IOUNIT_BMAP2_START;
53
        iounit->limit[2] = IOUNIT_BMAPM_START;
54
        iounit->limit[3] = IOUNIT_BMAPM_END;
55
        iounit->rotor[1] = IOUNIT_BMAP2_START;
56
        iounit->rotor[2] = IOUNIT_BMAPM_START;
57
 
58
        xpt = NULL;
59
        if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
60
                            sizeof(iommu_promregs)) != -1) {
61
                prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
62
                memset(&r, 0, sizeof(r));
63
                r.flags = iommu_promregs[2].which_io;
64
                r.start = iommu_promregs[2].phys_addr;
65
                xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
66
        }
67
        if(!xpt) panic("Cannot map External Page Table.");
68
 
69
        sbus->ofdev.dev.archdata.iommu = iounit;
70
        iounit->page_table = xpt;
71
        spin_lock_init(&iounit->lock);
72
 
73
        for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t);
74
             xpt < xptend;)
75
                iopte_val(*xpt++) = 0;
76
}
77
 
78
/* One has to hold iounit->lock to call this */
79
static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
80
{
81
        int i, j, k, npages;
82
        unsigned long rotor, scan, limit;
83
        iopte_t iopte;
84
 
85
        npages = ((vaddr & ~PAGE_MASK) + size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
86
 
87
        /* A tiny bit of magic ingredience :) */
88
        switch (npages) {
89
        case 1: i = 0x0231; break;
90
        case 2: i = 0x0132; break;
91
        default: i = 0x0213; break;
92
        }
93
 
94
        IOD(("iounit_get_area(%08lx,%d[%d])=", vaddr, size, npages));
95
 
96
next:   j = (i & 15);
97
        rotor = iounit->rotor[j - 1];
98
        limit = iounit->limit[j];
99
        scan = rotor;
100
nexti:  scan = find_next_zero_bit(iounit->bmap, limit, scan);
101
        if (scan + npages > limit) {
102
                if (limit != rotor) {
103
                        limit = rotor;
104
                        scan = iounit->limit[j - 1];
105
                        goto nexti;
106
                }
107
                i >>= 4;
108
                if (!(i & 15))
109
                        panic("iounit_get_area: Couldn't find free iopte slots for (%08lx,%d)\n", vaddr, size);
110
                goto next;
111
        }
112
        for (k = 1, scan++; k < npages; k++)
113
                if (test_bit(scan++, iounit->bmap))
114
                        goto nexti;
115
        iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
116
        scan -= npages;
117
        iopte = MKIOPTE(__pa(vaddr & PAGE_MASK));
118
        vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);
119
        for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {
120
                set_bit(scan, iounit->bmap);
121
                iounit->page_table[scan] = iopte;
122
        }
123
        IOD(("%08lx\n", vaddr));
124
        return vaddr;
125
}
126
 
127
static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
128
{
129
        unsigned long ret, flags;
130
        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
131
 
132
        spin_lock_irqsave(&iounit->lock, flags);
133
        ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
134
        spin_unlock_irqrestore(&iounit->lock, flags);
135
        return ret;
136
}
137
 
138
static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
139
{
140
        unsigned long flags;
141
        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
142
 
143
        /* FIXME: Cache some resolved pages - often several sg entries are to the same page */
144
        spin_lock_irqsave(&iounit->lock, flags);
145
        while (sz != 0) {
146
                --sz;
147
                sg->dvma_address = iounit_get_area(iounit, (unsigned long) sg_virt(sg), sg->length);
148
                sg->dvma_length = sg->length;
149
                sg = sg_next(sg);
150
        }
151
        spin_unlock_irqrestore(&iounit->lock, flags);
152
}
153
 
154
static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
155
{
156
        unsigned long flags;
157
        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
158
 
159
        spin_lock_irqsave(&iounit->lock, flags);
160
        len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
161
        vaddr = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
162
        IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
163
        for (len += vaddr; vaddr < len; vaddr++)
164
                clear_bit(vaddr, iounit->bmap);
165
        spin_unlock_irqrestore(&iounit->lock, flags);
166
}
167
 
168
static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
169
{
170
        unsigned long flags;
171
        unsigned long vaddr, len;
172
        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
173
 
174
        spin_lock_irqsave(&iounit->lock, flags);
175
        while (sz != 0) {
176
                --sz;
177
                len = ((sg->dvma_address & ~PAGE_MASK) + sg->length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
178
                vaddr = (sg->dvma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
179
                IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
180
                for (len += vaddr; vaddr < len; vaddr++)
181
                        clear_bit(vaddr, iounit->bmap);
182
                sg = sg_next(sg);
183
        }
184
        spin_unlock_irqrestore(&iounit->lock, flags);
185
}
186
 
187
#ifdef CONFIG_SBUS
188
static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
189
{
190
        unsigned long page, end;
191
        pgprot_t dvma_prot;
192
        iopte_t *iopte;
193
        struct sbus_bus *sbus;
194
 
195
        *pba = addr;
196
 
197
        dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
198
        end = PAGE_ALIGN((addr + len));
199
        while(addr < end) {
200
                page = va;
201
                {
202
                        pgd_t *pgdp;
203
                        pmd_t *pmdp;
204
                        pte_t *ptep;
205
                        long i;
206
 
207
                        pgdp = pgd_offset(&init_mm, addr);
208
                        pmdp = pmd_offset(pgdp, addr);
209
                        ptep = pte_offset_map(pmdp, addr);
210
 
211
                        set_pte(ptep, mk_pte(virt_to_page(page), dvma_prot));
212
 
213
                        i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
214
 
215
                        for_each_sbus(sbus) {
216
                                struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
217
 
218
                                iopte = (iopte_t *)(iounit->page_table + i);
219
                                *iopte = MKIOPTE(__pa(page));
220
                        }
221
                }
222
                addr += PAGE_SIZE;
223
                va += PAGE_SIZE;
224
        }
225
        flush_cache_all();
226
        flush_tlb_all();
227
 
228
        return 0;
229
}
230
 
231
static void iounit_unmap_dma_area(unsigned long addr, int len)
232
{
233
        /* XXX Somebody please fill this in */
234
}
235
 
236
/* XXX We do not pass sbus device here, bad. */
237
static struct page *iounit_translate_dvma(unsigned long addr)
238
{
239
        struct sbus_bus *sbus = sbus_root;      /* They are all the same */
240
        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
241
        int i;
242
        iopte_t *iopte;
243
 
244
        i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
245
        iopte = (iopte_t *)(iounit->page_table + i);
246
        return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
247
}
248
#endif
249
 
250
static char *iounit_lockarea(char *vaddr, unsigned long len)
251
{
252
/* FIXME: Write this */
253
        return vaddr;
254
}
255
 
256
static void iounit_unlockarea(char *vaddr, unsigned long len)
257
{
258
/* FIXME: Write this */
259
}
260
 
261
void __init ld_mmu_iounit(void)
262
{
263
        BTFIXUPSET_CALL(mmu_lockarea, iounit_lockarea, BTFIXUPCALL_RETO0);
264
        BTFIXUPSET_CALL(mmu_unlockarea, iounit_unlockarea, BTFIXUPCALL_NOP);
265
 
266
        BTFIXUPSET_CALL(mmu_get_scsi_one, iounit_get_scsi_one, BTFIXUPCALL_NORM);
267
        BTFIXUPSET_CALL(mmu_get_scsi_sgl, iounit_get_scsi_sgl, BTFIXUPCALL_NORM);
268
        BTFIXUPSET_CALL(mmu_release_scsi_one, iounit_release_scsi_one, BTFIXUPCALL_NORM);
269
        BTFIXUPSET_CALL(mmu_release_scsi_sgl, iounit_release_scsi_sgl, BTFIXUPCALL_NORM);
270
 
271
#ifdef CONFIG_SBUS
272
        BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
273
        BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
274
        BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
275
#endif
276
}
277
 
278
__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
279
{
280
        int i, j, k, npages;
281
        unsigned long rotor, scan, limit;
282
        unsigned long flags;
283
        __u32 ret;
284
        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
285
 
286
        npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
287
        i = 0x0213;
288
        spin_lock_irqsave(&iounit->lock, flags);
289
next:   j = (i & 15);
290
        rotor = iounit->rotor[j - 1];
291
        limit = iounit->limit[j];
292
        scan = rotor;
293
nexti:  scan = find_next_zero_bit(iounit->bmap, limit, scan);
294
        if (scan + npages > limit) {
295
                if (limit != rotor) {
296
                        limit = rotor;
297
                        scan = iounit->limit[j - 1];
298
                        goto nexti;
299
                }
300
                i >>= 4;
301
                if (!(i & 15))
302
                        panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
303
                goto next;
304
        }
305
        for (k = 1, scan++; k < npages; k++)
306
                if (test_bit(scan++, iounit->bmap))
307
                        goto nexti;
308
        iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
309
        scan -= npages;
310
        ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
311
        for (k = 0; k < npages; k++, scan++)
312
                set_bit(scan, iounit->bmap);
313
        spin_unlock_irqrestore(&iounit->lock, flags);
314
        return ret;
315
}
316
 
317
__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
318
{
319
        int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
320
        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
321
 
322
        iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
323
        return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
324
}

powered by: WebSVN 2.1.0

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