xref: /dflybsd-src/contrib/gdb-7/gdb/dcache.c (revision a45ae5f869d9cfcb3e41dbab486e10bfa9e336bf)
15796c8dcSSimon Schubert /* Caching code for GDB, the GNU debugger.
25796c8dcSSimon Schubert 
3*a45ae5f8SJohn Marino    Copyright (C) 1992-1993, 1995-1996, 1998-2001, 2003, 2007-2012 Free
4*a45ae5f8SJohn Marino    Software Foundation, Inc.
55796c8dcSSimon Schubert 
65796c8dcSSimon Schubert    This file is part of GDB.
75796c8dcSSimon Schubert 
85796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
95796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
105796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
115796c8dcSSimon Schubert    (at your option) any later version.
125796c8dcSSimon Schubert 
135796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
145796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
155796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165796c8dcSSimon Schubert    GNU General Public License for more details.
175796c8dcSSimon Schubert 
185796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
195796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
205796c8dcSSimon Schubert 
215796c8dcSSimon Schubert #include "defs.h"
225796c8dcSSimon Schubert #include "dcache.h"
235796c8dcSSimon Schubert #include "gdbcmd.h"
245796c8dcSSimon Schubert #include "gdb_string.h"
255796c8dcSSimon Schubert #include "gdbcore.h"
265796c8dcSSimon Schubert #include "target.h"
275796c8dcSSimon Schubert #include "inferior.h"
285796c8dcSSimon Schubert #include "splay-tree.h"
295796c8dcSSimon Schubert 
30*a45ae5f8SJohn Marino /* Commands with a prefix of `{set,show} dcache'.  */
31*a45ae5f8SJohn Marino static struct cmd_list_element *dcache_set_list = NULL;
32*a45ae5f8SJohn Marino static struct cmd_list_element *dcache_show_list = NULL;
33*a45ae5f8SJohn Marino 
345796c8dcSSimon Schubert /* The data cache could lead to incorrect results because it doesn't
355796c8dcSSimon Schubert    know about volatile variables, thus making it impossible to debug
365796c8dcSSimon Schubert    functions which use memory mapped I/O devices.  Set the nocache
375796c8dcSSimon Schubert    memory region attribute in those cases.
385796c8dcSSimon Schubert 
395796c8dcSSimon Schubert    In general the dcache speeds up performance.  Some speed improvement
405796c8dcSSimon Schubert    comes from the actual caching mechanism, but the major gain is in
415796c8dcSSimon Schubert    the reduction of the remote protocol overhead; instead of reading
425796c8dcSSimon Schubert    or writing a large area of memory in 4 byte requests, the cache
435796c8dcSSimon Schubert    bundles up the requests into LINE_SIZE chunks, reducing overhead
445796c8dcSSimon Schubert    significantly.  This is most useful when accessing a large amount
455796c8dcSSimon Schubert    of data, such as when performing a backtrace.
465796c8dcSSimon Schubert 
475796c8dcSSimon Schubert    The cache is a splay tree along with a linked list for replacement.
48cf7f2e2dSJohn Marino    Each block caches a LINE_SIZE area of memory.  Within each line we
49cf7f2e2dSJohn Marino    remember the address of the line (which must be a multiple of
50cf7f2e2dSJohn Marino    LINE_SIZE) and the actual data block.
515796c8dcSSimon Schubert 
525796c8dcSSimon Schubert    Lines are only allocated as needed, so DCACHE_SIZE really specifies the
535796c8dcSSimon Schubert    *maximum* number of lines in the cache.
545796c8dcSSimon Schubert 
555796c8dcSSimon Schubert    At present, the cache is write-through rather than writeback: as soon
565796c8dcSSimon Schubert    as data is written to the cache, it is also immediately written to
575796c8dcSSimon Schubert    the target.  Therefore, cache lines are never "dirty".  Whether a given
585796c8dcSSimon Schubert    line is valid or not depends on where it is stored in the dcache_struct;
595796c8dcSSimon Schubert    there is no per-block valid flag.  */
605796c8dcSSimon Schubert 
615796c8dcSSimon Schubert /* NOTE: Interaction of dcache and memory region attributes
625796c8dcSSimon Schubert 
635796c8dcSSimon Schubert    As there is no requirement that memory region attributes be aligned
645796c8dcSSimon Schubert    to or be a multiple of the dcache page size, dcache_read_line() and
655796c8dcSSimon Schubert    dcache_write_line() must break up the page by memory region.  If a
665796c8dcSSimon Schubert    chunk does not have the cache attribute set, an invalid memory type
675796c8dcSSimon Schubert    is set, etc., then the chunk is skipped.  Those chunks are handled
685796c8dcSSimon Schubert    in target_xfer_memory() (or target_xfer_memory_partial()).
695796c8dcSSimon Schubert 
705796c8dcSSimon Schubert    This doesn't occur very often.  The most common occurance is when
715796c8dcSSimon Schubert    the last bit of the .text segment and the first bit of the .data
725796c8dcSSimon Schubert    segment fall within the same dcache page with a ro/cacheable memory
735796c8dcSSimon Schubert    region defined for the .text segment and a rw/non-cacheable memory
745796c8dcSSimon Schubert    region defined for the .data segment.  */
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert /* The maximum number of lines stored.  The total size of the cache is
775796c8dcSSimon Schubert    equal to DCACHE_SIZE times LINE_SIZE.  */
78*a45ae5f8SJohn Marino #define DCACHE_DEFAULT_SIZE 4096
79*a45ae5f8SJohn Marino static unsigned dcache_size = DCACHE_DEFAULT_SIZE;
805796c8dcSSimon Schubert 
81*a45ae5f8SJohn Marino /* The default size of a cache line.  Smaller values reduce the time taken to
825796c8dcSSimon Schubert    read a single byte and make the cache more granular, but increase
835796c8dcSSimon Schubert    overhead and reduce the effectiveness of the cache as a prefetcher.  */
84*a45ae5f8SJohn Marino #define DCACHE_DEFAULT_LINE_SIZE 64
85*a45ae5f8SJohn Marino static unsigned dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
865796c8dcSSimon Schubert 
875796c8dcSSimon Schubert /* Each cache block holds LINE_SIZE bytes of data
885796c8dcSSimon Schubert    starting at a multiple-of-LINE_SIZE address.  */
895796c8dcSSimon Schubert 
90*a45ae5f8SJohn Marino #define LINE_SIZE_MASK(dcache)  ((dcache->line_size - 1))
91*a45ae5f8SJohn Marino #define XFORM(dcache, x) 	((x) & LINE_SIZE_MASK (dcache))
92*a45ae5f8SJohn Marino #define MASK(dcache, x)         ((x) & ~LINE_SIZE_MASK (dcache))
935796c8dcSSimon Schubert 
945796c8dcSSimon Schubert struct dcache_block
955796c8dcSSimon Schubert {
96c50c785cSJohn Marino   /* For least-recently-allocated and free lists.  */
97cf7f2e2dSJohn Marino   struct dcache_block *prev;
98cf7f2e2dSJohn Marino   struct dcache_block *next;
99cf7f2e2dSJohn Marino 
1005796c8dcSSimon Schubert   CORE_ADDR addr;		/* address of data */
1015796c8dcSSimon Schubert   int refs;			/* # hits */
102*a45ae5f8SJohn Marino   gdb_byte data[1];		/* line_size bytes at given address */
1035796c8dcSSimon Schubert };
1045796c8dcSSimon Schubert 
1055796c8dcSSimon Schubert struct dcache_struct
1065796c8dcSSimon Schubert {
1075796c8dcSSimon Schubert   splay_tree tree;
108c50c785cSJohn Marino   struct dcache_block *oldest; /* least-recently-allocated list.  */
1095796c8dcSSimon Schubert 
110cf7f2e2dSJohn Marino   /* The free list is maintained identically to OLDEST to simplify
111cf7f2e2dSJohn Marino      the code: we only need one set of accessors.  */
1125796c8dcSSimon Schubert   struct dcache_block *freelist;
1135796c8dcSSimon Schubert 
1145796c8dcSSimon Schubert   /* The number of in-use lines in the cache.  */
1155796c8dcSSimon Schubert   int size;
116*a45ae5f8SJohn Marino   CORE_ADDR line_size;  /* current line_size.  */
1175796c8dcSSimon Schubert 
1185796c8dcSSimon Schubert   /* The ptid of last inferior to use cache or null_ptid.  */
1195796c8dcSSimon Schubert   ptid_t ptid;
1205796c8dcSSimon Schubert };
1215796c8dcSSimon Schubert 
122cf7f2e2dSJohn Marino typedef void (block_func) (struct dcache_block *block, void *param);
1235796c8dcSSimon Schubert 
124cf7f2e2dSJohn Marino static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr);
1255796c8dcSSimon Schubert 
1265796c8dcSSimon Schubert static int dcache_read_line (DCACHE *dcache, struct dcache_block *db);
1275796c8dcSSimon Schubert 
1285796c8dcSSimon Schubert static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr);
1295796c8dcSSimon Schubert 
1305796c8dcSSimon Schubert static void dcache_info (char *exp, int tty);
1315796c8dcSSimon Schubert 
1325796c8dcSSimon Schubert void _initialize_dcache (void);
1335796c8dcSSimon Schubert 
1345796c8dcSSimon Schubert static int dcache_enabled_p = 0; /* OBSOLETE */
1355796c8dcSSimon Schubert 
1365796c8dcSSimon Schubert static void
1375796c8dcSSimon Schubert show_dcache_enabled_p (struct ui_file *file, int from_tty,
1385796c8dcSSimon Schubert 		       struct cmd_list_element *c, const char *value)
1395796c8dcSSimon Schubert {
1405796c8dcSSimon Schubert   fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value);
1415796c8dcSSimon Schubert }
1425796c8dcSSimon Schubert 
143c50c785cSJohn Marino static DCACHE *last_cache; /* Used by info dcache.  */
1445796c8dcSSimon Schubert 
145cf7f2e2dSJohn Marino /* Add BLOCK to circular block list BLIST, behind the block at *BLIST.
146cf7f2e2dSJohn Marino    *BLIST is not updated (unless it was previously NULL of course).
147cf7f2e2dSJohn Marino    This is for the least-recently-allocated list's sake:
148cf7f2e2dSJohn Marino    BLIST points to the oldest block.
149cf7f2e2dSJohn Marino    ??? This makes for poor cache usage of the free list,
150cf7f2e2dSJohn Marino    but is it measurable?  */
151cf7f2e2dSJohn Marino 
152cf7f2e2dSJohn Marino static void
153cf7f2e2dSJohn Marino append_block (struct dcache_block **blist, struct dcache_block *block)
154cf7f2e2dSJohn Marino {
155cf7f2e2dSJohn Marino   if (*blist)
156cf7f2e2dSJohn Marino     {
157cf7f2e2dSJohn Marino       block->next = *blist;
158cf7f2e2dSJohn Marino       block->prev = (*blist)->prev;
159cf7f2e2dSJohn Marino       block->prev->next = block;
160cf7f2e2dSJohn Marino       (*blist)->prev = block;
161cf7f2e2dSJohn Marino       /* We don't update *BLIST here to maintain the invariant that for the
162cf7f2e2dSJohn Marino 	 least-recently-allocated list *BLIST points to the oldest block.  */
163cf7f2e2dSJohn Marino     }
164cf7f2e2dSJohn Marino   else
165cf7f2e2dSJohn Marino     {
166cf7f2e2dSJohn Marino       block->next = block;
167cf7f2e2dSJohn Marino       block->prev = block;
168cf7f2e2dSJohn Marino       *blist = block;
169cf7f2e2dSJohn Marino     }
170cf7f2e2dSJohn Marino }
171cf7f2e2dSJohn Marino 
172cf7f2e2dSJohn Marino /* Remove BLOCK from circular block list BLIST.  */
173cf7f2e2dSJohn Marino 
174cf7f2e2dSJohn Marino static void
175cf7f2e2dSJohn Marino remove_block (struct dcache_block **blist, struct dcache_block *block)
176cf7f2e2dSJohn Marino {
177cf7f2e2dSJohn Marino   if (block->next == block)
178cf7f2e2dSJohn Marino     {
179cf7f2e2dSJohn Marino       *blist = NULL;
180cf7f2e2dSJohn Marino     }
181cf7f2e2dSJohn Marino   else
182cf7f2e2dSJohn Marino     {
183cf7f2e2dSJohn Marino       block->next->prev = block->prev;
184cf7f2e2dSJohn Marino       block->prev->next = block->next;
185cf7f2e2dSJohn Marino       /* If we removed the block *BLIST points to, shift it to the next block
186cf7f2e2dSJohn Marino 	 to maintain the invariant that for the least-recently-allocated list
187cf7f2e2dSJohn Marino 	 *BLIST points to the oldest block.  */
188cf7f2e2dSJohn Marino       if (*blist == block)
189cf7f2e2dSJohn Marino 	*blist = block->next;
190cf7f2e2dSJohn Marino     }
191cf7f2e2dSJohn Marino }
192cf7f2e2dSJohn Marino 
193cf7f2e2dSJohn Marino /* Iterate over all elements in BLIST, calling FUNC.
194cf7f2e2dSJohn Marino    PARAM is passed to FUNC.
195cf7f2e2dSJohn Marino    FUNC may remove the block it's passed, but only that block.  */
196cf7f2e2dSJohn Marino 
197cf7f2e2dSJohn Marino static void
198cf7f2e2dSJohn Marino for_each_block (struct dcache_block **blist, block_func *func, void *param)
199cf7f2e2dSJohn Marino {
200cf7f2e2dSJohn Marino   struct dcache_block *db;
201cf7f2e2dSJohn Marino 
202cf7f2e2dSJohn Marino   if (*blist == NULL)
203cf7f2e2dSJohn Marino     return;
204cf7f2e2dSJohn Marino 
205cf7f2e2dSJohn Marino   db = *blist;
206cf7f2e2dSJohn Marino   do
207cf7f2e2dSJohn Marino     {
208cf7f2e2dSJohn Marino       struct dcache_block *next = db->next;
209cf7f2e2dSJohn Marino 
210cf7f2e2dSJohn Marino       func (db, param);
211cf7f2e2dSJohn Marino       db = next;
212cf7f2e2dSJohn Marino     }
213cf7f2e2dSJohn Marino   while (*blist && db != *blist);
214cf7f2e2dSJohn Marino }
215cf7f2e2dSJohn Marino 
216*a45ae5f8SJohn Marino /* BLOCK_FUNC routine for dcache_free.  */
217*a45ae5f8SJohn Marino 
218*a45ae5f8SJohn Marino static void
219*a45ae5f8SJohn Marino free_block (struct dcache_block *block, void *param)
220*a45ae5f8SJohn Marino {
221*a45ae5f8SJohn Marino   xfree (block);
222*a45ae5f8SJohn Marino }
223*a45ae5f8SJohn Marino 
224*a45ae5f8SJohn Marino /* Free a data cache.  */
225*a45ae5f8SJohn Marino 
226*a45ae5f8SJohn Marino void
227*a45ae5f8SJohn Marino dcache_free (DCACHE *dcache)
228*a45ae5f8SJohn Marino {
229*a45ae5f8SJohn Marino   if (last_cache == dcache)
230*a45ae5f8SJohn Marino     last_cache = NULL;
231*a45ae5f8SJohn Marino 
232*a45ae5f8SJohn Marino   splay_tree_delete (dcache->tree);
233*a45ae5f8SJohn Marino   for_each_block (&dcache->oldest, free_block, NULL);
234*a45ae5f8SJohn Marino   for_each_block (&dcache->freelist, free_block, NULL);
235*a45ae5f8SJohn Marino   xfree (dcache);
236*a45ae5f8SJohn Marino }
237*a45ae5f8SJohn Marino 
238*a45ae5f8SJohn Marino 
239cf7f2e2dSJohn Marino /* BLOCK_FUNC function for dcache_invalidate.
240cf7f2e2dSJohn Marino    This doesn't remove the block from the oldest list on purpose.
241cf7f2e2dSJohn Marino    dcache_invalidate will do it later.  */
242cf7f2e2dSJohn Marino 
243cf7f2e2dSJohn Marino static void
244cf7f2e2dSJohn Marino invalidate_block (struct dcache_block *block, void *param)
245cf7f2e2dSJohn Marino {
246cf7f2e2dSJohn Marino   DCACHE *dcache = (DCACHE *) param;
247cf7f2e2dSJohn Marino 
248cf7f2e2dSJohn Marino   splay_tree_remove (dcache->tree, (splay_tree_key) block->addr);
249cf7f2e2dSJohn Marino   append_block (&dcache->freelist, block);
250cf7f2e2dSJohn Marino }
251cf7f2e2dSJohn Marino 
2525796c8dcSSimon Schubert /* Free all the data cache blocks, thus discarding all cached data.  */
2535796c8dcSSimon Schubert 
2545796c8dcSSimon Schubert void
2555796c8dcSSimon Schubert dcache_invalidate (DCACHE *dcache)
2565796c8dcSSimon Schubert {
257cf7f2e2dSJohn Marino   for_each_block (&dcache->oldest, invalidate_block, dcache);
2585796c8dcSSimon Schubert 
2595796c8dcSSimon Schubert   dcache->oldest = NULL;
2605796c8dcSSimon Schubert   dcache->size = 0;
2615796c8dcSSimon Schubert   dcache->ptid = null_ptid;
262*a45ae5f8SJohn Marino 
263*a45ae5f8SJohn Marino   if (dcache->line_size != dcache_line_size)
264*a45ae5f8SJohn Marino     {
265*a45ae5f8SJohn Marino       /* We've been asked to use a different line size.
266*a45ae5f8SJohn Marino 	 All of our freelist blocks are now the wrong size, so free them.  */
267*a45ae5f8SJohn Marino 
268*a45ae5f8SJohn Marino       for_each_block (&dcache->freelist, free_block, dcache);
269*a45ae5f8SJohn Marino       dcache->freelist = NULL;
270*a45ae5f8SJohn Marino       dcache->line_size = dcache_line_size;
271*a45ae5f8SJohn Marino     }
2725796c8dcSSimon Schubert }
2735796c8dcSSimon Schubert 
2745796c8dcSSimon Schubert /* Invalidate the line associated with ADDR.  */
2755796c8dcSSimon Schubert 
2765796c8dcSSimon Schubert static void
2775796c8dcSSimon Schubert dcache_invalidate_line (DCACHE *dcache, CORE_ADDR addr)
2785796c8dcSSimon Schubert {
2795796c8dcSSimon Schubert   struct dcache_block *db = dcache_hit (dcache, addr);
2805796c8dcSSimon Schubert 
2815796c8dcSSimon Schubert   if (db)
2825796c8dcSSimon Schubert     {
2835796c8dcSSimon Schubert       splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
284cf7f2e2dSJohn Marino       remove_block (&dcache->oldest, db);
285cf7f2e2dSJohn Marino       append_block (&dcache->freelist, db);
2865796c8dcSSimon Schubert       --dcache->size;
2875796c8dcSSimon Schubert     }
2885796c8dcSSimon Schubert }
2895796c8dcSSimon Schubert 
2905796c8dcSSimon Schubert /* If addr is present in the dcache, return the address of the block
291cf7f2e2dSJohn Marino    containing it.  Otherwise return NULL.  */
2925796c8dcSSimon Schubert 
2935796c8dcSSimon Schubert static struct dcache_block *
2945796c8dcSSimon Schubert dcache_hit (DCACHE *dcache, CORE_ADDR addr)
2955796c8dcSSimon Schubert {
2965796c8dcSSimon Schubert   struct dcache_block *db;
2975796c8dcSSimon Schubert 
2985796c8dcSSimon Schubert   splay_tree_node node = splay_tree_lookup (dcache->tree,
299*a45ae5f8SJohn Marino 					    (splay_tree_key) MASK (dcache, addr));
3005796c8dcSSimon Schubert 
3015796c8dcSSimon Schubert   if (!node)
3025796c8dcSSimon Schubert     return NULL;
3035796c8dcSSimon Schubert 
3045796c8dcSSimon Schubert   db = (struct dcache_block *) node->value;
3055796c8dcSSimon Schubert   db->refs++;
3065796c8dcSSimon Schubert   return db;
3075796c8dcSSimon Schubert }
3085796c8dcSSimon Schubert 
309cf7f2e2dSJohn Marino /* Fill a cache line from target memory.
310cf7f2e2dSJohn Marino    The result is 1 for success, 0 if the (entire) cache line
311cf7f2e2dSJohn Marino    wasn't readable.  */
3125796c8dcSSimon Schubert 
3135796c8dcSSimon Schubert static int
3145796c8dcSSimon Schubert dcache_read_line (DCACHE *dcache, struct dcache_block *db)
3155796c8dcSSimon Schubert {
3165796c8dcSSimon Schubert   CORE_ADDR memaddr;
3175796c8dcSSimon Schubert   gdb_byte *myaddr;
3185796c8dcSSimon Schubert   int len;
3195796c8dcSSimon Schubert   int res;
3205796c8dcSSimon Schubert   int reg_len;
3215796c8dcSSimon Schubert   struct mem_region *region;
3225796c8dcSSimon Schubert 
323*a45ae5f8SJohn Marino   len = dcache->line_size;
3245796c8dcSSimon Schubert   memaddr = db->addr;
3255796c8dcSSimon Schubert   myaddr  = db->data;
3265796c8dcSSimon Schubert 
3275796c8dcSSimon Schubert   while (len > 0)
3285796c8dcSSimon Schubert     {
3295796c8dcSSimon Schubert       /* Don't overrun if this block is right at the end of the region.  */
3305796c8dcSSimon Schubert       region = lookup_mem_region (memaddr);
3315796c8dcSSimon Schubert       if (region->hi == 0 || memaddr + len < region->hi)
3325796c8dcSSimon Schubert 	reg_len = len;
3335796c8dcSSimon Schubert       else
3345796c8dcSSimon Schubert 	reg_len = region->hi - memaddr;
3355796c8dcSSimon Schubert 
3365796c8dcSSimon Schubert       /* Skip non-readable regions.  The cache attribute can be ignored,
3375796c8dcSSimon Schubert          since we may be loading this for a stack access.  */
3385796c8dcSSimon Schubert       if (region->attrib.mode == MEM_WO)
3395796c8dcSSimon Schubert 	{
3405796c8dcSSimon Schubert 	  memaddr += reg_len;
3415796c8dcSSimon Schubert 	  myaddr  += reg_len;
3425796c8dcSSimon Schubert 	  len     -= reg_len;
3435796c8dcSSimon Schubert 	  continue;
3445796c8dcSSimon Schubert 	}
3455796c8dcSSimon Schubert 
3465796c8dcSSimon Schubert       res = target_read (&current_target, TARGET_OBJECT_RAW_MEMORY,
3475796c8dcSSimon Schubert 			 NULL, myaddr, memaddr, reg_len);
3485796c8dcSSimon Schubert       if (res < reg_len)
3495796c8dcSSimon Schubert 	return 0;
3505796c8dcSSimon Schubert 
3515796c8dcSSimon Schubert       memaddr += res;
3525796c8dcSSimon Schubert       myaddr += res;
3535796c8dcSSimon Schubert       len -= res;
3545796c8dcSSimon Schubert     }
3555796c8dcSSimon Schubert 
3565796c8dcSSimon Schubert   return 1;
3575796c8dcSSimon Schubert }
3585796c8dcSSimon Schubert 
3595796c8dcSSimon Schubert /* Get a free cache block, put or keep it on the valid list,
3605796c8dcSSimon Schubert    and return its address.  */
3615796c8dcSSimon Schubert 
3625796c8dcSSimon Schubert static struct dcache_block *
3635796c8dcSSimon Schubert dcache_alloc (DCACHE *dcache, CORE_ADDR addr)
3645796c8dcSSimon Schubert {
3655796c8dcSSimon Schubert   struct dcache_block *db;
3665796c8dcSSimon Schubert 
367*a45ae5f8SJohn Marino   if (dcache->size >= dcache_size)
3685796c8dcSSimon Schubert     {
369cf7f2e2dSJohn Marino       /* Evict the least recently allocated line.  */
3705796c8dcSSimon Schubert       db = dcache->oldest;
371cf7f2e2dSJohn Marino       remove_block (&dcache->oldest, db);
3725796c8dcSSimon Schubert 
3735796c8dcSSimon Schubert       splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
3745796c8dcSSimon Schubert     }
3755796c8dcSSimon Schubert   else
3765796c8dcSSimon Schubert     {
3775796c8dcSSimon Schubert       db = dcache->freelist;
3785796c8dcSSimon Schubert       if (db)
379cf7f2e2dSJohn Marino 	remove_block (&dcache->freelist, db);
3805796c8dcSSimon Schubert       else
381*a45ae5f8SJohn Marino 	db = xmalloc (offsetof (struct dcache_block, data) +
382*a45ae5f8SJohn Marino 		      dcache->line_size);
3835796c8dcSSimon Schubert 
3845796c8dcSSimon Schubert       dcache->size++;
3855796c8dcSSimon Schubert     }
3865796c8dcSSimon Schubert 
387*a45ae5f8SJohn Marino   db->addr = MASK (dcache, addr);
3885796c8dcSSimon Schubert   db->refs = 0;
3895796c8dcSSimon Schubert 
390cf7f2e2dSJohn Marino   /* Put DB at the end of the list, it's the newest.  */
391cf7f2e2dSJohn Marino   append_block (&dcache->oldest, db);
3925796c8dcSSimon Schubert 
3935796c8dcSSimon Schubert   splay_tree_insert (dcache->tree, (splay_tree_key) db->addr,
3945796c8dcSSimon Schubert 		     (splay_tree_value) db);
3955796c8dcSSimon Schubert 
3965796c8dcSSimon Schubert   return db;
3975796c8dcSSimon Schubert }
3985796c8dcSSimon Schubert 
399cf7f2e2dSJohn Marino /* Using the data cache DCACHE, store in *PTR the contents of the byte at
4005796c8dcSSimon Schubert    address ADDR in the remote machine.
4015796c8dcSSimon Schubert 
4025796c8dcSSimon Schubert    Returns 1 for success, 0 for error.  */
4035796c8dcSSimon Schubert 
4045796c8dcSSimon Schubert static int
4055796c8dcSSimon Schubert dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
4065796c8dcSSimon Schubert {
4075796c8dcSSimon Schubert   struct dcache_block *db = dcache_hit (dcache, addr);
4085796c8dcSSimon Schubert 
4095796c8dcSSimon Schubert   if (!db)
4105796c8dcSSimon Schubert     {
4115796c8dcSSimon Schubert       db = dcache_alloc (dcache, addr);
4125796c8dcSSimon Schubert 
4135796c8dcSSimon Schubert       if (!dcache_read_line (dcache, db))
4145796c8dcSSimon Schubert          return 0;
4155796c8dcSSimon Schubert     }
4165796c8dcSSimon Schubert 
417*a45ae5f8SJohn Marino   *ptr = db->data[XFORM (dcache, addr)];
4185796c8dcSSimon Schubert   return 1;
4195796c8dcSSimon Schubert }
4205796c8dcSSimon Schubert 
4215796c8dcSSimon Schubert /* Write the byte at PTR into ADDR in the data cache.
4225796c8dcSSimon Schubert 
4235796c8dcSSimon Schubert    The caller is responsible for also promptly writing the data
4245796c8dcSSimon Schubert    through to target memory.
4255796c8dcSSimon Schubert 
4265796c8dcSSimon Schubert    If addr is not in cache, this function does nothing; writing to
4275796c8dcSSimon Schubert    an area of memory which wasn't present in the cache doesn't cause
4285796c8dcSSimon Schubert    it to be loaded in.
4295796c8dcSSimon Schubert 
4305796c8dcSSimon Schubert    Always return 1 (meaning success) to simplify dcache_xfer_memory.  */
4315796c8dcSSimon Schubert 
4325796c8dcSSimon Schubert static int
4335796c8dcSSimon Schubert dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
4345796c8dcSSimon Schubert {
4355796c8dcSSimon Schubert   struct dcache_block *db = dcache_hit (dcache, addr);
4365796c8dcSSimon Schubert 
4375796c8dcSSimon Schubert   if (db)
438*a45ae5f8SJohn Marino     db->data[XFORM (dcache, addr)] = *ptr;
4395796c8dcSSimon Schubert 
4405796c8dcSSimon Schubert   return 1;
4415796c8dcSSimon Schubert }
4425796c8dcSSimon Schubert 
4435796c8dcSSimon Schubert static int
4445796c8dcSSimon Schubert dcache_splay_tree_compare (splay_tree_key a, splay_tree_key b)
4455796c8dcSSimon Schubert {
4465796c8dcSSimon Schubert   if (a > b)
4475796c8dcSSimon Schubert     return 1;
4485796c8dcSSimon Schubert   else if (a == b)
4495796c8dcSSimon Schubert     return 0;
4505796c8dcSSimon Schubert   else
4515796c8dcSSimon Schubert     return -1;
4525796c8dcSSimon Schubert }
4535796c8dcSSimon Schubert 
454cf7f2e2dSJohn Marino /* Allocate and initialize a data cache.  */
4555796c8dcSSimon Schubert 
4565796c8dcSSimon Schubert DCACHE *
4575796c8dcSSimon Schubert dcache_init (void)
4585796c8dcSSimon Schubert {
4595796c8dcSSimon Schubert   DCACHE *dcache;
4605796c8dcSSimon Schubert 
4615796c8dcSSimon Schubert   dcache = (DCACHE *) xmalloc (sizeof (*dcache));
4625796c8dcSSimon Schubert 
4635796c8dcSSimon Schubert   dcache->tree = splay_tree_new (dcache_splay_tree_compare,
4645796c8dcSSimon Schubert 				 NULL,
4655796c8dcSSimon Schubert 				 NULL);
4665796c8dcSSimon Schubert 
4675796c8dcSSimon Schubert   dcache->oldest = NULL;
4685796c8dcSSimon Schubert   dcache->freelist = NULL;
4695796c8dcSSimon Schubert   dcache->size = 0;
470*a45ae5f8SJohn Marino   dcache->line_size = dcache_line_size;
4715796c8dcSSimon Schubert   dcache->ptid = null_ptid;
4725796c8dcSSimon Schubert   last_cache = dcache;
4735796c8dcSSimon Schubert 
4745796c8dcSSimon Schubert   return dcache;
4755796c8dcSSimon Schubert }
4765796c8dcSSimon Schubert 
4775796c8dcSSimon Schubert 
4785796c8dcSSimon Schubert /* Read or write LEN bytes from inferior memory at MEMADDR, transferring
4795796c8dcSSimon Schubert    to or from debugger address MYADDR.  Write to inferior if SHOULD_WRITE is
4805796c8dcSSimon Schubert    nonzero.
4815796c8dcSSimon Schubert 
482cf7f2e2dSJohn Marino    Return the number of bytes actually transfered, or -1 if the
483cf7f2e2dSJohn Marino    transfer is not supported or otherwise fails.  Return of a non-negative
484cf7f2e2dSJohn Marino    value less than LEN indicates that no further transfer is possible.
485cf7f2e2dSJohn Marino    NOTE: This is different than the to_xfer_partial interface, in which
486cf7f2e2dSJohn Marino    positive values less than LEN mean further transfers may be possible.  */
4875796c8dcSSimon Schubert 
4885796c8dcSSimon Schubert int
4895796c8dcSSimon Schubert dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache,
4905796c8dcSSimon Schubert 		    CORE_ADDR memaddr, gdb_byte *myaddr,
4915796c8dcSSimon Schubert 		    int len, int should_write)
4925796c8dcSSimon Schubert {
4935796c8dcSSimon Schubert   int i;
4945796c8dcSSimon Schubert   int res;
4955796c8dcSSimon Schubert   int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr);
496cf7f2e2dSJohn Marino 
4975796c8dcSSimon Schubert   xfunc = should_write ? dcache_poke_byte : dcache_peek_byte;
4985796c8dcSSimon Schubert 
4995796c8dcSSimon Schubert   /* If this is a different inferior from what we've recorded,
5005796c8dcSSimon Schubert      flush the cache.  */
5015796c8dcSSimon Schubert 
5025796c8dcSSimon Schubert   if (! ptid_equal (inferior_ptid, dcache->ptid))
5035796c8dcSSimon Schubert     {
5045796c8dcSSimon Schubert       dcache_invalidate (dcache);
5055796c8dcSSimon Schubert       dcache->ptid = inferior_ptid;
5065796c8dcSSimon Schubert     }
5075796c8dcSSimon Schubert 
5085796c8dcSSimon Schubert   /* Do write-through first, so that if it fails, we don't write to
5095796c8dcSSimon Schubert      the cache at all.  */
5105796c8dcSSimon Schubert 
5115796c8dcSSimon Schubert   if (should_write)
5125796c8dcSSimon Schubert     {
5135796c8dcSSimon Schubert       res = target_write (ops, TARGET_OBJECT_RAW_MEMORY,
5145796c8dcSSimon Schubert 			  NULL, myaddr, memaddr, len);
5155796c8dcSSimon Schubert       if (res <= 0)
5165796c8dcSSimon Schubert 	return res;
5175796c8dcSSimon Schubert       /* Update LEN to what was actually written.  */
5185796c8dcSSimon Schubert       len = res;
5195796c8dcSSimon Schubert     }
5205796c8dcSSimon Schubert 
5215796c8dcSSimon Schubert   for (i = 0; i < len; i++)
5225796c8dcSSimon Schubert     {
5235796c8dcSSimon Schubert       if (!xfunc (dcache, memaddr + i, myaddr + i))
5245796c8dcSSimon Schubert 	{
5255796c8dcSSimon Schubert 	  /* That failed.  Discard its cache line so we don't have a
5265796c8dcSSimon Schubert 	     partially read line.  */
5275796c8dcSSimon Schubert 	  dcache_invalidate_line (dcache, memaddr + i);
5285796c8dcSSimon Schubert 	  /* If we're writing, we still wrote LEN bytes.  */
5295796c8dcSSimon Schubert 	  if (should_write)
5305796c8dcSSimon Schubert 	    return len;
5315796c8dcSSimon Schubert 	  else
5325796c8dcSSimon Schubert 	    return i;
5335796c8dcSSimon Schubert 	}
5345796c8dcSSimon Schubert     }
5355796c8dcSSimon Schubert 
5365796c8dcSSimon Schubert   return len;
5375796c8dcSSimon Schubert }
5385796c8dcSSimon Schubert 
5395796c8dcSSimon Schubert /* FIXME: There would be some benefit to making the cache write-back and
5405796c8dcSSimon Schubert    moving the writeback operation to a higher layer, as it could occur
5415796c8dcSSimon Schubert    after a sequence of smaller writes have been completed (as when a stack
5425796c8dcSSimon Schubert    frame is constructed for an inferior function call).  Note that only
5435796c8dcSSimon Schubert    moving it up one level to target_xfer_memory[_partial]() is not
5445796c8dcSSimon Schubert    sufficient since we want to coalesce memory transfers that are
5455796c8dcSSimon Schubert    "logically" connected but not actually a single call to one of the
5465796c8dcSSimon Schubert    memory transfer functions.  */
5475796c8dcSSimon Schubert 
5485796c8dcSSimon Schubert /* Just update any cache lines which are already present.  This is called
5495796c8dcSSimon Schubert    by memory_xfer_partial in cases where the access would otherwise not go
5505796c8dcSSimon Schubert    through the cache.  */
5515796c8dcSSimon Schubert 
5525796c8dcSSimon Schubert void
5535796c8dcSSimon Schubert dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len)
5545796c8dcSSimon Schubert {
5555796c8dcSSimon Schubert   int i;
556cf7f2e2dSJohn Marino 
5575796c8dcSSimon Schubert   for (i = 0; i < len; i++)
5585796c8dcSSimon Schubert     dcache_poke_byte (dcache, memaddr + i, myaddr + i);
5595796c8dcSSimon Schubert }
5605796c8dcSSimon Schubert 
5615796c8dcSSimon Schubert static void
5625796c8dcSSimon Schubert dcache_print_line (int index)
5635796c8dcSSimon Schubert {
5645796c8dcSSimon Schubert   splay_tree_node n;
5655796c8dcSSimon Schubert   struct dcache_block *db;
5665796c8dcSSimon Schubert   int i, j;
5675796c8dcSSimon Schubert 
5685796c8dcSSimon Schubert   if (!last_cache)
5695796c8dcSSimon Schubert     {
5705796c8dcSSimon Schubert       printf_filtered (_("No data cache available.\n"));
5715796c8dcSSimon Schubert       return;
5725796c8dcSSimon Schubert     }
5735796c8dcSSimon Schubert 
5745796c8dcSSimon Schubert   n = splay_tree_min (last_cache->tree);
5755796c8dcSSimon Schubert 
5765796c8dcSSimon Schubert   for (i = index; i > 0; --i)
5775796c8dcSSimon Schubert     {
5785796c8dcSSimon Schubert       if (!n)
5795796c8dcSSimon Schubert 	break;
5805796c8dcSSimon Schubert       n = splay_tree_successor (last_cache->tree, n->key);
5815796c8dcSSimon Schubert     }
5825796c8dcSSimon Schubert 
5835796c8dcSSimon Schubert   if (!n)
5845796c8dcSSimon Schubert     {
5855796c8dcSSimon Schubert       printf_filtered (_("No such cache line exists.\n"));
5865796c8dcSSimon Schubert       return;
5875796c8dcSSimon Schubert     }
5885796c8dcSSimon Schubert 
5895796c8dcSSimon Schubert   db = (struct dcache_block *) n->value;
5905796c8dcSSimon Schubert 
5915796c8dcSSimon Schubert   printf_filtered (_("Line %d: address %s [%d hits]\n"),
5925796c8dcSSimon Schubert 		   index, paddress (target_gdbarch, db->addr), db->refs);
5935796c8dcSSimon Schubert 
594*a45ae5f8SJohn Marino   for (j = 0; j < last_cache->line_size; j++)
5955796c8dcSSimon Schubert     {
5965796c8dcSSimon Schubert       printf_filtered ("%02x ", db->data[j]);
5975796c8dcSSimon Schubert 
598c50c785cSJohn Marino       /* Print a newline every 16 bytes (48 characters).  */
599*a45ae5f8SJohn Marino       if ((j % 16 == 15) && (j != last_cache->line_size - 1))
6005796c8dcSSimon Schubert 	printf_filtered ("\n");
6015796c8dcSSimon Schubert     }
6025796c8dcSSimon Schubert   printf_filtered ("\n");
6035796c8dcSSimon Schubert }
6045796c8dcSSimon Schubert 
6055796c8dcSSimon Schubert static void
6065796c8dcSSimon Schubert dcache_info (char *exp, int tty)
6075796c8dcSSimon Schubert {
6085796c8dcSSimon Schubert   splay_tree_node n;
609cf7f2e2dSJohn Marino   int i, refcount;
6105796c8dcSSimon Schubert 
6115796c8dcSSimon Schubert   if (exp)
6125796c8dcSSimon Schubert     {
6135796c8dcSSimon Schubert       char *linestart;
614cf7f2e2dSJohn Marino 
6155796c8dcSSimon Schubert       i = strtol (exp, &linestart, 10);
6165796c8dcSSimon Schubert       if (linestart == exp || i < 0)
6175796c8dcSSimon Schubert 	{
6185796c8dcSSimon Schubert 	  printf_filtered (_("Usage: info dcache [linenumber]\n"));
6195796c8dcSSimon Schubert           return;
6205796c8dcSSimon Schubert 	}
6215796c8dcSSimon Schubert 
6225796c8dcSSimon Schubert       dcache_print_line (i);
6235796c8dcSSimon Schubert       return;
6245796c8dcSSimon Schubert     }
6255796c8dcSSimon Schubert 
626*a45ae5f8SJohn Marino   printf_filtered (_("Dcache %u lines of %u bytes each.\n"),
627*a45ae5f8SJohn Marino 		   dcache_size,
628*a45ae5f8SJohn Marino 		   last_cache ? (unsigned) last_cache->line_size
629*a45ae5f8SJohn Marino 		   : dcache_line_size);
6305796c8dcSSimon Schubert 
6315796c8dcSSimon Schubert   if (!last_cache || ptid_equal (last_cache->ptid, null_ptid))
6325796c8dcSSimon Schubert     {
6335796c8dcSSimon Schubert       printf_filtered (_("No data cache available.\n"));
6345796c8dcSSimon Schubert       return;
6355796c8dcSSimon Schubert     }
6365796c8dcSSimon Schubert 
6375796c8dcSSimon Schubert   printf_filtered (_("Contains data for %s\n"),
6385796c8dcSSimon Schubert 		   target_pid_to_str (last_cache->ptid));
6395796c8dcSSimon Schubert 
6405796c8dcSSimon Schubert   refcount = 0;
6415796c8dcSSimon Schubert 
6425796c8dcSSimon Schubert   n = splay_tree_min (last_cache->tree);
6435796c8dcSSimon Schubert   i = 0;
6445796c8dcSSimon Schubert 
6455796c8dcSSimon Schubert   while (n)
6465796c8dcSSimon Schubert     {
6475796c8dcSSimon Schubert       struct dcache_block *db = (struct dcache_block *) n->value;
6485796c8dcSSimon Schubert 
6495796c8dcSSimon Schubert       printf_filtered (_("Line %d: address %s [%d hits]\n"),
6505796c8dcSSimon Schubert 		       i, paddress (target_gdbarch, db->addr), db->refs);
6515796c8dcSSimon Schubert       i++;
6525796c8dcSSimon Schubert       refcount += db->refs;
6535796c8dcSSimon Schubert 
6545796c8dcSSimon Schubert       n = splay_tree_successor (last_cache->tree, n->key);
6555796c8dcSSimon Schubert     }
6565796c8dcSSimon Schubert 
6575796c8dcSSimon Schubert   printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount);
6585796c8dcSSimon Schubert }
6595796c8dcSSimon Schubert 
660*a45ae5f8SJohn Marino static void
661*a45ae5f8SJohn Marino set_dcache_size (char *args, int from_tty,
662*a45ae5f8SJohn Marino 		 struct cmd_list_element *c)
663*a45ae5f8SJohn Marino {
664*a45ae5f8SJohn Marino   if (dcache_size == 0)
665*a45ae5f8SJohn Marino     {
666*a45ae5f8SJohn Marino       dcache_size = DCACHE_DEFAULT_SIZE;
667*a45ae5f8SJohn Marino       error (_("Dcache size must be greater than 0."));
668*a45ae5f8SJohn Marino     }
669*a45ae5f8SJohn Marino   if (last_cache)
670*a45ae5f8SJohn Marino     dcache_invalidate (last_cache);
671*a45ae5f8SJohn Marino }
672*a45ae5f8SJohn Marino 
673*a45ae5f8SJohn Marino static void
674*a45ae5f8SJohn Marino set_dcache_line_size (char *args, int from_tty,
675*a45ae5f8SJohn Marino 		      struct cmd_list_element *c)
676*a45ae5f8SJohn Marino {
677*a45ae5f8SJohn Marino   if (dcache_line_size < 2
678*a45ae5f8SJohn Marino       || (dcache_line_size & (dcache_line_size - 1)) != 0)
679*a45ae5f8SJohn Marino     {
680*a45ae5f8SJohn Marino       unsigned d = dcache_line_size;
681*a45ae5f8SJohn Marino       dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
682*a45ae5f8SJohn Marino       error (_("Invalid dcache line size: %u (must be power of 2)."), d);
683*a45ae5f8SJohn Marino     }
684*a45ae5f8SJohn Marino   if (last_cache)
685*a45ae5f8SJohn Marino     dcache_invalidate (last_cache);
686*a45ae5f8SJohn Marino }
687*a45ae5f8SJohn Marino 
688*a45ae5f8SJohn Marino static void
689*a45ae5f8SJohn Marino set_dcache_command (char *arg, int from_tty)
690*a45ae5f8SJohn Marino {
691*a45ae5f8SJohn Marino   printf_unfiltered (
692*a45ae5f8SJohn Marino      "\"set dcache\" must be followed by the name of a subcommand.\n");
693*a45ae5f8SJohn Marino   help_list (dcache_set_list, "set dcache ", -1, gdb_stdout);
694*a45ae5f8SJohn Marino }
695*a45ae5f8SJohn Marino 
696*a45ae5f8SJohn Marino static void
697*a45ae5f8SJohn Marino show_dcache_command (char *args, int from_tty)
698*a45ae5f8SJohn Marino {
699*a45ae5f8SJohn Marino   cmd_show_list (dcache_show_list, from_tty, "");
700*a45ae5f8SJohn Marino }
701*a45ae5f8SJohn Marino 
7025796c8dcSSimon Schubert void
7035796c8dcSSimon Schubert _initialize_dcache (void)
7045796c8dcSSimon Schubert {
7055796c8dcSSimon Schubert   add_setshow_boolean_cmd ("remotecache", class_support,
7065796c8dcSSimon Schubert 			   &dcache_enabled_p, _("\
7075796c8dcSSimon Schubert Set cache use for remote targets."), _("\
7085796c8dcSSimon Schubert Show cache use for remote targets."), _("\
7095796c8dcSSimon Schubert This used to enable the data cache for remote targets.  The cache\n\
7105796c8dcSSimon Schubert functionality is now controlled by the memory region system and the\n\
7115796c8dcSSimon Schubert \"stack-cache\" flag; \"remotecache\" now does nothing and\n\
7125796c8dcSSimon Schubert exists only for compatibility reasons."),
7135796c8dcSSimon Schubert 			   NULL,
7145796c8dcSSimon Schubert 			   show_dcache_enabled_p,
7155796c8dcSSimon Schubert 			   &setlist, &showlist);
7165796c8dcSSimon Schubert 
7175796c8dcSSimon Schubert   add_info ("dcache", dcache_info,
7185796c8dcSSimon Schubert 	    _("\
7195796c8dcSSimon Schubert Print information on the dcache performance.\n\
7205796c8dcSSimon Schubert With no arguments, this command prints the cache configuration and a\n\
7215796c8dcSSimon Schubert summary of each line in the cache.  Use \"info dcache <lineno> to dump\"\n\
7225796c8dcSSimon Schubert the contents of a given line."));
723*a45ae5f8SJohn Marino 
724*a45ae5f8SJohn Marino   add_prefix_cmd ("dcache", class_obscure, set_dcache_command, _("\
725*a45ae5f8SJohn Marino Use this command to set number of lines in dcache and line-size."),
726*a45ae5f8SJohn Marino 		  &dcache_set_list, "set dcache ", /*allow_unknown*/0, &setlist);
727*a45ae5f8SJohn Marino   add_prefix_cmd ("dcache", class_obscure, show_dcache_command, _("\
728*a45ae5f8SJohn Marino Show dcachesettings."),
729*a45ae5f8SJohn Marino 		  &dcache_show_list, "show dcache ", /*allow_unknown*/0, &showlist);
730*a45ae5f8SJohn Marino 
731*a45ae5f8SJohn Marino   add_setshow_uinteger_cmd ("line-size", class_obscure,
732*a45ae5f8SJohn Marino 			    &dcache_line_size, _("\
733*a45ae5f8SJohn Marino Set dcache line size in bytes (must be power of 2)."), _("\
734*a45ae5f8SJohn Marino Show dcache line size."),
735*a45ae5f8SJohn Marino 			    NULL,
736*a45ae5f8SJohn Marino 			    set_dcache_line_size,
737*a45ae5f8SJohn Marino 			    NULL,
738*a45ae5f8SJohn Marino 			    &dcache_set_list, &dcache_show_list);
739*a45ae5f8SJohn Marino   add_setshow_uinteger_cmd ("size", class_obscure,
740*a45ae5f8SJohn Marino 			    &dcache_size, _("\
741*a45ae5f8SJohn Marino Set number of dcache lines."), _("\
742*a45ae5f8SJohn Marino Show number of dcache lines."),
743*a45ae5f8SJohn Marino 			    NULL,
744*a45ae5f8SJohn Marino 			    set_dcache_size,
745*a45ae5f8SJohn Marino 			    NULL,
746*a45ae5f8SJohn Marino 			    &dcache_set_list, &dcache_show_list);
7475796c8dcSSimon Schubert }
748