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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [sparc64/] [kernel/] [iommu_common.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* $Id: iommu_common.c,v 1.1.1.1 2004-04-15 01:34:43 phoenix Exp $
2
 * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
3
 *
4
 * Copyright (C) 1999 David S. Miller (davem@redhat.com)
5
 */
6
 
7
#include "iommu_common.h"
8
 
9
/* You are _strongly_ advised to enable the following debugging code
10
 * any time you make changes to the sg code below, run it for a while
11
 * with filesystems mounted read-only before buying the farm... -DaveM
12
 */
13
 
14
#ifdef VERIFY_SG
15
static int verify_lengths(struct scatterlist *sg, int nents, int npages)
16
{
17
        int sg_len, dma_len;
18
        int i, pgcount;
19
 
20
        sg_len = 0;
21
        for (i = 0; i < nents; i++)
22
                sg_len += sg[i].length;
23
 
24
        dma_len = 0;
25
        for (i = 0; i < nents && sg[i].dma_length; i++)
26
                dma_len += sg[i].dma_length;
27
 
28
        if (sg_len != dma_len) {
29
                printk("verify_lengths: Error, different, sg[%d] dma[%d]\n",
30
                       sg_len, dma_len);
31
                return -1;
32
        }
33
 
34
        pgcount = 0;
35
        for (i = 0; i < nents && sg[i].dma_length; i++) {
36
                unsigned long start, end;
37
 
38
                start = sg[i].dma_address;
39
                start = start & IO_PAGE_MASK;
40
 
41
                end = sg[i].dma_address + sg[i].dma_length;
42
                end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK;
43
 
44
                pgcount += ((end - start) >> IO_PAGE_SHIFT);
45
        }
46
 
47
        if (pgcount != npages) {
48
                printk("verify_lengths: Error, page count wrong, "
49
                       "npages[%d] pgcount[%d]\n",
50
                       npages, pgcount);
51
                return -1;
52
        }
53
 
54
        /* This test passes... */
55
        return 0;
56
}
57
 
58
static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte)
59
{
60
        struct scatterlist *sg = *__sg;
61
        iopte_t *iopte = *__iopte;
62
        u32 dlen = dma_sg->dma_length;
63
        u32 daddr;
64
        unsigned int sglen;
65
        unsigned long sgaddr;
66
 
67
        daddr = dma_sg->dma_address;
68
        sglen = sg->length;
69
        sgaddr = (unsigned long) (sg->address ?
70
                                  sg->address :
71
                                  page_address(sg->page) + sg->offset);
72
        while (dlen > 0) {
73
                unsigned long paddr;
74
 
75
                /* SG and DMA_SG must begin at the same sub-page boundary. */
76
                if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) {
77
                        printk("verify_one_map: Wrong start offset "
78
                               "sg[%08lx] dma[%08x]\n",
79
                               sgaddr, daddr);
80
                        nents = -1;
81
                        goto out;
82
                }
83
 
84
                /* Verify the IOPTE points to the right page. */
85
                paddr = iopte_val(*iopte) & IOPTE_PAGE;
86
                if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) {
87
                        printk("verify_one_map: IOPTE[%08lx] maps the "
88
                               "wrong page, should be [%08lx]\n",
89
                               iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET);
90
                        nents = -1;
91
                        goto out;
92
                }
93
 
94
                /* If this SG crosses a page, adjust to that next page
95
                 * boundary and loop.
96
                 */
97
                if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) {
98
                        unsigned long next_page, diff;
99
 
100
                        next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK;
101
                        diff = next_page - sgaddr;
102
                        sgaddr += diff;
103
                        daddr += diff;
104
                        sglen -= diff;
105
                        dlen -= diff;
106
                        if (dlen > 0)
107
                                iopte++;
108
                        continue;
109
                }
110
 
111
                /* SG wholly consumed within this page. */
112
                daddr += sglen;
113
                dlen -= sglen;
114
 
115
                if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0))
116
                        iopte++;
117
 
118
                sg++;
119
                if (--nents <= 0)
120
                        break;
