chmc.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: chmc.c,v 1.3 2001/04/03 12:49:47 davem Exp $
  2.  * memctrlr.c: Driver for UltraSPARC-III memory controller.
  3.  *
  4.  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
  5.  */
  6. #include <linux/module.h>
  7. #include <linux/kernel.h>
  8. #include <linux/types.h>
  9. #include <linux/slab.h>
  10. #include <linux/list.h>
  11. #include <linux/init.h>
  12. #include <asm/spitfire.h>
  13. #include <asm/chmctrl.h>
  14. #include <asm/oplib.h>
  15. #include <asm/io.h>
  16. #define CHMCTRL_NDGRPS 2
  17. #define CHMCTRL_NDIMMS 4
  18. #define DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
  19. /* OBP memory-layout property format. */
  20. struct obp_map {
  21. unsigned char dimm_map[144];
  22. unsigned char pin_map[576];
  23. };
  24. #define DIMM_LABEL_SZ 8
  25. struct obp_mem_layout {
  26. /* One max 8-byte string label per DIMM.  Usually
  27.  * this matches the label on the motherboard where
  28.  * that DIMM resides.
  29.  */
  30. char dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ];
  31. /* If symmetric use map[0], else it is
  32.  * asymmetric and map[1] should be used.
  33.  */
  34. char symmetric;
  35. struct obp_map map[2];
  36. };
  37. #define CHMCTRL_NBANKS 4
  38. struct bank_info {
  39. struct mctrl_info *mp;
  40. int bank_id;
  41. u64 raw_reg;
  42. int valid;
  43. int uk;
  44. int um;
  45. int lk;
  46. int lm;
  47. int interleave;
  48. unsigned long base;
  49. unsigned long size;
  50. };
  51. struct mctrl_info {
  52. struct list_head list;
  53. int portid;
  54. int index;
  55. struct obp_mem_layout layout_prop;
  56. int layout_size;
  57. void *regs;
  58. u64 timing_control1;
  59. u64 timing_control2;
  60. u64 timing_control3;
  61. u64 timing_control4;
  62. u64 memaddr_control;
  63. struct bank_info logical_banks[CHMCTRL_NBANKS];
  64. };
  65. static LIST_HEAD(mctrl_list);
  66. /* Does BANK decode PHYS_ADDR? */
  67. static int bank_match(struct bank_info *bp, unsigned long phys_addr)
  68. {
  69. unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
  70. unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
  71. /* Bank must be enabled to match. */
  72. if (bp->valid == 0)
  73. return 0;
  74. /* Would BANK match upper bits? */
  75. upper_bits ^= bp->um; /* What bits are different? */
  76. upper_bits  = ~upper_bits; /* Invert. */
  77. upper_bits |= bp->uk; /* What bits don't matter for matching? */
  78. upper_bits  = ~upper_bits; /* Invert. */
  79. if (upper_bits)
  80. return 0;
  81. /* Would BANK match lower bits? */
  82. lower_bits ^= bp->lm; /* What bits are different? */
  83. lower_bits  = ~lower_bits; /* Invert. */
  84. lower_bits |= bp->lk; /* What bits don't matter for matching? */
  85. lower_bits  = ~lower_bits; /* Invert. */
  86. if (lower_bits)
  87. return 0;
  88. /* I always knew you'd be the one. */
  89. return 1;
  90. }
  91. /* Given PHYS_ADDR, search memory controller banks for a match. */
  92. static struct bank_info *find_bank(unsigned long phys_addr)
  93. {
  94. struct list_head *mctrl_head = &mctrl_list;
  95. struct list_head *mctrl_entry = mctrl_head->next;
  96. for (;;) {
  97. struct mctrl_info *mp =
  98. list_entry(mctrl_entry, struct mctrl_info, list);
  99. int bank_no;
  100. if (mctrl_entry == mctrl_head)
  101. break;
  102. mctrl_entry = mctrl_entry->next;
  103. for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
  104. struct bank_info *bp;
  105. bp = &mp->logical_banks[bank_no];
  106. if (bank_match(bp, phys_addr))
  107. return bp;
  108. }
  109. }
  110. return NULL;
  111. }
  112. /* This is the main purpose of this driver. */
  113. #define SYNDROME_MIN -1
  114. #define SYNDROME_MAX 144
  115. int chmc_getunumber(int syndrome_code,
  116.     unsigned long phys_addr,
  117.     char *buf, int buflen)
  118. {
  119. struct bank_info *bp;
  120. struct obp_mem_layout *prop;
  121. int bank_in_controller, first_dimm;
  122. bp = find_bank(phys_addr);
  123. if (bp == NULL ||
  124.     syndrome_code < SYNDROME_MIN ||
  125.     syndrome_code > SYNDROME_MAX) {
  126. buf[0] = '?';
  127. buf[1] = '?';
  128. buf[2] = '?';
  129. buf[3] = '';
  130. return 0;
  131. }
  132. prop = &bp->mp->layout_prop;
  133. bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
  134. first_dimm  = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
  135. first_dimm *= CHMCTRL_NDIMMS;
  136. if (syndrome_code != SYNDROME_MIN) {
  137. struct obp_map *map;
  138. int qword, where_in_line, where, map_index, map_offset;
  139. unsigned int map_val;
  140. /* Yaay, single bit error so we can figure out
  141.  * the exact dimm.
  142.  */
  143. if (prop->symmetric)
  144. map = &prop->map[0];
  145. else
  146. map = &prop->map[1];
  147. /* Covert syndrome code into the way the bits are
  148.  * positioned on the bus.
  149.  */
  150. if (syndrome_code < 144 - 16)
  151. syndrome_code += 16;
  152. else if (syndrome_code < 144)
  153. syndrome_code -= (144 - 7);
  154. else if (syndrome_code < (144 + 3))
  155. syndrome_code -= (144 + 3 - 4);
  156. else
  157. syndrome_code -= 144 + 3;
  158. /* All this magic has to do with how a cache line
  159.  * comes over the wire on Safari.  A 64-bit line
  160.  * comes over in 4 quadword cycles, each of which
  161.  * transmit ECC/MTAG info as well as the actual
  162.  * data.  144 bits per quadword, 576 total.
  163.  */
  164. #define LINE_SIZE 64
  165. #define LINE_ADDR_MSK (LINE_SIZE - 1)
  166. #define QW_PER_LINE 4
  167. #define QW_BYTES (LINE_SIZE / QW_PER_LINE)
  168. #define QW_BITS 144
  169. #define LAST_BIT (576 - 1)
  170. qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES;
  171. where_in_line = ((3 - qword) * QW_BITS) + syndrome_code;
  172. where = (LAST_BIT - where_in_line);
  173. map_index = where >> 2;
  174. map_offset = where & 0x3;
  175. map_val = map->dimm_map[map_index];
  176. map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1));
  177. sprintf(buf, "%s, pin %3d",
  178. prop->dimm_labels[first_dimm + map_val],
  179. map->pin_map[where_in_line]);
  180. } else {
  181. int dimm;
  182. /* Multi-bit error, we just dump out all the
  183.  * dimm labels assosciated with this bank.
  184.  */
  185. for (dimm = 0; dimm < CHMCTRL_NDIMMS; dimm++) {
  186. sprintf(buf, "%s ",
  187. prop->dimm_labels[first_dimm + dimm]);
  188. buf += strlen(buf);
  189. }
  190. }
  191. return 0;
  192. }
  193. /* Accessing the registers is slightly complicated.  If you want
  194.  * to get at the memory controller which is on the same processor
  195.  * the code is executing, you must use special ASI load/store else
  196.  * you go through the global mapping.
  197.  */
  198. static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
  199. {
  200. unsigned long ret;
  201. if (mp->portid == smp_processor_id()) {
  202. __asm__ __volatile__("ldxa [%1] %2, %0"
  203.      : "=r" (ret)
  204.      : "r" (offset), "i" (ASI_MCU_CTRL_REG));
  205. } else {
  206. __asm__ __volatile__("ldxa [%1] %2, %0"
  207.      : "=r" (ret)
  208.      : "r" (mp->regs + offset),
  209.        "i" (ASI_PHYS_BYPASS_EC_E));
  210. }
  211. return ret;
  212. }
  213. #if 0 /* currently unused */
  214. static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val)
  215. {
  216. if (mp->portid == smp_processor_id()) {
  217. __asm__ __volatile__("stxa %0, [%1] %2"
  218.      : : "r" (val),
  219.          "r" (offset), "i" (ASI_MCU_CTRL_REG));
  220. } else {
  221. __asm__ __volatile__("ldxa %0, [%1] %2"
  222.      : : "r" (val),
  223.          "r" (mp->regs + offset),
  224.          "i" (ASI_PHYS_BYPASS_EC_E));
  225. }
  226. }
  227. #endif
  228. static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val)
  229. {
  230. struct bank_info *p = &mp->logical_banks[which_bank];
  231. p->mp = mp;
  232. p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank;
  233. p->raw_reg = val;
  234. p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
  235. p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
  236. p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
  237. p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
  238. p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
  239. p->base  =  (p->um);
  240. p->base &= ~(p->uk);
  241. p->base <<= PA_UPPER_BITS_SHIFT;
  242. switch(p->lk) {
  243. case 0xf:
  244. default:
  245. p->interleave = 1;
  246. break;
  247. case 0xe:
  248. p->interleave = 2;
  249. break;
  250. case 0xc:
  251. p->interleave = 4;
  252. break;
  253. case 0x8:
  254. p->interleave = 8;
  255. break;
  256. case 0x0:
  257. p->interleave = 16;
  258. break;
  259. };
  260. /* UK[10] is reserved, and UK[11] is not set for the SDRAM
  261.  * bank size definition.
  262.  */
  263. p->size = (((unsigned long)p->uk &
  264.     ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
  265. p->size /= p->interleave;
  266. }
  267. static void fetch_decode_regs(struct mctrl_info *mp)
  268. {
  269. if (mp->layout_size == 0)
  270. return;
  271. interpret_one_decode_reg(mp, 0,
  272.  read_mcreg(mp, CHMCTRL_DECODE1));
  273. interpret_one_decode_reg(mp, 1,
  274.  read_mcreg(mp, CHMCTRL_DECODE2));
  275. interpret_one_decode_reg(mp, 2,
  276.  read_mcreg(mp, CHMCTRL_DECODE3));
  277. interpret_one_decode_reg(mp, 3,
  278.  read_mcreg(mp, CHMCTRL_DECODE4));
  279. }
  280. static int init_one_mctrl(int node, int index)
  281. {
  282. struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
  283. int portid = prom_getintdefault(node, "portid", -1);
  284. struct linux_prom64_registers p_reg_prop;
  285. int t;
  286. if (!mp)
  287. return -1;
  288. memset(mp, 0, sizeof(*mp));
  289. if (portid == -1)
  290. goto fail;
  291. mp->portid = portid;
  292. mp->layout_size = prom_getproplen(node, "memory-layout");
  293. if (mp->layout_size < 0)
  294. mp->layout_size = 0;
  295. if (mp->layout_size > sizeof(mp->layout_prop))
  296. goto fail;
  297. if (mp->layout_size > 0)
  298. prom_getproperty(node, "memory-layout",
  299.  (char *) &mp->layout_prop,
  300.  mp->layout_size);
  301. t = prom_getproperty(node, "reg",
  302.      (char *) &p_reg_prop,
  303.      sizeof(p_reg_prop));
  304. if (t < 0 || p_reg_prop.reg_size != 0x48)
  305. goto fail;
  306. mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size);
  307. if (mp->regs == NULL)
  308. goto fail;
  309. if (mp->layout_size != 0UL) {
  310. mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1);
  311. mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2);
  312. mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3);
  313. mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4);
  314. mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL);
  315. }
  316. fetch_decode_regs(mp);
  317. mp->index = index;
  318. list_add(&mp->list, &mctrl_list);
  319. /* Report the device. */
  320. printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]n",
  321.        mp->index,
  322.        mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
  323. return 0;
  324. fail:
  325. if (mp) {
  326. if (mp->regs != NULL)
  327. iounmap(mp->regs);
  328. kfree(mp);
  329. }
  330. return -1;
  331. }
  332. static int __init probe_for_string(char *name, int index)
  333. {
  334. int node = prom_getchild(prom_root_node);
  335. while ((node = prom_searchsiblings(node, name)) != 0) {
  336. int ret = init_one_mctrl(node, index);
  337. if (!ret)
  338. index++;
  339. node = prom_getsibling(node);
  340. if (!node)
  341. break;
  342. }
  343. return index;
  344. }
  345. static int __init chmc_init(void)
  346. {
  347. int index;
  348. /* This driver is only for cheetah platforms. */
  349. if (tlb_type != cheetah && tlb_type != cheetah_plus)
  350. return -ENODEV;
  351. index = probe_for_string("memory-controller", 0);
  352. index = probe_for_string("mc-us3", index);
  353. return 0;
  354. }
  355. static void __exit chmc_cleanup(void)
  356. {
  357. struct list_head *head = &mctrl_list;
  358. struct list_head *tmp = head->next;
  359. for (;;) {
  360. struct mctrl_info *p =
  361. list_entry(tmp, struct mctrl_info, list);
  362. if (tmp == head)
  363. break;
  364. tmp = tmp->next;
  365. list_del(&p->list);
  366. iounmap(p->regs);
  367. kfree(p);
  368. }
  369. }
  370. module_init(chmc_init);
  371. module_exit(chmc_cleanup);