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