omap_l3_noc.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * OMAP4XXX L3 Interconnect error handling driver
  3. *
  4. * Copyright (C) 2011 Texas Corporation
  5. * Santosh Shilimkar <santosh.shilimkar@ti.com>
  6. * Sricharan <r.sricharan@ti.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. * USA
  22. */
  23. #include <linux/init.h>
  24. #include <linux/io.h>
  25. #include <linux/platform_device.h>
  26. #include <linux/interrupt.h>
  27. #include <linux/kernel.h>
  28. #include <linux/slab.h>
  29. #include "omap_l3_noc.h"
  30. /*
  31. * Interrupt Handler for L3 error detection.
  32. * 1) Identify the L3 clockdomain partition to which the error belongs to.
  33. * 2) Identify the slave where the error information is logged
  34. * 3) Print the logged information.
  35. * 4) Add dump stack to provide kernel trace.
  36. *
  37. * Two Types of errors :
  38. * 1) Custom errors in L3 :
  39. * Target like DMM/FW/EMIF generates SRESP=ERR error
  40. * 2) Standard L3 error:
  41. * - Unsupported CMD.
  42. * L3 tries to access target while it is idle
  43. * - OCP disconnect.
  44. * - Address hole error:
  45. * If DSS/ISS/FDIF/USBHOSTFS access a target where they
  46. * do not have connectivity, the error is logged in
  47. * their default target which is DMM2.
  48. *
  49. * On High Secure devices, firewall errors are possible and those
  50. * can be trapped as well. But the trapping is implemented as part
  51. * secure software and hence need not be implemented here.
  52. */
  53. static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
  54. {
  55. struct omap4_l3 *l3 = _l3;
  56. int inttype, i, j;
  57. int err_src = 0;
  58. u32 std_err_main_addr, std_err_main, err_reg;
  59. u32 base, slave_addr, clear;
  60. char *source_name;
  61. /* Get the Type of interrupt */
  62. inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
  63. for (i = 0; i < L3_MODULES; i++) {
  64. /*
  65. * Read the regerr register of the clock domain
  66. * to determine the source
  67. */
  68. base = (u32)l3->l3_base[i];
  69. err_reg = readl(base + l3_flagmux[i] + (inttype << 3));
  70. /* Get the corresponding error and analyse */
  71. if (err_reg) {
  72. /* Identify the source from control status register */
  73. for (j = 0; !(err_reg & (1 << j)); j++)
  74. ;
  75. err_src = j;
  76. /* Read the stderrlog_main_source from clk domain */
  77. std_err_main_addr = base + *(l3_targ[i] + err_src);
  78. std_err_main = readl(std_err_main_addr);
  79. switch (std_err_main & CUSTOM_ERROR) {
  80. case STANDARD_ERROR:
  81. source_name =
  82. l3_targ_stderrlog_main_name[i][err_src];
  83. slave_addr = std_err_main_addr +
  84. L3_SLAVE_ADDRESS_OFFSET;
  85. WARN(true, "L3 standard error: SOURCE:%s at address 0x%x\n",
  86. source_name, readl(slave_addr));
  87. /* clear the std error log*/
  88. clear = std_err_main | CLEAR_STDERR_LOG;
  89. writel(clear, std_err_main_addr);
  90. break;
  91. case CUSTOM_ERROR:
  92. source_name =
  93. l3_targ_stderrlog_main_name[i][err_src];
  94. WARN(true, "CUSTOM SRESP error with SOURCE:%s\n",
  95. source_name);
  96. /* clear the std error log*/
  97. clear = std_err_main | CLEAR_STDERR_LOG;
  98. writel(clear, std_err_main_addr);
  99. break;
  100. default:
  101. /* Nothing to be handled here as of now */
  102. break;
  103. }
  104. /* Error found so break the for loop */
  105. break;
  106. }
  107. }
  108. return IRQ_HANDLED;
  109. }
  110. static int __init omap4_l3_probe(struct platform_device *pdev)
  111. {
  112. static struct omap4_l3 *l3;
  113. struct resource *res;
  114. int ret;
  115. int irq;
  116. l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
  117. if (!l3)
  118. return -ENOMEM;
  119. platform_set_drvdata(pdev, l3);
  120. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  121. if (!res) {
  122. dev_err(&pdev->dev, "couldn't find resource 0\n");
  123. ret = -ENODEV;
  124. goto err0;
  125. }
  126. l3->l3_base[0] = ioremap(res->start, resource_size(res));
  127. if (!l3->l3_base[0]) {
  128. dev_err(&pdev->dev, "ioremap failed\n");
  129. ret = -ENOMEM;
  130. goto err0;
  131. }
  132. res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  133. if (!res) {
  134. dev_err(&pdev->dev, "couldn't find resource 1\n");
  135. ret = -ENODEV;
  136. goto err1;
  137. }
  138. l3->l3_base[1] = ioremap(res->start, resource_size(res));
  139. if (!l3->l3_base[1]) {
  140. dev_err(&pdev->dev, "ioremap failed\n");
  141. ret = -ENOMEM;
  142. goto err1;
  143. }
  144. res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
  145. if (!res) {
  146. dev_err(&pdev->dev, "couldn't find resource 2\n");
  147. ret = -ENODEV;
  148. goto err2;
  149. }
  150. l3->l3_base[2] = ioremap(res->start, resource_size(res));
  151. if (!l3->l3_base[2]) {
  152. dev_err(&pdev->dev, "ioremap failed\n");
  153. ret = -ENOMEM;
  154. goto err2;
  155. }
  156. /*
  157. * Setup interrupt Handlers
  158. */
  159. irq = platform_get_irq(pdev, 0);
  160. ret = request_irq(irq,
  161. l3_interrupt_handler,
  162. IRQF_DISABLED, "l3-dbg-irq", l3);
  163. if (ret) {
  164. pr_crit("L3: request_irq failed to register for 0x%x\n",
  165. OMAP44XX_IRQ_L3_DBG);
  166. goto err3;
  167. }
  168. l3->debug_irq = irq;
  169. irq = platform_get_irq(pdev, 1);
  170. ret = request_irq(irq,
  171. l3_interrupt_handler,
  172. IRQF_DISABLED, "l3-app-irq", l3);
  173. if (ret) {
  174. pr_crit("L3: request_irq failed to register for 0x%x\n",
  175. OMAP44XX_IRQ_L3_APP);
  176. goto err4;
  177. }
  178. l3->app_irq = irq;
  179. return 0;
  180. err4:
  181. free_irq(l3->debug_irq, l3);
  182. err3:
  183. iounmap(l3->l3_base[2]);
  184. err2:
  185. iounmap(l3->l3_base[1]);
  186. err1:
  187. iounmap(l3->l3_base[0]);
  188. err0:
  189. kfree(l3);
  190. return ret;
  191. }
  192. static int __exit omap4_l3_remove(struct platform_device *pdev)
  193. {
  194. struct omap4_l3 *l3 = platform_get_drvdata(pdev);
  195. free_irq(l3->app_irq, l3);
  196. free_irq(l3->debug_irq, l3);
  197. iounmap(l3->l3_base[0]);
  198. iounmap(l3->l3_base[1]);
  199. iounmap(l3->l3_base[2]);
  200. kfree(l3);
  201. return 0;
  202. }
  203. static struct platform_driver omap4_l3_driver = {
  204. .remove = __exit_p(omap4_l3_remove),
  205. .driver = {
  206. .name = "omap_l3_noc",
  207. },
  208. };
  209. static int __init omap4_l3_init(void)
  210. {
  211. return platform_driver_probe(&omap4_l3_driver, omap4_l3_probe);
  212. }
  213. postcore_initcall_sync(omap4_l3_init);
  214. static void __exit omap4_l3_exit(void)
  215. {
  216. platform_driver_unregister(&omap4_l3_driver);
  217. }
  218. module_exit(omap4_l3_exit);