diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-10-13 12:13:56 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-10-13 12:13:56 -0400 |
commit | e758936e02700ff88a0b08b722a3847b95283ef2 (patch) | |
tree | 50c919bef1b459a778b85159d5929de95b6c4a01 /arch/sparc/mm/iommu.c | |
parent | 239cfbde1f5843c4a24199f117d5f67f637d72d5 (diff) | |
parent | 4480f15b3306f43bbb0310d461142b4e897ca45b (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
include/asm-x86/statfs.h
Diffstat (limited to 'arch/sparc/mm/iommu.c')
-rw-r--r-- | arch/sparc/mm/iommu.c | 113 |
1 files changed, 55 insertions, 58 deletions
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 4b934270f05e..e7a499e3aa3c 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c | |||
@@ -13,10 +13,11 @@ | |||
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/highmem.h> /* pte_offset_map => kmap_atomic */ | 14 | #include <linux/highmem.h> /* pte_offset_map => kmap_atomic */ |
15 | #include <linux/scatterlist.h> | 15 | #include <linux/scatterlist.h> |
16 | #include <linux/of.h> | ||
17 | #include <linux/of_device.h> | ||
16 | 18 | ||
17 | #include <asm/pgalloc.h> | 19 | #include <asm/pgalloc.h> |
18 | #include <asm/pgtable.h> | 20 | #include <asm/pgtable.h> |
19 | #include <asm/sbus.h> | ||
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
21 | #include <asm/mxcc.h> | 22 | #include <asm/mxcc.h> |
22 | #include <asm/mbus.h> | 23 | #include <asm/mbus.h> |
@@ -55,30 +56,21 @@ static pgprot_t dvma_prot; /* Consistent mapping pte flags */ | |||
55 | #define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) | 56 | #define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) |
56 | #define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ) | 57 | #define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ) |
57 | 58 | ||
58 | void __init | 59 | static void __init sbus_iommu_init(struct of_device *op) |
59 | iommu_init(int iommund, struct sbus_bus *sbus) | ||
60 | { | 60 | { |
61 | unsigned int impl, vers; | ||
62 | unsigned long tmp; | ||
63 | struct iommu_struct *iommu; | 61 | struct iommu_struct *iommu; |
64 | struct linux_prom_registers iommu_promregs[PROMREG_MAX]; | 62 | unsigned int impl, vers; |
65 | struct resource r; | ||
66 | unsigned long *bitmap; | 63 | unsigned long *bitmap; |
64 | unsigned long tmp; | ||
67 | 65 | ||
68 | iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); | 66 | iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); |
69 | if (!iommu) { | 67 | if (!iommu) { |
70 | prom_printf("Unable to allocate iommu structure\n"); | 68 | prom_printf("Unable to allocate iommu structure\n"); |
71 | prom_halt(); | 69 | prom_halt(); |
72 | } | 70 | } |
73 | iommu->regs = NULL; | 71 | |
74 | if (prom_getproperty(iommund, "reg", (void *) iommu_promregs, | 72 | iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3, |
75 | sizeof(iommu_promregs)) != -1) { | 73 | "iommu_regs"); |
76 | memset(&r, 0, sizeof(r)); | ||
77 | r.flags = iommu_promregs[0].which_io; | ||
78 | r.start = iommu_promregs[0].phys_addr; | ||
79 | iommu->regs = (struct iommu_regs *) | ||
80 | sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs"); | ||
81 | } | ||
82 | if (!iommu->regs) { | 74 | if (!iommu->regs) { |
83 | prom_printf("Cannot map IOMMU registers\n"); | 75 | prom_printf("Cannot map IOMMU registers\n"); |
84 | prom_halt(); | 76 | prom_halt(); |
@@ -128,13 +120,29 @@ iommu_init(int iommund, struct sbus_bus *sbus) | |||
128 | else | 120 | else |
129 | iommu->usemap.num_colors = 1; | 121 | iommu->usemap.num_colors = 1; |
130 | 122 | ||
131 | printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n", | 123 | printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n", |
132 | impl, vers, iommu->page_table, | 124 | impl, vers, iommu->page_table, |
133 | (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES); | 125 | (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES); |
126 | |||
127 | op->dev.archdata.iommu = iommu; | ||
128 | } | ||
129 | |||
130 | static int __init iommu_init(void) | ||
131 | { | ||
132 | struct device_node *dp; | ||
133 | |||
134 | for_each_node_by_name(dp, "iommu") { | ||
135 | struct of_device *op = of_find_device_by_node(dp); | ||
136 | |||
137 | sbus_iommu_init(op); | ||
138 | of_propagate_archdata(op); | ||
139 | } | ||
134 | 140 | ||
135 | sbus->ofdev.dev.archdata.iommu = iommu; | 141 | return 0; |
136 | } | 142 | } |
137 | 143 | ||
144 | subsys_initcall(iommu_init); | ||
145 | |||
138 | /* This begs to be btfixup-ed by srmmu. */ | 146 | /* This begs to be btfixup-ed by srmmu. */ |
139 | /* Flush the iotlb entries to ram. */ | 147 | /* Flush the iotlb entries to ram. */ |
140 | /* This could be better if we didn't have to flush whole pages. */ | 148 | /* This could be better if we didn't have to flush whole pages. */ |
@@ -164,9 +172,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) | |||
164 | } | 172 | } |
165 | } | 173 | } |
166 | 174 | ||
167 | static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) | 175 | static u32 iommu_get_one(struct device *dev, struct page *page, int npages) |
168 | { | 176 | { |
169 | struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu; | 177 | struct iommu_struct *iommu = dev->archdata.iommu; |
170 | int ioptex; | 178 | int ioptex; |
171 | iopte_t *iopte, *iopte0; | 179 | iopte_t *iopte, *iopte0; |
172 | unsigned int busa, busa0; | 180 | unsigned int busa, busa0; |
@@ -194,8 +202,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus) | |||
194 | return busa0; | 202 | return busa0; |
195 | } | 203 | } |
196 | 204 | ||
197 | static u32 iommu_get_scsi_one(char *vaddr, unsigned int len, | 205 | static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len) |
198 | struct sbus_bus *sbus) | ||
199 | { | 206 | { |
200 | unsigned long off; | 207 | unsigned long off; |
201 | int npages; | 208 | int npages; |
@@ -205,22 +212,22 @@ static u32 iommu_get_scsi_one(char *vaddr, unsigned int len, | |||
205 | off = (unsigned long)vaddr & ~PAGE_MASK; | 212 | off = (unsigned long)vaddr & ~PAGE_MASK; |
206 | npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT; | 213 | npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT; |
207 | page = virt_to_page((unsigned long)vaddr & PAGE_MASK); | 214 | page = virt_to_page((unsigned long)vaddr & PAGE_MASK); |
208 | busa = iommu_get_one(page, npages, sbus); | 215 | busa = iommu_get_one(dev, page, npages); |
209 | return busa + off; | 216 | return busa + off; |
210 | } | 217 | } |
211 | 218 | ||
212 | static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) | 219 | static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len) |
213 | { | 220 | { |
214 | return iommu_get_scsi_one(vaddr, len, sbus); | 221 | return iommu_get_scsi_one(dev, vaddr, len); |
215 | } | 222 | } |
216 | 223 | ||
217 | static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) | 224 | static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len) |
218 | { | 225 | { |
219 | flush_page_for_dma(0); | 226 | flush_page_for_dma(0); |
220 | return iommu_get_scsi_one(vaddr, len, sbus); | 227 | return iommu_get_scsi_one(dev, vaddr, len); |
221 | } | 228 | } |
222 | 229 | ||
223 | static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus) | 230 | static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len) |
224 | { | 231 | { |
225 | unsigned long page = ((unsigned long) vaddr) & PAGE_MASK; | 232 | unsigned long page = ((unsigned long) vaddr) & PAGE_MASK; |
226 | 233 | ||
@@ -228,23 +235,23 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sb | |||
228 | flush_page_for_dma(page); | 235 | flush_page_for_dma(page); |
229 | page += PAGE_SIZE; | 236 | page += PAGE_SIZE; |
230 | } | 237 | } |
231 | return iommu_get_scsi_one(vaddr, len, sbus); | 238 | return iommu_get_scsi_one(dev, vaddr, len); |
232 | } | 239 | } |
233 | 240 | ||
234 | static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) | 241 | static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz) |
235 | { | 242 | { |
236 | int n; | 243 | int n; |
237 | 244 | ||
238 | while (sz != 0) { | 245 | while (sz != 0) { |
239 | --sz; | 246 | --sz; |
240 | n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; | 247 | n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; |
241 | sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; | 248 | sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset; |
242 | sg->dvma_length = (__u32) sg->length; | 249 | sg->dvma_length = (__u32) sg->length; |
243 | sg = sg_next(sg); | 250 | sg = sg_next(sg); |
244 | } | 251 | } |
245 | } | 252 | } |
246 | 253 | ||
247 | static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) | 254 | static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz) |
248 | { | 255 | { |
249 | int n; | 256 | int n; |
250 | 257 | ||
@@ -252,13 +259,13 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu | |||
252 | while (sz != 0) { | 259 | while (sz != 0) { |
253 | --sz; | 260 | --sz; |
254 | n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; | 261 | n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; |
255 | sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; | 262 | sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset; |
256 | sg->dvma_length = (__u32) sg->length; | 263 | sg->dvma_length = (__u32) sg->length; |
257 | sg = sg_next(sg); | 264 | sg = sg_next(sg); |
258 | } | 265 | } |
259 | } | 266 | } |
260 | 267 | ||
261 | static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus) | 268 | static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz) |
262 | { | 269 | { |
263 | unsigned long page, oldpage = 0; | 270 | unsigned long page, oldpage = 0; |
264 | int n, i; | 271 | int n, i; |
@@ -283,15 +290,15 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu | |||
283 | } | 290 | } |
284 | } | 291 | } |
285 | 292 | ||
286 | sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset; | 293 | sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset; |
287 | sg->dvma_length = (__u32) sg->length; | 294 | sg->dvma_length = (__u32) sg->length; |
288 | sg = sg_next(sg); | 295 | sg = sg_next(sg); |
289 | } | 296 | } |
290 | } | 297 | } |
291 | 298 | ||
292 | static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus) | 299 | static void iommu_release_one(struct device *dev, u32 busa, int npages) |
293 | { | 300 | { |
294 | struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu; | 301 | struct iommu_struct *iommu = dev->archdata.iommu; |
295 | int ioptex; | 302 | int ioptex; |
296 | int i; | 303 | int i; |
297 | 304 | ||
@@ -305,17 +312,17 @@ static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus) | |||
305 | bit_map_clear(&iommu->usemap, ioptex, npages); | 312 | bit_map_clear(&iommu->usemap, ioptex, npages); |
306 | } | 313 | } |
307 | 314 | ||
308 | static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus) | 315 | static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len) |
309 | { | 316 | { |
310 | unsigned long off; | 317 | unsigned long off; |
311 | int npages; | 318 | int npages; |
312 | 319 | ||
313 | off = vaddr & ~PAGE_MASK; | 320 | off = vaddr & ~PAGE_MASK; |
314 | npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT; | 321 | npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT; |
315 | iommu_release_one(vaddr & PAGE_MASK, npages, sbus); | 322 | iommu_release_one(dev, vaddr & PAGE_MASK, npages); |
316 | } | 323 | } |
317 | 324 | ||
318 | static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus) | 325 | static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) |
319 | { | 326 | { |
320 | int n; | 327 | int n; |
321 | 328 | ||
@@ -323,18 +330,18 @@ static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_b | |||
323 | --sz; | 330 | --sz; |
324 | 331 | ||
325 | n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; | 332 | n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; |
326 | iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus); | 333 | iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n); |
327 | sg->dvma_address = 0x21212121; | 334 | sg->dvma_address = 0x21212121; |
328 | sg = sg_next(sg); | 335 | sg = sg_next(sg); |
329 | } | 336 | } |
330 | } | 337 | } |
331 | 338 | ||
332 | #ifdef CONFIG_SBUS | 339 | #ifdef CONFIG_SBUS |
333 | static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va, | 340 | static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, |
334 | unsigned long addr, int len) | 341 | unsigned long addr, int len) |
335 | { | 342 | { |
343 | struct iommu_struct *iommu = dev->archdata.iommu; | ||
336 | unsigned long page, end; | 344 | unsigned long page, end; |
337 | struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu; | ||
338 | iopte_t *iopte = iommu->page_table; | 345 | iopte_t *iopte = iommu->page_table; |
339 | iopte_t *first; | 346 | iopte_t *first; |
340 | int ioptex; | 347 | int ioptex; |
@@ -397,9 +404,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va, | |||
397 | return 0; | 404 | return 0; |
398 | } | 405 | } |
399 | 406 | ||
400 | static void iommu_unmap_dma_area(unsigned long busa, int len) | 407 | static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len) |
401 | { | 408 | { |
402 | struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu; | 409 | struct iommu_struct *iommu = dev->archdata.iommu; |
403 | iopte_t *iopte = iommu->page_table; | 410 | iopte_t *iopte = iommu->page_table; |
404 | unsigned long end; | 411 | unsigned long end; |
405 | int ioptex = (busa - iommu->start) >> PAGE_SHIFT; | 412 | int ioptex = (busa - iommu->start) >> PAGE_SHIFT; |
@@ -417,15 +424,6 @@ static void iommu_unmap_dma_area(unsigned long busa, int len) | |||
417 | iommu_invalidate(iommu->regs); | 424 | iommu_invalidate(iommu->regs); |
418 | bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT); | 425 | bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT); |
419 | } | 426 | } |
420 | |||
421 | static struct page *iommu_translate_dvma(unsigned long busa) | ||
422 | { | ||
423 | struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu; | ||
424 | iopte_t *iopte = iommu->page_table; | ||
425 | |||
426 | iopte += ((busa - iommu->start) >> PAGE_SHIFT); | ||
427 | return pfn_to_page((iopte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4)); | ||
428 | } | ||
429 | #endif | 427 | #endif |
430 | 428 | ||
431 | static char *iommu_lockarea(char *vaddr, unsigned long len) | 429 | static char *iommu_lockarea(char *vaddr, unsigned long len) |
@@ -461,7 +459,6 @@ void __init ld_mmu_iommu(void) | |||
461 | #ifdef CONFIG_SBUS | 459 | #ifdef CONFIG_SBUS |
462 | BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM); | 460 | BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM); |
463 | BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM); | 461 | BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM); |
464 | BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM); | ||
465 | #endif | 462 | #endif |
466 | 463 | ||
467 | if (viking_mxcc_present || srmmu_modtype == HyperSparc) { | 464 | if (viking_mxcc_present || srmmu_modtype == HyperSparc) { |