diff --git a/Makefile.am b/Makefile.am index 407d0f4c..936d7014 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,13 +46,13 @@ nobase_include_HEADERS += \ metal/drivers/sifive_fe310-g000_lfrosc.h \ metal/drivers/sifive_fe310-g000_pll.h \ metal/drivers/sifive_fe310-g000_prci.h \ - metal/drivers/sifive_fu540-c000_l2.h \ metal/drivers/sifive_global-external-interrupts0.h \ metal/drivers/sifive_gpio-buttons.h \ metal/drivers/sifive_gpio-leds.h \ metal/drivers/sifive_gpio-switches.h \ metal/drivers/sifive_gpio0.h \ metal/drivers/sifive_i2c0.h \ + metal/drivers/sifive_l2pf0.h \ metal/drivers/sifive_local-external-interrupts0.h \ metal/drivers/sifive_pwm0.h \ metal/drivers/sifive_rtc0.h \ @@ -115,13 +115,13 @@ libmetal_a_SOURCES = \ src/drivers/sifive_fe310-g000_lfrosc.c \ src/drivers/sifive_fe310-g000_pll.c \ src/drivers/sifive_fe310-g000_prci.c \ - src/drivers/sifive_fu540-c000_l2.c \ src/drivers/sifive_global-external-interrupts0.c \ src/drivers/sifive_gpio-buttons.c \ src/drivers/sifive_gpio-leds.c \ src/drivers/sifive_gpio-switches.c \ src/drivers/sifive_gpio0.c \ src/drivers/sifive_i2c0.c \ + src/drivers/sifive_l2pf0.c \ src/drivers/sifive_local-external-interrupts0.c \ src/drivers/sifive_pwm0.c \ src/drivers/sifive_rtc0.c \ diff --git a/Makefile.in b/Makefile.in index 6d5d3349..194891d3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -258,13 +258,13 @@ am_libmetal_a_OBJECTS = src/drivers/fixed-clock.$(OBJEXT) \ src/drivers/sifive_fe310-g000_lfrosc.$(OBJEXT) \ src/drivers/sifive_fe310-g000_pll.$(OBJEXT) \ src/drivers/sifive_fe310-g000_prci.$(OBJEXT) \ - src/drivers/sifive_fu540-c000_l2.$(OBJEXT) \ src/drivers/sifive_global-external-interrupts0.$(OBJEXT) \ src/drivers/sifive_gpio-buttons.$(OBJEXT) \ src/drivers/sifive_gpio-leds.$(OBJEXT) \ src/drivers/sifive_gpio-switches.$(OBJEXT) \ src/drivers/sifive_gpio0.$(OBJEXT) \ src/drivers/sifive_i2c0.$(OBJEXT) \ + src/drivers/sifive_l2pf0.$(OBJEXT) \ src/drivers/sifive_local-external-interrupts0.$(OBJEXT) \ src/drivers/sifive_pwm0.$(OBJEXT) \ src/drivers/sifive_rtc0.$(OBJEXT) \ @@ -490,12 +490,12 @@ nobase_include_HEADERS = metal/machine.h metal/machine/inline.h \ metal/drivers/sifive_fe310-g000_lfrosc.h \ metal/drivers/sifive_fe310-g000_pll.h \ metal/drivers/sifive_fe310-g000_prci.h \ - metal/drivers/sifive_fu540-c000_l2.h \ metal/drivers/sifive_global-external-interrupts0.h \ metal/drivers/sifive_gpio-buttons.h \ metal/drivers/sifive_gpio-leds.h \ metal/drivers/sifive_gpio-switches.h \ metal/drivers/sifive_gpio0.h metal/drivers/sifive_i2c0.h \ + metal/drivers/sifive_l2pf0.h \ metal/drivers/sifive_local-external-interrupts0.h \ metal/drivers/sifive_pwm0.h metal/drivers/sifive_rtc0.h \ metal/drivers/sifive_spi0.h metal/drivers/sifive_test0.h \ @@ -537,13 +537,13 @@ libmetal_a_SOURCES = \ src/drivers/sifive_fe310-g000_lfrosc.c \ src/drivers/sifive_fe310-g000_pll.c \ src/drivers/sifive_fe310-g000_prci.c \ - src/drivers/sifive_fu540-c000_l2.c \ src/drivers/sifive_global-external-interrupts0.c \ src/drivers/sifive_gpio-buttons.c \ src/drivers/sifive_gpio-leds.c \ src/drivers/sifive_gpio-switches.c \ src/drivers/sifive_gpio0.c \ src/drivers/sifive_i2c0.c \ + src/drivers/sifive_l2pf0.c \ src/drivers/sifive_local-external-interrupts0.c \ src/drivers/sifive_pwm0.c \ src/drivers/sifive_rtc0.c \ @@ -850,9 +850,6 @@ src/drivers/sifive_fe310-g000_pll.$(OBJEXT): \ src/drivers/sifive_fe310-g000_prci.$(OBJEXT): \ src/drivers/$(am__dirstamp) \ src/drivers/$(DEPDIR)/$(am__dirstamp) -src/drivers/sifive_fu540-c000_l2.$(OBJEXT): \ - src/drivers/$(am__dirstamp) \ - src/drivers/$(DEPDIR)/$(am__dirstamp) src/drivers/sifive_global-external-interrupts0.$(OBJEXT): \ src/drivers/$(am__dirstamp) \ src/drivers/$(DEPDIR)/$(am__dirstamp) @@ -868,6 +865,8 @@ src/drivers/sifive_gpio0.$(OBJEXT): src/drivers/$(am__dirstamp) \ src/drivers/$(DEPDIR)/$(am__dirstamp) src/drivers/sifive_i2c0.$(OBJEXT): src/drivers/$(am__dirstamp) \ src/drivers/$(DEPDIR)/$(am__dirstamp) +src/drivers/sifive_l2pf0.$(OBJEXT): src/drivers/$(am__dirstamp) \ + src/drivers/$(DEPDIR)/$(am__dirstamp) src/drivers/sifive_local-external-interrupts0.$(OBJEXT): \ src/drivers/$(am__dirstamp) \ src/drivers/$(DEPDIR)/$(am__dirstamp) @@ -1032,13 +1031,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_fe310-g000_lfrosc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_fe310-g000_pll.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_fe310-g000_prci.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_fu540-c000_l2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_global-external-interrupts0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_gpio-buttons.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_gpio-leds.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_gpio-switches.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_gpio0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_i2c0.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_l2pf0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_local-external-interrupts0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_pwm0.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/drivers/$(DEPDIR)/sifive_rtc0.Po@am__quote@ diff --git a/metal/cache.h b/metal/cache.h index 6e676870..673a8b13 100644 --- a/metal/cache.h +++ b/metal/cache.h @@ -1,4 +1,4 @@ -/* Copyright 2018 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #ifndef METAL__CACHE_H @@ -11,39 +11,56 @@ */ #include -struct metal_cache; - -struct __metal_cache_vtable { - void (*init)(struct metal_cache *cache, int ways); - int (*get_enabled_ways)(struct metal_cache *cache); - int (*set_enabled_ways)(struct metal_cache *cache, int ways); -}; - /*! * @brief a handle for a cache + * Note: To be deprecated in next release. */ struct metal_cache { - const struct __metal_cache_vtable *vtable; + uint8_t __no_empty_structs; }; +/*! + * @brief Initialize L2 cache controller. + * Enables all available cache ways. + * @param None + * @return 0 If no error + */ +int metal_l2cache_init(void); + +/*! + * @brief Get the current number of enabled L2 cache ways + * @param None + * @return The current number of enabled L2 cache ways + */ +int metal_l2cache_get_enabled_ways(void); + +/*! + * @brief Enable the requested number of L2 cache ways + * @param ways Number of ways to enable + * @return 0 if the ways are successfully enabled + */ +int metal_l2cache_set_enabled_ways(int ways); + /*! * @brief Initialize a cache * @param cache The handle for the cache to initialize * @param ways The number of ways to enable * * Initializes a cache with the requested number of ways enabled. + * Note: API to be deprecated in next release. */ __inline__ void metal_cache_init(struct metal_cache *cache, int ways) { - cache->vtable->init(cache, ways); + metal_l2cache_init(); } /*! * @brief Get the current number of enabled cache ways * @param cache The handle for the cache * @return The current number of enabled cache ways + * Note: API to be deprecated in next release. */ __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache) { - return cache->vtable->get_enabled_ways(cache); + return metal_l2cache_get_enabled_ways(); } /*! @@ -51,10 +68,11 @@ __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache) { * @param cache The handle for the cache * @param ways The number of ways to enabled * @return 0 if the ways are successfully enabled + * Note: API to be deprecated in next release. */ __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways) { - return cache->vtable->set_enabled_ways(cache, ways); + return metal_l2cache_set_enabled_ways(ways); } /*! diff --git a/metal/drivers/sifive_ccache0.h b/metal/drivers/sifive_ccache0.h index b2038637..9af1cb3f 100644 --- a/metal/drivers/sifive_ccache0.h +++ b/metal/drivers/sifive_ccache0.h @@ -1,22 +1,139 @@ -/* Copyright 2019 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #ifndef METAL__DRIVERS__SIFIVE_CCACHE0_H #define METAL__DRIVERS__SIFIVE_CCACHE0_H -#include -#include +/*! + * @file sifive_ccache0.h + * + * @brief API for configuring the SiFive L2 cache controller + */ -struct __metal_driver_vtable_sifive_ccache0 { - struct __metal_cache_vtable cache; -}; +#include +#include -struct __metal_driver_sifive_ccache0; +/*! @brief Cache configuration data */ +typedef struct { + uint32_t num_bank; + uint32_t num_ways; + uint32_t num_sets; + uint32_t block_size; +} sifive_ccache0_config; -__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_ccache0) +/*! @brief Set of values for ECC error type */ +typedef enum { + SIFIVE_CCACHE0_DATA = 0, + SIFIVE_CCACHE0_DIR = 1, +} sifive_ccache0_ecc_errtype_t; -struct __metal_driver_sifive_ccache0 { - struct metal_cache cache; -}; +/*! @brief Initialize cache controller, enables all available + * cache-ways. + * @param None. + * @return 0 If no error.*/ +int sifive_ccache0_init(void); + +/*! @brief Get cache configuration data. + * @param config User specified data buffer. + * @return None.*/ +void sifive_ccache0_get_config(sifive_ccache0_config *config); + +/*! @brief Get currently active cache ways. + * @param None. + * @return Number of cache ways enabled.*/ +uint32_t sifive_ccache0_get_enabled_ways(void); + +/*! @brief Enable specified cache ways. + * @param ways Number of ways to be enabled. + * @return 0 If no error.*/ +int sifive_ccache0_set_enabled_ways(uint32_t ways); + +/*! @brief Inject ECC error into data or meta-data. + * @param bitindex Bit index to be corrupted on next cache operation. + * @param type ECC error target location. + * @return None.*/ +void sifive_ccache0_inject_ecc_error(uint32_t bitindex, + sifive_ccache0_ecc_errtype_t type); + +/*! @brief Flush out entire cache block containing given address. + * @param flush_addr Address for the cache block to be flushed. + * @return None.*/ +void sifive_ccache0_flush(uintptr_t flush_addr); + +/*! @brief Get most recently ECC corrected address. + * @param type ECC error target location. + * @return Last corrected ECC address.*/ +uintptr_t sifive_ccache0_get_ecc_fix_addr(sifive_ccache0_ecc_errtype_t type); + +/*! @brief Get number of times ECC errors were corrected. + * Clears related ECC interrupt signals. + * @param type ECC error target location. + * @return Corrected ECC error count.*/ +uint32_t sifive_ccache0_get_ecc_fix_count(sifive_ccache0_ecc_errtype_t type); + +/*! @brief Get address location of most recent uncorrected ECC error. + * @param type ECC error target location. + * @return Last uncorrected ECC address.*/ +uintptr_t sifive_ccache0_get_ecc_fail_addr(sifive_ccache0_ecc_errtype_t type); + +/*! @brief Get number of times ECC errors were not corrected. + * Clears related ECC interrupt signals. + * @param type ECC error target location. + * @return Uncorrected ECC error count.*/ +uint32_t sifive_ccache0_get_ecc_fail_count(sifive_ccache0_ecc_errtype_t type); + +/*! @brief Get currently active way enable mask value for the given master ID. + * @param master_id Cache controller master ID. + * @return Way enable mask. */ +uint64_t sifive_ccache0_get_way_mask(uint32_t master_id); + +/*! @brief Set way enable mask for the given master ID. + * @param master_id Cache controller master ID. + * @param waymask Specify ways to be enabled. + * @return 0 If no error.*/ +int sifive_ccache0_set_way_mask(uint32_t master_id, uint64_t waymask); + +/*! @brief Select cache performance events to be counted. + * @param counter Cache performance monitor counter index. + * @param mask Event selection mask. + * @return None.*/ +void sifive_ccache0_set_pmevent_selector(uint32_t counter, uint64_t mask); + +/*! @brief Get currently set events for the given counter index. + * @param counter Cache performance monitor counter index. + * @return Event selection mask.*/ +uint64_t sifive_ccache0_get_pmevent_selector(uint32_t counter); + +/*! @brief Clears specified cache performance counter. + * @param counter Cache performance monitor counter index. + * @return None.*/ +void sifive_ccache0_clr_pmevent_counter(uint32_t counter); + +/*! @brief Reads specified cache performance counter. + * @param counter Cache performance monitor counter index. + * @return Counter value.*/ +uint64_t sifive_ccache0_get_pmevent_counter(uint32_t counter); + +/*! @brief Select cache clients to be excluded from performance monitoring. + * @param mask Client disable mask. + * @return None.*/ +void sifive_ccache0_set_client_filter(uint64_t mask); + +/*! @brief Get currently set cache client disable mask. + * @param None. + * @return Client disable mask.*/ +uint64_t sifive_ccache0_get_client_filter(void); + +/*! @brief Get interrupt IDs for the cache controller. + * @param src Interrupt trigger source index. + * @return Interrupt id.*/ +int sifive_ccache0_get_interrupt_id(uint32_t src); + +/*! @brief Get interrupt controller of the cache. + * The interrupt controller must be initialized before any interrupts can be + * registered or enabled with it. + * @param None. + * @return Handle for the interrupt controller.*/ +struct metal_interrupt *sifive_ccache0_interrupt_controller(void); #endif diff --git a/metal/drivers/sifive_fu540-c000_l2.h b/metal/drivers/sifive_fu540-c000_l2.h deleted file mode 100644 index 08992024..00000000 --- a/metal/drivers/sifive_fu540-c000_l2.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2018 SiFive, Inc */ -/* SPDX-License-Identifier: Apache-2.0 */ - -#ifndef METAL__DRIVERS__SIFIVE_FU540_C000_L2_H -#define METAL__DRIVERS__SIFIVE_FU540_C000_L2_H - -#include -#include - -struct __metal_driver_vtable_sifive_fu540_c000_l2 { - struct __metal_cache_vtable cache; -}; - -struct __metal_driver_sifive_fu540_c000_l2; - -__METAL_DECLARE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) - -struct __metal_driver_sifive_fu540_c000_l2 { - struct metal_cache cache; -}; - -#endif diff --git a/metal/drivers/sifive_l2pf0.h b/metal/drivers/sifive_l2pf0.h new file mode 100644 index 00000000..63c8e653 --- /dev/null +++ b/metal/drivers/sifive_l2pf0.h @@ -0,0 +1,78 @@ +/* Copyright 2020 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef METAL__DRIVERS__SIFIVE_L2PF0_H +#define METAL__DRIVERS__SIFIVE_L2PF0_H + +/*! + * @file sifive_l2pf0.h + * + * @brief API for configuring the SiFive L2 prefetcher. + */ + +#include + +/*! @brief L2 prefetcher configuration */ +typedef struct { + /* Enable L2 hardware prefetcher */ + uint8_t HwPrefetchEnable; + + /* Only works when CrossPageEn === 0. + Cross Page optimization disable: + 0 -> Entry goes into Pause state while crossing Page boundary. + Next time when the demand miss happens on the same page, it doesn’t need + to train again. 1 -> The entry is invalidated in case of a cross page. */ + uint8_t CrossPageOptmDisable; + + /* Enable prefetches to cross pages */ + uint8_t CrossPageEn; + + /* Age-out mechanism enable */ + uint8_t AgeOutEn; + + uint32_t PrefetchDistance; + + uint32_t MaxAllowedDistance; + + /* Linear to exponential threshold */ + uint32_t LinToExpThreshold; + + /* No. of non-matching loads to edge out an entry */ + uint32_t NumLdsToAgeOut; + + /* Threshold no. of Fullness (L2 MSHRs used/ total available) to stop + * sending hits */ + uint32_t QFullnessThreshold; + + /* Threshold no. of CacheHits for evicting SPF entry */ + uint32_t HitCacheThreshold; + + /* Threshold no. of MSHR hits for increasing SPF distance */ + uint32_t hitMSHRThreshold; + + /* Size of the comparison window for address matching */ + uint32_t Window; + +} sifive_l2pf0_config; + +/*! @brief Enable L2 hardware prefetcher unit. + * @param None. + * @return None.*/ +void sifive_l2pf0_enable(void); + +/*! @brief Disable L2 hardware prefetcher unit. + * @param None. + * @return None.*/ +void sifive_l2pf0_disable(void); + +/*! @brief Get currently active L2 prefetcher configuration. + * @param config Pointer to user specified configuration structure. + * @return None.*/ +void sifive_l2pf0_get_config(sifive_l2pf0_config *config); + +/*! @brief Enables fine grain access to L2 prefetcher configuration. + * @param config Pointer to user structure with values to be set. + * @return None.*/ +void sifive_l2pf0_set_config(sifive_l2pf0_config *config); + +#endif diff --git a/src/cache.c b/src/cache.c index f1e09c37..09c270e4 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1,14 +1,45 @@ -/* Copyright 2018 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #include #include +/* Macros to generate driver prefix string */ +#ifdef METAL_CACHE_DRIVER_PREFIX +#define METAL_FUNC_STR(a, b) a##_##b +#define METAL_FUNC_STR_(a, b) METAL_FUNC_STR(a, b) +#define METAL_FUNC(x) METAL_FUNC_STR_(METAL_CACHE_DRIVER_PREFIX, x) +#endif + extern __inline__ void metal_cache_init(struct metal_cache *cache, int ways); extern __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache); extern __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways); +int metal_l2cache_init(void) { +#ifdef METAL_CACHE_DRIVER_PREFIX + return METAL_FUNC(init)(); +#else + return -1; +#endif +} + +int metal_l2cache_get_enabled_ways(void) { +#ifdef METAL_CACHE_DRIVER_PREFIX + return METAL_FUNC(get_enabled_ways)(); +#else + return -1; +#endif +} + +int metal_l2cache_set_enabled_ways(int ways) { +#ifdef METAL_CACHE_DRIVER_PREFIX + return METAL_FUNC(set_enabled_ways)(ways); +#else + return -1; +#endif +} + int metal_dcache_l1_available(int hartid) { switch (hartid) { case 0: diff --git a/src/drivers/sifive_ccache0.c b/src/drivers/sifive_ccache0.c index f6461c5e..29b46ee4 100644 --- a/src/drivers/sifive_ccache0.c +++ b/src/drivers/sifive_ccache0.c @@ -1,4 +1,4 @@ -/* Copyright 2019 SiFive, Inc */ +/* Copyright 2020 SiFive, Inc */ /* SPDX-License-Identifier: Apache-2.0 */ #include @@ -7,80 +7,298 @@ #include #include -#include #include #include -#define L2_CONFIG_WAYS_SHIFT 8 -#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT) +/* Macros to access memory mapped registers */ +#define REGW(x) *(volatile uint32_t *)(METAL_SIFIVE_CCACHE0_0_BASE_ADDRESS + x) -void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways); +#define REGD(x) *(volatile uint64_t *)(METAL_SIFIVE_CCACHE0_0_BASE_ADDRESS + x) -METAL_CONSTRUCTOR(metal_driver_sifive_ccache0_init) { -#ifdef __METAL_DT_SIFIVE_CCACHE0_HANDLE - /* Get the handle for the L2 cache controller */ - struct metal_cache *l2 = __METAL_DT_SIFIVE_CCACHE0_HANDLE; - if (!l2) { - return; +/* Macros to specify register bit shift */ +#define REG_SHIFT_4 4 +#define REG_SHIFT_8 8 +#define REG_SHIFT_16 16 +#define REG_SHIFT_24 24 + +/* Masks to get cache configuration data */ +#define SIFIVE_CCACHE0_CONFIG_BANKS_MASK 0x000000FFUL +#define SIFIVE_CCACHE0_CONFIG_WAYS_MASK 0x0000FF00UL +#define SIFIVE_CCACHE0_CONFIG_SETS_MASK 0x00FF0000UL +#define SIFIVE_CCACHE0_CONFIG_BLOCKS_MASK 0xFF000000UL + +#define SIFIVE_CCACHE0_WAY_ENABLE_MASK 0x000000FFUL + +static int sifive_ccache0_interrupts[] = METAL_SIFIVE_CCACHE0_INTERRUPTS; + +/* Initialize cache at start-up via metal constructors */ +METAL_CONSTRUCTOR(_sifive_ccache0_init) { sifive_ccache0_init(); } + +int sifive_ccache0_init(void) { + int ret; + + sifive_ccache0_config config; + + /* Get cache configuration data */ + sifive_ccache0_get_config(&config); + + /* Enable ways */ + ret = sifive_ccache0_set_enabled_ways(config.num_ways); + + return ret; +} + +void sifive_ccache0_get_config(sifive_ccache0_config *config) { + uint32_t val; + + if (config) /* Check for NULL */ + { + val = REGW(METAL_SIFIVE_CCACHE0_CONFIG); + + /* Populate cache configuration data */ + config->num_bank = (val & SIFIVE_CCACHE0_CONFIG_BANKS_MASK); + config->num_ways = + (val & SIFIVE_CCACHE0_CONFIG_WAYS_MASK) >> REG_SHIFT_8; + config->num_sets = + 2 ^ ((val & SIFIVE_CCACHE0_CONFIG_SETS_MASK) >> REG_SHIFT_16); + config->block_size = + 2 ^ ((val & SIFIVE_CCACHE0_CONFIG_BLOCKS_MASK) >> REG_SHIFT_24); + } +} + +uint32_t sifive_ccache0_get_enabled_ways(void) { + + uint32_t val = 0; + + val = SIFIVE_CCACHE0_WAY_ENABLE_MASK & REGW(METAL_SIFIVE_CCACHE0_WAYENABLE); + + /* The stored number is the way index, so increment by 1 */ + val++; + + return val; +} + +int sifive_ccache0_set_enabled_ways(uint32_t ways) { + + int ret = 0; + + /* We can't decrease the number of enabled ways */ + if (sifive_ccache0_get_enabled_ways() > ways) { + ret = -1; + } else { + /* The stored value is the index, so subtract one */ + uint32_t value = 0xFF & (ways - 1); + + /* Set the number of enabled ways */ + REGW(METAL_SIFIVE_CCACHE0_WAYENABLE) = value; + + /* Make sure the number of ways was set correctly */ + if (sifive_ccache0_get_enabled_ways() != ways) { + ret = -2; + } } - /* Get the number of available ways per bank */ - unsigned long control_base = __metal_driver_sifive_ccache0_control_base(l2); - uint32_t ways = __METAL_ACCESS_ONCE( - (__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_CONFIG)); - ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT); + return ret; +} - /* Enable all the ways */ - __metal_driver_sifive_ccache0_init(l2, ways); +void sifive_ccache0_inject_ecc_error(uint32_t bitindex, + sifive_ccache0_ecc_errtype_t type) { + /* Induce ECC error at given bit index and location */ + REGW(METAL_SIFIVE_CCACHE0_ECCINJECTERROR) = + (uint32_t)(((type & 0x01) << REG_SHIFT_16) | (bitindex & 0xFF)); +} + +void sifive_ccache0_flush(uintptr_t flush_addr) { + /* Block memory access until operation completed */ + __asm volatile("fence rw, io" : : : "memory"); + +#if __riscv_xlen == 32 + REGW(METAL_SIFIVE_CCACHE0_FLUSH32) = flush_addr >> REG_SHIFT_4; +#else + REGD(METAL_SIFIVE_CCACHE0_FLUSH64) = flush_addr; #endif + + __asm volatile("fence io, rw" : : : "memory"); } -void __metal_driver_sifive_ccache0_init(struct metal_cache *l2, int ways) { - metal_cache_set_enabled_ways(l2, ways); +uintptr_t sifive_ccache0_get_ecc_fix_addr(sifive_ccache0_ecc_errtype_t type) { + uintptr_t addr = 0; + + switch (type) { + /* Get most recently ECC corrected address */ + case SIFIVE_CCACHE0_DATA: + addr = (uintptr_t)REGD(METAL_SIFIVE_CCACHE0_DATECCFIXLOW); + break; + + case SIFIVE_CCACHE0_DIR: + addr = (uintptr_t)REGD(METAL_SIFIVE_CCACHE0_DIRECCFIXLOW); + break; + } + + return addr; } -int __metal_driver_sifive_ccache0_get_enabled_ways(struct metal_cache *cache) { - unsigned long control_base = - __metal_driver_sifive_ccache0_control_base(cache); +uint32_t sifive_ccache0_get_ecc_fix_count(sifive_ccache0_ecc_errtype_t type) { + uint32_t count = 0; - uint32_t way_enable = __METAL_ACCESS_ONCE( - (__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)); + switch (type) { + /* Get number of times ECC errors were corrected */ + case SIFIVE_CCACHE0_DATA: + count = REGW(METAL_SIFIVE_CCACHE0_DATECCFIXCOUNT); + break; - /* The stored number is the index, so add one */ - return (0xFF & way_enable) + 1; + case SIFIVE_CCACHE0_DIR: + count = REGW(METAL_SIFIVE_CCACHE0_DIRECCFIXCOUNT); + break; + } + + return count; } -int __metal_driver_sifive_ccache0_set_enabled_ways(struct metal_cache *cache, - int ways) { - unsigned long control_base = - __metal_driver_sifive_ccache0_control_base(cache); +uintptr_t sifive_ccache0_get_ecc_fail_addr(sifive_ccache0_ecc_errtype_t type) { + uintptr_t addr = 0; - /* We can't decrease the number of enabled ways */ - if (metal_cache_get_enabled_ways(cache) > ways) { - return -2; + switch (type) { + /* Get address location of most recent uncorrected ECC error */ + case SIFIVE_CCACHE0_DATA: + addr = (uintptr_t)REGD(METAL_SIFIVE_CCACHE0_DATECCFAILLOW); + break; + + case SIFIVE_CCACHE0_DIR: + addr = (uintptr_t)REGD(METAL_SIFIVE_CCACHE0_DIRECCFAILLOW); + break; } - /* The stored value is the index, so subtract one */ - uint32_t value = 0xFF & (ways - 1); + return addr; +} + +uint32_t sifive_ccache0_get_ecc_fail_count(sifive_ccache0_ecc_errtype_t type) { + uint32_t count = 0; - /* Set the number of enabled ways */ - __METAL_ACCESS_ONCE( - (__metal_io_u32 *)(control_base + METAL_SIFIVE_CCACHE0_WAYENABLE)) = - value; + switch (type) { + /* Get number of times ECC errors were not corrected */ + case SIFIVE_CCACHE0_DATA: + count = REGW(METAL_SIFIVE_CCACHE0_DATECCFAILCOUNT); + break; - /* Make sure the number of ways was set correctly */ - if (metal_cache_get_enabled_ways(cache) != ways) { - return -3; + case SIFIVE_CCACHE0_DIR: + count = REGW(METAL_SIFIVE_CCACHE0_DIRECCFAILCOUNT); + break; } + return count; +} + +uint64_t sifive_ccache0_get_way_mask(uint32_t master_id) { + uint64_t val = 0; + + /* Get way mask for given master ID */ + val = REGD(METAL_SIFIVE_CCACHE0_WAYMASK0 + master_id * 8); + + return val; +} + +int sifive_ccache0_set_way_mask(uint32_t master_id, uint64_t waymask) { + + /* Set way mask for given master ID */ + REGD(METAL_SIFIVE_CCACHE0_WAYMASK0 + master_id * 8) = waymask; + return 0; } -__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_ccache0) = { - .cache.init = __metal_driver_sifive_ccache0_init, - .cache.get_enabled_ways = __metal_driver_sifive_ccache0_get_enabled_ways, - .cache.set_enabled_ways = __metal_driver_sifive_ccache0_set_enabled_ways, -}; +void sifive_ccache0_set_pmevent_selector(uint32_t counter, uint64_t mask) { + +#if METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS > 0 + if (counter < METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS) { + + /* Set event selector for specified L2 event counter */ + REGD(METAL_SIFIVE_CCACHE0_PMEVENTSELECT0 + counter * 8) = mask; + } +#endif + return; +} + +uint64_t sifive_ccache0_get_pmevent_selector(uint32_t counter) { + uint64_t val = 0; + +#if METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS > 0 + if (counter < METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS) { + + /* Get event selector for specified L2 event counter */ + val = REGD(METAL_SIFIVE_CCACHE0_PMEVENTSELECT0 + counter * 8); + } +#endif + return val; +} + +void sifive_ccache0_clr_pmevent_counter(uint32_t counter) { + +#if METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS > 0 + if (counter < METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS) { + /* Clear specified L2 event counter */ + REGD(METAL_SIFIVE_CCACHE0_PMEVENTCOUNTER0 + counter * 8) = 0; + } +#endif + return; +} + +uint64_t sifive_ccache0_get_pmevent_counter(uint32_t counter) { +#if __riscv_xlen == 32 + uint32_t vh = 0, vh1 = 0, vl = 0; +#else + uint64_t val = 0; +#endif +#if METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS > 0 + if (counter < METAL_SIFIVE_CCACHE0_PERFMON_COUNTERS) { + /* Set counter register offset */ + counter *= 8; + +#if __riscv_xlen == 32 + do { + vh = REGW(METAL_SIFIVE_CCACHE0_PMEVENTCOUNTER0 + counter + 4); + vl = REGW(METAL_SIFIVE_CCACHE0_PMEVENTCOUNTER0 + counter); + vh1 = REGW(METAL_SIFIVE_CCACHE0_PMEVENTCOUNTER0 + counter + 4); + } while (vh != vh1); +#else + val = REGD(METAL_SIFIVE_CCACHE0_PMEVENTCOUNTER0 + counter); +#endif + } +#endif +#if __riscv_xlen == 32 + return ((((unsigned long long)vh) << 32) | vl); +#else + return val; +#endif +} + +void sifive_ccache0_set_client_filter(uint64_t mask) { + + /* Set clients to be excluded from performance monitoring */ + REGD(METAL_SIFIVE_CCACHE0_PMCLIENTFILTER) = mask; +} + +uint64_t sifive_ccache0_get_client_filter(void) { + uint64_t val = 0; + + /* Get currently active client filter mask */ + val = REGD(METAL_SIFIVE_CCACHE0_PMCLIENTFILTER); + + return val; +} + +int sifive_ccache0_get_interrupt_id(uint32_t src) { + int ret = 0; + + if (src < (uint32_t)sizeof(sifive_ccache0_interrupts) / sizeof(int)) { + ret = sifive_ccache0_interrupts[src]; + } + + return ret; +} + +struct metal_interrupt *sifive_ccache0_interrupt_controller(void) { + return METAL_SIFIVE_CCACHE0_INTERRUPT_PARENT; +} #endif diff --git a/src/drivers/sifive_fu540-c000_l2.c b/src/drivers/sifive_fu540-c000_l2.c deleted file mode 100644 index 1227ac83..00000000 --- a/src/drivers/sifive_fu540-c000_l2.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright 2018 SiFive, Inc */ -/* SPDX-License-Identifier: Apache-2.0 */ - -#include - -#ifdef METAL_SIFIVE_FU540_C000_L2 - -#include -#include -#include -#include -#include - -#define L2_CONFIG_WAYS_SHIFT 8 -#define L2_CONFIG_WAYS_MASK (0xFF << L2_CONFIG_WAYS_SHIFT) - -void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, int ways); - -METAL_CONSTRUCTOR(metal_driver_sifive_fu540_c000_l2_init) { -#ifdef __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE - /* Get the handle for the L2 cache controller */ - struct metal_cache *l2 = __METAL_DT_SIFIVE_FU540_C000_L2_HANDLE; - if (!l2) { - return; - } - - /* Get the number of available ways per bank */ - unsigned long control_base = - __metal_driver_sifive_fu540_c000_l2_control_base(l2); - uint32_t ways = __METAL_ACCESS_ONCE( - (__metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_CONFIG)); - ways = ((ways & L2_CONFIG_WAYS_MASK) >> L2_CONFIG_WAYS_SHIFT); - - /* Enable all the ways */ - __metal_driver_sifive_fu540_c000_l2_init(l2, ways); -#endif -} - -void __metal_driver_sifive_fu540_c000_l2_init(struct metal_cache *l2, - int ways) { - metal_cache_set_enabled_ways(l2, ways); -} - -int __metal_driver_sifive_fu540_c000_l2_get_enabled_ways( - struct metal_cache *cache) { - unsigned long control_base = - __metal_driver_sifive_fu540_c000_l2_control_base(cache); - - uint32_t way_enable = __METAL_ACCESS_ONCE(( - __metal_io_u32 *)(control_base + METAL_SIFIVE_FU540_C000_L2_WAYENABLE)); - - /* The stored number is the index, so add one */ - return (0xFF & way_enable) + 1; -} - -int __metal_driver_sifive_fu540_c000_l2_set_enabled_ways( - struct metal_cache *cache, int ways) { - unsigned long control_base = - __metal_driver_sifive_fu540_c000_l2_control_base(cache); - - /* We can't decrease the number of enabled ways */ - if (metal_cache_get_enabled_ways(cache) > ways) { - return -2; - } - - /* The stored value is the index, so subtract one */ - uint32_t value = 0xFF & (ways - 1); - - /* Set the number of enabled ways */ - __METAL_ACCESS_ONCE( - (__metal_io_u32 *)(control_base + - METAL_SIFIVE_FU540_C000_L2_WAYENABLE)) = value; - - /* Make sure the number of ways was set correctly */ - if (metal_cache_get_enabled_ways(cache) != ways) { - return -3; - } - - return 0; -} - -__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_fu540_c000_l2) = { - .cache.init = __metal_driver_sifive_fu540_c000_l2_init, - .cache.get_enabled_ways = - __metal_driver_sifive_fu540_c000_l2_get_enabled_ways, - .cache.set_enabled_ways = - __metal_driver_sifive_fu540_c000_l2_set_enabled_ways, -}; - -#endif - -typedef int no_empty_translation_units; diff --git a/src/drivers/sifive_l2pf0.c b/src/drivers/sifive_l2pf0.c new file mode 100644 index 00000000..63690fa3 --- /dev/null +++ b/src/drivers/sifive_l2pf0.c @@ -0,0 +1,164 @@ +/* Copyright 2020 SiFive, Inc */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include + +#ifdef METAL_SIFIVE_L2PF0 + +#include +#include + +/* Macros to access memory mapped registers */ +#define REGW(x) \ + *(volatile uint32_t *)(METAL_SIFIVE_L2PF0_0_BASE_ADDRESS + \ + hartid * 0x2000 + x) + +/* Macros for register bit masks */ +#define REG_MASK_BITWIDTH1 0x01 +#define REG_MASK_BITWIDTH4 0x0F +#define REG_MASK_BITWIDTH5 0x1F +#define REG_MASK_BITWIDTH6 0x3F +#define REG_MASK_BITWIDTH7 0x7F + +/* Macros to specify register bit shift */ +#define REG_BITSHIFT_1 1 +#define REG_BITSHIFT_2 2 +#define REG_BITSHIFT_4 4 +#define REG_BITSHIFT_8 8 +#define REG_BITSHIFT_9 9 +#define REG_BITSHIFT_13 13 +#define REG_BITSHIFT_14 14 +#define REG_BITSHIFT_20 20 +#define REG_BITSHIFT_21 21 +#define REG_BITSHIFT_28 28 + +/* Macros to capture trap, if L2PF does not exist for a hart id. */ +#define SIFIVE_L2PF0_TRAP_CAPTURE(exit, mtvec) \ + __asm__ __volatile__("la %0, 1f \n\t" \ + "csrr %1, mtvec \n\t" \ + "csrw mtvec, %0 \n\t" \ + : "+r"(exit), "+r"(mtvec)) + +#define SIFIVE_L2PF0_TRAP_RESTORE(mtvec) \ + __asm__ __volatile__(".align 2 \n\t" \ + "1: \n\t" \ + "csrw mtvec, %0 \n\t" \ + : "+r"(mtvec)) + +void sifive_l2pf0_enable(void) { + volatile uintptr_t exit = 0, mtvec = 0; + int hartid; + __asm__ volatile("csrr %0, mhartid" : "=r"(hartid)); + + SIFIVE_L2PF0_TRAP_CAPTURE(exit, mtvec); + + uint32_t val = REGW(METAL_SIFIVE_L2PF0_BASIC_CONTROL); + + /* Enable L2 prefetch unit for current hart */ + val |= REG_MASK_BITWIDTH1; + + REGW(METAL_SIFIVE_L2PF0_BASIC_CONTROL) = val; + + SIFIVE_L2PF0_TRAP_RESTORE(mtvec); +} + +void sifive_l2pf0_disable(void) { + volatile uintptr_t exit = 0, mtvec = 0; + int hartid; + __asm__ volatile("csrr %0, mhartid" : "=r"(hartid)); + + SIFIVE_L2PF0_TRAP_CAPTURE(exit, mtvec); + + uint32_t val = REGW(METAL_SIFIVE_L2PF0_BASIC_CONTROL); + + /* Disable L2 prefetch unit for current hart */ + val &= ~REG_MASK_BITWIDTH1; + + REGW(METAL_SIFIVE_L2PF0_BASIC_CONTROL) = val; + + SIFIVE_L2PF0_TRAP_RESTORE(mtvec); +} + +void sifive_l2pf0_get_config(sifive_l2pf0_config *config) { + volatile uintptr_t exit = 0, mtvec = 0; + int hartid; + __asm__ volatile("csrr %0, mhartid" : "=r"(hartid)); + uint32_t val; + + SIFIVE_L2PF0_TRAP_CAPTURE(exit, mtvec); + + if (config) /* Check for NULL */ + { + /* Get currently active L2 prefetch configuration values */ + val = REGW(METAL_SIFIVE_L2PF0_BASIC_CONTROL); + + config->HwPrefetchEnable = (val & REG_MASK_BITWIDTH1); + config->CrossPageOptmDisable = + ((val >> REG_BITSHIFT_1) & REG_MASK_BITWIDTH1); + config->PrefetchDistance = + ((val >> REG_BITSHIFT_2) & REG_MASK_BITWIDTH6); + config->MaxAllowedDistance = + ((val >> REG_BITSHIFT_8) & REG_MASK_BITWIDTH6); + config->LinToExpThreshold = + ((val >> REG_BITSHIFT_14) & REG_MASK_BITWIDTH6); + config->AgeOutEn = ((val >> REG_BITSHIFT_20) & REG_MASK_BITWIDTH1); + config->NumLdsToAgeOut = + ((val >> REG_BITSHIFT_21) & REG_MASK_BITWIDTH7); + config->CrossPageEn = ((val >> REG_BITSHIFT_28) & REG_MASK_BITWIDTH1); + + val = REGW(METAL_SIFIVE_L2PF0_USER_CONTROL); + + config->QFullnessThreshold = (val & REG_MASK_BITWIDTH4); + config->HitCacheThreshold = + ((val >> REG_BITSHIFT_4) & REG_MASK_BITWIDTH5); + config->hitMSHRThreshold = + ((val >> REG_BITSHIFT_9) & REG_MASK_BITWIDTH4); + config->Window = ((val >> REG_BITSHIFT_13) & REG_MASK_BITWIDTH6); + } + SIFIVE_L2PF0_TRAP_RESTORE(mtvec); +} + +void sifive_l2pf0_set_config(sifive_l2pf0_config *config) { + volatile uintptr_t exit = 0, mtvec = 0; + int hartid; + __asm__ volatile("csrr %0, mhartid" : "=r"(hartid)); + uint32_t val; + + SIFIVE_L2PF0_TRAP_CAPTURE(exit, mtvec); + + if (config) /* Check for NULL */ + { + /* Get values from configuration to write into register */ + val = (uint32_t)( + (config->HwPrefetchEnable & REG_MASK_BITWIDTH1) | + ((config->CrossPageOptmDisable & REG_MASK_BITWIDTH1) + << REG_BITSHIFT_1) | + ((config->PrefetchDistance & REG_MASK_BITWIDTH6) + << REG_BITSHIFT_2) | + ((config->MaxAllowedDistance & REG_MASK_BITWIDTH6) + << REG_BITSHIFT_8) | + ((config->LinToExpThreshold & REG_MASK_BITWIDTH6) + << REG_BITSHIFT_14) | + ((config->AgeOutEn & REG_MASK_BITWIDTH1) << REG_BITSHIFT_20) | + ((config->NumLdsToAgeOut & REG_MASK_BITWIDTH7) << REG_BITSHIFT_21) | + ((config->CrossPageEn & REG_MASK_BITWIDTH1) << REG_BITSHIFT_28)); + + /* Set user specified L2 prefetch configuration values */ + REGW(METAL_SIFIVE_L2PF0_BASIC_CONTROL) = val; + + val = (uint32_t)( + (config->QFullnessThreshold & REG_MASK_BITWIDTH4) | + ((config->HitCacheThreshold & REG_MASK_BITWIDTH5) + << REG_BITSHIFT_4) | + ((config->hitMSHRThreshold & REG_MASK_BITWIDTH4) + << REG_BITSHIFT_9) | + ((config->Window & REG_MASK_BITWIDTH6) << REG_BITSHIFT_13)); + + REGW(METAL_SIFIVE_L2PF0_USER_CONTROL) = val; + } + SIFIVE_L2PF0_TRAP_RESTORE(mtvec); +} + +#endif + +typedef int no_empty_translation_units;