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