diff options
Diffstat (limited to 'drivers/test/l2cache/ppc4xx_l2cache_test_module.c')
-rw-r--r-- | drivers/test/l2cache/ppc4xx_l2cache_test_module.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/drivers/test/l2cache/ppc4xx_l2cache_test_module.c b/drivers/test/l2cache/ppc4xx_l2cache_test_module.c new file mode 100644 index 00000000000..71402cd442a --- /dev/null +++ b/drivers/test/l2cache/ppc4xx_l2cache_test_module.c @@ -0,0 +1,389 @@ +/**************************************************************************** + * + * Test driver for the PPC44x L2 Cache core. + * This driver will print out the L2 Cache statistics to the /proc/l2cache + * + * Author: Adam Graham <agraham@amcc.com> + * February 26, 2008 + * + * Copyright 2008 Applied Micro Circuits Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + **************************************************************************** + * + * Beware! The kernel PPC44x L2 Cache must be activated for this test. + * The example should work on any PPC440EX/GT based board, + * maybe also on PPC44x (not yet tested). + * To use this module: + * 1. Build it as a kenel module + * 2. insmod <module> + * cat /proc/l2cache/start to start the l2 cache statistics + * cat /proc/l2cache/stop to stop the l2 cache statistics + * cat /proc/l2cache/stats to read the statistics + * 3. rmmod <module> + * Everything you want to know will be printed out + * + */ + +#include <linux/module.h> /* needed by all modules */ +#include <linux/init.h> /* needed for the module_xxx_macros */ +#include <linux/fs.h> /* needed for registering a device */ +#include <linux/proc_fs.h> /* needed for registering a device */ +//#include "ppc4xx_l2cache_core.h" /* Driver Interface */ +//#include "ppc4xx_l2cache_proc.h" /* ProcFS Interface */ +#include <asm/dcr-regs.h> /* PPC4xx L2 Cache DCR defines */ +#include <asm/dcr.h> +#include <asm/reg.h> + + + + +#define DRV_NAME "ppc4xx_l2cache_test_module" +#define DRV_VERSION "0.1" + +MODULE_DESCRIPTION("PPC4xx L2 Cache test driver"); +MODULE_AUTHOR("agraham@amcc.com"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); + +uint32_t ppc4xx_l2cache_base; /* Set by ioremap function */ + +#define DCR_L2C_BASE 0x30 + +#define PPC4xx_L2CACHE_BASEADDR 0xefxxxxx; + +/* PPC4xx L2 Cache core registers */ +#define PPC4xx_L2CACHE_CONFIG 0x0 +#define PPC4xx_L2CACHE_COMMAND 0x1 +#define PPC4xx_L2CACHE_ADDRESS 0x2 +#define PPC4xx_L2CACHE_DATA 0x3 +#define PPC4xx_L2CACHE_STATUS 0x4 +#define PPC4xx_L2CACHE_CORE_VERSION 0x5 +#define PPC4xx_L2CACHE_SNOOP0 0x6 +#define PPC4xx_L2CACHE_SNOOP1 0x7 + +/* Function Prototypes */ +static void ppc4xx_l2cache_cleanup(void); +static int ppc4xx_l2cache_proc_start(char *, char **, off_t, int, int *, void *); +static int ppc4xx_l2cache_proc_stop(char *, char **, off_t, int, int *, void *); +static int ppc4xx_l2cache_proc_perf(char *, char **, off_t, int, int *, void *); +static int ppc4xx_l2cache_proc_query(char *, char **, off_t, int, int *, void *); +static int ppc4xx_l2cache_proc_regs(char *, char **, off_t, int, int *, void *); +int ppc4xx_l2cache_createProcEntry(void); +void ppc4xx_l2cache_removeProcEntry(void); +static u32 ppc4xx_l2cache_read_reg(u32); +static u32 ppc4xx_l2cache_read_config_reg(void); +static u32 ppc4xx_l2cache_read_status_reg(void); +static u32 ppc4xx_l2cache_diag(u32); + +/* + * Kernel Logging + */ +#define LOG(string, args...) \ + printk(KERN_INFO DRV_NAME ": " string "\n",##args) + +#define ALERT(string, args...) \ + printk(KERN_ALERT DRV_NAME ": " string "\n",##args) + +#define WARNING(string, args...) \ + printk(KERN_WARNING DRV_NAME ": WARNING, " string "\n",##args) + +#define ERR(string, args...) \ + printk(KERN_ALERT DRV_NAME ": ERROR, " string "\n",##args) + +#if defined(CONFIG_PPC4XX_L2CACHE_DEBUG) +#define DBG(string, args...) \DCRN_L2C0_CFG + printk(KERN_INFO DRV_NAME ": " string "\n",##args) +#else +#define DBG(string, args...) do { } while (0) +#endif + +static inline u32 ppc4xx_l2cache_read_reg(u32 l2_reg) +{ + u32 reg; + + //reg = mfdcr(l2_reg); + + return reg; +} + +static inline u32 ppc4xx_l2cache_read_config_reg(void) +{ + u32 reg; + reg = mfdcr(DCR_L2C_BASE + DCRN_L2C0_CFG); + printk("base 0x%08x\n", ppc4xx_l2cache_base); + return reg; +} + +static inline u32 ppc4xx_l2cache_read_status_reg(void) +{ + u32 reg; + reg = mfdcr(DCR_L2C_BASE + DCRN_L2C0_SR); + return reg; +} + +/******************************************************************************* + * Static Variables: + ******************************************************************************/ +static struct proc_dir_entry *proc_driver = NULL; /* /proc/ */ +static struct proc_dir_entry *proc_regs = NULL; /* /proc/driver/l2cache/ */ +static struct proc_dir_entry *proc_start = NULL; /* /proc/driver/l2cache/ */ +static struct proc_dir_entry *proc_stop = NULL; /* /proc/driver/l2cache/ */ +static struct proc_dir_entry *proc_perf = NULL; /* /proc/driver/l2cache/ */ +static struct proc_dir_entry *proc_query = NULL; /* /proc/driver/l2cache/ */ + +/* Issue L2C diagnostic command */ +static inline u32 ppc4xx_l2cache_diag(u32 addr) +{ + asm volatile ("sync" ::: "memory"); + mtdcr(DCR_L2C_BASE + DCRN_L2C0_ADDR, addr); + mtdcr(DCR_L2C_BASE + DCRN_L2C0_CMD, L2C_CMD_DIAG); + + while (!(mfdcr(DCR_L2C_BASE + DCRN_L2C0_SR) & L2C_SR_CC)) { + ; + } + asm volatile ("sync; isync" ::: "memory"); + + return mfdcr(DCR_L2C_BASE + DCRN_L2C0_DATA); +} + +static int ppc4xx_l2cache_proc_start(char *buffer, char **start_off, + off_t offset, int buff_len, int *eof, void *data) +{ + int len = 0; + u32 sr = mfdcr(DCR_L2C_BASE + DCRN_L2C0_SR); + +#if defined(L2_TEST_DEBUG) + len += sprintf(buffer + len, + "PPC4xx L2 Cache Start L2C Performance counter.\n"); +#endif + + if (sr & L2C_SR_PCS) { + /* Start Performance monitor counters */ + mtdcr(DCR_L2C_BASE + DCRN_L2C0_CMD, L2C_CMD_STRC); + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance counter started.\n"); + } else { + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance counter is already started.\n"); + } + + return len; +} + +static int ppc4xx_l2cache_proc_query(char *buffer, char **start_off, + off_t offset, int buff_len, int *eof, void *data) +{ + int len = 0; + u32 sr = mfdcr(DCR_L2C_BASE + DCRN_L2C0_SR); + +#if defined(L2_TEST_DEBUG) + len += sprintf(buffer + len, + "PPC4xx L2 Cache Query L2C Performance monitor.\n"); +#endif + + if (sr & L2C_SR_PCS) { + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance counter is stopped.\n"); + } else { + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance counter is running.\n"); + } + + return len; +} + +static int ppc4xx_l2cache_proc_stop(char *buffer, char **start_off, + off_t offset, int buff_len, int *eof, void *data) +{ + int len = 0; + u32 sr = mfdcr(DCR_L2C_BASE + DCRN_L2C0_SR); + +#if defined(L2_TEST_DEBUG) + len += sprintf(buffer + len, + "PPC4xx L2 Cache Stop L2C Performance counter.\n"); +#endif + + if (sr & L2C_SR_PCS) { + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance counter is already stopped.\n"); + } else { + /* Start Performance monitor counters */ + mtdcr(DCR_L2C_BASE + DCRN_L2C0_CMD, L2C_CMD_STPC); + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance counter stopped.\n"); + } + + return len; +} + +static int ppc4xx_l2cache_proc_perf(char *buffer, char **start_off, + off_t offset, int buff_len, int *eof, void *data) +{ + u32 l2_data; + int len = 0; + u32 sr = mfdcr(DCR_L2C_BASE + DCRN_L2C0_SR); + +#if defined(L2_TEST_DEBUG) + len += sprintf(buffer + len, + "PPC4xx L2 Cache perf L2C read Performance Counter registers.\n"); +#endif + + if (sr & L2C_SR_PCS) { + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance counter is not running.\n"); + } else { + /* read diagnostics stats */ + l2_data = ppc4xx_l2cache_diag(0x22000000); + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance Hit Counter Read 0x%08x\n", l2_data); + + l2_data = ppc4xx_l2cache_diag(0x24000000); + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance Request Counter Read 0x%08x\n", l2_data); + + l2_data = ppc4xx_l2cache_diag(0x28000000); + len += sprintf(buffer + len, + "PPC4xx L2 Cache Performance Cycle Counter Read 0x%08x\n", l2_data); + } + + return len; +} + +static int ppc4xx_l2cache_proc_regs(char *buffer, char **start_off, + off_t offset, int buff_len, int *eof, void *data) +{ + int len = 0; + +#if defined(L2_TEST_DEBUG) + len += sprintf(buffer + len, + "PPC4xx L2 Cache Registers.\n"); +#endif + + len += sprintf(buffer + len, + "PPC4xx L2_CONFIG Register 0x%08x\n", + ppc4xx_l2cache_read_config_reg()); + + len += sprintf(buffer + len, + "PPC4xx L2_STATUS Register 0x%08x\n", + ppc4xx_l2cache_read_status_reg()); + + return len; +} + +int ppc4xx_l2cache_createProcEntry(void) +{ + proc_driver = proc_mkdir("driver/l2cache", NULL); + + + if (proc_driver == NULL) { + ERR("while creating proc directory"); + return -ENOMEM; + } + + proc_regs = create_proc_entry("registers", 0, proc_driver); + + if (proc_regs == NULL) { + ERR("while creating proc register file"); + return -ENOMEM; + }else { + proc_regs->read_proc = ppc4xx_l2cache_proc_regs; + } + + proc_start = create_proc_entry("start", 0, proc_driver); + + + if (proc_start == NULL) { + ERR("while creating proc start file"); + return -ENOMEM; + }else { + proc_start->read_proc = ppc4xx_l2cache_proc_start; + } + + + proc_stop = create_proc_entry("stop", 0, proc_driver); + + if (proc_stop == NULL) { + ERR("while creating proc stop file"); + return -ENOMEM; + }else { + proc_stop->read_proc = ppc4xx_l2cache_proc_stop; + } + + proc_perf = create_proc_entry("performance", 0, proc_driver); + + if (proc_perf == NULL) { + ERR("while creating proc perf file"); + return -ENOMEM; + }else { + proc_perf->read_proc = ppc4xx_l2cache_proc_perf; + } + + proc_query = create_proc_entry("query", 0, proc_driver); + + if (proc_query == NULL) { + ERR("while creating proc query file"); + return -ENOMEM; + }else { + proc_query->read_proc = ppc4xx_l2cache_proc_query; + } + + return 0; +} + +static int __init ppc4xx_l2cache_init_module(void) +{ + int retval = 0; + + LOG("initializing"); + LOG("version %s", DRV_VERSION); + + retval = ppc4xx_l2cache_createProcEntry(); + + if (retval < 0) { + ERR("while registering l2cache test driver."); + } + + return retval; +} + +module_init(ppc4xx_l2cache_init_module); + +static void __exit ppc4xx_l2cache_cleanup_module(void) +{ + LOG("cleaning up"); + + ppc4xx_l2cache_cleanup(); +} + +module_exit(ppc4xx_l2cache_cleanup_module); + +static void +ppc4xx_l2cache_cleanup(void) +{ + ppc4xx_l2cache_removeProcEntry(); +} + +void +ppc4xx_l2cache_removeProcEntry(void) +{ + if (proc_regs) remove_proc_entry("registers", proc_driver); + if (proc_start) remove_proc_entry("start", proc_driver); + if (proc_stop) remove_proc_entry("stop", proc_driver); + if (proc_perf) remove_proc_entry("performance", proc_driver); + if (proc_query) remove_proc_entry("query", proc_driver); + if (proc_driver) remove_proc_entry("l2cache", NULL); +} |