root/arch/riscv/mm/sifive_l2_cache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. l2_write
  2. setup_sifive_debug
  3. l2_config_read
  4. register_sifive_l2_error_notifier
  5. unregister_sifive_l2_error_notifier
  6. l2_int_handler
  7. sifive_l2_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * SiFive L2 cache controller Driver
   4  *
   5  * Copyright (C) 2018-2019 SiFive, Inc.
   6  *
   7  */
   8 #include <linux/debugfs.h>
   9 #include <linux/interrupt.h>
  10 #include <linux/of_irq.h>
  11 #include <linux/of_address.h>
  12 #include <asm/sifive_l2_cache.h>
  13 
  14 #define SIFIVE_L2_DIRECCFIX_LOW 0x100
  15 #define SIFIVE_L2_DIRECCFIX_HIGH 0x104
  16 #define SIFIVE_L2_DIRECCFIX_COUNT 0x108
  17 
  18 #define SIFIVE_L2_DATECCFIX_LOW 0x140
  19 #define SIFIVE_L2_DATECCFIX_HIGH 0x144
  20 #define SIFIVE_L2_DATECCFIX_COUNT 0x148
  21 
  22 #define SIFIVE_L2_DATECCFAIL_LOW 0x160
  23 #define SIFIVE_L2_DATECCFAIL_HIGH 0x164
  24 #define SIFIVE_L2_DATECCFAIL_COUNT 0x168
  25 
  26 #define SIFIVE_L2_CONFIG 0x00
  27 #define SIFIVE_L2_WAYENABLE 0x08
  28 #define SIFIVE_L2_ECCINJECTERR 0x40
  29 
  30 #define SIFIVE_L2_MAX_ECCINTR 3
  31 
  32 static void __iomem *l2_base;
  33 static int g_irq[SIFIVE_L2_MAX_ECCINTR];
  34 
  35 enum {
  36         DIR_CORR = 0,
  37         DATA_CORR,
  38         DATA_UNCORR,
  39 };
  40 
  41 #ifdef CONFIG_DEBUG_FS
  42 static struct dentry *sifive_test;
  43 
  44 static ssize_t l2_write(struct file *file, const char __user *data,
  45                         size_t count, loff_t *ppos)
  46 {
  47         unsigned int val;
  48 
  49         if (kstrtouint_from_user(data, count, 0, &val))
  50                 return -EINVAL;
  51         if ((val >= 0 && val < 0xFF) || (val >= 0x10000 && val < 0x100FF))
  52                 writel(val, l2_base + SIFIVE_L2_ECCINJECTERR);
  53         else
  54                 return -EINVAL;
  55         return count;
  56 }
  57 
  58 static const struct file_operations l2_fops = {
  59         .owner = THIS_MODULE,
  60         .open = simple_open,
  61         .write = l2_write
  62 };
  63 
  64 static void setup_sifive_debug(void)
  65 {
  66         sifive_test = debugfs_create_dir("sifive_l2_cache", NULL);
  67 
  68         debugfs_create_file("sifive_debug_inject_error", 0200,
  69                             sifive_test, NULL, &l2_fops);
  70 }
  71 #endif
  72 
  73 static void l2_config_read(void)
  74 {
  75         u32 regval, val;
  76 
  77         regval = readl(l2_base + SIFIVE_L2_CONFIG);
  78         val = regval & 0xFF;
  79         pr_info("L2CACHE: No. of Banks in the cache: %d\n", val);
  80         val = (regval & 0xFF00) >> 8;
  81         pr_info("L2CACHE: No. of ways per bank: %d\n", val);
  82         val = (regval & 0xFF0000) >> 16;
  83         pr_info("L2CACHE: Sets per bank: %llu\n", (uint64_t)1 << val);
  84         val = (regval & 0xFF000000) >> 24;
  85         pr_info("L2CACHE: Bytes per cache block: %llu\n", (uint64_t)1 << val);
  86 
  87         regval = readl(l2_base + SIFIVE_L2_WAYENABLE);
  88         pr_info("L2CACHE: Index of the largest way enabled: %d\n", regval);
  89 }
  90 
  91 static const struct of_device_id sifive_l2_ids[] = {
  92         { .compatible = "sifive,fu540-c000-ccache" },
  93         { /* end of table */ },
  94 };
  95 
  96 static ATOMIC_NOTIFIER_HEAD(l2_err_chain);
  97 
  98 int register_sifive_l2_error_notifier(struct notifier_block *nb)
  99 {
 100         return atomic_notifier_chain_register(&l2_err_chain, nb);
 101 }
 102 EXPORT_SYMBOL_GPL(register_sifive_l2_error_notifier);
 103 
 104 int unregister_sifive_l2_error_notifier(struct notifier_block *nb)
 105 {
 106         return atomic_notifier_chain_unregister(&l2_err_chain, nb);
 107 }
 108 EXPORT_SYMBOL_GPL(unregister_sifive_l2_error_notifier);
 109 
 110 static irqreturn_t l2_int_handler(int irq, void *device)
 111 {
 112         unsigned int add_h, add_l;
 113 
 114         if (irq == g_irq[DIR_CORR]) {
 115                 add_h = readl(l2_base + SIFIVE_L2_DIRECCFIX_HIGH);
 116                 add_l = readl(l2_base + SIFIVE_L2_DIRECCFIX_LOW);
 117                 pr_err("L2CACHE: DirError @ 0x%08X.%08X\n", add_h, add_l);
 118                 /* Reading this register clears the DirError interrupt sig */
 119                 readl(l2_base + SIFIVE_L2_DIRECCFIX_COUNT);
 120                 atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
 121                                            "DirECCFix");
 122         }
 123         if (irq == g_irq[DATA_CORR]) {
 124                 add_h = readl(l2_base + SIFIVE_L2_DATECCFIX_HIGH);
 125                 add_l = readl(l2_base + SIFIVE_L2_DATECCFIX_LOW);
 126                 pr_err("L2CACHE: DataError @ 0x%08X.%08X\n", add_h, add_l);
 127                 /* Reading this register clears the DataError interrupt sig */
 128                 readl(l2_base + SIFIVE_L2_DATECCFIX_COUNT);
 129                 atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_CE,
 130                                            "DatECCFix");
 131         }
 132         if (irq == g_irq[DATA_UNCORR]) {
 133                 add_h = readl(l2_base + SIFIVE_L2_DATECCFAIL_HIGH);
 134                 add_l = readl(l2_base + SIFIVE_L2_DATECCFAIL_LOW);
 135                 pr_err("L2CACHE: DataFail @ 0x%08X.%08X\n", add_h, add_l);
 136                 /* Reading this register clears the DataFail interrupt sig */
 137                 readl(l2_base + SIFIVE_L2_DATECCFAIL_COUNT);
 138                 atomic_notifier_call_chain(&l2_err_chain, SIFIVE_L2_ERR_TYPE_UE,
 139                                            "DatECCFail");
 140         }
 141 
 142         return IRQ_HANDLED;
 143 }
 144 
 145 static int __init sifive_l2_init(void)
 146 {
 147         struct device_node *np;
 148         struct resource res;
 149         int i, rc;
 150 
 151         np = of_find_matching_node(NULL, sifive_l2_ids);
 152         if (!np)
 153                 return -ENODEV;
 154 
 155         if (of_address_to_resource(np, 0, &res))
 156                 return -ENODEV;
 157 
 158         l2_base = ioremap(res.start, resource_size(&res));
 159         if (!l2_base)
 160                 return -ENOMEM;
 161 
 162         for (i = 0; i < SIFIVE_L2_MAX_ECCINTR; i++) {
 163                 g_irq[i] = irq_of_parse_and_map(np, i);
 164                 rc = request_irq(g_irq[i], l2_int_handler, 0, "l2_ecc", NULL);
 165                 if (rc) {
 166                         pr_err("L2CACHE: Could not request IRQ %d\n", g_irq[i]);
 167                         return rc;
 168                 }
 169         }
 170 
 171         l2_config_read();
 172 
 173 #ifdef CONFIG_DEBUG_FS
 174         setup_sifive_debug();
 175 #endif
 176         return 0;
 177 }
 178 device_initcall(sifive_l2_init);

/* [<][>][^][v][top][bottom][index][help] */