diff options
Diffstat (limited to 'arch/sparc/mm/io-unit.c')
-rw-r--r-- | arch/sparc/mm/io-unit.c | 136 |
1 files changed, 41 insertions, 95 deletions
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index f167835db3df..daadf5f88050 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c | |||
@@ -12,10 +12,11 @@ | |||
12 | #include <linux/highmem.h> /* pte_offset_map => kmap_atomic */ | 12 | #include <linux/highmem.h> /* pte_offset_map => kmap_atomic */ |
13 | #include <linux/bitops.h> | 13 | #include <linux/bitops.h> |
14 | #include <linux/scatterlist.h> | 14 | #include <linux/scatterlist.h> |
15 | #include <linux/of.h> | ||
16 | #include <linux/of_device.h> | ||
15 | 17 | ||
16 | #include <asm/pgalloc.h> | 18 | #include <asm/pgalloc.h> |
17 | #include <asm/pgtable.h> | 19 | #include <asm/pgtable.h> |
18 | #include <asm/sbus.h> | ||
19 | #include <asm/io.h> | 20 | #include <asm/io.h> |
20 | #include <asm/io-unit.h> | 21 | #include <asm/io-unit.h> |
21 | #include <asm/mxcc.h> | 22 | #include <asm/mxcc.h> |
@@ -34,13 +35,10 @@ | |||
34 | #define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID) | 35 | #define IOPERM (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID) |
35 | #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM) | 36 | #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM) |
36 | 37 | ||
37 | void __init | 38 | static void __init iounit_iommu_init(struct of_device *op) |
38 | iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus) | ||
39 | { | 39 | { |
40 | iopte_t *xpt, *xptend; | ||
41 | struct iounit_struct *iounit; | 40 | struct iounit_struct *iounit; |
42 | struct linux_prom_registers iommu_promregs[PROMREG_MAX]; | 41 | iopte_t *xpt, *xptend; |
43 | struct resource r; | ||
44 | 42 | ||
45 | iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC); | 43 | iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC); |
46 | if (!iounit) { | 44 | if (!iounit) { |
@@ -55,18 +53,13 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus) | |||
55 | iounit->rotor[1] = IOUNIT_BMAP2_START; | 53 | iounit->rotor[1] = IOUNIT_BMAP2_START; |
56 | iounit->rotor[2] = IOUNIT_BMAPM_START; | 54 | iounit->rotor[2] = IOUNIT_BMAPM_START; |
57 | 55 | ||
58 | xpt = NULL; | 56 | xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT"); |
59 | if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs, | 57 | if (!xpt) { |
60 | sizeof(iommu_promregs)) != -1) { | 58 | prom_printf("SUN4D: Cannot map External Page Table."); |
61 | prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3); | 59 | prom_halt(); |
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 | } | 60 | } |
67 | if(!xpt) panic("Cannot map External Page Table."); | ||
68 | 61 | ||
69 | sbus->ofdev.dev.archdata.iommu = iounit; | 62 | op->dev.archdata.iommu = iounit; |
70 | iounit->page_table = xpt; | 63 | iounit->page_table = xpt; |
71 | spin_lock_init(&iounit->lock); | 64 | spin_lock_init(&iounit->lock); |
72 | 65 | ||
@@ -75,6 +68,25 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus) | |||
75 | iopte_val(*xpt++) = 0; | 68 | iopte_val(*xpt++) = 0; |
76 | } | 69 | } |
77 | 70 | ||
71 | static int __init iounit_init(void) | ||
72 | { | ||
73 | extern void sun4d_init_sbi_irq(void); | ||
74 | struct device_node *dp; | ||
75 | |||
76 | for_each_node_by_name(dp, "sbi") { | ||
77 | struct of_device *op = of_find_device_by_node(dp); | ||
78 | |||
79 | iounit_iommu_init(op); | ||
80 | of_propagate_archdata(op); | ||
81 | } | ||
82 | |||
83 | sun4d_init_sbi_irq(); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | subsys_initcall(iounit_init); | ||
89 | |||
78 | /* One has to hold iounit->lock to call this */ | 90 | /* 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) | 91 | static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size) |
80 | { | 92 | { |
@@ -124,10 +136,10 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan); | |||
124 | return vaddr; | 136 | return vaddr; |
125 | } | 137 | } |
126 | 138 | ||
127 | static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus) | 139 | static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len) |
128 | { | 140 | { |
141 | struct iounit_struct *iounit = dev->archdata.iommu; | ||
129 | unsigned long ret, flags; | 142 | unsigned long ret, flags; |
130 | struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu; | ||
131 | 143 | ||
132 | spin_lock_irqsave(&iounit->lock, flags); | 144 | spin_lock_irqsave(&iounit->lock, flags); |
133 | ret = iounit_get_area(iounit, (unsigned long)vaddr, len); | 145 | ret = iounit_get_area(iounit, (unsigned long)vaddr, len); |
@@ -135,10 +147,10 @@ static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus | |||
135 | return ret; | 147 | return ret; |
136 | } | 148 | } |
137 | 149 | ||
138 | static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) | 150 | static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) |
139 | { | 151 | { |
152 | struct iounit_struct *iounit = dev->archdata.iommu; | ||
140 | unsigned long flags; | 153 | unsigned long flags; |
141 | struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu; | ||
142 | 154 | ||
143 | /* FIXME: Cache some resolved pages - often several sg entries are to the same page */ | 155 | /* FIXME: Cache some resolved pages - often several sg entries are to the same page */ |
144 | spin_lock_irqsave(&iounit->lock, flags); | 156 | spin_lock_irqsave(&iounit->lock, flags); |
@@ -151,10 +163,10 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus | |||
151 | spin_unlock_irqrestore(&iounit->lock, flags); | 163 | spin_unlock_irqrestore(&iounit->lock, flags); |
152 | } | 164 | } |
153 | 165 | ||
154 | static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus) | 166 | static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len) |
155 | { | 167 | { |
168 | struct iounit_struct *iounit = dev->archdata.iommu; | ||
156 | unsigned long flags; | 169 | unsigned long flags; |
157 | struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu; | ||
158 | 170 | ||
159 | spin_lock_irqsave(&iounit->lock, flags); | 171 | spin_lock_irqsave(&iounit->lock, flags); |
160 | len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT; | 172 | len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT; |
@@ -165,11 +177,11 @@ static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_ | |||
165 | spin_unlock_irqrestore(&iounit->lock, flags); | 177 | spin_unlock_irqrestore(&iounit->lock, flags); |
166 | } | 178 | } |
167 | 179 | ||
168 | static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) | 180 | static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) |
169 | { | 181 | { |
182 | struct iounit_struct *iounit = dev->archdata.iommu; | ||
170 | unsigned long flags; | 183 | unsigned long flags; |
171 | unsigned long vaddr, len; | 184 | unsigned long vaddr, len; |
172 | struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu; | ||
173 | 185 | ||
174 | spin_lock_irqsave(&iounit->lock, flags); | 186 | spin_lock_irqsave(&iounit->lock, flags); |
175 | while (sz != 0) { | 187 | while (sz != 0) { |
@@ -185,12 +197,12 @@ static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_ | |||
185 | } | 197 | } |
186 | 198 | ||
187 | #ifdef CONFIG_SBUS | 199 | #ifdef CONFIG_SBUS |
188 | static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len) | 200 | static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len) |
189 | { | 201 | { |
202 | struct iounit_struct *iounit = dev->archdata.iommu; | ||
190 | unsigned long page, end; | 203 | unsigned long page, end; |
191 | pgprot_t dvma_prot; | 204 | pgprot_t dvma_prot; |
192 | iopte_t *iopte; | 205 | iopte_t *iopte; |
193 | struct sbus_bus *sbus; | ||
194 | 206 | ||
195 | *pba = addr; | 207 | *pba = addr; |
196 | 208 | ||
@@ -212,12 +224,8 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in | |||
212 | 224 | ||
213 | i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); | 225 | i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); |
214 | 226 | ||
215 | for_each_sbus(sbus) { | 227 | iopte = (iopte_t *)(iounit->page_table + i); |
216 | struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu; | 228 | *iopte = MKIOPTE(__pa(page)); |
217 | |||
218 | iopte = (iopte_t *)(iounit->page_table + i); | ||
219 | *iopte = MKIOPTE(__pa(page)); | ||
220 | } | ||
221 | } | 229 | } |
222 | addr += PAGE_SIZE; | 230 | addr += PAGE_SIZE; |
223 | va += PAGE_SIZE; | 231 | va += PAGE_SIZE; |
@@ -228,23 +236,10 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in | |||
228 | return 0; | 236 | return 0; |
229 | } | 237 | } |
230 | 238 | ||
231 | static void iounit_unmap_dma_area(unsigned long addr, int len) | 239 | static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len) |
232 | { | 240 | { |
233 | /* XXX Somebody please fill this in */ | 241 | /* XXX Somebody please fill this in */ |
234 | } | 242 | } |
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 | 243 | #endif |
249 | 244 | ||
250 | static char *iounit_lockarea(char *vaddr, unsigned long len) | 245 | static char *iounit_lockarea(char *vaddr, unsigned long len) |
@@ -271,54 +266,5 @@ void __init ld_mmu_iounit(void) | |||
271 | #ifdef CONFIG_SBUS | 266 | #ifdef CONFIG_SBUS |
272 | BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM); | 267 | 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); | 268 | 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 | 269 | #endif |
276 | } | 270 | } |
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 | } | ||