Cell: Use multiple DMA tags for the dcache.
[mesa.git] / src / gallium / drivers / cell / spu / spu_dcache.c
1 /*
2 * (C) Copyright IBM Corporation 2008
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * AUTHORS, COPYRIGHT HOLDERS, AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "cell/common.h"
26 #include "spu_main.h"
27 #include "spu_dcache.h"
28
29 #define CACHELINE_LOG2SIZE 7
30 #define LINE_SIZE (1U << 7)
31 #define ALIGN_MASK (~(LINE_SIZE - 1))
32
33 #define CACHE_NAME data
34 #define CACHED_TYPE qword
35 #define CACHE_TYPE CACHE_TYPE_RO
36 #define CACHE_SET_TAGID(set) (((set) & 0x03) + TAG_DCACHE0)
37 #define CACHE_LOG2NNWAY 2
38 #define CACHE_LOG2NSETS 6
39 #include <cache-api.h>
40
41 /* Yes folks, this is ugly.
42 */
43 #undef CACHE_NWAY
44 #undef CACHE_NSETS
45 #define CACHE_NAME data
46 #define CACHE_NWAY 4
47 #define CACHE_NSETS (1U << 6)
48
49
50 /**
51 * Fetch between arbitrary number of bytes from an unaligned address
52 */
53 void
54 spu_dcache_fetch_unaligned(qword *dst, unsigned ea, unsigned size)
55 {
56 const int shift = ea & 0x0f;
57 const unsigned aligned_start_ea = ea & ~0x0f;
58 const unsigned aligned_end_ea = ROUNDUP16(ea + size);
59 const unsigned num_entries = (aligned_end_ea - aligned_start_ea) / 16;
60 unsigned i;
61
62
63 if (shift == 0) {
64 /* Data is already aligned. Fetch directly into the destination buffer.
65 */
66 for (i = 0; i < num_entries; i++) {
67 dst[i] = cache_rd(data, ea + (i * 16));
68 }
69 } else {
70 qword tmp[2] ALIGN16_ATTRIB;
71
72
73 tmp[0] = cache_rd(data, (ea & ~0x0f));
74 for (i = 0; i < (num_entries & ~1); i++) {
75 const unsigned curr = i & 1;
76 const unsigned next = curr ^ 1;
77
78 tmp[next] = cache_rd(data, (ea & ~0x0f) + (next * 16));
79
80 dst[i] = si_or((qword) spu_slqwbyte(tmp[curr], shift),
81 (qword) spu_rlmaskqwbyte(tmp[next], shift - 16));
82 }
83
84 if (i < num_entries) {
85 dst[i] = si_or((qword) spu_slqwbyte(tmp[(i & 1)], shift),
86 si_il(0));
87 }
88 }
89 }
90
91
92 /**
93 * Notify the cache that a range of main memory may have been modified
94 */
95 void
96 spu_dcache_mark_dirty(unsigned ea, unsigned size)
97 {
98 unsigned i;
99 const unsigned aligned_start = (ea & ALIGN_MASK);
100 const unsigned aligned_end = (ea + size + (LINE_SIZE - 1))
101 & ALIGN_MASK;
102
103
104 for (i = 0; i < (CACHE_NWAY * CACHE_NSETS); i++) {
105 const unsigned entry = __cache_dir[i];
106 const unsigned addr = entry & ~0x0f;
107
108 __cache_dir[i] = ((addr >= aligned_start) && (addr < aligned_end))
109 ? (entry & ~CACHELINE_VALID) : entry;
110 }
111 }