diff options
Diffstat (limited to 'arch/powerpc/platforms/ps3/mm.c')
-rw-r--r-- | arch/powerpc/platforms/ps3/mm.c | 632 |
1 files changed, 518 insertions, 114 deletions
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index f8a3e206c584..7bb3e1620974 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c | |||
@@ -30,9 +30,9 @@ | |||
30 | #include "platform.h" | 30 | #include "platform.h" |
31 | 31 | ||
32 | #if defined(DEBUG) | 32 | #if defined(DEBUG) |
33 | #define DBG(fmt...) udbg_printf(fmt) | 33 | #define DBG udbg_printf |
34 | #else | 34 | #else |
35 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 35 | #define DBG pr_debug |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | enum { | 38 | enum { |
@@ -115,7 +115,8 @@ struct map { | |||
115 | }; | 115 | }; |
116 | 116 | ||
117 | #define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__) | 117 | #define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__) |
118 | static void _debug_dump_map(const struct map* m, const char* func, int line) | 118 | static void __maybe_unused _debug_dump_map(const struct map *m, |
119 | const char *func, int line) | ||
119 | { | 120 | { |
120 | DBG("%s:%d: map.total = %lxh\n", func, line, m->total); | 121 | DBG("%s:%d: map.total = %lxh\n", func, line, m->total); |
121 | DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size); | 122 | DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size); |
@@ -212,9 +213,15 @@ fail: | |||
212 | 213 | ||
213 | void ps3_mm_vas_destroy(void) | 214 | void ps3_mm_vas_destroy(void) |
214 | { | 215 | { |
216 | int result; | ||
217 | |||
218 | DBG("%s:%d: map.vas_id = %lu\n", __func__, __LINE__, map.vas_id); | ||
219 | |||
215 | if (map.vas_id) { | 220 | if (map.vas_id) { |
216 | lv1_select_virtual_address_space(0); | 221 | result = lv1_select_virtual_address_space(0); |
217 | lv1_destruct_virtual_address_space(map.vas_id); | 222 | BUG_ON(result); |
223 | result = lv1_destruct_virtual_address_space(map.vas_id); | ||
224 | BUG_ON(result); | ||
218 | map.vas_id = 0; | 225 | map.vas_id = 0; |
219 | } | 226 | } |
220 | } | 227 | } |
@@ -232,7 +239,7 @@ void ps3_mm_vas_destroy(void) | |||
232 | * @size is rounded down to a multiple of the vas large page size. | 239 | * @size is rounded down to a multiple of the vas large page size. |
233 | */ | 240 | */ |
234 | 241 | ||
235 | int ps3_mm_region_create(struct mem_region *r, unsigned long size) | 242 | static int ps3_mm_region_create(struct mem_region *r, unsigned long size) |
236 | { | 243 | { |
237 | int result; | 244 | int result; |
238 | unsigned long muid; | 245 | unsigned long muid; |
@@ -273,10 +280,14 @@ zero_region: | |||
273 | * @r: pointer to struct mem_region | 280 | * @r: pointer to struct mem_region |
274 | */ | 281 | */ |
275 | 282 | ||
276 | void ps3_mm_region_destroy(struct mem_region *r) | 283 | static void ps3_mm_region_destroy(struct mem_region *r) |
277 | { | 284 | { |
285 | int result; | ||
286 | |||
287 | DBG("%s:%d: r->base = %lxh\n", __func__, __LINE__, r->base); | ||
278 | if (r->base) { | 288 | if (r->base) { |
279 | lv1_release_memory(r->base); | 289 | result = lv1_release_memory(r->base); |
290 | BUG_ON(result); | ||
280 | r->size = r->base = r->offset = 0; | 291 | r->size = r->base = r->offset = 0; |
281 | map.total = map.rm.size; | 292 | map.total = map.rm.size; |
282 | } | 293 | } |
@@ -329,31 +340,34 @@ core_initcall(ps3_mm_add_memory); | |||
329 | /*============================================================================*/ | 340 | /*============================================================================*/ |
330 | 341 | ||
331 | /** | 342 | /** |
332 | * dma_lpar_to_bus - Translate an lpar address to ioc mapped bus address. | 343 | * dma_sb_lpar_to_bus - Translate an lpar address to ioc mapped bus address. |
333 | * @r: pointer to dma region structure | 344 | * @r: pointer to dma region structure |
334 | * @lpar_addr: HV lpar address | 345 | * @lpar_addr: HV lpar address |
335 | */ | 346 | */ |
336 | 347 | ||
337 | static unsigned long dma_lpar_to_bus(struct ps3_dma_region *r, | 348 | static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r, |
338 | unsigned long lpar_addr) | 349 | unsigned long lpar_addr) |
339 | { | 350 | { |
340 | BUG_ON(lpar_addr >= map.r1.base + map.r1.size); | 351 | if (lpar_addr >= map.rm.size) |
341 | return r->bus_addr + (lpar_addr <= map.rm.size ? lpar_addr | 352 | lpar_addr -= map.r1.offset; |
342 | : lpar_addr - map.r1.offset); | 353 | BUG_ON(lpar_addr < r->offset); |
354 | BUG_ON(lpar_addr >= r->offset + r->len); | ||
355 | return r->bus_addr + lpar_addr - r->offset; | ||
343 | } | 356 | } |
344 | 357 | ||
345 | #define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__) | 358 | #define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__) |
346 | static void _dma_dump_region(const struct ps3_dma_region *r, const char* func, | 359 | static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r, |
347 | int line) | 360 | const char *func, int line) |
348 | { | 361 | { |
349 | DBG("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, | 362 | DBG("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, |
350 | r->did.dev_id); | 363 | r->dev->dev_id); |
351 | DBG("%s:%d: page_size %u\n", func, line, r->page_size); | 364 | DBG("%s:%d: page_size %u\n", func, line, r->page_size); |
352 | DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | 365 | DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); |
353 | DBG("%s:%d: len %lxh\n", func, line, r->len); | 366 | DBG("%s:%d: len %lxh\n", func, line, r->len); |
367 | DBG("%s:%d: offset %lxh\n", func, line, r->offset); | ||
354 | } | 368 | } |
355 | 369 | ||
356 | /** | 370 | /** |
357 | * dma_chunk - A chunk of dma pages mapped by the io controller. | 371 | * dma_chunk - A chunk of dma pages mapped by the io controller. |
358 | * @region - The dma region that owns this chunk. | 372 | * @region - The dma region that owns this chunk. |
359 | * @lpar_addr: Starting lpar address of the area to map. | 373 | * @lpar_addr: Starting lpar address of the area to map. |
@@ -381,10 +395,11 @@ static void _dma_dump_chunk (const struct dma_chunk* c, const char* func, | |||
381 | int line) | 395 | int line) |
382 | { | 396 | { |
383 | DBG("%s:%d: r.dev %u:%u\n", func, line, | 397 | DBG("%s:%d: r.dev %u:%u\n", func, line, |
384 | c->region->did.bus_id, c->region->did.dev_id); | 398 | c->region->dev->bus_id, c->region->dev->dev_id); |
385 | DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); | 399 | DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); |
386 | DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); | 400 | DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); |
387 | DBG("%s:%d: r.len %lxh\n", func, line, c->region->len); | 401 | DBG("%s:%d: r.len %lxh\n", func, line, c->region->len); |
402 | DBG("%s:%d: r.offset %lxh\n", func, line, c->region->offset); | ||
388 | DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr); | 403 | DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr); |
389 | DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr); | 404 | DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr); |
390 | DBG("%s:%d: c.len %lxh\n", func, line, c->len); | 405 | DBG("%s:%d: c.len %lxh\n", func, line, c->len); |
@@ -395,39 +410,68 @@ static struct dma_chunk * dma_find_chunk(struct ps3_dma_region *r, | |||
395 | { | 410 | { |
396 | struct dma_chunk *c; | 411 | struct dma_chunk *c; |
397 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); | 412 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); |
398 | unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size); | 413 | unsigned long aligned_len = _ALIGN_UP(len+bus_addr-aligned_bus, |
414 | 1 << r->page_size); | ||
399 | 415 | ||
400 | list_for_each_entry(c, &r->chunk_list.head, link) { | 416 | list_for_each_entry(c, &r->chunk_list.head, link) { |
401 | /* intersection */ | 417 | /* intersection */ |
402 | if (aligned_bus >= c->bus_addr | 418 | if (aligned_bus >= c->bus_addr && |
403 | && aligned_bus < c->bus_addr + c->len | 419 | aligned_bus + aligned_len <= c->bus_addr + c->len) |
404 | && aligned_bus + aligned_len <= c->bus_addr + c->len) { | ||
405 | return c; | 420 | return c; |
406 | } | 421 | |
407 | /* below */ | 422 | /* below */ |
408 | if (aligned_bus + aligned_len <= c->bus_addr) { | 423 | if (aligned_bus + aligned_len <= c->bus_addr) |
409 | continue; | 424 | continue; |
410 | } | 425 | |
411 | /* above */ | 426 | /* above */ |
412 | if (aligned_bus >= c->bus_addr + c->len) { | 427 | if (aligned_bus >= c->bus_addr + c->len) |
413 | continue; | 428 | continue; |
414 | } | ||
415 | 429 | ||
416 | /* we don't handle the multi-chunk case for now */ | 430 | /* we don't handle the multi-chunk case for now */ |
417 | |||
418 | dma_dump_chunk(c); | 431 | dma_dump_chunk(c); |
419 | BUG(); | 432 | BUG(); |
420 | } | 433 | } |
421 | return NULL; | 434 | return NULL; |
422 | } | 435 | } |
423 | 436 | ||
424 | static int dma_free_chunk(struct dma_chunk *c) | 437 | static struct dma_chunk *dma_find_chunk_lpar(struct ps3_dma_region *r, |
438 | unsigned long lpar_addr, unsigned long len) | ||
439 | { | ||
440 | struct dma_chunk *c; | ||
441 | unsigned long aligned_lpar = _ALIGN_DOWN(lpar_addr, 1 << r->page_size); | ||
442 | unsigned long aligned_len = _ALIGN_UP(len + lpar_addr - aligned_lpar, | ||
443 | 1 << r->page_size); | ||
444 | |||
445 | list_for_each_entry(c, &r->chunk_list.head, link) { | ||
446 | /* intersection */ | ||
447 | if (c->lpar_addr <= aligned_lpar && | ||
448 | aligned_lpar < c->lpar_addr + c->len) { | ||
449 | if (aligned_lpar + aligned_len <= c->lpar_addr + c->len) | ||
450 | return c; | ||
451 | else { | ||
452 | dma_dump_chunk(c); | ||
453 | BUG(); | ||
454 | } | ||
455 | } | ||
456 | /* below */ | ||
457 | if (aligned_lpar + aligned_len <= c->lpar_addr) { | ||
458 | continue; | ||
459 | } | ||
460 | /* above */ | ||
461 | if (c->lpar_addr + c->len <= aligned_lpar) { | ||
462 | continue; | ||
463 | } | ||
464 | } | ||
465 | return NULL; | ||
466 | } | ||
467 | |||
468 | static int dma_sb_free_chunk(struct dma_chunk *c) | ||
425 | { | 469 | { |
426 | int result = 0; | 470 | int result = 0; |
427 | 471 | ||
428 | if (c->bus_addr) { | 472 | if (c->bus_addr) { |
429 | result = lv1_unmap_device_dma_region(c->region->did.bus_id, | 473 | result = lv1_unmap_device_dma_region(c->region->dev->bus_id, |
430 | c->region->did.dev_id, c->bus_addr, c->len); | 474 | c->region->dev->dev_id, c->bus_addr, c->len); |
431 | BUG_ON(result); | 475 | BUG_ON(result); |
432 | } | 476 | } |
433 | 477 | ||
@@ -435,8 +479,39 @@ static int dma_free_chunk(struct dma_chunk *c) | |||
435 | return result; | 479 | return result; |
436 | } | 480 | } |
437 | 481 | ||
482 | static int dma_ioc0_free_chunk(struct dma_chunk *c) | ||
483 | { | ||
484 | int result = 0; | ||
485 | int iopage; | ||
486 | unsigned long offset; | ||
487 | struct ps3_dma_region *r = c->region; | ||
488 | |||
489 | DBG("%s:start\n", __func__); | ||
490 | for (iopage = 0; iopage < (c->len >> r->page_size); iopage++) { | ||
491 | offset = (1 << r->page_size) * iopage; | ||
492 | /* put INVALID entry */ | ||
493 | result = lv1_put_iopte(0, | ||
494 | c->bus_addr + offset, | ||
495 | c->lpar_addr + offset, | ||
496 | r->ioid, | ||
497 | 0); | ||
498 | DBG("%s: bus=%#lx, lpar=%#lx, ioid=%d\n", __func__, | ||
499 | c->bus_addr + offset, | ||
500 | c->lpar_addr + offset, | ||
501 | r->ioid); | ||
502 | |||
503 | if (result) { | ||
504 | DBG("%s:%d: lv1_put_iopte failed: %s\n", __func__, | ||
505 | __LINE__, ps3_result(result)); | ||
506 | } | ||
507 | } | ||
508 | kfree(c); | ||
509 | DBG("%s:end\n", __func__); | ||
510 | return result; | ||
511 | } | ||
512 | |||
438 | /** | 513 | /** |
439 | * dma_map_pages - Maps dma pages into the io controller bus address space. | 514 | * dma_sb_map_pages - Maps dma pages into the io controller bus address space. |
440 | * @r: Pointer to a struct ps3_dma_region. | 515 | * @r: Pointer to a struct ps3_dma_region. |
441 | * @phys_addr: Starting physical address of the area to map. | 516 | * @phys_addr: Starting physical address of the area to map. |
442 | * @len: Length in bytes of the area to map. | 517 | * @len: Length in bytes of the area to map. |
@@ -446,8 +521,8 @@ static int dma_free_chunk(struct dma_chunk *c) | |||
446 | * make the HV call to add the pages into the io controller address space. | 521 | * make the HV call to add the pages into the io controller address space. |
447 | */ | 522 | */ |
448 | 523 | ||
449 | static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, | 524 | static int dma_sb_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, |
450 | unsigned long len, struct dma_chunk **c_out) | 525 | unsigned long len, struct dma_chunk **c_out, u64 iopte_flag) |
451 | { | 526 | { |
452 | int result; | 527 | int result; |
453 | struct dma_chunk *c; | 528 | struct dma_chunk *c; |
@@ -461,13 +536,13 @@ static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, | |||
461 | 536 | ||
462 | c->region = r; | 537 | c->region = r; |
463 | c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); | 538 | c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); |
464 | c->bus_addr = dma_lpar_to_bus(r, c->lpar_addr); | 539 | c->bus_addr = dma_sb_lpar_to_bus(r, c->lpar_addr); |
465 | c->len = len; | 540 | c->len = len; |
466 | 541 | ||
467 | result = lv1_map_device_dma_region(c->region->did.bus_id, | 542 | BUG_ON(iopte_flag != 0xf800000000000000UL); |
468 | c->region->did.dev_id, c->lpar_addr, c->bus_addr, c->len, | 543 | result = lv1_map_device_dma_region(c->region->dev->bus_id, |
469 | 0xf800000000000000UL); | 544 | c->region->dev->dev_id, c->lpar_addr, |
470 | 545 | c->bus_addr, c->len, iopte_flag); | |
471 | if (result) { | 546 | if (result) { |
472 | DBG("%s:%d: lv1_map_device_dma_region failed: %s\n", | 547 | DBG("%s:%d: lv1_map_device_dma_region failed: %s\n", |
473 | __func__, __LINE__, ps3_result(result)); | 548 | __func__, __LINE__, ps3_result(result)); |
@@ -487,26 +562,120 @@ fail_alloc: | |||
487 | return result; | 562 | return result; |
488 | } | 563 | } |
489 | 564 | ||
565 | static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, | ||
566 | unsigned long len, struct dma_chunk **c_out, | ||
567 | u64 iopte_flag) | ||
568 | { | ||
569 | int result; | ||
570 | struct dma_chunk *c, *last; | ||
571 | int iopage, pages; | ||
572 | unsigned long offset; | ||
573 | |||
574 | DBG(KERN_ERR "%s: phy=%#lx, lpar%#lx, len=%#lx\n", __func__, | ||
575 | phys_addr, ps3_mm_phys_to_lpar(phys_addr), len); | ||
576 | c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC); | ||
577 | |||
578 | if (!c) { | ||
579 | result = -ENOMEM; | ||
580 | goto fail_alloc; | ||
581 | } | ||
582 | |||
583 | c->region = r; | ||
584 | c->len = len; | ||
585 | c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); | ||
586 | /* allocate IO address */ | ||
587 | if (list_empty(&r->chunk_list.head)) { | ||
588 | /* first one */ | ||
589 | c->bus_addr = r->bus_addr; | ||
590 | } else { | ||
591 | /* derive from last bus addr*/ | ||
592 | last = list_entry(r->chunk_list.head.next, | ||
593 | struct dma_chunk, link); | ||
594 | c->bus_addr = last->bus_addr + last->len; | ||
595 | DBG("%s: last bus=%#lx, len=%#lx\n", __func__, | ||
596 | last->bus_addr, last->len); | ||
597 | } | ||
598 | |||
599 | /* FIXME: check whether length exceeds region size */ | ||
600 | |||
601 | /* build ioptes for the area */ | ||
602 | pages = len >> r->page_size; | ||
603 | DBG("%s: pgsize=%#x len=%#lx pages=%#x iopteflag=%#lx\n", __func__, | ||
604 | r->page_size, r->len, pages, iopte_flag); | ||
605 | for (iopage = 0; iopage < pages; iopage++) { | ||
606 | offset = (1 << r->page_size) * iopage; | ||
607 | result = lv1_put_iopte(0, | ||
608 | c->bus_addr + offset, | ||
609 | c->lpar_addr + offset, | ||
610 | r->ioid, | ||
611 | iopte_flag); | ||
612 | if (result) { | ||
613 | printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region " | ||
614 | "failed: %s\n", __func__, __LINE__, | ||
615 | ps3_result(result)); | ||
616 | goto fail_map; | ||
617 | } | ||
618 | DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__, | ||
619 | iopage, c->bus_addr + offset, c->lpar_addr + offset, | ||
620 | r->ioid); | ||
621 | } | ||
622 | |||
623 | /* be sure that last allocated one is inserted at head */ | ||
624 | list_add(&c->link, &r->chunk_list.head); | ||
625 | |||
626 | *c_out = c; | ||
627 | DBG("%s: end\n", __func__); | ||
628 | return 0; | ||
629 | |||
630 | fail_map: | ||
631 | for (iopage--; 0 <= iopage; iopage--) { | ||
632 | lv1_put_iopte(0, | ||
633 | c->bus_addr + offset, | ||
634 | c->lpar_addr + offset, | ||
635 | r->ioid, | ||
636 | 0); | ||
637 | } | ||
638 | kfree(c); | ||
639 | fail_alloc: | ||
640 | *c_out = NULL; | ||
641 | return result; | ||
642 | } | ||
643 | |||
490 | /** | 644 | /** |
491 | * dma_region_create - Create a device dma region. | 645 | * dma_sb_region_create - Create a device dma region. |
492 | * @r: Pointer to a struct ps3_dma_region. | 646 | * @r: Pointer to a struct ps3_dma_region. |
493 | * | 647 | * |
494 | * This is the lowest level dma region create routine, and is the one that | 648 | * This is the lowest level dma region create routine, and is the one that |
495 | * will make the HV call to create the region. | 649 | * will make the HV call to create the region. |
496 | */ | 650 | */ |
497 | 651 | ||
498 | static int dma_region_create(struct ps3_dma_region* r) | 652 | static int dma_sb_region_create(struct ps3_dma_region *r) |
499 | { | 653 | { |
500 | int result; | 654 | int result; |
501 | 655 | ||
502 | r->len = _ALIGN_UP(map.total, 1 << r->page_size); | 656 | pr_info(" -> %s:%d:\n", __func__, __LINE__); |
657 | |||
658 | BUG_ON(!r); | ||
659 | |||
660 | if (!r->dev->bus_id) { | ||
661 | pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, | ||
662 | r->dev->bus_id, r->dev->dev_id); | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | DBG("%s:%u: len = 0x%lx, page_size = %u, offset = 0x%lx\n", __func__, | ||
667 | __LINE__, r->len, r->page_size, r->offset); | ||
668 | |||
669 | BUG_ON(!r->len); | ||
670 | BUG_ON(!r->page_size); | ||
671 | BUG_ON(!r->region_ops); | ||
672 | |||
503 | INIT_LIST_HEAD(&r->chunk_list.head); | 673 | INIT_LIST_HEAD(&r->chunk_list.head); |
504 | spin_lock_init(&r->chunk_list.lock); | 674 | spin_lock_init(&r->chunk_list.lock); |
505 | 675 | ||
506 | result = lv1_allocate_device_dma_region(r->did.bus_id, r->did.dev_id, | 676 | result = lv1_allocate_device_dma_region(r->dev->bus_id, r->dev->dev_id, |
507 | r->len, r->page_size, r->region_type, &r->bus_addr); | 677 | roundup_pow_of_two(r->len), r->page_size, r->region_type, |
508 | 678 | &r->bus_addr); | |
509 | dma_dump_region(r); | ||
510 | 679 | ||
511 | if (result) { | 680 | if (result) { |
512 | DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n", | 681 | DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n", |
@@ -517,6 +686,27 @@ static int dma_region_create(struct ps3_dma_region* r) | |||
517 | return result; | 686 | return result; |
518 | } | 687 | } |
519 | 688 | ||
689 | static int dma_ioc0_region_create(struct ps3_dma_region *r) | ||
690 | { | ||
691 | int result; | ||
692 | |||
693 | INIT_LIST_HEAD(&r->chunk_list.head); | ||
694 | spin_lock_init(&r->chunk_list.lock); | ||
695 | |||
696 | result = lv1_allocate_io_segment(0, | ||
697 | r->len, | ||
698 | r->page_size, | ||
699 | &r->bus_addr); | ||
700 | if (result) { | ||
701 | DBG("%s:%d: lv1_allocate_io_segment failed: %s\n", | ||
702 | __func__, __LINE__, ps3_result(result)); | ||
703 | r->len = r->bus_addr = 0; | ||
704 | } | ||
705 | DBG("%s: len=%#lx, pg=%d, bus=%#lx\n", __func__, | ||
706 | r->len, r->page_size, r->bus_addr); | ||
707 | return result; | ||
708 | } | ||
709 | |||
520 | /** | 710 | /** |
521 | * dma_region_free - Free a device dma region. | 711 | * dma_region_free - Free a device dma region. |
522 | * @r: Pointer to a struct ps3_dma_region. | 712 | * @r: Pointer to a struct ps3_dma_region. |
@@ -525,31 +715,62 @@ static int dma_region_create(struct ps3_dma_region* r) | |||
525 | * will make the HV call to free the region. | 715 | * will make the HV call to free the region. |
526 | */ | 716 | */ |
527 | 717 | ||
528 | static int dma_region_free(struct ps3_dma_region* r) | 718 | static int dma_sb_region_free(struct ps3_dma_region *r) |
529 | { | 719 | { |
530 | int result; | 720 | int result; |
531 | struct dma_chunk *c; | 721 | struct dma_chunk *c; |
532 | struct dma_chunk *tmp; | 722 | struct dma_chunk *tmp; |
533 | 723 | ||
724 | BUG_ON(!r); | ||
725 | |||
726 | if (!r->dev->bus_id) { | ||
727 | pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, | ||
728 | r->dev->bus_id, r->dev->dev_id); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
534 | list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) { | 732 | list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) { |
535 | list_del(&c->link); | 733 | list_del(&c->link); |
536 | dma_free_chunk(c); | 734 | dma_sb_free_chunk(c); |
537 | } | 735 | } |
538 | 736 | ||
539 | result = lv1_free_device_dma_region(r->did.bus_id, r->did.dev_id, | 737 | result = lv1_free_device_dma_region(r->dev->bus_id, r->dev->dev_id, |
540 | r->bus_addr); | 738 | r->bus_addr); |
541 | 739 | ||
542 | if (result) | 740 | if (result) |
543 | DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", | 741 | DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", |
544 | __func__, __LINE__, ps3_result(result)); | 742 | __func__, __LINE__, ps3_result(result)); |
545 | 743 | ||
546 | r->len = r->bus_addr = 0; | 744 | r->bus_addr = 0; |
745 | |||
746 | return result; | ||
747 | } | ||
748 | |||
749 | static int dma_ioc0_region_free(struct ps3_dma_region *r) | ||
750 | { | ||
751 | int result; | ||
752 | struct dma_chunk *c, *n; | ||
753 | |||
754 | DBG("%s: start\n", __func__); | ||
755 | list_for_each_entry_safe(c, n, &r->chunk_list.head, link) { | ||
756 | list_del(&c->link); | ||
757 | dma_ioc0_free_chunk(c); | ||
758 | } | ||
759 | |||
760 | result = lv1_release_io_segment(0, r->bus_addr); | ||
761 | |||
762 | if (result) | ||
763 | DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", | ||
764 | __func__, __LINE__, ps3_result(result)); | ||
765 | |||
766 | r->bus_addr = 0; | ||
767 | DBG("%s: end\n", __func__); | ||
547 | 768 | ||
548 | return result; | 769 | return result; |
549 | } | 770 | } |
550 | 771 | ||
551 | /** | 772 | /** |
552 | * dma_map_area - Map an area of memory into a device dma region. | 773 | * dma_sb_map_area - Map an area of memory into a device dma region. |
553 | * @r: Pointer to a struct ps3_dma_region. | 774 | * @r: Pointer to a struct ps3_dma_region. |
554 | * @virt_addr: Starting virtual address of the area to map. | 775 | * @virt_addr: Starting virtual address of the area to map. |
555 | * @len: Length in bytes of the area to map. | 776 | * @len: Length in bytes of the area to map. |
@@ -559,16 +780,19 @@ static int dma_region_free(struct ps3_dma_region* r) | |||
559 | * This is the common dma mapping routine. | 780 | * This is the common dma mapping routine. |
560 | */ | 781 | */ |
561 | 782 | ||
562 | static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | 783 | static int dma_sb_map_area(struct ps3_dma_region *r, unsigned long virt_addr, |
563 | unsigned long len, unsigned long *bus_addr) | 784 | unsigned long len, unsigned long *bus_addr, |
785 | u64 iopte_flag) | ||
564 | { | 786 | { |
565 | int result; | 787 | int result; |
566 | unsigned long flags; | 788 | unsigned long flags; |
567 | struct dma_chunk *c; | 789 | struct dma_chunk *c; |
568 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) | 790 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) |
569 | : virt_addr; | 791 | : virt_addr; |
570 | 792 | unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size); | |
571 | *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); | 793 | unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys, |
794 | 1 << r->page_size); | ||
795 | *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); | ||
572 | 796 | ||
573 | if (!USE_DYNAMIC_DMA) { | 797 | if (!USE_DYNAMIC_DMA) { |
574 | unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr); | 798 | unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr); |
@@ -588,17 +812,18 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | |||
588 | c = dma_find_chunk(r, *bus_addr, len); | 812 | c = dma_find_chunk(r, *bus_addr, len); |
589 | 813 | ||
590 | if (c) { | 814 | if (c) { |
815 | DBG("%s:%d: reusing mapped chunk", __func__, __LINE__); | ||
816 | dma_dump_chunk(c); | ||
591 | c->usage_count++; | 817 | c->usage_count++; |
592 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | 818 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); |
593 | return 0; | 819 | return 0; |
594 | } | 820 | } |
595 | 821 | ||
596 | result = dma_map_pages(r, _ALIGN_DOWN(phys_addr, 1 << r->page_size), | 822 | result = dma_sb_map_pages(r, aligned_phys, aligned_len, &c, iopte_flag); |
597 | _ALIGN_UP(len, 1 << r->page_size), &c); | ||
598 | 823 | ||
599 | if (result) { | 824 | if (result) { |
600 | *bus_addr = 0; | 825 | *bus_addr = 0; |
601 | DBG("%s:%d: dma_map_pages failed (%d)\n", | 826 | DBG("%s:%d: dma_sb_map_pages failed (%d)\n", |
602 | __func__, __LINE__, result); | 827 | __func__, __LINE__, result); |
603 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | 828 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); |
604 | return result; | 829 | return result; |
@@ -610,8 +835,57 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | |||
610 | return result; | 835 | return result; |
611 | } | 836 | } |
612 | 837 | ||
838 | static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | ||
839 | unsigned long len, unsigned long *bus_addr, | ||
840 | u64 iopte_flag) | ||
841 | { | ||
842 | int result; | ||
843 | unsigned long flags; | ||
844 | struct dma_chunk *c; | ||
845 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) | ||
846 | : virt_addr; | ||
847 | unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size); | ||
848 | unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys, | ||
849 | 1 << r->page_size); | ||
850 | |||
851 | DBG(KERN_ERR "%s: vaddr=%#lx, len=%#lx\n", __func__, | ||
852 | virt_addr, len); | ||
853 | DBG(KERN_ERR "%s: ph=%#lx a_ph=%#lx a_l=%#lx\n", __func__, | ||
854 | phys_addr, aligned_phys, aligned_len); | ||
855 | |||
856 | spin_lock_irqsave(&r->chunk_list.lock, flags); | ||
857 | c = dma_find_chunk_lpar(r, ps3_mm_phys_to_lpar(phys_addr), len); | ||
858 | |||
859 | if (c) { | ||
860 | /* FIXME */ | ||
861 | BUG(); | ||
862 | *bus_addr = c->bus_addr + phys_addr - aligned_phys; | ||
863 | c->usage_count++; | ||
864 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | result = dma_ioc0_map_pages(r, aligned_phys, aligned_len, &c, | ||
869 | iopte_flag); | ||
870 | |||
871 | if (result) { | ||
872 | *bus_addr = 0; | ||
873 | DBG("%s:%d: dma_ioc0_map_pages failed (%d)\n", | ||
874 | __func__, __LINE__, result); | ||
875 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
876 | return result; | ||
877 | } | ||
878 | *bus_addr = c->bus_addr + phys_addr - aligned_phys; | ||
879 | DBG("%s: va=%#lx pa=%#lx a_pa=%#lx bus=%#lx\n", __func__, | ||
880 | virt_addr, phys_addr, aligned_phys, *bus_addr); | ||
881 | c->usage_count = 1; | ||
882 | |||
883 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
884 | return result; | ||
885 | } | ||
886 | |||
613 | /** | 887 | /** |
614 | * dma_unmap_area - Unmap an area of memory from a device dma region. | 888 | * dma_sb_unmap_area - Unmap an area of memory from a device dma region. |
615 | * @r: Pointer to a struct ps3_dma_region. | 889 | * @r: Pointer to a struct ps3_dma_region. |
616 | * @bus_addr: The starting ioc bus address of the area to unmap. | 890 | * @bus_addr: The starting ioc bus address of the area to unmap. |
617 | * @len: Length in bytes of the area to unmap. | 891 | * @len: Length in bytes of the area to unmap. |
@@ -619,7 +893,7 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, | |||
619 | * This is the common dma unmap routine. | 893 | * This is the common dma unmap routine. |
620 | */ | 894 | */ |
621 | 895 | ||
622 | int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, | 896 | static int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, |
623 | unsigned long len) | 897 | unsigned long len) |
624 | { | 898 | { |
625 | unsigned long flags; | 899 | unsigned long flags; |
@@ -631,7 +905,8 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, | |||
631 | if (!c) { | 905 | if (!c) { |
632 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, | 906 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, |
633 | 1 << r->page_size); | 907 | 1 << r->page_size); |
634 | unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size); | 908 | unsigned long aligned_len = _ALIGN_UP(len + bus_addr |
909 | - aligned_bus, 1 << r->page_size); | ||
635 | DBG("%s:%d: not found: bus_addr %lxh\n", | 910 | DBG("%s:%d: not found: bus_addr %lxh\n", |
636 | __func__, __LINE__, bus_addr); | 911 | __func__, __LINE__, bus_addr); |
637 | DBG("%s:%d: not found: len %lxh\n", | 912 | DBG("%s:%d: not found: len %lxh\n", |
@@ -647,94 +922,166 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, | |||
647 | 922 | ||
648 | if (!c->usage_count) { | 923 | if (!c->usage_count) { |
649 | list_del(&c->link); | 924 | list_del(&c->link); |
650 | dma_free_chunk(c); | 925 | dma_sb_free_chunk(c); |
651 | } | 926 | } |
652 | 927 | ||
653 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | 928 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); |
654 | return 0; | 929 | return 0; |
655 | } | 930 | } |
656 | 931 | ||
932 | static int dma_ioc0_unmap_area(struct ps3_dma_region *r, | ||
933 | unsigned long bus_addr, unsigned long len) | ||
934 | { | ||
935 | unsigned long flags; | ||
936 | struct dma_chunk *c; | ||
937 | |||
938 | DBG("%s: start a=%#lx l=%#lx\n", __func__, bus_addr, len); | ||
939 | spin_lock_irqsave(&r->chunk_list.lock, flags); | ||
940 | c = dma_find_chunk(r, bus_addr, len); | ||
941 | |||
942 | if (!c) { | ||
943 | unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, | ||
944 | 1 << r->page_size); | ||
945 | unsigned long aligned_len = _ALIGN_UP(len + bus_addr | ||
946 | - aligned_bus, | ||
947 | 1 << r->page_size); | ||
948 | DBG("%s:%d: not found: bus_addr %lxh\n", | ||
949 | __func__, __LINE__, bus_addr); | ||
950 | DBG("%s:%d: not found: len %lxh\n", | ||
951 | __func__, __LINE__, len); | ||
952 | DBG("%s:%d: not found: aligned_bus %lxh\n", | ||
953 | __func__, __LINE__, aligned_bus); | ||
954 | DBG("%s:%d: not found: aligned_len %lxh\n", | ||
955 | __func__, __LINE__, aligned_len); | ||
956 | BUG(); | ||
957 | } | ||
958 | |||
959 | c->usage_count--; | ||
960 | |||
961 | if (!c->usage_count) { | ||
962 | list_del(&c->link); | ||
963 | dma_ioc0_free_chunk(c); | ||
964 | } | ||
965 | |||
966 | spin_unlock_irqrestore(&r->chunk_list.lock, flags); | ||
967 | DBG("%s: end\n", __func__); | ||
968 | return 0; | ||
969 | } | ||
970 | |||
657 | /** | 971 | /** |
658 | * dma_region_create_linear - Setup a linear dma maping for a device. | 972 | * dma_sb_region_create_linear - Setup a linear dma mapping for a device. |
659 | * @r: Pointer to a struct ps3_dma_region. | 973 | * @r: Pointer to a struct ps3_dma_region. |
660 | * | 974 | * |
661 | * This routine creates an HV dma region for the device and maps all available | 975 | * This routine creates an HV dma region for the device and maps all available |
662 | * ram into the io controller bus address space. | 976 | * ram into the io controller bus address space. |
663 | */ | 977 | */ |
664 | 978 | ||
665 | static int dma_region_create_linear(struct ps3_dma_region *r) | 979 | static int dma_sb_region_create_linear(struct ps3_dma_region *r) |
666 | { | 980 | { |
667 | int result; | 981 | int result; |
668 | unsigned long tmp; | 982 | unsigned long virt_addr, len, tmp; |
669 | 983 | ||
670 | /* force 16M dma pages for linear mapping */ | 984 | if (r->len > 16*1024*1024) { /* FIXME: need proper fix */ |
671 | 985 | /* force 16M dma pages for linear mapping */ | |
672 | if (r->page_size != PS3_DMA_16M) { | 986 | if (r->page_size != PS3_DMA_16M) { |
673 | pr_info("%s:%d: forcing 16M pages for linear map\n", | 987 | pr_info("%s:%d: forcing 16M pages for linear map\n", |
674 | __func__, __LINE__); | 988 | __func__, __LINE__); |
675 | r->page_size = PS3_DMA_16M; | 989 | r->page_size = PS3_DMA_16M; |
990 | r->len = _ALIGN_UP(r->len, 1 << r->page_size); | ||
991 | } | ||
676 | } | 992 | } |
677 | 993 | ||
678 | result = dma_region_create(r); | 994 | result = dma_sb_region_create(r); |
679 | BUG_ON(result); | 995 | BUG_ON(result); |
680 | 996 | ||
681 | result = dma_map_area(r, map.rm.base, map.rm.size, &tmp); | 997 | if (r->offset < map.rm.size) { |
682 | BUG_ON(result); | 998 | /* Map (part of) 1st RAM chunk */ |
683 | 999 | virt_addr = map.rm.base + r->offset; | |
684 | if (USE_LPAR_ADDR) | 1000 | len = map.rm.size - r->offset; |
685 | result = dma_map_area(r, map.r1.base, map.r1.size, | 1001 | if (len > r->len) |
686 | &tmp); | 1002 | len = r->len; |
687 | else | 1003 | result = dma_sb_map_area(r, virt_addr, len, &tmp, |
688 | result = dma_map_area(r, map.rm.size, map.r1.size, | 1004 | IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); |
689 | &tmp); | 1005 | BUG_ON(result); |
1006 | } | ||
690 | 1007 | ||
691 | BUG_ON(result); | 1008 | if (r->offset + r->len > map.rm.size) { |
1009 | /* Map (part of) 2nd RAM chunk */ | ||
1010 | virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; | ||
1011 | len = r->len; | ||
1012 | if (r->offset >= map.rm.size) | ||
1013 | virt_addr += r->offset - map.rm.size; | ||
1014 | else | ||
1015 | len -= map.rm.size - r->offset; | ||
1016 | result = dma_sb_map_area(r, virt_addr, len, &tmp, | ||
1017 | IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); | ||
1018 | BUG_ON(result); | ||
1019 | } | ||
692 | 1020 | ||
693 | return result; | 1021 | return result; |
694 | } | 1022 | } |
695 | 1023 | ||
696 | /** | 1024 | /** |
697 | * dma_region_free_linear - Free a linear dma mapping for a device. | 1025 | * dma_sb_region_free_linear - Free a linear dma mapping for a device. |
698 | * @r: Pointer to a struct ps3_dma_region. | 1026 | * @r: Pointer to a struct ps3_dma_region. |
699 | * | 1027 | * |
700 | * This routine will unmap all mapped areas and free the HV dma region. | 1028 | * This routine will unmap all mapped areas and free the HV dma region. |
701 | */ | 1029 | */ |
702 | 1030 | ||
703 | static int dma_region_free_linear(struct ps3_dma_region *r) | 1031 | static int dma_sb_region_free_linear(struct ps3_dma_region *r) |
704 | { | 1032 | { |
705 | int result; | 1033 | int result; |
1034 | unsigned long bus_addr, len, lpar_addr; | ||
1035 | |||
1036 | if (r->offset < map.rm.size) { | ||
1037 | /* Unmap (part of) 1st RAM chunk */ | ||
1038 | lpar_addr = map.rm.base + r->offset; | ||
1039 | len = map.rm.size - r->offset; | ||
1040 | if (len > r->len) | ||
1041 | len = r->len; | ||
1042 | bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); | ||
1043 | result = dma_sb_unmap_area(r, bus_addr, len); | ||
1044 | BUG_ON(result); | ||
1045 | } | ||
706 | 1046 | ||
707 | result = dma_unmap_area(r, dma_lpar_to_bus(r, 0), map.rm.size); | 1047 | if (r->offset + r->len > map.rm.size) { |
708 | BUG_ON(result); | 1048 | /* Unmap (part of) 2nd RAM chunk */ |
709 | 1049 | lpar_addr = map.r1.base; | |
710 | result = dma_unmap_area(r, dma_lpar_to_bus(r, map.r1.base), | 1050 | len = r->len; |
711 | map.r1.size); | 1051 | if (r->offset >= map.rm.size) |
712 | BUG_ON(result); | 1052 | lpar_addr += r->offset - map.rm.size; |
1053 | else | ||
1054 | len -= map.rm.size - r->offset; | ||
1055 | bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); | ||
1056 | result = dma_sb_unmap_area(r, bus_addr, len); | ||
1057 | BUG_ON(result); | ||
1058 | } | ||
713 | 1059 | ||
714 | result = dma_region_free(r); | 1060 | result = dma_sb_region_free(r); |
715 | BUG_ON(result); | 1061 | BUG_ON(result); |
716 | 1062 | ||
717 | return result; | 1063 | return result; |
718 | } | 1064 | } |
719 | 1065 | ||
720 | /** | 1066 | /** |
721 | * dma_map_area_linear - Map an area of memory into a device dma region. | 1067 | * dma_sb_map_area_linear - Map an area of memory into a device dma region. |
722 | * @r: Pointer to a struct ps3_dma_region. | 1068 | * @r: Pointer to a struct ps3_dma_region. |
723 | * @virt_addr: Starting virtual address of the area to map. | 1069 | * @virt_addr: Starting virtual address of the area to map. |
724 | * @len: Length in bytes of the area to map. | 1070 | * @len: Length in bytes of the area to map. |
725 | * @bus_addr: A pointer to return the starting ioc bus address of the area to | 1071 | * @bus_addr: A pointer to return the starting ioc bus address of the area to |
726 | * map. | 1072 | * map. |
727 | * | 1073 | * |
728 | * This routine just returns the coresponding bus address. Actual mapping | 1074 | * This routine just returns the corresponding bus address. Actual mapping |
729 | * occurs in dma_region_create_linear(). | 1075 | * occurs in dma_region_create_linear(). |
730 | */ | 1076 | */ |
731 | 1077 | ||
732 | static int dma_map_area_linear(struct ps3_dma_region *r, | 1078 | static int dma_sb_map_area_linear(struct ps3_dma_region *r, |
733 | unsigned long virt_addr, unsigned long len, unsigned long *bus_addr) | 1079 | unsigned long virt_addr, unsigned long len, unsigned long *bus_addr, |
1080 | u64 iopte_flag) | ||
734 | { | 1081 | { |
735 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) | 1082 | unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) |
736 | : virt_addr; | 1083 | : virt_addr; |
737 | *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); | 1084 | *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); |
738 | return 0; | 1085 | return 0; |
739 | } | 1086 | } |
740 | 1087 | ||
@@ -744,42 +1091,98 @@ static int dma_map_area_linear(struct ps3_dma_region *r, | |||
744 | * @bus_addr: The starting ioc bus address of the area to unmap. | 1091 | * @bus_addr: The starting ioc bus address of the area to unmap. |
745 | * @len: Length in bytes of the area to unmap. | 1092 | * @len: Length in bytes of the area to unmap. |
746 | * | 1093 | * |
747 | * This routine does nothing. Unmapping occurs in dma_region_free_linear(). | 1094 | * This routine does nothing. Unmapping occurs in dma_sb_region_free_linear(). |
748 | */ | 1095 | */ |
749 | 1096 | ||
750 | static int dma_unmap_area_linear(struct ps3_dma_region *r, | 1097 | static int dma_sb_unmap_area_linear(struct ps3_dma_region *r, |
751 | unsigned long bus_addr, unsigned long len) | 1098 | unsigned long bus_addr, unsigned long len) |
752 | { | 1099 | { |
753 | return 0; | 1100 | return 0; |
1101 | }; | ||
1102 | |||
1103 | static const struct ps3_dma_region_ops ps3_dma_sb_region_ops = { | ||
1104 | .create = dma_sb_region_create, | ||
1105 | .free = dma_sb_region_free, | ||
1106 | .map = dma_sb_map_area, | ||
1107 | .unmap = dma_sb_unmap_area | ||
1108 | }; | ||
1109 | |||
1110 | static const struct ps3_dma_region_ops ps3_dma_sb_region_linear_ops = { | ||
1111 | .create = dma_sb_region_create_linear, | ||
1112 | .free = dma_sb_region_free_linear, | ||
1113 | .map = dma_sb_map_area_linear, | ||
1114 | .unmap = dma_sb_unmap_area_linear | ||
1115 | }; | ||
1116 | |||
1117 | static const struct ps3_dma_region_ops ps3_dma_ioc0_region_ops = { | ||
1118 | .create = dma_ioc0_region_create, | ||
1119 | .free = dma_ioc0_region_free, | ||
1120 | .map = dma_ioc0_map_area, | ||
1121 | .unmap = dma_ioc0_unmap_area | ||
1122 | }; | ||
1123 | |||
1124 | int ps3_dma_region_init(struct ps3_system_bus_device *dev, | ||
1125 | struct ps3_dma_region *r, enum ps3_dma_page_size page_size, | ||
1126 | enum ps3_dma_region_type region_type, void *addr, unsigned long len) | ||
1127 | { | ||
1128 | unsigned long lpar_addr; | ||
1129 | |||
1130 | lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0; | ||
1131 | |||
1132 | r->dev = dev; | ||
1133 | r->page_size = page_size; | ||
1134 | r->region_type = region_type; | ||
1135 | r->offset = lpar_addr; | ||
1136 | if (r->offset >= map.rm.size) | ||
1137 | r->offset -= map.r1.offset; | ||
1138 | r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size); | ||
1139 | |||
1140 | switch (dev->dev_type) { | ||
1141 | case PS3_DEVICE_TYPE_SB: | ||
1142 | r->region_ops = (USE_DYNAMIC_DMA) | ||
1143 | ? &ps3_dma_sb_region_ops | ||
1144 | : &ps3_dma_sb_region_linear_ops; | ||
1145 | break; | ||
1146 | case PS3_DEVICE_TYPE_IOC0: | ||
1147 | r->region_ops = &ps3_dma_ioc0_region_ops; | ||
1148 | break; | ||
1149 | default: | ||
1150 | BUG(); | ||
1151 | return -EINVAL; | ||
1152 | } | ||
1153 | return 0; | ||
754 | } | 1154 | } |
1155 | EXPORT_SYMBOL(ps3_dma_region_init); | ||
755 | 1156 | ||
756 | int ps3_dma_region_create(struct ps3_dma_region *r) | 1157 | int ps3_dma_region_create(struct ps3_dma_region *r) |
757 | { | 1158 | { |
758 | return (USE_DYNAMIC_DMA) | 1159 | BUG_ON(!r); |
759 | ? dma_region_create(r) | 1160 | BUG_ON(!r->region_ops); |
760 | : dma_region_create_linear(r); | 1161 | BUG_ON(!r->region_ops->create); |
1162 | return r->region_ops->create(r); | ||
761 | } | 1163 | } |
1164 | EXPORT_SYMBOL(ps3_dma_region_create); | ||
762 | 1165 | ||
763 | int ps3_dma_region_free(struct ps3_dma_region *r) | 1166 | int ps3_dma_region_free(struct ps3_dma_region *r) |
764 | { | 1167 | { |
765 | return (USE_DYNAMIC_DMA) | 1168 | BUG_ON(!r); |
766 | ? dma_region_free(r) | 1169 | BUG_ON(!r->region_ops); |
767 | : dma_region_free_linear(r); | 1170 | BUG_ON(!r->region_ops->free); |
1171 | return r->region_ops->free(r); | ||
768 | } | 1172 | } |
1173 | EXPORT_SYMBOL(ps3_dma_region_free); | ||
769 | 1174 | ||
770 | int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr, | 1175 | int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr, |
771 | unsigned long len, unsigned long *bus_addr) | 1176 | unsigned long len, unsigned long *bus_addr, |
1177 | u64 iopte_flag) | ||
772 | { | 1178 | { |
773 | return (USE_DYNAMIC_DMA) | 1179 | return r->region_ops->map(r, virt_addr, len, bus_addr, iopte_flag); |
774 | ? dma_map_area(r, virt_addr, len, bus_addr) | ||
775 | : dma_map_area_linear(r, virt_addr, len, bus_addr); | ||
776 | } | 1180 | } |
777 | 1181 | ||
778 | int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr, | 1182 | int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr, |
779 | unsigned long len) | 1183 | unsigned long len) |
780 | { | 1184 | { |
781 | return (USE_DYNAMIC_DMA) ? dma_unmap_area(r, bus_addr, len) | 1185 | return r->region_ops->unmap(r, bus_addr, len); |
782 | : dma_unmap_area_linear(r, bus_addr, len); | ||
783 | } | 1186 | } |
784 | 1187 | ||
785 | /*============================================================================*/ | 1188 | /*============================================================================*/ |
@@ -810,12 +1213,13 @@ void __init ps3_mm_init(void) | |||
810 | BUG_ON(map.rm.base); | 1213 | BUG_ON(map.rm.base); |
811 | BUG_ON(!map.rm.size); | 1214 | BUG_ON(!map.rm.size); |
812 | 1215 | ||
813 | lmb_add(map.rm.base, map.rm.size); | ||
814 | lmb_analyze(); | ||
815 | 1216 | ||
816 | /* arrange to do this in ps3_mm_add_memory */ | 1217 | /* arrange to do this in ps3_mm_add_memory */ |
817 | ps3_mm_region_create(&map.r1, map.total - map.rm.size); | 1218 | ps3_mm_region_create(&map.r1, map.total - map.rm.size); |
818 | 1219 | ||
1220 | /* correct map.total for the real total amount of memory we use */ | ||
1221 | map.total = map.rm.size + map.r1.size; | ||
1222 | |||
819 | DBG(" <- %s:%d\n", __func__, __LINE__); | 1223 | DBG(" <- %s:%d\n", __func__, __LINE__); |
820 | } | 1224 | } |
821 | 1225 | ||