blob: 6b300d8285d0a4840207afd98f0ea5f0b8fbe7d0 [file] [log] [blame]
Rajkumar Raghupathyc01decf2013-03-29 17:39:58 +05301/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Stepan Moskovchenko57884842012-06-07 17:35:49 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/interrupt.h>
14#include <linux/io.h>
15#include <linux/irq.h>
16#include <linux/platform_device.h>
17#include <linux/module.h>
18#include <linux/errno.h>
19#include <linux/proc_fs.h>
20#include <linux/cpu.h>
Rajkumar Raghupathyc01decf2013-03-29 17:39:58 +053021#include <mach/usb_trace.h>
22
23DEFINE_TRACE(usb_daytona_invalid_access);
Stepan Moskovchenko57884842012-06-07 17:35:49 -070024
25#define MODULE_NAME "msm_ebi_erp"
26
27#define EBI_ERR_ADDR 0x100
28#define SLV_ERR_APACKET_0 0x108
29#define SLV_ERR_APACKET_1 0x10C
30#define SLV_ERR_CNTL 0x114
31
32#define CNTL_ERR_OCCURRED BIT(4)
33#define CNTL_CLEAR_ERR BIT(8)
34#define CNTL_IRQ_EN BIT(12)
35
36#define AMID_MASK 0xFFFF
37#define ERR_AWRITE BIT(0)
38#define ERR_AOOOWR BIT(1)
39#define ERR_AOOORD BIT(2)
40#define ERR_APTORNS BIT(3)
41#define ERR_ALOCK_SHIFT 6
42#define ERR_ALOCK_MASK 0x3
43#define ERR_ATYPE_SHIFT 8
44#define ERR_ATYPE_MASK 0xF
45#define ERR_ABURST BIT(12)
46#define ERR_ASIZE_SHIFT 13
47#define ERR_ASIZE_MASK 0x7
48#define ERR_ATID_SHIFT 16
49#define ERR_ATID_MASK 0xFF
50#define ERR_ALEN_SHIFT 24
51#define ERR_ALEN_MASK 0xF
52
53#define ERR_CODE_DECODE_ERROR BIT(0)
54#define ERR_CODE_MPU_ERROR BIT(1)
55
56struct msm_ebi_erp_data {
57 void __iomem *base;
58 struct device *dev;
59};
60
61static const char *err_lock_types[4] = {
62 "normal",
63 "exclusive",
64 "locked",
65 "barrier",
66};
67
68static const char *err_sizes[8] = {
69 "byte",
70 "half word",
71 "word",
72 "double word",
73 "reserved_4",
74 "reserved_5",
75 "reserved_6",
76 "reserved_7",
77};
78
79static irqreturn_t msm_ebi_irq(int irq, void *dev_id)
80{
81 struct msm_ebi_erp_data *drvdata = dev_id;
82 void __iomem *base = drvdata->base;
83 unsigned int err_addr, err_apacket0, err_apacket1, err_cntl;
84
85 err_addr = readl_relaxed(base + EBI_ERR_ADDR);
86 err_apacket0 = readl_relaxed(base + SLV_ERR_APACKET_0);
87 err_apacket1 = readl_relaxed(base + SLV_ERR_APACKET_1);
88 err_cntl = readl_relaxed(base + SLV_ERR_CNTL);
89
90 if (!(err_cntl & CNTL_ERR_OCCURRED))
91 return IRQ_NONE;
92
93 pr_alert("EBI error detected!\n");
94 pr_alert("\tDevice = %s\n", dev_name(drvdata->dev));
95 pr_alert("\tERR_ADDR = 0x%08x\n", err_addr);
96 pr_alert("\tAPACKET0 = 0x%08x\n", err_apacket0);
97 pr_alert("\tAPACKET1 = 0x%08x\n", err_apacket1);
98 pr_alert("\tERR_CNTL = 0x%08x\n", err_cntl);
99
100 pr_alert("\tAMID = 0x%08x\n", err_apacket0 & AMID_MASK);
101 pr_alert("\tType = %s, %s, %s\n",
102 err_apacket1 & ERR_AWRITE ? "write" : "read",
103 err_sizes[(err_apacket1 >> ERR_ASIZE_SHIFT) & ERR_ASIZE_MASK],
104 err_apacket1 & ERR_APTORNS ? "non-secure" : "secure");
105
106 pr_alert("\tALOCK = %s\n",
107 err_lock_types[(err_apacket1 >> ERR_ALOCK_SHIFT) & ERR_ALOCK_MASK]);
108
109 pr_alert("\tABURST = %s\n", err_apacket1 & ERR_ABURST ?
110 "increment" : "wrap");
111
112 pr_alert("\tCODE = %s %s\n", err_cntl & ERR_CODE_DECODE_ERROR ?
113 "decode error" : "",
114 err_cntl & ERR_CODE_MPU_ERROR ?
115 "mpu error" : "");
116 err_cntl |= CNTL_CLEAR_ERR;
117 writel_relaxed(err_cntl, base + SLV_ERR_CNTL);
118 mb(); /* Ensure interrupt is cleared before returning */
Rajkumar Raghupathyc01decf2013-03-29 17:39:58 +0530119
120 if ((err_apacket0 & AMID_MASK) == 0x00000102)
121 trace_usb_daytona_invalid_access(err_addr, err_apacket0,
122 err_apacket1);
123
Stepan Moskovchenko57884842012-06-07 17:35:49 -0700124 return IRQ_HANDLED;
125}
126
127static int __devinit msm_ebi_erp_probe(struct platform_device *pdev)
128{
129 struct resource *r;
130 struct msm_ebi_erp_data *drvdata;
131 int ret, irq;
132 unsigned int err_cntl;
133
134 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
135 if (!drvdata)
136 return -ENOMEM;
137
138 drvdata->dev = &pdev->dev;
139 platform_set_drvdata(pdev, drvdata);
140
141 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
142 if (!r)
143 return -EINVAL;
144
145 drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
146 if (!drvdata->base)
147 return -ENOMEM;
148
149 irq = platform_get_irq(pdev, 0);
150 if (irq < 0)
151 return irq;
152
153 ret = devm_request_irq(&pdev->dev, irq, msm_ebi_irq, IRQF_TRIGGER_HIGH,
154 dev_name(&pdev->dev), drvdata);
155 if (ret)
156 return ret;
157
158 /* Enable the interrupt */
159 err_cntl = readl_relaxed(drvdata->base + SLV_ERR_CNTL);
160 err_cntl |= CNTL_IRQ_EN;
161 writel_relaxed(err_cntl, drvdata->base + SLV_ERR_CNTL);
162 mb(); /* Ensure interrupt is enabled before returning */
163 return 0;
164}
165
166static int msm_ebi_erp_remove(struct platform_device *pdev)
167{
168 struct msm_ebi_erp_data *drvdata = platform_get_drvdata(pdev);
169 unsigned int err_cntl;
170
171 /* Disable the interrupt */
172 err_cntl = readl_relaxed(drvdata->base + SLV_ERR_CNTL);
173 err_cntl &= ~CNTL_IRQ_EN;
174 writel_relaxed(err_cntl, drvdata->base + SLV_ERR_CNTL);
175 mb(); /* Ensure interrupt is disabled before returning */
176 return 0;
177}
178
179static struct platform_driver msm_ebi_erp_driver = {
180 .probe = msm_ebi_erp_probe,
181 .remove = __devexit_p(msm_ebi_erp_remove),
182 .driver = {
183 .name = MODULE_NAME,
184 .owner = THIS_MODULE,
185 },
186};
187
188static int __init msm_ebi_erp_init(void)
189{
190 return platform_driver_register(&msm_ebi_erp_driver);
191}
192
193static void __exit msm_ebi_erp_exit(void)
194{
195 platform_driver_unregister(&msm_ebi_erp_driver);
196}
197
198
199module_init(msm_ebi_erp_init);
200module_exit(msm_ebi_erp_exit);
201MODULE_LICENSE("GPL v2");
202MODULE_DESCRIPTION("MSM cache error reporting driver");