Add version to PATCH_LOG and LAST_LOG.
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / kernel / sn1 / cache.c
1 /*
2  * 
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  * 
7  * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
8  *
9  */
10
11 #include <linux/kernel.h>
12 #include <asm/pgalloc.h>
13 #include <asm/sn/arch.h>
14 #include <asm/sn/sn_cpuid.h>
15 #include <asm/sn/sn1/synergy.h>
16 #include <asm/delay.h>
17
18 #ifndef MB
19 #define MB      (1024*1024)
20 #endif
21
22 /*
23  * Lock for protecting SYN_TAG_DISABLE_WAY.
24  * Consider making this a per-FSB lock. 
25  */
26 static spinlock_t flush_lock = SPIN_LOCK_UNLOCKED;
27
28 /**
29  * sn_flush_all_caches - flush a range of addresses from all caches (incl. L4)
30  * @flush_addr: identity mapped region 7 address to start flushing
31  * @bytes: number of bytes to flush
32  *
33  * Flush a range of addresses from all caches including L4.  All addresses 
34  * fully or partially contained within @flush_addr to @flush_addr + @bytes 
35  * are flushed from the all caches.
36  */
37 void
38 sn_flush_all_caches(long flush_addr, long bytes)
39 {
40         ulong   addr, baddr, eaddr, bitbucket;
41         int     way, alias;
42
43         /*
44          * Because of the way synergy implements "fc", this flushes the
45          * data from all caches on all cpus & L4's on OTHER FSBs. It also
46          * flushes both cpus on the local FSB. It does NOT flush it from 
47          * the local FSB.
48          */
49         flush_icache_range(flush_addr, flush_addr+bytes);
50
51         /*
52          * Memory DIMMs are a minimum of 256MB and start on 256MB
53          * boundaries. Convert the start address to an address
54          * that is between +0MB & +128 of the same DIMM. 
55          * Then add 8MB to skip the uncached MinState areas if the address
56          * is on the master node.
57          */
58         if (bytes > SYNERGY_L4_BYTES_PER_WAY)
59                 bytes = SYNERGY_L4_BYTES_PER_WAY;
60         baddr = TO_NODE(smp_physical_node_id(), PAGE_OFFSET + (flush_addr & (128*MB-1)) + 8*MB); 
61         eaddr = (baddr+bytes+SYNERGY_BLOCK_SIZE-1) & ~(SYNERGY_BLOCK_SIZE-1);
62         baddr = baddr & ~(SYNERGY_BLOCK_SIZE-1);
63
64         /*
65          * Now flush the local synergy.
66          */
67         spin_lock(&flush_lock);
68         for(way=0; way<SYNERGY_L4_WAYS; way++) {
69                 WRITE_LOCAL_SYNERGY_REG(SYN_TAG_DISABLE_WAY, 0xffL ^ (1L<<way));
70                 mb();
71                 for(alias=0; alias < 9; alias++)
72                         for(addr=baddr; addr<eaddr; addr+=SYNERGY_BLOCK_SIZE)
73                                 bitbucket = *(volatile ulong *)(addr+alias*8*MB);
74                 mb();
75         }
76         WRITE_LOCAL_SYNERGY_REG(SYN_TAG_DISABLE_WAY, 0);
77         spin_unlock(&flush_lock);
78
79 }
80
81