Linux Audio

Check our new training course

Loading...
v6.8
  1/*
  2 * This file is subject to the terms and conditions of the GNU General Public
  3 * License.  See the file "COPYING" in the main directory of this archive
  4 * for more details.
  5 *
  6 * Copyright (C) 2012 Cavium, Inc.
  7 *
  8 * Copyright (C) 2009 Wind River Systems,
  9 *   written by Ralf Baechle <ralf@linux-mips.org>
 10 */
 11#include <linux/module.h>
 12#include <linux/init.h>
 13#include <linux/slab.h>
 14#include <linux/interrupt.h>
 15#include <linux/io.h>
 16#include <linux/edac.h>
 17
 
 18#include "edac_module.h"
 19
 20#include <asm/octeon/cvmx.h>
 21#include <asm/mipsregs.h>
 22
 23extern int register_co_cache_error_notifier(struct notifier_block *nb);
 24extern int unregister_co_cache_error_notifier(struct notifier_block *nb);
 25
 26extern unsigned long long cache_err_dcache[NR_CPUS];
 27
 28struct co_cache_error {
 29	struct notifier_block notifier;
 30	struct edac_device_ctl_info *ed;
 31};
 32
 33/**
 34 * EDAC CPU cache error callback
 35 *
 36 * @event: non-zero if unrecoverable.
 37 */
 38static int  co_cache_error_event(struct notifier_block *this,
 39	unsigned long event, void *ptr)
 40{
 41	struct co_cache_error *p = container_of(this, struct co_cache_error,
 42						notifier);
 43
 44	unsigned int core = cvmx_get_core_num();
 45	unsigned int cpu = smp_processor_id();
 46	u64 icache_err = read_octeon_c0_icacheerr();
 47	u64 dcache_err;
 48
 49	if (event) {
 50		dcache_err = cache_err_dcache[core];
 51		cache_err_dcache[core] = 0;
 52	} else {
 53		dcache_err = read_octeon_c0_dcacheerr();
 54	}
 55
 56	if (icache_err & 1) {
 57		edac_device_printk(p->ed, KERN_ERR,
 58				   "CacheErr (Icache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n",
 59				   (unsigned long long)icache_err, core, cpu,
 60				   read_c0_errorepc());
 61		write_octeon_c0_icacheerr(0);
 62		edac_device_handle_ce(p->ed, cpu, 1, "icache");
 63	}
 64	if (dcache_err & 1) {
 65		edac_device_printk(p->ed, KERN_ERR,
 66				   "CacheErr (Dcache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n",
 67				   (unsigned long long)dcache_err, core, cpu,
 68				   read_c0_errorepc());
 69		if (event)
 70			edac_device_handle_ue(p->ed, cpu, 0, "dcache");
 71		else
 72			edac_device_handle_ce(p->ed, cpu, 0, "dcache");
 73
 74		/* Clear the error indication */
 75		if (OCTEON_IS_OCTEON2())
 76			write_octeon_c0_dcacheerr(1);
 77		else
 78			write_octeon_c0_dcacheerr(0);
 79	}
 80
 81	return NOTIFY_STOP;
 82}
 83
 84static int co_cache_error_probe(struct platform_device *pdev)
 85{
 86	struct co_cache_error *p = devm_kzalloc(&pdev->dev, sizeof(*p),
 87						GFP_KERNEL);
 88	if (!p)
 89		return -ENOMEM;
 90
 91	p->notifier.notifier_call = co_cache_error_event;
 92	platform_set_drvdata(pdev, p);
 93
 94	p->ed = edac_device_alloc_ctl_info(0, "cpu", num_possible_cpus(),
 95					   "cache", 2, 0, NULL, 0,
 96					   edac_device_alloc_index());
 97	if (!p->ed)
 98		goto err;
 99
100	p->ed->dev = &pdev->dev;
101
102	p->ed->dev_name = dev_name(&pdev->dev);
103
104	p->ed->mod_name = "octeon-cpu";
105	p->ed->ctl_name = "cache";
106
107	if (edac_device_add_device(p->ed)) {
108		pr_err("%s: edac_device_add_device() failed\n", __func__);
109		goto err1;
110	}
111
112	register_co_cache_error_notifier(&p->notifier);
113
114	return 0;
115
116err1:
117	edac_device_free_ctl_info(p->ed);
118err:
119	return -ENXIO;
120}
121
122static void co_cache_error_remove(struct platform_device *pdev)
123{
124	struct co_cache_error *p = platform_get_drvdata(pdev);
125
126	unregister_co_cache_error_notifier(&p->notifier);
127	edac_device_del_device(&pdev->dev);
128	edac_device_free_ctl_info(p->ed);
 
129}
130
131static struct platform_driver co_cache_error_driver = {
132	.probe = co_cache_error_probe,
133	.remove_new = co_cache_error_remove,
134	.driver = {
135		   .name = "octeon_pc_edac",
136	}
137};
138module_platform_driver(co_cache_error_driver);
139
140MODULE_LICENSE("GPL");
141MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
v4.6
  1/*
  2 * This file is subject to the terms and conditions of the GNU General Public
  3 * License.  See the file "COPYING" in the main directory of this archive
  4 * for more details.
  5 *
  6 * Copyright (C) 2012 Cavium, Inc.
  7 *
  8 * Copyright (C) 2009 Wind River Systems,
  9 *   written by Ralf Baechle <ralf@linux-mips.org>
 10 */
 11#include <linux/module.h>
 12#include <linux/init.h>
 13#include <linux/slab.h>
 14#include <linux/interrupt.h>
 15#include <linux/io.h>
 16#include <linux/edac.h>
 17
 18#include "edac_core.h"
 19#include "edac_module.h"
 20
 21#include <asm/octeon/cvmx.h>
 22#include <asm/mipsregs.h>
 23
 24extern int register_co_cache_error_notifier(struct notifier_block *nb);
 25extern int unregister_co_cache_error_notifier(struct notifier_block *nb);
 26
 27extern unsigned long long cache_err_dcache[NR_CPUS];
 28
 29struct co_cache_error {
 30	struct notifier_block notifier;
 31	struct edac_device_ctl_info *ed;
 32};
 33
 34/**
 35 * EDAC CPU cache error callback
 36 *
 37 * @event: non-zero if unrecoverable.
 38 */
 39static int  co_cache_error_event(struct notifier_block *this,
 40	unsigned long event, void *ptr)
 41{
 42	struct co_cache_error *p = container_of(this, struct co_cache_error,
 43						notifier);
 44
 45	unsigned int core = cvmx_get_core_num();
 46	unsigned int cpu = smp_processor_id();
 47	u64 icache_err = read_octeon_c0_icacheerr();
 48	u64 dcache_err;
 49
 50	if (event) {
 51		dcache_err = cache_err_dcache[core];
 52		cache_err_dcache[core] = 0;
 53	} else {
 54		dcache_err = read_octeon_c0_dcacheerr();
 55	}
 56
 57	if (icache_err & 1) {
 58		edac_device_printk(p->ed, KERN_ERR,
 59				   "CacheErr (Icache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n",
 60				   (unsigned long long)icache_err, core, cpu,
 61				   read_c0_errorepc());
 62		write_octeon_c0_icacheerr(0);
 63		edac_device_handle_ce(p->ed, cpu, 1, "icache");
 64	}
 65	if (dcache_err & 1) {
 66		edac_device_printk(p->ed, KERN_ERR,
 67				   "CacheErr (Dcache):%llx, core %d/cpu %d, cp0_errorepc == %lx\n",
 68				   (unsigned long long)dcache_err, core, cpu,
 69				   read_c0_errorepc());
 70		if (event)
 71			edac_device_handle_ue(p->ed, cpu, 0, "dcache");
 72		else
 73			edac_device_handle_ce(p->ed, cpu, 0, "dcache");
 74
 75		/* Clear the error indication */
 76		if (OCTEON_IS_OCTEON2())
 77			write_octeon_c0_dcacheerr(1);
 78		else
 79			write_octeon_c0_dcacheerr(0);
 80	}
 81
 82	return NOTIFY_STOP;
 83}
 84
 85static int co_cache_error_probe(struct platform_device *pdev)
 86{
 87	struct co_cache_error *p = devm_kzalloc(&pdev->dev, sizeof(*p),
 88						GFP_KERNEL);
 89	if (!p)
 90		return -ENOMEM;
 91
 92	p->notifier.notifier_call = co_cache_error_event;
 93	platform_set_drvdata(pdev, p);
 94
 95	p->ed = edac_device_alloc_ctl_info(0, "cpu", num_possible_cpus(),
 96					   "cache", 2, 0, NULL, 0,
 97					   edac_device_alloc_index());
 98	if (!p->ed)
 99		goto err;
100
101	p->ed->dev = &pdev->dev;
102
103	p->ed->dev_name = dev_name(&pdev->dev);
104
105	p->ed->mod_name = "octeon-cpu";
106	p->ed->ctl_name = "cache";
107
108	if (edac_device_add_device(p->ed)) {
109		pr_err("%s: edac_device_add_device() failed\n", __func__);
110		goto err1;
111	}
112
113	register_co_cache_error_notifier(&p->notifier);
114
115	return 0;
116
117err1:
118	edac_device_free_ctl_info(p->ed);
119err:
120	return -ENXIO;
121}
122
123static int co_cache_error_remove(struct platform_device *pdev)
124{
125	struct co_cache_error *p = platform_get_drvdata(pdev);
126
127	unregister_co_cache_error_notifier(&p->notifier);
128	edac_device_del_device(&pdev->dev);
129	edac_device_free_ctl_info(p->ed);
130	return 0;
131}
132
133static struct platform_driver co_cache_error_driver = {
134	.probe = co_cache_error_probe,
135	.remove = co_cache_error_remove,
136	.driver = {
137		   .name = "octeon_pc_edac",
138	}
139};
140module_platform_driver(co_cache_error_driver);
141
142MODULE_LICENSE("GPL");
143MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");