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.
4 * Copyright (C) 1999 David S. Miller (davem@redhat.com)
7 #include <linux/dma-mapping.h>
8 #include "iommu_common.h"
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
16 static int verify_lengths(struct scatterlist
*sglist
, int nents
, int npages
)
20 struct scatterlist
*sg
;
23 for_each_sg(sglist
, sg
, nents
, i
)
27 for_each_sg(sglist
, sg
, nents
, i
) {
30 dma_len
+= sg
->dma_length
;
33 if (sg_len
!= dma_len
) {
34 printk("verify_lengths: Error, different, sg[%d] dma[%d]\n",
40 for_each_sg(sglist
, sg
, nents
, i
) {
41 unsigned long start
, end
;
46 start
= sg
->dma_address
;
47 start
= start
& IO_PAGE_MASK
;
49 end
= sg
->dma_address
+ sg
->dma_length
;
50 end
= (end
+ (IO_PAGE_SIZE
- 1)) & IO_PAGE_MASK
;
52 pgcount
+= ((end
- start
) >> IO_PAGE_SHIFT
);
55 if (pgcount
!= npages
) {
56 printk("verify_lengths: Error, page count wrong, "
57 "npages[%d] pgcount[%d]\n",
62 /* This test passes... */
66 static int verify_one_map(struct scatterlist
*dma_sg
, struct scatterlist
**__sg
, int nents
, iopte_t
**__iopte
)
68 struct scatterlist
*sg
= *__sg
;
69 iopte_t
*iopte
= *__iopte
;
70 u32 dlen
= dma_sg
->dma_length
;
75 daddr
= dma_sg
->dma_address
;
77 sgaddr
= (unsigned long) sg_virt(sg
);
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",
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
);
100 /* If this SG crosses a page, adjust to that next page
103 if ((sgaddr
& IO_PAGE_MASK
) ^ ((sgaddr
+ sglen
- 1) & IO_PAGE_MASK
)) {
104 unsigned long next_page
, diff
;
106 next_page
= (sgaddr
+ IO_PAGE_SIZE
) & IO_PAGE_MASK
;
107 diff
= next_page
- sgaddr
;
117 /* SG wholly consumed within this page. */
121 if (dlen
> 0 && ((daddr
& ~IO_PAGE_MASK
) == 0))
127 sgaddr
= (unsigned long) sg_virt(sg
);
131 /* Transfer overrun, big problems. */
132 printk("verify_one_map: Transfer overrun by %d bytes.\n",
136 /* Advance to next dma_sg implies that the next iopte will
148 static int verify_maps(struct scatterlist
*sg
, int nents
, iopte_t
*iopte
)
150 struct scatterlist
*dma_sg
= sg
;
151 struct scatterlist
*orig_dma_sg
= dma_sg
;
152 int orig_nents
= nents
;
155 nents
= verify_one_map(dma_sg
, &sg
, nents
, &iopte
);
158 dma_sg
= sg_next(dma_sg
);
159 if (dma_sg
->dma_length
== 0)
164 printk("verify_maps: dma maps consumed by some sgs remain (%d)\n",
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
));
176 /* This test passes... */
180 void verify_sglist(struct scatterlist
*sglist
, int nents
, iopte_t
*iopte
, int npages
)
182 struct scatterlist
*sg
;
184 if (verify_lengths(sglist
, nents
, npages
) < 0 ||
185 verify_maps(sglist
, nents
, iopte
) < 0) {
188 printk("verify_sglist: Crap, messed up mappings, dumping, iodma at ");
189 printk("%016lx.\n", sglist
->dma_address
& IO_PAGE_MASK
);
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",
195 page_address(sg_page(sg
)), sg
->offset
,
197 sg
->dma_address
, sg
->dma_length
);
205 unsigned long prepare_sg(struct device
*dev
, struct scatterlist
*sg
, int nents
)
207 struct scatterlist
*dma_sg
= sg
;
209 u32 dent_addr
, dent_len
;
210 unsigned int max_seg_size
;
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
);
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
);
227 dent_addr
= ((dent_addr
+
229 (IO_PAGE_SIZE
- 1UL)) >> IO_PAGE_SHIFT
);
230 dent_addr
<<= IO_PAGE_SHIFT
;
231 dent_addr
+= addr
& (IO_PAGE_SIZE
- 1UL);
234 dent_len
+= sg
->length
;
235 prev
= addr
+ sg
->length
;
237 dma_sg
->dma_address
= dent_addr
;
238 dma_sg
->dma_length
= dent_len
;
241 dma_sg
= sg_next(dma_sg
);
242 dma_sg
->dma_length
= 0;
245 return ((unsigned long) dent_addr
+
246 (unsigned long) dent_len
+
247 (IO_PAGE_SIZE
- 1UL)) >> IO_PAGE_SHIFT
;