diff options
author | Zoltan Menyhart <Zoltan.Menyhart@bull.net> | 2005-06-03 08:36:00 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2005-07-12 18:33:18 -0400 |
commit | 08357f82d4decc48bbfd39ae30d5fe0754f7f576 (patch) | |
tree | c8516a8f208e1cb253bd33f41857b0699104b130 /arch/ia64 | |
parent | 60a762b6a6dec17cc4339b60154902fd04c2f9f2 (diff) |
[IA64] improve flush_icache_range()
Check with PAL to see what the i-cache line size is for
each level of the cache, and so use the correct stride
when flushing the cache.
Acked-by: David Mosberger
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64')
-rw-r--r-- | arch/ia64/kernel/setup.c | 37 | ||||
-rw-r--r-- | arch/ia64/lib/flush.S | 46 |
2 files changed, 69 insertions, 14 deletions
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 2693e1522d7c..7fc891aca446 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c | |||
@@ -20,6 +20,7 @@ | |||
20 | * 02/01/00 R.Seth fixed get_cpuinfo for SMP | 20 | * 02/01/00 R.Seth fixed get_cpuinfo for SMP |
21 | * 01/07/99 S.Eranian added the support for command line argument | 21 | * 01/07/99 S.Eranian added the support for command line argument |
22 | * 06/24/99 W.Drummond added boot_cpu_data. | 22 | * 06/24/99 W.Drummond added boot_cpu_data. |
23 | * 05/28/05 Z. Menyhart Dynamic stride size for "flush_icache_range()" | ||
23 | */ | 24 | */ |
24 | #include <linux/config.h> | 25 | #include <linux/config.h> |
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
@@ -83,6 +84,13 @@ EXPORT_SYMBOL(io_space); | |||
83 | unsigned int num_io_spaces; | 84 | unsigned int num_io_spaces; |
84 | 85 | ||
85 | /* | 86 | /* |
87 | * "flush_icache_range()" needs to know what processor dependent stride size to use | ||
88 | * when it makes i-cache(s) coherent with d-caches. | ||
89 | */ | ||
90 | #define I_CACHE_STRIDE_SHIFT 5 /* Safest way to go: 32 bytes by 32 bytes */ | ||
91 | unsigned long ia64_i_cache_stride_shift = ~0; | ||
92 | |||
93 | /* | ||
86 | * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1). This | 94 | * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1). This |
87 | * mask specifies a mask of address bits that must be 0 in order for two buffers to be | 95 | * mask specifies a mask of address bits that must be 0 in order for two buffers to be |
88 | * mergeable by the I/O MMU (i.e., the end address of the first buffer and the start | 96 | * mergeable by the I/O MMU (i.e., the end address of the first buffer and the start |
@@ -626,6 +634,12 @@ setup_per_cpu_areas (void) | |||
626 | /* start_kernel() requires this... */ | 634 | /* start_kernel() requires this... */ |
627 | } | 635 | } |
628 | 636 | ||
637 | /* | ||
638 | * Calculate the max. cache line size. | ||
639 | * | ||
640 | * In addition, the minimum of the i-cache stride sizes is calculated for | ||
641 | * "flush_icache_range()". | ||
642 | */ | ||
629 | static void | 643 | static void |
630 | get_max_cacheline_size (void) | 644 | get_max_cacheline_size (void) |
631 | { | 645 | { |
@@ -639,6 +653,8 @@ get_max_cacheline_size (void) | |||
639 | printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n", | 653 | printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n", |
640 | __FUNCTION__, status); | 654 | __FUNCTION__, status); |
641 | max = SMP_CACHE_BYTES; | 655 | max = SMP_CACHE_BYTES; |
656 | /* Safest setup for "flush_icache_range()" */ | ||
657 | ia64_i_cache_stride_shift = I_CACHE_STRIDE_SHIFT; | ||
642 | goto out; | 658 | goto out; |
643 | } | 659 | } |
644 | 660 | ||
@@ -647,14 +663,31 @@ get_max_cacheline_size (void) | |||
647 | &cci); | 663 | &cci); |
648 | if (status != 0) { | 664 | if (status != 0) { |
649 | printk(KERN_ERR | 665 | printk(KERN_ERR |
650 | "%s: ia64_pal_cache_config_info(l=%lu) failed (status=%ld)\n", | 666 | "%s: ia64_pal_cache_config_info(l=%lu, 2) failed (status=%ld)\n", |
651 | __FUNCTION__, l, status); | 667 | __FUNCTION__, l, status); |
652 | max = SMP_CACHE_BYTES; | 668 | max = SMP_CACHE_BYTES; |
669 | /* The safest setup for "flush_icache_range()" */ | ||
670 | cci.pcci_stride = I_CACHE_STRIDE_SHIFT; | ||
671 | cci.pcci_unified = 1; | ||
653 | } | 672 | } |
654 | line_size = 1 << cci.pcci_line_size; | 673 | line_size = 1 << cci.pcci_line_size; |
655 | if (line_size > max) | 674 | if (line_size > max) |
656 | max = line_size; | 675 | max = line_size; |
657 | } | 676 | if (!cci.pcci_unified) { |
677 | status = ia64_pal_cache_config_info(l, | ||
678 | /* cache_type (instruction)= */ 1, | ||
679 | &cci); | ||
680 | if (status != 0) { | ||
681 | printk(KERN_ERR | ||
682 | "%s: ia64_pal_cache_config_info(l=%lu, 1) failed (status=%ld)\n", | ||
683 | __FUNCTION__, l, status); | ||
684 | /* The safest setup for "flush_icache_range()" */ | ||
685 | cci.pcci_stride = I_CACHE_STRIDE_SHIFT; | ||
686 | } | ||
687 | } | ||
688 | if (cci.pcci_stride < ia64_i_cache_stride_shift) | ||
689 | ia64_i_cache_stride_shift = cci.pcci_stride; | ||
690 | } | ||
658 | out: | 691 | out: |
659 | if (max > ia64_max_cacheline_size) | 692 | if (max > ia64_max_cacheline_size) |
660 | ia64_max_cacheline_size = max; | 693 | ia64_max_cacheline_size = max; |
diff --git a/arch/ia64/lib/flush.S b/arch/ia64/lib/flush.S index a1af9146cfdb..3e2cfa2c6d39 100644 --- a/arch/ia64/lib/flush.S +++ b/arch/ia64/lib/flush.S | |||
@@ -3,37 +3,59 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 1999-2001, 2005 Hewlett-Packard Co | 4 | * Copyright (C) 1999-2001, 2005 Hewlett-Packard Co |
5 | * David Mosberger-Tang <davidm@hpl.hp.com> | 5 | * David Mosberger-Tang <davidm@hpl.hp.com> |
6 | * | ||
7 | * 05/28/05 Zoltan Menyhart Dynamic stride size | ||
6 | */ | 8 | */ |
9 | |||
7 | #include <asm/asmmacro.h> | 10 | #include <asm/asmmacro.h> |
8 | #include <asm/page.h> | 11 | |
9 | 12 | ||
10 | /* | 13 | /* |
11 | * flush_icache_range(start,end) | 14 | * flush_icache_range(start,end) |
12 | * Must flush range from start to end-1 but nothing else (need to | 15 | * |
16 | * Make i-cache(s) coherent with d-caches. | ||
17 | * | ||
18 | * Must deal with range from start to end-1 but nothing else (need to | ||
13 | * be careful not to touch addresses that may be unmapped). | 19 | * be careful not to touch addresses that may be unmapped). |
20 | * | ||
21 | * Note: "in0" and "in1" are preserved for debugging purposes. | ||
14 | */ | 22 | */ |
15 | GLOBAL_ENTRY(flush_icache_range) | 23 | GLOBAL_ENTRY(flush_icache_range) |
24 | |||
16 | .prologue | 25 | .prologue |
17 | alloc r2=ar.pfs,2,0,0,0 | 26 | alloc r2=ar.pfs,2,0,0,0 |
18 | sub r8=in1,in0,1 | 27 | movl r3=ia64_i_cache_stride_shift |
28 | mov r21=1 | ||
29 | ;; | ||
30 | ld8 r20=[r3] // r20: stride shift | ||
31 | sub r22=in1,r0,1 // last byte address | ||
19 | ;; | 32 | ;; |
20 | shr.u r8=r8,5 // we flush 32 bytes per iteration | 33 | shr.u r23=in0,r20 // start / (stride size) |
21 | .save ar.lc, r3 | 34 | shr.u r22=r22,r20 // (last byte address) / (stride size) |
22 | mov r3=ar.lc // save ar.lc | 35 | shl r21=r21,r20 // r21: stride size of the i-cache(s) |
36 | ;; | ||
37 | sub r8=r22,r23 // number of strides - 1 | ||
38 | shl r24=r23,r20 // r24: addresses for "fc.i" = | ||
39 | // "start" rounded down to stride boundary | ||
40 | .save ar.lc,r3 | ||
41 | mov r3=ar.lc // save ar.lc | ||
23 | ;; | 42 | ;; |
24 | 43 | ||
25 | .body | 44 | .body |
26 | 45 | mov ar.lc=r8 | |
27 | mov ar.lc=r8 | ||
28 | ;; | 46 | ;; |
29 | .Loop: fc.i in0 // issuable on M2 only | 47 | /* |
30 | add in0=32,in0 | 48 | * 32 byte aligned loop, even number of (actually 2) bundles |
49 | */ | ||
50 | .Loop: fc.i r24 // issuable on M0 only | ||
51 | add r24=r21,r24 // we flush "stride size" bytes per iteration | ||
52 | nop.i 0 | ||
31 | br.cloop.sptk.few .Loop | 53 | br.cloop.sptk.few .Loop |
32 | ;; | 54 | ;; |
33 | sync.i | 55 | sync.i |
34 | ;; | 56 | ;; |
35 | srlz.i | 57 | srlz.i |
36 | ;; | 58 | ;; |
37 | mov ar.lc=r3 // restore ar.lc | 59 | mov ar.lc=r3 // restore ar.lc |
38 | br.ret.sptk.many rp | 60 | br.ret.sptk.many rp |
39 | END(flush_icache_range) | 61 | END(flush_icache_range) |