diff options
Diffstat (limited to 'arch/sparc/kernel/ioport.c')
-rw-r--r-- | arch/sparc/kernel/ioport.c | 227 |
1 files changed, 25 insertions, 202 deletions
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 2a8a847764d8..4f025b36934b 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c | |||
@@ -42,10 +42,13 @@ | |||
42 | #include <asm/vaddrs.h> | 42 | #include <asm/vaddrs.h> |
43 | #include <asm/oplib.h> | 43 | #include <asm/oplib.h> |
44 | #include <asm/prom.h> | 44 | #include <asm/prom.h> |
45 | #include <asm/sbus.h> | ||
46 | #include <asm/page.h> | 45 | #include <asm/page.h> |
47 | #include <asm/pgalloc.h> | 46 | #include <asm/pgalloc.h> |
48 | #include <asm/dma.h> | 47 | #include <asm/dma.h> |
48 | #include <asm/iommu.h> | ||
49 | #include <asm/io-unit.h> | ||
50 | |||
51 | #include "dma.h" | ||
49 | 52 | ||
50 | #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ | 53 | #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ |
51 | 54 | ||
@@ -139,15 +142,6 @@ void iounmap(volatile void __iomem *virtual) | |||
139 | } | 142 | } |
140 | } | 143 | } |
141 | 144 | ||
142 | /* | ||
143 | */ | ||
144 | void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset, | ||
145 | unsigned long size, char *name) | ||
146 | { | ||
147 | return _sparc_alloc_io(phyres->flags & 0xF, | ||
148 | phyres->start + offset, size, name); | ||
149 | } | ||
150 | |||
151 | void __iomem *of_ioremap(struct resource *res, unsigned long offset, | 145 | void __iomem *of_ioremap(struct resource *res, unsigned long offset, |
152 | unsigned long size, char *name) | 146 | unsigned long size, char *name) |
153 | { | 147 | { |
@@ -164,13 +158,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size) | |||
164 | EXPORT_SYMBOL(of_iounmap); | 158 | EXPORT_SYMBOL(of_iounmap); |
165 | 159 | ||
166 | /* | 160 | /* |
167 | */ | ||
168 | void sbus_iounmap(volatile void __iomem *addr, unsigned long size) | ||
169 | { | ||
170 | iounmap(addr); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Meat of mapping | 161 | * Meat of mapping |
175 | */ | 162 | */ |
176 | static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, | 163 | static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, |
@@ -246,63 +233,19 @@ static void _sparc_free_io(struct resource *res) | |||
246 | 233 | ||
247 | #ifdef CONFIG_SBUS | 234 | #ifdef CONFIG_SBUS |
248 | 235 | ||
249 | void sbus_set_sbus64(struct sbus_dev *sdev, int x) | 236 | void sbus_set_sbus64(struct device *dev, int x) |
250 | { | 237 | { |
251 | printk("sbus_set_sbus64: unsupported\n"); | 238 | printk("sbus_set_sbus64: unsupported\n"); |
252 | } | 239 | } |
253 | 240 | ||
254 | extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq); | ||
255 | void __init sbus_fill_device_irq(struct sbus_dev *sdev) | ||
256 | { | ||
257 | struct linux_prom_irqs irqs[PROMINTR_MAX]; | ||
258 | int len; | ||
259 | |||
260 | len = prom_getproperty(sdev->prom_node, "intr", | ||
261 | (char *)irqs, sizeof(irqs)); | ||
262 | if (len != -1) { | ||
263 | sdev->num_irqs = len / 8; | ||
264 | if (sdev->num_irqs == 0) { | ||
265 | sdev->irqs[0] = 0; | ||
266 | } else if (sparc_cpu_model == sun4d) { | ||
267 | for (len = 0; len < sdev->num_irqs; len++) | ||
268 | sdev->irqs[len] = | ||
269 | sun4d_build_irq(sdev, irqs[len].pri); | ||
270 | } else { | ||
271 | for (len = 0; len < sdev->num_irqs; len++) | ||
272 | sdev->irqs[len] = irqs[len].pri; | ||
273 | } | ||
274 | } else { | ||
275 | int interrupts[PROMINTR_MAX]; | ||
276 | |||
277 | /* No "intr" node found-- check for "interrupts" node. | ||
278 | * This node contains SBus interrupt levels, not IPLs | ||
279 | * as in "intr", and no vector values. We convert | ||
280 | * SBus interrupt levels to PILs (platform specific). | ||
281 | */ | ||
282 | len = prom_getproperty(sdev->prom_node, "interrupts", | ||
283 | (char *)interrupts, sizeof(interrupts)); | ||
284 | if (len == -1) { | ||
285 | sdev->irqs[0] = 0; | ||
286 | sdev->num_irqs = 0; | ||
287 | } else { | ||
288 | sdev->num_irqs = len / sizeof(int); | ||
289 | for (len = 0; len < sdev->num_irqs; len++) { | ||
290 | sdev->irqs[len] = | ||
291 | sbint_to_irq(sdev, interrupts[len]); | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* | 241 | /* |
298 | * Allocate a chunk of memory suitable for DMA. | 242 | * Allocate a chunk of memory suitable for DMA. |
299 | * Typically devices use them for control blocks. | 243 | * Typically devices use them for control blocks. |
300 | * CPU may access them without any explicit flushing. | 244 | * CPU may access them without any explicit flushing. |
301 | * | ||
302 | * XXX Some clever people know that sdev is not used and supply NULL. Watch. | ||
303 | */ | 245 | */ |
304 | void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) | 246 | void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp) |
305 | { | 247 | { |
248 | struct of_device *op = to_of_device(dev); | ||
306 | unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; | 249 | unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; |
307 | unsigned long va; | 250 | unsigned long va; |
308 | struct resource *res; | 251 | struct resource *res; |
@@ -336,13 +279,10 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) | |||
336 | * XXX That's where sdev would be used. Currently we load | 279 | * XXX That's where sdev would be used. Currently we load |
337 | * all iommu tables with the same translations. | 280 | * all iommu tables with the same translations. |
338 | */ | 281 | */ |
339 | if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0) | 282 | if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) |
340 | goto err_noiommu; | 283 | goto err_noiommu; |
341 | 284 | ||
342 | /* Set the resource name, if known. */ | 285 | res->name = op->node->name; |
343 | if (sdev) { | ||
344 | res->name = sdev->prom_name; | ||
345 | } | ||
346 | 286 | ||
347 | return (void *)(unsigned long)res->start; | 287 | return (void *)(unsigned long)res->start; |
348 | 288 | ||
@@ -356,7 +296,7 @@ err_nopages: | |||
356 | return NULL; | 296 | return NULL; |
357 | } | 297 | } |
358 | 298 | ||
359 | void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) | 299 | void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) |
360 | { | 300 | { |
361 | struct resource *res; | 301 | struct resource *res; |
362 | struct page *pgv; | 302 | struct page *pgv; |
@@ -383,8 +323,8 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) | |||
383 | kfree(res); | 323 | kfree(res); |
384 | 324 | ||
385 | /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ | 325 | /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ |
386 | pgv = mmu_translate_dvma(ba); | 326 | pgv = virt_to_page(p); |
387 | mmu_unmap_dma_area(ba, n); | 327 | mmu_unmap_dma_area(dev, ba, n); |
388 | 328 | ||
389 | __free_pages(pgv, get_order(n)); | 329 | __free_pages(pgv, get_order(n)); |
390 | } | 330 | } |
@@ -394,7 +334,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) | |||
394 | * CPU view of this memory may be inconsistent with | 334 | * CPU view of this memory may be inconsistent with |
395 | * a device view and explicit flushing is necessary. | 335 | * a device view and explicit flushing is necessary. |
396 | */ | 336 | */ |
397 | dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction) | 337 | dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction) |
398 | { | 338 | { |
399 | /* XXX why are some lengths signed, others unsigned? */ | 339 | /* XXX why are some lengths signed, others unsigned? */ |
400 | if (len <= 0) { | 340 | if (len <= 0) { |
@@ -404,17 +344,17 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int dire | |||
404 | if (len > 256*1024) { /* __get_free_pages() limit */ | 344 | if (len > 256*1024) { /* __get_free_pages() limit */ |
405 | return 0; | 345 | return 0; |
406 | } | 346 | } |
407 | return mmu_get_scsi_one(va, len, sdev->bus); | 347 | return mmu_get_scsi_one(dev, va, len); |
408 | } | 348 | } |
409 | 349 | ||
410 | void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction) | 350 | void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction) |
411 | { | 351 | { |
412 | mmu_release_scsi_one(ba, n, sdev->bus); | 352 | mmu_release_scsi_one(dev, ba, n); |
413 | } | 353 | } |
414 | 354 | ||
415 | int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 355 | int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction) |
416 | { | 356 | { |
417 | mmu_get_scsi_sgl(sg, n, sdev->bus); | 357 | mmu_get_scsi_sgl(dev, sg, n); |
418 | 358 | ||
419 | /* | 359 | /* |
420 | * XXX sparc64 can return a partial length here. sun4c should do this | 360 | * XXX sparc64 can return a partial length here. sun4c should do this |
@@ -423,145 +363,28 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direct | |||
423 | return n; | 363 | return n; |
424 | } | 364 | } |
425 | 365 | ||
426 | void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 366 | void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction) |
427 | { | ||
428 | mmu_release_scsi_sgl(sg, n, sdev->bus); | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | */ | ||
433 | void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction) | ||
434 | { | ||
435 | #if 0 | ||
436 | unsigned long va; | ||
437 | struct resource *res; | ||
438 | |||
439 | /* We do not need the resource, just print a message if invalid. */ | ||
440 | res = _sparc_find_resource(&_sparc_dvma, ba); | ||
441 | if (res == NULL) | ||
442 | panic("sbus_dma_sync_single: 0x%x\n", ba); | ||
443 | |||
444 | va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */ | ||
445 | /* | ||
446 | * XXX This bogosity will be fixed with the iommu rewrite coming soon | ||
447 | * to a kernel near you. - Anton | ||
448 | */ | ||
449 | /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */ | ||
450 | #endif | ||
451 | } | ||
452 | |||
453 | void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction) | ||
454 | { | 367 | { |
455 | #if 0 | 368 | mmu_release_scsi_sgl(dev, sg, n); |
456 | unsigned long va; | ||
457 | struct resource *res; | ||
458 | |||
459 | /* We do not need the resource, just print a message if invalid. */ | ||
460 | res = _sparc_find_resource(&_sparc_dvma, ba); | ||
461 | if (res == NULL) | ||
462 | panic("sbus_dma_sync_single: 0x%x\n", ba); | ||
463 | |||
464 | va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */ | ||
465 | /* | ||
466 | * XXX This bogosity will be fixed with the iommu rewrite coming soon | ||
467 | * to a kernel near you. - Anton | ||
468 | */ | ||
469 | /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */ | ||
470 | #endif | ||
471 | } | 369 | } |
472 | 370 | ||
473 | void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 371 | void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction) |
474 | { | 372 | { |
475 | printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n"); | ||
476 | } | 373 | } |
477 | 374 | ||
478 | void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 375 | void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction) |
479 | { | 376 | { |
480 | printk("sbus_dma_sync_sg_for_device: not implemented yet\n"); | ||
481 | } | ||
482 | |||
483 | /* Support code for sbus_init(). */ | ||
484 | /* | ||
485 | * XXX This functions appears to be a distorted version of | ||
486 | * prom_sbus_ranges_init(), with all sun4d stuff cut away. | ||
487 | * Ask DaveM what is going on here, how is sun4d supposed to work... XXX | ||
488 | */ | ||
489 | /* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */ | ||
490 | void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus) | ||
491 | { | ||
492 | int parent_node = pn->node; | ||
493 | |||
494 | if (sparc_cpu_model == sun4d) { | ||
495 | struct linux_prom_ranges iounit_ranges[PROMREG_MAX]; | ||
496 | int num_iounit_ranges, len; | ||
497 | |||
498 | len = prom_getproperty(parent_node, "ranges", | ||
499 | (char *) iounit_ranges, | ||
500 | sizeof (iounit_ranges)); | ||
501 | if (len != -1) { | ||
502 | num_iounit_ranges = | ||
503 | (len / sizeof(struct linux_prom_ranges)); | ||
504 | prom_adjust_ranges(sbus->sbus_ranges, | ||
505 | sbus->num_sbus_ranges, | ||
506 | iounit_ranges, num_iounit_ranges); | ||
507 | } | ||
508 | } | ||
509 | } | 377 | } |
510 | 378 | ||
511 | void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp) | 379 | static int __init sparc_register_ioport(void) |
512 | { | ||
513 | #ifndef CONFIG_SUN4 | ||
514 | struct device_node *parent = dp->parent; | ||
515 | |||
516 | if (sparc_cpu_model != sun4d && | ||
517 | parent != NULL && | ||
518 | !strcmp(parent->name, "iommu")) { | ||
519 | extern void iommu_init(int iommu_node, struct sbus_bus *sbus); | ||
520 | |||
521 | iommu_init(parent->node, sbus); | ||
522 | } | ||
523 | |||
524 | if (sparc_cpu_model == sun4d) { | ||
525 | extern void iounit_init(int sbi_node, int iounit_node, | ||
526 | struct sbus_bus *sbus); | ||
527 | |||
528 | iounit_init(dp->node, parent->node, sbus); | ||
529 | } | ||
530 | #endif | ||
531 | } | ||
532 | |||
533 | void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp) | ||
534 | { | ||
535 | if (sparc_cpu_model == sun4d) { | ||
536 | struct device_node *parent = dp->parent; | ||
537 | |||
538 | sbus->devid = of_getintprop_default(parent, "device-id", 0); | ||
539 | sbus->board = of_getintprop_default(parent, "board#", 0); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | int __init sbus_arch_preinit(void) | ||
544 | { | 380 | { |
545 | register_proc_sparc_ioport(); | 381 | register_proc_sparc_ioport(); |
546 | 382 | ||
547 | #ifdef CONFIG_SUN4 | ||
548 | { | ||
549 | extern void sun4_dvma_init(void); | ||
550 | sun4_dvma_init(); | ||
551 | } | ||
552 | return 1; | ||
553 | #else | ||
554 | return 0; | 383 | return 0; |
555 | #endif | ||
556 | } | 384 | } |
557 | 385 | ||
558 | void __init sbus_arch_postinit(void) | 386 | arch_initcall(sparc_register_ioport); |
559 | { | 387 | |
560 | if (sparc_cpu_model == sun4d) { | ||
561 | extern void sun4d_init_sbi_irq(void); | ||
562 | sun4d_init_sbi_irq(); | ||
563 | } | ||
564 | } | ||
565 | #endif /* CONFIG_SBUS */ | 388 | #endif /* CONFIG_SBUS */ |
566 | 389 | ||
567 | #ifdef CONFIG_PCI | 390 | #ifdef CONFIG_PCI |