blob: bec3819671c9a1eb0e98493996289d5d68f48591 [file] [log] [blame]
/* Copyright (c) 2009 The Regents of the University of California.
* See the COPYRIGHT files at the top of this source tree for full
* license information.
*
* Kevin Klues <klueska@cs.berkeley.edu>
*/
#ifdef __SHARC__
#pragma nosharc
#define SINIT(x) x
#endif
#include <ros/common.h>
#include <arch/mmu.h>
#include <bitmask.h>
#include <colored_caches.h>
#include <stdio.h>
#include <atomic.h>
#include <kmalloc.h>
#include <page_alloc.h>
#define l1 (available_caches.l1)
#define l2 (available_caches.l2)
#define l3 (available_caches.l3)
spinlock_t cache_colors_lock = SPINLOCK_INITIALIZER_IRQSAVE;
/************** Cache Related Functions *****************/
inline void init_cache_properties(cache_t *c, size_t sz_k, size_t wa, size_t clsz) {
c->wa = SINIT(wa);
c->sz_k = SINIT(sz_k);
c->clsz = SINIT(clsz);
#ifdef CONFIG_PAGE_COLORING
//Added as optimization (derived from above);
size_t nc = get_cache_num_page_colors(c);
c->num_colors = SINIT(nc);
#else
c->num_colors = 1;
#endif
}
inline void init_free_cache_colors_map(cache_t* c)
{
// Initialize the free colors map
c->free_colors_map = kmalloc(c->num_colors, 0);
FILL_BITMASK(c->free_colors_map, c->num_colors);
}
inline size_t get_offset_in_cache_line(uintptr_t addr, cache_t *c) {
return (addr % get_cache_bytes_per_line(c));
}
void print_cache_properties(char *NT lstring, cache_t *c)
{
printk("%s_WAYS_ASSOCIATIVE: %ld\n", lstring, get_cache_ways_associative(c));
printk("%s_LINE_SIZE_BYTES: %ld\n", lstring, get_cache_line_size_bytes(c));
printk("%s_SIZE_BYTES: %ld\n", lstring, get_cache_size_bytes(c));
printk("%s_SIZE_KILOBYTES: %ld\n", lstring, get_cache_size_kilobytes(c));
printk("%s_SIZE_MEGABYTES: %ld\n", lstring, get_cache_size_megabytes(c));
printk("%s_OFFSET_BITS: %ld\n", lstring, get_cache_num_offset_bits(c));
printk("%s_INDEX_BITS: %ld\n", lstring, get_cache_num_index_bits(c));
printk("%s_TAG_BITS: %ld\n", lstring, get_cache_num_tag_bits(c));
printk("%s_PAGE_COLOR_BITS: %ld\n", lstring, get_cache_num_page_color_bits(c));
printk("%s_BYTES_PER_LINE: %ld\n", lstring, get_cache_bytes_per_line(c));
printk("%s_NUM_LINES: %ld\n", lstring, get_cache_num_lines(c));
printk("%s_NUM_SETS: %ld\n", lstring, get_cache_num_sets(c));
printk("%s_LINES_PER_SET: %ld\n", lstring, get_cache_lines_per_set(c));
printk("%s_LINES_PER_PAGE: %ld\n", lstring, get_cache_lines_per_page(c));
printk("%s_BYTES_PER_WAY: %ld\n", lstring, get_cache_bytes_per_way(c));
printk("%s_LINES_PER_WAY: %ld\n", lstring, get_cache_lines_per_way(c));
printk("%s_PAGES_PER_WAY: %ld\n", lstring, get_cache_pages_per_way(c));
printk("%s_NUM_PAGE_COLORS: %ld\n", lstring, get_cache_num_page_colors(c));
}
/****************** Cache Properties *********************/
inline size_t get_cache_ways_associative(cache_t *c) {
return (c->wa);
}
inline size_t get_cache_line_size_bytes(cache_t *c) {
return (c->clsz);
}
inline size_t get_cache_size_bytes(cache_t *c) {
return (c->sz_k * ONE_KILOBYTE);
}
inline size_t get_cache_size_kilobytes(cache_t *c) {
return (c->sz_k);
}
inline size_t get_cache_size_megabytes(cache_t *c) {
return (c->sz_k / ONE_KILOBYTE);
}
inline size_t get_cache_num_offset_bits(cache_t *c) {
return (LOG2_UP(get_cache_line_size_bytes(c)));
}
inline size_t get_cache_num_index_bits(cache_t *c) {
return (LOG2_UP(get_cache_size_bytes(c)
/ get_cache_ways_associative(c)
/ get_cache_line_size_bytes(c)));
}
inline size_t get_cache_num_tag_bits(cache_t *c) {
return (NUM_ADDR_BITS - get_cache_num_offset_bits(c)
- get_cache_num_index_bits(c));
}
inline size_t get_cache_num_page_color_bits(cache_t *c) {
return (get_cache_num_offset_bits(c)
+ get_cache_num_index_bits(c)
- PGSHIFT);
}
inline size_t get_cache_bytes_per_line(cache_t *c) {
return (1 << get_cache_num_offset_bits(c));
}
inline size_t get_cache_num_lines(cache_t *c) {
return (get_cache_size_bytes(c)/get_cache_bytes_per_line(c));
}
inline size_t get_cache_num_sets(cache_t *c) {
return (get_cache_num_lines(c)/get_cache_ways_associative(c));
}
inline size_t get_cache_lines_per_set(cache_t *c) {
return (get_cache_ways_associative(c));
}
inline size_t get_cache_lines_per_page(cache_t *c) {
return (PGSIZE / get_cache_bytes_per_line(c));
}
inline size_t get_cache_bytes_per_way(cache_t *c) {
return (get_cache_size_bytes(c)/get_cache_ways_associative(c));
}
inline size_t get_cache_lines_per_way(cache_t *c) {
return (get_cache_num_lines(c)/get_cache_ways_associative(c));
}
inline size_t get_cache_pages_per_way(cache_t *c) {
return (get_cache_lines_per_way(c)/get_cache_lines_per_page(c));
}
inline size_t get_cache_num_page_colors(cache_t *c) {
return get_cache_pages_per_way(c);
}
static inline void set_color_range(uint16_t color, uint8_t* map,
cache_t* smaller, cache_t* bigger)
{
size_t base, r;
if(smaller->num_colors <= bigger->num_colors) {
r = bigger->num_colors / smaller->num_colors;
base = color*r;
SET_BITMASK_RANGE(map, base, base+r);
}
else {
r = smaller->num_colors / bigger->num_colors;
base = color/r;
if(BITMASK_IS_SET_IN_RANGE(smaller->free_colors_map,
base*r, base*r+r-1))
SET_BITMASK_BIT(map, base);
}
}
static inline void clr_color_range(uint16_t color, uint8_t* map,
cache_t* smaller, cache_t* bigger)
{
size_t base, r;
if(smaller->num_colors <= bigger->num_colors) {
r = bigger->num_colors / smaller->num_colors;
base = color*r;
CLR_BITMASK_RANGE(map, base, base+r);
}
else {
r = smaller->num_colors / bigger->num_colors;
base = color/r;
CLR_BITMASK_BIT(map, base);
}
}
static inline error_t __cache_color_alloc_specific(size_t color, cache_t* c,
uint8_t* colors_map)
{
if(!GET_BITMASK_BIT(c->free_colors_map, color))
return -ENOCACHE;
if(l1)
clr_color_range(color, l1->free_colors_map, c, l1);
if(l2)
clr_color_range(color, l2->free_colors_map, c, l2);
if(l3)
clr_color_range(color, l3->free_colors_map, c, l3);
set_color_range(color, colors_map, c, llc_cache);
return ESUCCESS;
}
static inline error_t __cache_color_alloc(cache_t* c, uint8_t* colors_map)
{
if(BITMASK_IS_CLEAR(c->free_colors_map, c->num_colors))
return -ENOCACHE;
int color=0;
do {
if(GET_BITMASK_BIT(c->free_colors_map, color))
break;
} while(++color);
return __cache_color_alloc_specific(color, c, colors_map);
}
static inline void __cache_color_free_specific(size_t color, cache_t* c,
uint8_t* colors_map)
{
if(GET_BITMASK_BIT(c->free_colors_map, color))
return;
else {
size_t r = llc_cache->num_colors / c->num_colors;
size_t base = color*r;
if(!BITMASK_IS_SET_IN_RANGE(colors_map, base, base+r))
return;
}
if(l3)
set_color_range(color, l3->free_colors_map, c, l3);
if(l2)
set_color_range(color, l2->free_colors_map, c, l2);
if(l1)
set_color_range(color, l1->free_colors_map, c, l1);
clr_color_range(color, colors_map, c, llc_cache);
}
static inline void __cache_color_free(cache_t* c, uint8_t* colors_map)
{
if(BITMASK_IS_FULL(c->free_colors_map, c->num_colors))
return;
int color=0;
do {
if(!GET_BITMASK_BIT(c->free_colors_map, color)) {
size_t r = llc_cache->num_colors / c->num_colors;
size_t base = color*r;
if(BITMASK_IS_SET_IN_RANGE(colors_map, base, base+r))
break;
}
} while(++color < c->num_colors);
if(color == c->num_colors)
return;
__cache_color_free_specific(color, c, colors_map);
}
uint8_t* cache_colors_map_alloc() {
#ifdef CONFIG_PAGE_COLORING
uint8_t* colors_map = kmalloc(llc_cache->num_colors, 0);
if(colors_map)
CLR_BITMASK(colors_map, llc_cache->num_colors);
return colors_map;
#else
return global_cache_colors_map;
#endif
}
void cache_colors_map_free(uint8_t* colors_map) {
#ifdef CONFIG_PAGE_COLORING
kfree(colors_map);
#endif
}
error_t cache_color_alloc(cache_t* c, uint8_t* colors_map)
{
spin_lock_irqsave(&cache_colors_lock);
error_t e = __cache_color_alloc(c, colors_map);
spin_unlock_irqsave(&cache_colors_lock);
return e;
}
error_t cache_color_alloc_specific(size_t color, cache_t* c, uint8_t* colors_map)
{
spin_lock_irqsave(&cache_colors_lock);
error_t e = __cache_color_alloc_specific(color, c, colors_map);
spin_unlock_irqsave(&cache_colors_lock);
return e;
}
void cache_color_free(cache_t* c, uint8_t* colors_map)
{
spin_lock_irqsave(&cache_colors_lock);
__cache_color_free(c, colors_map);
spin_unlock_irqsave(&cache_colors_lock);
}
void cache_color_free_specific(size_t color, cache_t* c, uint8_t* colors_map)
{
spin_lock_irqsave(&cache_colors_lock);
__cache_color_free_specific(color, c, colors_map);
spin_unlock_irqsave(&cache_colors_lock);
}