cache.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * Cache control for MicroBlaze cache memories
  3. *
  4. * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  5. * Copyright (C) 2007-2009 PetaLogix
  6. * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com>
  7. *
  8. * This file is subject to the terms and conditions of the GNU General
  9. * Public License. See the file COPYING in the main directory of this
  10. * archive for more details.
  11. */
  12. #include <asm/cacheflush.h>
  13. #include <linux/cache.h>
  14. #include <asm/cpuinfo.h>
  15. #include <asm/pvr.h>
  16. static inline void __invalidate_flush_icache(unsigned int addr)
  17. {
  18. __asm__ __volatile__ ("wic %0, r0;" \
  19. : : "r" (addr));
  20. }
  21. static inline void __flush_dcache(unsigned int addr)
  22. {
  23. __asm__ __volatile__ ("wdc.flush %0, r0;" \
  24. : : "r" (addr));
  25. }
  26. static inline void __invalidate_dcache(unsigned int baseaddr,
  27. unsigned int offset)
  28. {
  29. __asm__ __volatile__ ("wdc.clear %0, %1;" \
  30. : : "r" (baseaddr), "r" (offset));
  31. }
  32. static inline void __enable_icache_msr(void)
  33. {
  34. __asm__ __volatile__ (" msrset r0, %0; \
  35. nop; " \
  36. : : "i" (MSR_ICE) : "memory");
  37. }
  38. static inline void __disable_icache_msr(void)
  39. {
  40. __asm__ __volatile__ (" msrclr r0, %0; \
  41. nop; " \
  42. : : "i" (MSR_ICE) : "memory");
  43. }
  44. static inline void __enable_dcache_msr(void)
  45. {
  46. __asm__ __volatile__ (" msrset r0, %0; \
  47. nop; " \
  48. : \
  49. : "i" (MSR_DCE) \
  50. : "memory");
  51. }
  52. static inline void __disable_dcache_msr(void)
  53. {
  54. __asm__ __volatile__ (" msrclr r0, %0; \
  55. nop; " \
  56. : \
  57. : "i" (MSR_DCE) \
  58. : "memory");
  59. }
  60. static inline void __enable_icache_nomsr(void)
  61. {
  62. __asm__ __volatile__ (" mfs r12, rmsr; \
  63. nop; \
  64. ori r12, r12, %0; \
  65. mts rmsr, r12; \
  66. nop; " \
  67. : \
  68. : "i" (MSR_ICE) \
  69. : "memory", "r12");
  70. }
  71. static inline void __disable_icache_nomsr(void)
  72. {
  73. __asm__ __volatile__ (" mfs r12, rmsr; \
  74. nop; \
  75. andi r12, r12, ~%0; \
  76. mts rmsr, r12; \
  77. nop; " \
  78. : \
  79. : "i" (MSR_ICE) \
  80. : "memory", "r12");
  81. }
  82. static inline void __enable_dcache_nomsr(void)
  83. {
  84. __asm__ __volatile__ (" mfs r12, rmsr; \
  85. nop; \
  86. ori r12, r12, %0; \
  87. mts rmsr, r12; \
  88. nop; " \
  89. : \
  90. : "i" (MSR_DCE) \
  91. : "memory", "r12");
  92. }
  93. static inline void __disable_dcache_nomsr(void)
  94. {
  95. __asm__ __volatile__ (" mfs r12, rmsr; \
  96. nop; \
  97. andi r12, r12, ~%0; \
  98. mts rmsr, r12; \
  99. nop; " \
  100. : \
  101. : "i" (MSR_DCE) \
  102. : "memory", "r12");
  103. }
  104. /* Helper macro for computing the limits of cache range loops */
  105. #define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size) \
  106. do { \
  107. int align = ~(cache_line_length - 1); \
  108. end = min(start + cache_size, end); \
  109. start &= align; \
  110. end = ((end & align) + cache_line_length); \
  111. } while (0);
  112. /*
  113. * Helper macro to loop over the specified cache_size/line_length and
  114. * execute 'op' on that cacheline
  115. */
  116. #define CACHE_ALL_LOOP(cache_size, line_length, op) \
  117. do { \
  118. unsigned int len = cache_size; \
  119. int step = -line_length; \
  120. BUG_ON(step >= 0); \
  121. \
  122. __asm__ __volatile__ (" 1: " #op " %0, r0; \
  123. bgtid %0, 1b; \
  124. addk %0, %0, %1; \
  125. " : : "r" (len), "r" (step) \
  126. : "memory"); \
  127. } while (0);
  128. #define CACHE_ALL_LOOP2(cache_size, line_length, op) \
  129. do { \
  130. unsigned int len = cache_size; \
  131. int step = -line_length; \
  132. BUG_ON(step >= 0); \
  133. \
  134. __asm__ __volatile__ (" 1: " #op " r0, %0; \
  135. bgtid %0, 1b; \
  136. addk %0, %0, %1; \
  137. " : : "r" (len), "r" (step) \
  138. : "memory"); \
  139. } while (0);
  140. /* for wdc.flush/clear */
  141. #define CACHE_RANGE_LOOP_2(start, end, line_length, op) \
  142. do { \
  143. int step = -line_length; \
  144. int count = end - start; \
  145. BUG_ON(count <= 0); \
  146. \
  147. __asm__ __volatile__ (" 1: " #op " %0, %1; \
  148. bgtid %1, 1b; \
  149. addk %1, %1, %2; \
  150. " : : "r" (start), "r" (count), \
  151. "r" (step) : "memory"); \
  152. } while (0);
  153. /* It is used only first parameter for OP - for wic, wdc */
  154. #define CACHE_RANGE_LOOP_1(start, end, line_length, op) \
  155. do { \
  156. int volatile temp; \
  157. BUG_ON(end - start <= 0); \
  158. \
  159. __asm__ __volatile__ (" 1: " #op " %1, r0; \
  160. cmpu %0, %1, %2; \
  161. bgtid %0, 1b; \
  162. addk %1, %1, %3; \
  163. " : : "r" (temp), "r" (start), "r" (end),\
  164. "r" (line_length) : "memory"); \
  165. } while (0);
  166. static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
  167. {
  168. unsigned long flags;
  169. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  170. (unsigned int)start, (unsigned int) end);
  171. CACHE_LOOP_LIMITS(start, end,
  172. cpuinfo.icache_line_length, cpuinfo.icache_size);
  173. local_irq_save(flags);
  174. __disable_icache_msr();
  175. CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
  176. __enable_icache_msr();
  177. local_irq_restore(flags);
  178. }
  179. static void __flush_icache_range_nomsr_irq(unsigned long start,
  180. unsigned long end)
  181. {
  182. unsigned long flags;
  183. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  184. (unsigned int)start, (unsigned int) end);
  185. CACHE_LOOP_LIMITS(start, end,
  186. cpuinfo.icache_line_length, cpuinfo.icache_size);
  187. local_irq_save(flags);
  188. __disable_icache_nomsr();
  189. CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
  190. __enable_icache_nomsr();
  191. local_irq_restore(flags);
  192. }
  193. static void __flush_icache_range_noirq(unsigned long start,
  194. unsigned long end)
  195. {
  196. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  197. (unsigned int)start, (unsigned int) end);
  198. CACHE_LOOP_LIMITS(start, end,
  199. cpuinfo.icache_line_length, cpuinfo.icache_size);
  200. CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
  201. }
  202. static void __flush_icache_all_msr_irq(void)
  203. {
  204. unsigned long flags;
  205. pr_debug("%s\n", __func__);
  206. local_irq_save(flags);
  207. __disable_icache_msr();
  208. CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
  209. __enable_icache_msr();
  210. local_irq_restore(flags);
  211. }
  212. static void __flush_icache_all_nomsr_irq(void)
  213. {
  214. unsigned long flags;
  215. pr_debug("%s\n", __func__);
  216. local_irq_save(flags);
  217. __disable_icache_nomsr();
  218. CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
  219. __enable_icache_nomsr();
  220. local_irq_restore(flags);
  221. }
  222. static void __flush_icache_all_noirq(void)
  223. {
  224. pr_debug("%s\n", __func__);
  225. CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
  226. }
  227. static void __invalidate_dcache_all_msr_irq(void)
  228. {
  229. unsigned long flags;
  230. pr_debug("%s\n", __func__);
  231. local_irq_save(flags);
  232. __disable_dcache_msr();
  233. CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
  234. __enable_dcache_msr();
  235. local_irq_restore(flags);
  236. }
  237. static void __invalidate_dcache_all_nomsr_irq(void)
  238. {
  239. unsigned long flags;
  240. pr_debug("%s\n", __func__);
  241. local_irq_save(flags);
  242. __disable_dcache_nomsr();
  243. CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
  244. __enable_dcache_nomsr();
  245. local_irq_restore(flags);
  246. }
  247. static void __invalidate_dcache_all_noirq_wt(void)
  248. {
  249. pr_debug("%s\n", __func__);
  250. CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc)
  251. }
  252. /* FIXME this is weird - should be only wdc but not work
  253. * MS: I am getting bus errors and other weird things */
  254. static void __invalidate_dcache_all_wb(void)
  255. {
  256. pr_debug("%s\n", __func__);
  257. CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
  258. wdc.clear)
  259. }
  260. static void __invalidate_dcache_range_wb(unsigned long start,
  261. unsigned long end)
  262. {
  263. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  264. (unsigned int)start, (unsigned int) end);
  265. CACHE_LOOP_LIMITS(start, end,
  266. cpuinfo.dcache_line_length, cpuinfo.dcache_size);
  267. CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
  268. }
  269. static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
  270. unsigned long end)
  271. {
  272. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  273. (unsigned int)start, (unsigned int) end);
  274. CACHE_LOOP_LIMITS(start, end,
  275. cpuinfo.dcache_line_length, cpuinfo.dcache_size);
  276. CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
  277. }
  278. static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
  279. unsigned long end)
  280. {
  281. unsigned long flags;
  282. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  283. (unsigned int)start, (unsigned int) end);
  284. CACHE_LOOP_LIMITS(start, end,
  285. cpuinfo.dcache_line_length, cpuinfo.dcache_size);
  286. local_irq_save(flags);
  287. __disable_dcache_msr();
  288. CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
  289. __enable_dcache_msr();
  290. local_irq_restore(flags);
  291. }
  292. static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
  293. unsigned long end)
  294. {
  295. unsigned long flags;
  296. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  297. (unsigned int)start, (unsigned int) end);
  298. CACHE_LOOP_LIMITS(start, end,
  299. cpuinfo.dcache_line_length, cpuinfo.dcache_size);
  300. local_irq_save(flags);
  301. __disable_dcache_nomsr();
  302. CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
  303. __enable_dcache_nomsr();
  304. local_irq_restore(flags);
  305. }
  306. static void __flush_dcache_all_wb(void)
  307. {
  308. pr_debug("%s\n", __func__);
  309. CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
  310. wdc.flush);
  311. }
  312. static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
  313. {
  314. pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
  315. (unsigned int)start, (unsigned int) end);
  316. CACHE_LOOP_LIMITS(start, end,
  317. cpuinfo.dcache_line_length, cpuinfo.dcache_size);
  318. CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
  319. }
  320. /* struct for wb caches and for wt caches */
  321. struct scache *mbc;
  322. /* new wb cache model */
  323. const struct scache wb_msr = {
  324. .ie = __enable_icache_msr,
  325. .id = __disable_icache_msr,
  326. .ifl = __flush_icache_all_noirq,
  327. .iflr = __flush_icache_range_noirq,
  328. .iin = __flush_icache_all_noirq,
  329. .iinr = __flush_icache_range_noirq,
  330. .de = __enable_dcache_msr,
  331. .dd = __disable_dcache_msr,
  332. .dfl = __flush_dcache_all_wb,
  333. .dflr = __flush_dcache_range_wb,
  334. .din = __invalidate_dcache_all_wb,
  335. .dinr = __invalidate_dcache_range_wb,
  336. };
  337. /* There is only difference in ie, id, de, dd functions */
  338. const struct scache wb_nomsr = {
  339. .ie = __enable_icache_nomsr,
  340. .id = __disable_icache_nomsr,
  341. .ifl = __flush_icache_all_noirq,
  342. .iflr = __flush_icache_range_noirq,
  343. .iin = __flush_icache_all_noirq,
  344. .iinr = __flush_icache_range_noirq,
  345. .de = __enable_dcache_nomsr,
  346. .dd = __disable_dcache_nomsr,
  347. .dfl = __flush_dcache_all_wb,
  348. .dflr = __flush_dcache_range_wb,
  349. .din = __invalidate_dcache_all_wb,
  350. .dinr = __invalidate_dcache_range_wb,
  351. };
  352. /* Old wt cache model with disabling irq and turn off cache */
  353. const struct scache wt_msr = {
  354. .ie = __enable_icache_msr,
  355. .id = __disable_icache_msr,
  356. .ifl = __flush_icache_all_msr_irq,
  357. .iflr = __flush_icache_range_msr_irq,
  358. .iin = __flush_icache_all_msr_irq,
  359. .iinr = __flush_icache_range_msr_irq,
  360. .de = __enable_dcache_msr,
  361. .dd = __disable_dcache_msr,
  362. .dfl = __invalidate_dcache_all_msr_irq,
  363. .dflr = __invalidate_dcache_range_msr_irq_wt,
  364. .din = __invalidate_dcache_all_msr_irq,
  365. .dinr = __invalidate_dcache_range_msr_irq_wt,
  366. };
  367. const struct scache wt_nomsr = {
  368. .ie = __enable_icache_nomsr,
  369. .id = __disable_icache_nomsr,
  370. .ifl = __flush_icache_all_nomsr_irq,
  371. .iflr = __flush_icache_range_nomsr_irq,
  372. .iin = __flush_icache_all_nomsr_irq,
  373. .iinr = __flush_icache_range_nomsr_irq,
  374. .de = __enable_dcache_nomsr,
  375. .dd = __disable_dcache_nomsr,
  376. .dfl = __invalidate_dcache_all_nomsr_irq,
  377. .dflr = __invalidate_dcache_range_nomsr_irq,
  378. .din = __invalidate_dcache_all_nomsr_irq,
  379. .dinr = __invalidate_dcache_range_nomsr_irq,
  380. };
  381. /* New wt cache model for newer Microblaze versions */
  382. const struct scache wt_msr_noirq = {
  383. .ie = __enable_icache_msr,
  384. .id = __disable_icache_msr,
  385. .ifl = __flush_icache_all_noirq,
  386. .iflr = __flush_icache_range_noirq,
  387. .iin = __flush_icache_all_noirq,
  388. .iinr = __flush_icache_range_noirq,
  389. .de = __enable_dcache_msr,
  390. .dd = __disable_dcache_msr,
  391. .dfl = __invalidate_dcache_all_noirq_wt,
  392. .dflr = __invalidate_dcache_range_nomsr_wt,
  393. .din = __invalidate_dcache_all_noirq_wt,
  394. .dinr = __invalidate_dcache_range_nomsr_wt,
  395. };
  396. const struct scache wt_nomsr_noirq = {
  397. .ie = __enable_icache_nomsr,
  398. .id = __disable_icache_nomsr,
  399. .ifl = __flush_icache_all_noirq,
  400. .iflr = __flush_icache_range_noirq,
  401. .iin = __flush_icache_all_noirq,
  402. .iinr = __flush_icache_range_noirq,
  403. .de = __enable_dcache_nomsr,
  404. .dd = __disable_dcache_nomsr,
  405. .dfl = __invalidate_dcache_all_noirq_wt,
  406. .dflr = __invalidate_dcache_range_nomsr_wt,
  407. .din = __invalidate_dcache_all_noirq_wt,
  408. .dinr = __invalidate_dcache_range_nomsr_wt,
  409. };
  410. /* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
  411. #define CPUVER_7_20_A 0x0c
  412. #define CPUVER_7_20_D 0x0f
  413. #define INFO(s) printk(KERN_INFO "cache: " s " \n");
  414. void microblaze_cache_init(void)
  415. {
  416. if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
  417. if (cpuinfo.dcache_wb) {
  418. INFO("wb_msr");
  419. mbc = (struct scache *)&wb_msr;
  420. if (cpuinfo.ver_code < CPUVER_7_20_D) {
  421. /* MS: problem with signal handling - hw bug */
  422. INFO("WB won't work properly");
  423. }
  424. } else {
  425. if (cpuinfo.ver_code >= CPUVER_7_20_A) {
  426. INFO("wt_msr_noirq");
  427. mbc = (struct scache *)&wt_msr_noirq;
  428. } else {
  429. INFO("wt_msr");
  430. mbc = (struct scache *)&wt_msr;
  431. }
  432. }
  433. } else {
  434. if (cpuinfo.dcache_wb) {
  435. INFO("wb_nomsr");
  436. mbc = (struct scache *)&wb_nomsr;
  437. if (cpuinfo.ver_code < CPUVER_7_20_D) {
  438. /* MS: problem with signal handling - hw bug */
  439. INFO("WB won't work properly");
  440. }
  441. } else {
  442. if (cpuinfo.ver_code >= CPUVER_7_20_A) {
  443. INFO("wt_nomsr_noirq");
  444. mbc = (struct scache *)&wt_nomsr_noirq;
  445. } else {
  446. INFO("wt_nomsr");
  447. mbc = (struct scache *)&wt_nomsr;
  448. }
  449. }
  450. }
  451. }