| #ifndef _METAG_L2CACHE_H |
| #define _METAG_L2CACHE_H |
| |
| #ifdef CONFIG_METAG_L2C |
| |
| #include <asm/global_lock.h> |
| #include <asm/io.h> |
| |
| /* |
| * Store the last known value of pfenable (we don't want prefetch enabled while |
| * L2 is off). |
| */ |
| extern int l2c_pfenable; |
| |
| /* defined in arch/metag/drivers/core-sysfs.c */ |
| extern struct sysdev_class cache_sysclass; |
| |
| static inline void wr_fence(void); |
| |
| /* |
| * Functions for reading of L2 cache configuration. |
| */ |
| |
| /* Get raw L2 config register (CORE_CONFIG3) */ |
| static inline unsigned int meta_l2c_config(void) |
| { |
| const unsigned int *corecfg3 = (const unsigned int *)METAC_CORE_CONFIG3; |
| return *corecfg3; |
| } |
| |
| /* Get whether the L2 is present */ |
| static inline int meta_l2c_is_present(void) |
| { |
| return meta_l2c_config() & METAC_CORECFG3_L2C_HAVE_L2C_BIT; |
| } |
| |
| /* Get whether the L2 is configured for write-back instead of write-through */ |
| static inline int meta_l2c_is_writeback(void) |
| { |
| return meta_l2c_config() & METAC_CORECFG3_L2C_MODE_BIT; |
| } |
| |
| /* Get whether the L2 is unified instead of separated code/data */ |
| static inline int meta_l2c_is_unified(void) |
| { |
| return meta_l2c_config() & METAC_CORECFG3_L2C_UNIFIED_BIT; |
| } |
| |
| /* Get the L2 cache size in bytes */ |
| static inline unsigned int meta_l2c_size(void) |
| { |
| unsigned int size_s; |
| if (!meta_l2c_is_present()) |
| return 0; |
| size_s = (meta_l2c_config() & METAC_CORECFG3_L2C_SIZE_BITS) |
| >> METAC_CORECFG3_L2C_SIZE_S; |
| /* L2CSIZE is in KiB */ |
| return 1024 << size_s; |
| } |
| |
| /* Get the number of ways in the L2 cache */ |
| static inline unsigned int meta_l2c_ways(void) |
| { |
| unsigned int ways_s; |
| if (!meta_l2c_is_present()) |
| return 0; |
| ways_s = (meta_l2c_config() & METAC_CORECFG3_L2C_NUM_WAYS_BITS) |
| >> METAC_CORECFG3_L2C_NUM_WAYS_S; |
| return 0x1 << ways_s; |
| } |
| |
| /* Get the line size of the L2 cache */ |
| static inline unsigned int meta_l2c_linesize(void) |
| { |
| unsigned int line_size; |
| if (!meta_l2c_is_present()) |
| return 0; |
| line_size = (meta_l2c_config() & METAC_CORECFG3_L2C_LINE_SIZE_BITS) |
| >> METAC_CORECFG3_L2C_LINE_SIZE_S; |
| switch (line_size) { |
| case METAC_CORECFG3_L2C_LINE_SIZE_64B: |
| return 64; |
| default: |
| return 0; |
| } |
| } |
| |
| /* Get the revision ID of the L2 cache */ |
| static inline unsigned int meta_l2c_revision(void) |
| { |
| return (meta_l2c_config() & METAC_CORECFG3_L2C_REV_ID_BITS) |
| >> METAC_CORECFG3_L2C_REV_ID_S; |
| } |
| |
| |
| /* |
| * Start an initialisation of the L2 cachelines and wait for completion. |
| * This should only be done in a LOCK1 or LOCK2 critical section while the L2 |
| * is disabled. |
| */ |
| static inline void _meta_l2c_init(void) |
| { |
| metag_out32(SYSC_L2C_INIT_INIT, SYSC_L2C_INIT); |
| while (metag_in32(SYSC_L2C_INIT) == SYSC_L2C_INIT_IN_PROGRESS) |
| /* do nothing */; |
| } |
| |
| /* |
| * Start a writeback of dirty L2 cachelines and wait for completion. |
| * This should only be done in a LOCK1 or LOCK2 critical section. |
| */ |
| static inline void _meta_l2c_purge(void) |
| { |
| metag_out32(SYSC_L2C_PURGE_PURGE, SYSC_L2C_PURGE); |
| while (metag_in32(SYSC_L2C_PURGE) == SYSC_L2C_PURGE_IN_PROGRESS) |
| /* do nothing */; |
| } |
| |
| /* Set whether the L2 cache is enabled. */ |
| static inline void _meta_l2c_enable(int enabled) |
| { |
| unsigned int enable; |
| |
| enable = metag_in32(SYSC_L2C_ENABLE); |
| if (enabled) |
| enable |= SYSC_L2C_ENABLE_ENABLE_BIT; |
| else |
| enable &= ~SYSC_L2C_ENABLE_ENABLE_BIT; |
| metag_out32(enable, SYSC_L2C_ENABLE); |
| } |
| |
| /* Set whether the L2 cache prefetch is enabled. */ |
| static inline void _meta_l2c_pf_enable(int pfenabled) |
| { |
| unsigned int enable; |
| |
| enable = metag_in32(SYSC_L2C_ENABLE); |
| if (pfenabled) |
| enable |= SYSC_L2C_ENABLE_PFENABLE_BIT; |
| else |
| enable &= ~SYSC_L2C_ENABLE_PFENABLE_BIT; |
| metag_out32(enable, SYSC_L2C_ENABLE); |
| } |
| |
| /* Return whether the L2 cache is enabled */ |
| static inline int _meta_l2c_is_enabled(void) |
| { |
| return metag_in32(SYSC_L2C_ENABLE) & SYSC_L2C_ENABLE_ENABLE_BIT; |
| } |
| |
| /* Return whether the L2 cache prefetch is enabled */ |
| static inline int _meta_l2c_pf_is_enabled(void) |
| { |
| return metag_in32(SYSC_L2C_ENABLE) & SYSC_L2C_ENABLE_PFENABLE_BIT; |
| } |
| |
| |
| /* Return whether the L2 cache is enabled */ |
| static inline int meta_l2c_is_enabled(void) |
| { |
| int en; |
| |
| /* |
| * There is no need to lock at the moment, as the enable bit is never |
| * intermediately changed, so we will never see an intermediate result. |
| */ |
| en = _meta_l2c_is_enabled(); |
| |
| return en; |
| } |
| |
| /* |
| * Ensure the L2 cache is disabled. |
| * Return whether the L2 was previously disabled. |
| */ |
| int meta_l2c_disable(void); |
| |
| /* |
| * Ensure the L2 cache is enabled. |
| * Return whether the L2 was previously enabled. |
| */ |
| int meta_l2c_enable(void); |
| |
| /* Return whether the L2 cache prefetch is enabled */ |
| static inline int meta_l2c_pf_is_enabled(void) |
| { |
| return l2c_pfenable; |
| } |
| |
| /* |
| * Set whether the L2 cache prefetch is enabled. |
| * Return whether the L2 prefetch was previously enabled. |
| */ |
| int meta_l2c_pf_enable(int pfenable); |
| |
| /* |
| * Flush the L2 cache. |
| * Return 1 if the L2 is disabled. |
| */ |
| int meta_l2c_flush(void); |
| |
| /* |
| * Write back all dirty cache lines in the L2 cache. |
| * Return 1 if the L2 is disabled or there isn't any writeback. |
| */ |
| static inline int meta_l2c_writeback(void) |
| { |
| unsigned long flags; |
| int en; |
| |
| /* no need to purge if it's not a writeback cache */ |
| if (!meta_l2c_is_writeback()) |
| return 1; |
| |
| /* |
| * Purge only works if the L2 is enabled, and involves reading back to |
| * detect completion, so keep this operation atomic with other threads. |
| */ |
| __global_lock1(flags); |
| en = meta_l2c_is_enabled(); |
| if (likely(en)) { |
| wr_fence(); |
| _meta_l2c_purge(); |
| } |
| __global_unlock1(flags); |
| |
| return !en; |
| } |
| |
| #else /* CONFIG_METAG_L2C */ |
| |
| #define meta_l2c_config() 0 |
| #define meta_l2c_is_present() 0 |
| #define meta_l2c_is_writeback() 0 |
| #define meta_l2c_is_unified() 0 |
| #define meta_l2c_size() 0 |
| #define meta_l2c_ways() 0 |
| #define meta_l2c_linesize() 0 |
| #define meta_l2c_revision() 0 |
| |
| #define meta_l2c_is_enabled() 0 |
| #define _meta_l2c_pf_is_enabled() 0 |
| #define meta_l2c_pf_is_enabled() 0 |
| #define meta_l2c_disable() 1 |
| #define meta_l2c_enable() 0 |
| #define meta_l2c_pf_enable(X) 0 |
| static inline int meta_l2c_flush(void) |
| { |
| return 1; |
| } |
| static inline int meta_l2c_writeback(void) |
| { |
| return 1; |
| } |
| |
| #endif /* CONFIG_METAG_L2C */ |
| |
| #endif /* _METAG_L2CACHE_H */ |