2 * io-unit.c: IO-UNIT specific routines for memory management.
4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7 #include <linux/kernel.h>
8 #include <linux/init.h>
9 #include <linux/slab.h>
10 #include <linux/spinlock.h>
12 #include <linux/highmem.h> /* pte_offset_map => kmap_atomic */
13 #include <linux/bitops.h>
14 #include <linux/scatterlist.h>
16 #include <linux/of_device.h>
18 #include <asm/pgalloc.h>
19 #include <asm/pgtable.h>
21 #include <asm/io-unit.h>
23 #include <asm/cacheflush.h>
24 #include <asm/tlbflush.h>
26 #include <asm/oplib.h>
28 /* #define IOUNIT_DEBUG */
30 #define IOD(x) printk(x)
32 #define IOD(x) do { } while (0)
35 #define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
36 #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
38 static void __init
iounit_iommu_init(struct platform_device
*op
)
40 struct iounit_struct
*iounit
;
41 iopte_t
*xpt
, *xptend
;
43 iounit
= kzalloc(sizeof(struct iounit_struct
), GFP_ATOMIC
);
45 prom_printf("SUN4D: Cannot alloc iounit, halting.\n");
49 iounit
->limit
[0] = IOUNIT_BMAP1_START
;
50 iounit
->limit
[1] = IOUNIT_BMAP2_START
;
51 iounit
->limit
[2] = IOUNIT_BMAPM_START
;
52 iounit
->limit
[3] = IOUNIT_BMAPM_END
;
53 iounit
->rotor
[1] = IOUNIT_BMAP2_START
;
54 iounit
->rotor
[2] = IOUNIT_BMAPM_START
;
56 xpt
= of_ioremap(&op
->resource
[2], 0, PAGE_SIZE
* 16, "XPT");
58 prom_printf("SUN4D: Cannot map External Page Table.");
62 op
->dev
.archdata
.iommu
= iounit
;
63 iounit
->page_table
= xpt
;
64 spin_lock_init(&iounit
->lock
);
66 for (xptend
= iounit
->page_table
+ (16 * PAGE_SIZE
) / sizeof(iopte_t
);
68 iopte_val(*xpt
++) = 0;
71 static int __init
iounit_init(void)
73 extern void sun4d_init_sbi_irq(void);
74 struct device_node
*dp
;
76 for_each_node_by_name(dp
, "sbi") {
77 struct platform_device
*op
= of_find_device_by_node(dp
);
79 iounit_iommu_init(op
);
80 of_propagate_archdata(op
);
88 subsys_initcall(iounit_init
);
90 /* One has to hold iounit->lock to call this */
91 static unsigned long iounit_get_area(struct iounit_struct
*iounit
, unsigned long vaddr
, int size
)
94 unsigned long rotor
, scan
, limit
;
97 npages
= ((vaddr
& ~PAGE_MASK
) + size
+ (PAGE_SIZE
-1)) >> PAGE_SHIFT
;
99 /* A tiny bit of magic ingredience :) */
101 case 1: i
= 0x0231; break;
102 case 2: i
= 0x0132; break;
103 default: i
= 0x0213; break;
106 IOD(("iounit_get_area(%08lx,%d[%d])=", vaddr
, size
, npages
));
109 rotor
= iounit
->rotor
[j
- 1];
110 limit
= iounit
->limit
[j
];
112 nexti
: scan
= find_next_zero_bit(iounit
->bmap
, limit
, scan
);
113 if (scan
+ npages
> limit
) {
114 if (limit
!= rotor
) {
116 scan
= iounit
->limit
[j
- 1];
121 panic("iounit_get_area: Couldn't find free iopte slots for (%08lx,%d)\n", vaddr
, size
);
124 for (k
= 1, scan
++; k
< npages
; k
++)
125 if (test_bit(scan
++, iounit
->bmap
))
127 iounit
->rotor
[j
- 1] = (scan
< limit
) ? scan
: iounit
->limit
[j
- 1];
129 iopte
= MKIOPTE(__pa(vaddr
& PAGE_MASK
));
130 vaddr
= IOUNIT_DMA_BASE
+ (scan
<< PAGE_SHIFT
) + (vaddr
& ~PAGE_MASK
);
131 for (k
= 0; k
< npages
; k
++, iopte
= __iopte(iopte_val(iopte
) + 0x100), scan
++) {
132 set_bit(scan
, iounit
->bmap
);
133 iounit
->page_table
[scan
] = iopte
;
135 IOD(("%08lx\n", vaddr
));
139 static __u32
iounit_get_scsi_one(struct device
*dev
, char *vaddr
, unsigned long len
)
141 struct iounit_struct
*iounit
= dev
->archdata
.iommu
;
142 unsigned long ret
, flags
;
144 spin_lock_irqsave(&iounit
->lock
, flags
);
145 ret
= iounit_get_area(iounit
, (unsigned long)vaddr
, len
);
146 spin_unlock_irqrestore(&iounit
->lock
, flags
);
150 static void iounit_get_scsi_sgl(struct device
*dev
, struct scatterlist
*sg
, int sz
)
152 struct iounit_struct
*iounit
= dev
->archdata
.iommu
;
155 /* FIXME: Cache some resolved pages - often several sg entries are to the same page */
156 spin_lock_irqsave(&iounit
->lock
, flags
);
159 sg
->dma_address
= iounit_get_area(iounit
, (unsigned long) sg_virt(sg
), sg
->length
);
160 sg
->dma_length
= sg
->length
;
163 spin_unlock_irqrestore(&iounit
->lock
, flags
);
166 static void iounit_release_scsi_one(struct device
*dev
, __u32 vaddr
, unsigned long len
)
168 struct iounit_struct
*iounit
= dev
->archdata
.iommu
;
171 spin_lock_irqsave(&iounit
->lock
, flags
);
172 len
= ((vaddr
& ~PAGE_MASK
) + len
+ (PAGE_SIZE
-1)) >> PAGE_SHIFT
;
173 vaddr
= (vaddr
- IOUNIT_DMA_BASE
) >> PAGE_SHIFT
;
174 IOD(("iounit_release %08lx-%08lx\n", (long)vaddr
, (long)len
+vaddr
));
175 for (len
+= vaddr
; vaddr
< len
; vaddr
++)
176 clear_bit(vaddr
, iounit
->bmap
);
177 spin_unlock_irqrestore(&iounit
->lock
, flags
);
180 static void iounit_release_scsi_sgl(struct device
*dev
, struct scatterlist
*sg
, int sz
)
182 struct iounit_struct
*iounit
= dev
->archdata
.iommu
;
184 unsigned long vaddr
, len
;
186 spin_lock_irqsave(&iounit
->lock
, flags
);
189 len
= ((sg
->dma_address
& ~PAGE_MASK
) + sg
->length
+ (PAGE_SIZE
-1)) >> PAGE_SHIFT
;
190 vaddr
= (sg
->dma_address
- IOUNIT_DMA_BASE
) >> PAGE_SHIFT
;
191 IOD(("iounit_release %08lx-%08lx\n", (long)vaddr
, (long)len
+vaddr
));
192 for (len
+= vaddr
; vaddr
< len
; vaddr
++)
193 clear_bit(vaddr
, iounit
->bmap
);
196 spin_unlock_irqrestore(&iounit
->lock
, flags
);
200 static int iounit_map_dma_area(struct device
*dev
, dma_addr_t
*pba
, unsigned long va
, unsigned long addr
, int len
)
202 struct iounit_struct
*iounit
= dev
->archdata
.iommu
;
203 unsigned long page
, end
;
209 dvma_prot
= __pgprot(SRMMU_CACHE
| SRMMU_ET_PTE
| SRMMU_PRIV
);
210 end
= PAGE_ALIGN((addr
+ len
));
219 pgdp
= pgd_offset(&init_mm
, addr
);
220 pmdp
= pmd_offset(pgdp
, addr
);
221 ptep
= pte_offset_map(pmdp
, addr
);
223 set_pte(ptep
, mk_pte(virt_to_page(page
), dvma_prot
));
225 i
= ((addr
- IOUNIT_DMA_BASE
) >> PAGE_SHIFT
);
227 iopte
= (iopte_t
*)(iounit
->page_table
+ i
);
228 *iopte
= MKIOPTE(__pa(page
));
239 static void iounit_unmap_dma_area(struct device
*dev
, unsigned long addr
, int len
)
241 /* XXX Somebody please fill this in */
245 static const struct sparc32_dma_ops iounit_dma_ops
= {
246 .get_scsi_one
= iounit_get_scsi_one
,
247 .get_scsi_sgl
= iounit_get_scsi_sgl
,
248 .release_scsi_one
= iounit_release_scsi_one
,
249 .release_scsi_sgl
= iounit_release_scsi_sgl
,
251 .map_dma_area
= iounit_map_dma_area
,
252 .unmap_dma_area
= iounit_unmap_dma_area
,
256 void __init
ld_mmu_iounit(void)
258 sparc32_dma_ops
= &iounit_dma_ops
;