| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: bus.c,v 1.59 2018/01/20 17:37:15 tsutsui Exp $ */ | | 1 | /* $NetBSD: bus.c,v 1.60 2018/03/10 03:44:43 tsutsui Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, | | 8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center and by Chris G. Demetriou. | | 9 | * NASA Ames Research Center and by Chris G. Demetriou. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -23,27 +23,27 @@ | | | @@ -23,27 +23,27 @@ |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include "opt_m68k_arch.h" | | 33 | #include "opt_m68k_arch.h" |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.59 2018/01/20 17:37:15 tsutsui Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.60 2018/03/10 03:44:43 tsutsui Exp $"); |
37 | | | 37 | |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/systm.h> | | 39 | #include <sys/systm.h> |
40 | #include <sys/extent.h> | | 40 | #include <sys/extent.h> |
41 | #include <sys/malloc.h> | | 41 | #include <sys/malloc.h> |
42 | #include <sys/mbuf.h> | | 42 | #include <sys/mbuf.h> |
43 | #include <sys/proc.h> | | 43 | #include <sys/proc.h> |
44 | | | 44 | |
45 | #include <uvm/uvm.h> | | 45 | #include <uvm/uvm.h> |
46 | | | 46 | |
47 | #include <machine/cpu.h> | | 47 | #include <machine/cpu.h> |
48 | #include <m68k/cacheops.h> | | 48 | #include <m68k/cacheops.h> |
49 | #define _ATARI_BUS_DMA_PRIVATE | | 49 | #define _ATARI_BUS_DMA_PRIVATE |
| @@ -538,66 +538,223 @@ _bus_dmamap_unload(bus_dma_tag_t t, bus_ | | | @@ -538,66 +538,223 @@ _bus_dmamap_unload(bus_dma_tag_t t, bus_ |
538 | * No resources to free; just mark the mappings as | | 538 | * No resources to free; just mark the mappings as |
539 | * invalid. | | 539 | * invalid. |
540 | */ | | 540 | */ |
541 | map->dm_maxsegsz = map->_dm_maxmaxsegsz; | | 541 | map->dm_maxsegsz = map->_dm_maxmaxsegsz; |
542 | map->dm_mapsize = 0; | | 542 | map->dm_mapsize = 0; |
543 | map->dm_nsegs = 0; | | 543 | map->dm_nsegs = 0; |
544 | } | | 544 | } |
545 | | | 545 | |
546 | /* | | 546 | /* |
547 | * Common function for DMA map synchronization. May be called | | 547 | * Common function for DMA map synchronization. May be called |
548 | * by bus-specific DMA map synchronization functions. | | 548 | * by bus-specific DMA map synchronization functions. |
549 | */ | | 549 | */ |
550 | void | | 550 | void |
551 | _bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t off, | | 551 | _bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, |
552 | bus_size_t len, int ops) | | 552 | bus_size_t len, int ops) |
553 | { | | 553 | { |
554 | #if defined(M68040) || defined(M68060) | | 554 | #if defined(M68040) || defined(M68060) |
555 | int i, pa_off, inc, seglen; | | 555 | bus_addr_t p, e, ps, pe; |
556 | u_long pa, end_pa; | | 556 | bus_size_t seglen; |
| | | 557 | bus_dma_segment_t *seg; |
| | | 558 | int i; |
| | | 559 | #endif |
557 | | | 560 | |
558 | pa_off = t->_displacement; | | 561 | #if defined(M68020) || defined(M68030) |
| | | 562 | #if defined(M68040) || defined(M68060) |
| | | 563 | if (cputype == CPU_68020 || cputype == CPU_68030) |
| | | 564 | #endif |
| | | 565 | /* assume no L2 physical cache */ |
| | | 566 | return; |
| | | 567 | #endif |
559 | | | 568 | |
560 | /* Flush granularity */ | | 569 | #if defined(M68040) || defined(M68060) |
561 | inc = (len > 1024) ? PAGE_SIZE : 16; | | 570 | /* If the whole DMA map is uncached, do nothing. */ |
| | | 571 | if ((map->_dm_flags & BUS_DMA_COHERENT) != 0) |
| | | 572 | return; |
| | | 573 | |
| | | 574 | /* Short-circuit for unsupported `ops' */ |
| | | 575 | if ((ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) == 0) |
| | | 576 | return; |
562 | | | 577 | |
563 | for (i = 0; i < map->dm_nsegs && len > 0; i++) { | | 578 | /* |
564 | if (map->dm_segs[i].ds_len <= off) { | | 579 | * flush/purge the cache. |
| | | 580 | */ |
| | | 581 | for (i = 0; i < map->dm_nsegs && len != 0; i++) { |
| | | 582 | seg = &map->dm_segs[i]; |
| | | 583 | if (seg->ds_len <= offset) { |
565 | /* Segment irrelevant - before requested offset */ | | 584 | /* Segment irrelevant - before requested offset */ |
566 | off -= map->dm_segs[i].ds_len; | | 585 | offset -= seg->ds_len; |
567 | continue; | | 586 | continue; |
568 | } | | 587 | } |
569 | seglen = map->dm_segs[i].ds_len - off; | | 588 | |
| | | 589 | /* |
| | | 590 | * Now at the first segment to sync; nail |
| | | 591 | * each segment until we have exhausted the |
| | | 592 | * length. |
| | | 593 | */ |
| | | 594 | seglen = seg->ds_len - offset; |
570 | if (seglen > len) | | 595 | if (seglen > len) |
571 | seglen = len; | | 596 | seglen = len; |
572 | len -= seglen; | | | |
573 | pa = map->dm_segs[i].ds_addr + off - pa_off; | | | |
574 | end_pa = pa + seglen; | | | |
575 | | | 597 | |
576 | if (inc == 16) { | | 598 | ps = seg->ds_addr + offset; |
577 | pa &= ~15; | | 599 | pe = ps + seglen; |
578 | while (pa < end_pa) { | | 600 | |
579 | DCFL(pa); | | 601 | if (ops & BUS_DMASYNC_PREWRITE) { |
580 | pa += 16; | | 602 | p = ps & ~CACHELINE_MASK; |
| | | 603 | e = (pe + CACHELINE_MASK) & ~CACHELINE_MASK; |
| | | 604 | |
| | | 605 | /* flush cacheline */ |
| | | 606 | while ((p < e) && (p & (CACHELINE_SIZE * 8 - 1)) != 0) { |
| | | 607 | DCFL(p); |
| | | 608 | p += CACHELINE_SIZE; |
581 | } | | 609 | } |
582 | } else { | | 610 | |
583 | pa &= ~PGOFSET; | | 611 | /* flush cachelines per 128bytes */ |
584 | while (pa < end_pa) { | | 612 | while ((p < e) && (p & PAGE_MASK) != 0) { |
585 | DCFP(pa); | | 613 | DCFL(p); |
586 | pa += PAGE_SIZE; | | 614 | p += CACHELINE_SIZE; |
| | | 615 | DCFL(p); |
| | | 616 | p += CACHELINE_SIZE; |
| | | 617 | DCFL(p); |
| | | 618 | p += CACHELINE_SIZE; |
| | | 619 | DCFL(p); |
| | | 620 | p += CACHELINE_SIZE; |
| | | 621 | DCFL(p); |
| | | 622 | p += CACHELINE_SIZE; |
| | | 623 | DCFL(p); |
| | | 624 | p += CACHELINE_SIZE; |
| | | 625 | DCFL(p); |
| | | 626 | p += CACHELINE_SIZE; |
| | | 627 | DCFL(p); |
| | | 628 | p += CACHELINE_SIZE; |
| | | 629 | } |
| | | 630 | |
| | | 631 | /* flush page */ |
| | | 632 | while (p + PAGE_SIZE <= e) { |
| | | 633 | DCFP(p); |
| | | 634 | p += PAGE_SIZE; |
| | | 635 | } |
| | | 636 | |
| | | 637 | /* flush cachelines per 128bytes */ |
| | | 638 | while (p + CACHELINE_SIZE * 8 <= e) { |
| | | 639 | DCFL(p); |
| | | 640 | p += CACHELINE_SIZE; |
| | | 641 | DCFL(p); |
| | | 642 | p += CACHELINE_SIZE; |
| | | 643 | DCFL(p); |
| | | 644 | p += CACHELINE_SIZE; |
| | | 645 | DCFL(p); |
| | | 646 | p += CACHELINE_SIZE; |
| | | 647 | DCFL(p); |
| | | 648 | p += CACHELINE_SIZE; |
| | | 649 | DCFL(p); |
| | | 650 | p += CACHELINE_SIZE; |
| | | 651 | DCFL(p); |
| | | 652 | p += CACHELINE_SIZE; |
| | | 653 | DCFL(p); |
| | | 654 | p += CACHELINE_SIZE; |
| | | 655 | } |
| | | 656 | |
| | | 657 | /* flush cacheline */ |
| | | 658 | while (p < e) { |
| | | 659 | DCFL(p); |
| | | 660 | p += CACHELINE_SIZE; |
587 | } | | 661 | } |
588 | } | | 662 | } |
| | | 663 | |
| | | 664 | /* |
| | | 665 | * Normally, the `PREREAD' flag instructs us to purge the |
| | | 666 | * cache for the specified offset and length. However, if |
| | | 667 | * the offset/length is not aligned to a cacheline boundary, |
| | | 668 | * we may end up purging some legitimate data from the |
| | | 669 | * start/end of the cache. In such a case, *flush* the |
| | | 670 | * cachelines at the start and end of the required region. |
| | | 671 | */ |
| | | 672 | else if (ops & BUS_DMASYNC_PREREAD) { |
| | | 673 | /* flush cacheline on start boundary */ |
| | | 674 | if (ps & CACHELINE_MASK) { |
| | | 675 | DCFL(ps & ~CACHELINE_MASK); |
| | | 676 | } |
| | | 677 | |
| | | 678 | p = (ps + CACHELINE_MASK) & ~CACHELINE_MASK; |
| | | 679 | e = pe & ~CACHELINE_MASK; |
| | | 680 | |
| | | 681 | /* purge cacheline */ |
| | | 682 | while ((p < e) && (p & (CACHELINE_SIZE * 8 - 1)) != 0) { |
| | | 683 | DCPL(p); |
| | | 684 | p += CACHELINE_SIZE; |
| | | 685 | } |
| | | 686 | |
| | | 687 | /* purge cachelines per 128bytes */ |
| | | 688 | while ((p < e) && (p & PAGE_MASK) != 0) { |
| | | 689 | DCPL(p); |
| | | 690 | p += CACHELINE_SIZE; |
| | | 691 | DCPL(p); |
| | | 692 | p += CACHELINE_SIZE; |
| | | 693 | DCPL(p); |
| | | 694 | p += CACHELINE_SIZE; |
| | | 695 | DCPL(p); |
| | | 696 | p += CACHELINE_SIZE; |
| | | 697 | DCPL(p); |
| | | 698 | p += CACHELINE_SIZE; |
| | | 699 | DCPL(p); |
| | | 700 | p += CACHELINE_SIZE; |
| | | 701 | DCPL(p); |
| | | 702 | p += CACHELINE_SIZE; |
| | | 703 | DCPL(p); |
| | | 704 | p += CACHELINE_SIZE; |
| | | 705 | } |
| | | 706 | |
| | | 707 | /* purge page */ |
| | | 708 | while (p + PAGE_SIZE <= e) { |
| | | 709 | DCPP(p); |
| | | 710 | p += PAGE_SIZE; |
| | | 711 | } |
| | | 712 | |
| | | 713 | /* purge cachelines per 128bytes */ |
| | | 714 | while (p + CACHELINE_SIZE * 8 <= e) { |
| | | 715 | DCPL(p); |
| | | 716 | p += CACHELINE_SIZE; |
| | | 717 | DCPL(p); |
| | | 718 | p += CACHELINE_SIZE; |
| | | 719 | DCPL(p); |
| | | 720 | p += CACHELINE_SIZE; |
| | | 721 | DCPL(p); |
| | | 722 | p += CACHELINE_SIZE; |
| | | 723 | DCPL(p); |
| | | 724 | p += CACHELINE_SIZE; |
| | | 725 | DCPL(p); |
| | | 726 | p += CACHELINE_SIZE; |
| | | 727 | DCPL(p); |
| | | 728 | p += CACHELINE_SIZE; |
| | | 729 | DCPL(p); |
| | | 730 | p += CACHELINE_SIZE; |
| | | 731 | } |
| | | 732 | |
| | | 733 | /* purge cacheline */ |
| | | 734 | while (p < e) { |
| | | 735 | DCPL(p); |
| | | 736 | p += CACHELINE_SIZE; |
| | | 737 | } |
| | | 738 | |
| | | 739 | /* flush cacheline on end boundary */ |
| | | 740 | if (p < pe) { |
| | | 741 | DCFL(p); |
| | | 742 | } |
| | | 743 | } |
| | | 744 | offset = 0; |
| | | 745 | len -= seglen; |
589 | } | | 746 | } |
590 | #endif | | 747 | #endif /* defined(M68040) || defined(M68060) */ |
591 | } | | 748 | } |
592 | | | 749 | |
593 | /* | | 750 | /* |
594 | * Common function for DMA-safe memory allocation. May be called | | 751 | * Common function for DMA-safe memory allocation. May be called |
595 | * by bus-specific DMA memory allocation functions. | | 752 | * by bus-specific DMA memory allocation functions. |
596 | */ | | 753 | */ |
597 | int | | 754 | int |
598 | bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, | | 755 | bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, |
599 | bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, | | 756 | bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, |
600 | int flags) | | 757 | int flags) |
601 | { | | 758 | { |
602 | | | 759 | |
603 | return bus_dmamem_alloc_range(t, size, alignment, boundary, | | 760 | return bus_dmamem_alloc_range(t, size, alignment, boundary, |