121
                sgaddr = (unsigned long) (sg->address ?
122
                                          sg->address :
123
                                          page_address(sg->page) + sg->offset);
124
                sglen = sg->length;
125
        }
126
        if (dlen < 0) {
127
                /* Transfer overrun, big problems. */
128
                printk("verify_one_map: Transfer overrun by %d bytes.\n",
129
                       -dlen);
130
                nents = -1;
131
        } else {
132
                /* Advance to next dma_sg implies that the next iopte will
133
                 * begin it.
134
                 */
135
                iopte++;
136
        }
137
 
138
out:
139
        *__sg = sg;
140
        *__iopte = iopte;
141
        return nents;
142
}
143
 
144
static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte)
145
{
146
        struct scatterlist *dma_sg = sg;
147
        struct scatterlist *orig_dma_sg = dma_sg;
148
        int orig_nents = nents;
149
 
150
        for (;;) {
151
                nents = verify_one_map(dma_sg, &sg, nents, &iopte);
152
                if (nents <= 0)
153
                        break;
154
                dma_sg++;
155
                if (dma_sg->dma_length == 0)
156
                        break;
157
        }
158
 
159
        if (nents > 0) {
160
                printk("verify_maps: dma maps consumed by some sgs remain (%d)\n",
161
                       nents);
162
                return -1;
163
        }
164
 
165
        if (nents < 0) {
166
                printk("verify_maps: Error, messed up mappings, "
167
                       "at sg %d dma_sg %d\n",
168
                       (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg));
169
                return -1;
170
        }
171
 
172
        /* This test passes... */
173
        return 0;
174
}
175
 
176
void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages)
177
{
178
        if (verify_lengths(sg, nents, npages) < 0 ||
179
            verify_maps(sg, nents, iopte) < 0) {
180
                int i;
181
 
182
                printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
183
                printk("%016lx.\n", sg->dma_address & IO_PAGE_MASK);
184
 
185
                for (i = 0; i < nents; i++) {
186
                        printk("sg(%d): address(%p) length(%x) "
187
                               "dma_address[%016lx] dma_length[%016lx]\n",
188
                               i,
189
                               sg[i].address, sg[i].length,
190
                               sg[i].dma_address, sg[i].dma_length);
191
                }
192
        }
193
 
194
        /* Seems to be ok */
195
}
196
#endif
197
 
198
unsigned long prepare_sg(struct scatterlist *sg, int nents)
199
{
200
        struct scatterlist *dma_sg = sg;
201
        unsigned long prev;
202
        u32 dent_addr, dent_len;
203
 
204
        prev  = (unsigned long) (sg->address ?
205
                                 sg->address :
206
                                 page_address(sg->page) + sg->offset);
207
        prev += (unsigned long) (dent_len = sg->length);
208
        dent_addr = (u32) ((unsigned long)(sg->address ?
209
                                           sg->address :
210
                                           page_address(sg->page) + sg->offset)
211
                           & (IO_PAGE_SIZE - 1UL));
212
        while (--nents) {
213
                unsigned long addr;
214
 
215
                sg++;
216
                addr = (unsigned long) (sg->address ?
217
                                        sg->address :
218
                                        page_address(sg->page) + sg->offset);
219
                if (! VCONTIG(prev, addr)) {
220
                        dma_sg->dma_address = dent_addr;
221
                        dma_sg->dma_length = dent_len;
222
                        dma_sg++;
223
 
224
                        dent_addr = ((dent_addr +
225
                                      dent_len +
226
                                      (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT);
227
                        dent_addr <<= IO_PAGE_SHIFT;
228
                        dent_addr += addr & (IO_PAGE_SIZE - 1UL);
229
                        dent_len = 0;
230
                }
231
                dent_len += sg->length;
232
                prev = addr + sg->length;
233
        }
234
        dma_sg->dma_address = dent_addr;
235
        dma_sg->dma_length = dent_len;
236
 
237
        return ((unsigned long) dent_addr +
238
                (unsigned long) dent_len +
239
                (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
240
}

powered by: WebSVN 2.1.0

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