aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc64/kernel/chmc.c237
1 files changed, 120 insertions, 117 deletions
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index b9cd736a11f7..2f73ddc8676d 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -35,35 +35,35 @@ MODULE_VERSION(DRV_MODULE_VERSION);
35#define CHMCTRL_NDGRPS 2 35#define CHMCTRL_NDGRPS 2
36#define CHMCTRL_NDIMMS 4 36#define CHMCTRL_NDIMMS 4
37 37
38#define DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS) 38#define CHMC_DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
39 39
40/* OBP memory-layout property format. */ 40/* OBP memory-layout property format. */
41struct obp_map { 41struct chmc_obp_map {
42 unsigned char dimm_map[144]; 42 unsigned char dimm_map[144];
43 unsigned char pin_map[576]; 43 unsigned char pin_map[576];
44}; 44};
45 45
46#define DIMM_LABEL_SZ 8 46#define DIMM_LABEL_SZ 8
47 47
48struct obp_mem_layout { 48struct chmc_obp_mem_layout {
49 /* One max 8-byte string label per DIMM. Usually 49 /* One max 8-byte string label per DIMM. Usually
50 * this matches the label on the motherboard where 50 * this matches the label on the motherboard where
51 * that DIMM resides. 51 * that DIMM resides.
52 */ 52 */
53 char dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ]; 53 char dimm_labels[CHMC_DIMMS_PER_MC][DIMM_LABEL_SZ];
54 54
55 /* If symmetric use map[0], else it is 55 /* If symmetric use map[0], else it is
56 * asymmetric and map[1] should be used. 56 * asymmetric and map[1] should be used.
57 */ 57 */
58 char symmetric; 58 char symmetric;
59 59
60 struct obp_map map[2]; 60 struct chmc_obp_map map[2];
61}; 61};
62 62
63#define CHMCTRL_NBANKS 4 63#define CHMCTRL_NBANKS 4
64 64
65struct bank_info { 65struct chmc_bank_info {
66 struct mctrl_info *mp; 66 struct chmc *p;
67 int bank_id; 67 int bank_id;
68 68
69 u64 raw_reg; 69 u64 raw_reg;
@@ -77,28 +77,28 @@ struct bank_info {
77 unsigned long size; 77 unsigned long size;
78}; 78};
79 79
80struct mctrl_info { 80struct chmc {
81 struct list_head list; 81 struct list_head list;
82 int portid; 82 int portid;
83 83
84 struct obp_mem_layout layout_prop; 84 struct chmc_obp_mem_layout layout_prop;
85 int layout_size; 85 int layout_size;
86 86
87 void __iomem *regs; 87 void __iomem *regs;
88 88
89 u64 timing_control1; 89 u64 timing_control1;
90 u64 timing_control2; 90 u64 timing_control2;
91 u64 timing_control3; 91 u64 timing_control3;
92 u64 timing_control4; 92 u64 timing_control4;
93 u64 memaddr_control; 93 u64 memaddr_control;
94 94
95 struct bank_info logical_banks[CHMCTRL_NBANKS]; 95 struct chmc_bank_info logical_banks[CHMCTRL_NBANKS];
96}; 96};
97 97
98static LIST_HEAD(mctrl_list); 98static LIST_HEAD(mctrl_list);
99 99
100/* Does BANK decode PHYS_ADDR? */ 100/* Does BANK decode PHYS_ADDR? */
101static int bank_match(struct bank_info *bp, unsigned long phys_addr) 101static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
102{ 102{
103 unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT; 103 unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
104 unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT; 104 unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
@@ -130,14 +130,13 @@ static int bank_match(struct bank_info *bp, unsigned long phys_addr)
130} 130}
131 131
132/* Given PHYS_ADDR, search memory controller banks for a match. */ 132/* Given PHYS_ADDR, search memory controller banks for a match. */
133static struct bank_info *find_bank(unsigned long phys_addr) 133static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
134{ 134{
135 struct list_head *mctrl_head = &mctrl_list; 135 struct list_head *mctrl_head = &mctrl_list;
136 struct list_head *mctrl_entry = mctrl_head->next; 136 struct list_head *mctrl_entry = mctrl_head->next;
137 137
138 for (;;) { 138 for (;;) {
139 struct mctrl_info *mp = 139 struct chmc *p = list_entry(mctrl_entry, struct chmc, list);
140 list_entry(mctrl_entry, struct mctrl_info, list);
141 int bank_no; 140 int bank_no;
142 141
143 if (mctrl_entry == mctrl_head) 142 if (mctrl_entry == mctrl_head)
@@ -145,10 +144,10 @@ static struct bank_info *find_bank(unsigned long phys_addr)
145 mctrl_entry = mctrl_entry->next; 144 mctrl_entry = mctrl_entry->next;
146 145
147 for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) { 146 for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
148 struct bank_info *bp; 147 struct chmc_bank_info *bp;
149 148
150 bp = &mp->logical_banks[bank_no]; 149 bp = &p->logical_banks[bank_no];
151 if (bank_match(bp, phys_addr)) 150 if (chmc_bank_match(bp, phys_addr))
152 return bp; 151 return bp;
153 } 152 }
154 } 153 }
@@ -163,11 +162,11 @@ int chmc_getunumber(int syndrome_code,
163 unsigned long phys_addr, 162 unsigned long phys_addr,
164 char *buf, int buflen) 163 char *buf, int buflen)
165{ 164{
166 struct bank_info *bp; 165 struct chmc_bank_info *bp;
167 struct obp_mem_layout *prop; 166 struct chmc_obp_mem_layout *prop;
168 int bank_in_controller, first_dimm; 167 int bank_in_controller, first_dimm;
169 168
170 bp = find_bank(phys_addr); 169 bp = chmc_find_bank(phys_addr);
171 if (bp == NULL || 170 if (bp == NULL ||
172 syndrome_code < SYNDROME_MIN || 171 syndrome_code < SYNDROME_MIN ||
173 syndrome_code > SYNDROME_MAX) { 172 syndrome_code > SYNDROME_MAX) {
@@ -178,13 +177,13 @@ int chmc_getunumber(int syndrome_code,
178 return 0; 177 return 0;
179 } 178 }
180 179
181 prop = &bp->mp->layout_prop; 180 prop = &bp->p->layout_prop;
182 bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1); 181 bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
183 first_dimm = (bank_in_controller & (CHMCTRL_NDGRPS - 1)); 182 first_dimm = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
184 first_dimm *= CHMCTRL_NDIMMS; 183 first_dimm *= CHMCTRL_NDIMMS;
185 184
186 if (syndrome_code != SYNDROME_MIN) { 185 if (syndrome_code != SYNDROME_MIN) {
187 struct obp_map *map; 186 struct chmc_obp_map *map;
188 int qword, where_in_line, where, map_index, map_offset; 187 int qword, where_in_line, where, map_index, map_offset;
189 unsigned int map_val; 188 unsigned int map_val;
190 189
@@ -252,7 +251,7 @@ int chmc_getunumber(int syndrome_code,
252 * the code is executing, you must use special ASI load/store else 251 * the code is executing, you must use special ASI load/store else
253 * you go through the global mapping. 252 * you go through the global mapping.
254 */ 253 */
255static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset) 254static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset)
256{ 255{
257 unsigned long ret, this_cpu; 256 unsigned long ret, this_cpu;
258 257
@@ -260,14 +259,14 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
260 259
261 this_cpu = real_hard_smp_processor_id(); 260 this_cpu = real_hard_smp_processor_id();
262 261
263 if (mp->portid == this_cpu) { 262 if (p->portid == this_cpu) {
264 __asm__ __volatile__("ldxa [%1] %2, %0" 263 __asm__ __volatile__("ldxa [%1] %2, %0"
265 : "=r" (ret) 264 : "=r" (ret)
266 : "r" (offset), "i" (ASI_MCU_CTRL_REG)); 265 : "r" (offset), "i" (ASI_MCU_CTRL_REG));
267 } else { 266 } else {
268 __asm__ __volatile__("ldxa [%1] %2, %0" 267 __asm__ __volatile__("ldxa [%1] %2, %0"
269 : "=r" (ret) 268 : "=r" (ret)
270 : "r" (mp->regs + offset), 269 : "r" (p->regs + offset),
271 "i" (ASI_PHYS_BYPASS_EC_E)); 270 "i" (ASI_PHYS_BYPASS_EC_E));
272 } 271 }
273 272
@@ -277,164 +276,168 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
277} 276}
278 277
279#if 0 /* currently unused */ 278#if 0 /* currently unused */
280static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val) 279static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val)
281{ 280{
282 if (mp->portid == smp_processor_id()) { 281 if (p->portid == smp_processor_id()) {
283 __asm__ __volatile__("stxa %0, [%1] %2" 282 __asm__ __volatile__("stxa %0, [%1] %2"
284 : : "r" (val), 283 : : "r" (val),
285 "r" (offset), "i" (ASI_MCU_CTRL_REG)); 284 "r" (offset), "i" (ASI_MCU_CTRL_REG));
286 } else { 285 } else {
287 __asm__ __volatile__("ldxa %0, [%1] %2" 286 __asm__ __volatile__("ldxa %0, [%1] %2"
288 : : "r" (val), 287 : : "r" (val),
289 "r" (mp->regs + offset), 288 "r" (p->regs + offset),
290 "i" (ASI_PHYS_BYPASS_EC_E)); 289 "i" (ASI_PHYS_BYPASS_EC_E));
291 } 290 }
292} 291}
293#endif 292#endif
294 293
295static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val) 294static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val)
296{ 295{
297 struct bank_info *p = &mp->logical_banks[which_bank]; 296 struct chmc_bank_info *bp = &p->logical_banks[which_bank];
298 297
299 p->mp = mp; 298 bp->p = p;
300 p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank; 299 bp->bank_id = (CHMCTRL_NBANKS * p->portid) + which_bank;
301 p->raw_reg = val; 300 bp->raw_reg = val;
302 p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT; 301 bp->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
303 p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT; 302 bp->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
304 p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT; 303 bp->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
305 p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT; 304 bp->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
306 p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT; 305 bp->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
307 306
308 p->base = (p->um); 307 bp->base = (bp->um);
309 p->base &= ~(p->uk); 308 bp->base &= ~(bp->uk);
310 p->base <<= PA_UPPER_BITS_SHIFT; 309 bp->base <<= PA_UPPER_BITS_SHIFT;
311 310
312 switch(p->lk) { 311 switch(bp->lk) {
313 case 0xf: 312 case 0xf:
314 default: 313 default:
315 p->interleave = 1; 314 bp->interleave = 1;
316 break; 315 break;
317 316
318 case 0xe: 317 case 0xe:
319 p->interleave = 2; 318 bp->interleave = 2;
320 break; 319 break;
321 320
322 case 0xc: 321 case 0xc:
323 p->interleave = 4; 322 bp->interleave = 4;
324 break; 323 break;
325 324
326 case 0x8: 325 case 0x8:
327 p->interleave = 8; 326 bp->interleave = 8;
328 break; 327 break;
329 328
330 case 0x0: 329 case 0x0:
331 p->interleave = 16; 330 bp->interleave = 16;
332 break; 331 break;
333 }; 332 };
334 333
335 /* UK[10] is reserved, and UK[11] is not set for the SDRAM 334 /* UK[10] is reserved, and UK[11] is not set for the SDRAM
336 * bank size definition. 335 * bank size definition.
337 */ 336 */
338 p->size = (((unsigned long)p->uk & 337 bp->size = (((unsigned long)bp->uk &
339 ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT; 338 ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
340 p->size /= p->interleave; 339 bp->size /= bp->interleave;
341} 340}
342 341
343static void fetch_decode_regs(struct mctrl_info *mp) 342static void chmc_fetch_decode_regs(struct chmc *p)
344{ 343{
345 if (mp->layout_size == 0) 344 if (p->layout_size == 0)
346 return; 345 return;
347 346
348 interpret_one_decode_reg(mp, 0, 347 chmc_interpret_one_decode_reg(p, 0,
349 read_mcreg(mp, CHMCTRL_DECODE1)); 348 chmc_read_mcreg(p, CHMCTRL_DECODE1));
350 interpret_one_decode_reg(mp, 1, 349 chmc_interpret_one_decode_reg(p, 1,
351 read_mcreg(mp, CHMCTRL_DECODE2)); 350 chmc_read_mcreg(p, CHMCTRL_DECODE2));
352 interpret_one_decode_reg(mp, 2, 351 chmc_interpret_one_decode_reg(p, 2,
353 read_mcreg(mp, CHMCTRL_DECODE3)); 352 chmc_read_mcreg(p, CHMCTRL_DECODE3));
354 interpret_one_decode_reg(mp, 3, 353 chmc_interpret_one_decode_reg(p, 3,
355 read_mcreg(mp, CHMCTRL_DECODE4)); 354 chmc_read_mcreg(p, CHMCTRL_DECODE4));
356} 355}
357 356
358static int __devinit chmc_probe(struct of_device *op, 357static int __devinit chmc_probe(struct of_device *op,
359 const struct of_device_id *match) 358 const struct of_device_id *match)
360{ 359{
361 struct device_node *dp = op->node; 360 struct device_node *dp = op->node;
362 struct mctrl_info *mp;
363 unsigned long ver; 361 unsigned long ver;
364 const void *pval; 362 const void *pval;
365 int len, portid; 363 int len, portid;
364 struct chmc *p;
365 int err;
366 366
367 err = -ENODEV;
367 __asm__ ("rdpr %%ver, %0" : "=r" (ver)); 368 __asm__ ("rdpr %%ver, %0" : "=r" (ver));
368 if ((ver >> 32UL) == __JALAPENO_ID || 369 if ((ver >> 32UL) == __JALAPENO_ID ||
369 (ver >> 32UL) == __SERRANO_ID) 370 (ver >> 32UL) == __SERRANO_ID)
370 return -ENODEV; 371 goto out;
371
372 mp = kzalloc(sizeof(*mp), GFP_KERNEL);
373 if (!mp)
374 return -ENOMEM;
375 372
376 portid = of_getintprop_default(dp, "portid", -1); 373 portid = of_getintprop_default(dp, "portid", -1);
377 if (portid == -1) 374 if (portid == -1)
378 goto fail; 375 goto out;
379 376
380 mp->portid = portid;
381 pval = of_get_property(dp, "memory-layout", &len); 377 pval = of_get_property(dp, "memory-layout", &len);
382 mp->layout_size = len; 378 if (pval && len > sizeof(p->layout_prop)) {
383 if (!pval) 379 printk(KERN_ERR PFX "Unexpected memory-layout property "
384 mp->layout_size = 0; 380 "size %d.\n", len);
385 else { 381 goto out;
386 if (mp->layout_size > sizeof(mp->layout_prop)) { 382 }
387 printk(KERN_ERR PFX "Unexpected memory-layout property " 383
388 "size %d.\n", mp->layout_size); 384 err = -ENOMEM;
389 goto fail; 385 p = kzalloc(sizeof(*p), GFP_KERNEL);
390 } 386 if (!p) {
391 memcpy(&mp->layout_prop, pval, len); 387 printk(KERN_ERR PFX "Could not allocate struct chmc.\n");
388 goto out;
392 } 389 }
393 390
394 mp->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc"); 391 p->portid = portid;
395 if (!mp->regs) { 392 p->layout_size = len;
393 if (!pval)
394 p->layout_size = 0;
395 else
396 memcpy(&p->layout_prop, pval, len);
397
398 p->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc");
399 if (!p->regs) {
396 printk(KERN_ERR PFX "Could not map registers.\n"); 400 printk(KERN_ERR PFX "Could not map registers.\n");
397 goto fail; 401 goto out_free;
398 } 402 }
399 403
400 if (mp->layout_size != 0UL) { 404 if (p->layout_size != 0UL) {
401 mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1); 405 p->timing_control1 = chmc_read_mcreg(p, CHMCTRL_TCTRL1);
402 mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2); 406 p->timing_control2 = chmc_read_mcreg(p, CHMCTRL_TCTRL2);
403 mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3); 407 p->timing_control3 = chmc_read_mcreg(p, CHMCTRL_TCTRL3);
404 mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4); 408 p->timing_control4 = chmc_read_mcreg(p, CHMCTRL_TCTRL4);
405 mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL); 409 p->memaddr_control = chmc_read_mcreg(p, CHMCTRL_MACTRL);
406 } 410 }
407 411
408 fetch_decode_regs(mp); 412 chmc_fetch_decode_regs(p);
409 413
410 list_add(&mp->list, &mctrl_list); 414 list_add(&p->list, &mctrl_list);
411 415
412 /* Report the device. */ 416 /* Report the device. */
413 printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n", 417 printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n",
414 dp->full_name, 418 dp->full_name,
415 (mp->layout_size ? "ACTIVE" : "INACTIVE")); 419 (p->layout_size ? "ACTIVE" : "INACTIVE"));
416 420
417 dev_set_drvdata(&op->dev, mp); 421 dev_set_drvdata(&op->dev, p);
418 422
419 return 0; 423 err = 0;
420 424
421fail: 425out:
422 if (mp) { 426 return err;
423 if (mp->regs != NULL) 427
424 of_iounmap(&op->resource[0], mp->regs, 0x48); 428out_free:
425 kfree(mp); 429 kfree(p);
426 } 430 goto out;
427 return -1;
428} 431}
429 432
430static int __devexit chmc_remove(struct of_device *op) 433static int __devexit chmc_remove(struct of_device *op)
431{ 434{
432 struct mctrl_info *mp = dev_get_drvdata(&op->dev); 435 struct chmc *p = dev_get_drvdata(&op->dev);
433 436
434 if (mp) { 437 if (p) {
435 list_del(&mp->list); 438 list_del(&p->list);
436 of_iounmap(&op->resource[0], mp->regs, 0x48); 439 of_iounmap(&op->resource[0], p->regs, 0x48);
437 kfree(mp); 440 kfree(p);
438 } 441 }
439 return 0; 442 return 0;
440} 443}