aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/mca_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/mca_drv.c')
-rw-r--r--arch/ia64/kernel/mca_drv.c135
1 files changed, 84 insertions, 51 deletions
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index 6e683745af49..f081c60ab206 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -56,8 +56,9 @@ static struct page *page_isolate[MAX_PAGE_ISOLATE];
56static int num_page_isolate = 0; 56static int num_page_isolate = 0;
57 57
58typedef enum { 58typedef enum {
59 ISOLATE_NG = 0, 59 ISOLATE_NG,
60 ISOLATE_OK = 1 60 ISOLATE_OK,
61 ISOLATE_NONE
61} isolate_status_t; 62} isolate_status_t;
62 63
63/* 64/*
@@ -74,7 +75,7 @@ static struct {
74 * @paddr: poisoned memory location 75 * @paddr: poisoned memory location
75 * 76 *
76 * Return value: 77 * Return value:
77 * ISOLATE_OK / ISOLATE_NG 78 * one of isolate_status_t, ISOLATE_OK/NG/NONE.
78 */ 79 */
79 80
80static isolate_status_t 81static isolate_status_t
@@ -84,23 +85,26 @@ mca_page_isolate(unsigned long paddr)
84 struct page *p; 85 struct page *p;
85 86
86 /* whether physical address is valid or not */ 87 /* whether physical address is valid or not */
87 if ( !ia64_phys_addr_valid(paddr) ) 88 if (!ia64_phys_addr_valid(paddr))
88 return ISOLATE_NG; 89 return ISOLATE_NONE;
90
91 if (!pfn_valid(paddr))
92 return ISOLATE_NONE;
89 93
90 /* convert physical address to physical page number */ 94 /* convert physical address to physical page number */
91 p = pfn_to_page(paddr>>PAGE_SHIFT); 95 p = pfn_to_page(paddr>>PAGE_SHIFT);
92 96
93 /* check whether a page number have been already registered or not */ 97 /* check whether a page number have been already registered or not */
94 for( i = 0; i < num_page_isolate; i++ ) 98 for (i = 0; i < num_page_isolate; i++)
95 if( page_isolate[i] == p ) 99 if (page_isolate[i] == p)
96 return ISOLATE_OK; /* already listed */ 100 return ISOLATE_OK; /* already listed */
97 101
98 /* limitation check */ 102 /* limitation check */
99 if( num_page_isolate == MAX_PAGE_ISOLATE ) 103 if (num_page_isolate == MAX_PAGE_ISOLATE)
100 return ISOLATE_NG; 104 return ISOLATE_NG;
101 105
102 /* kick pages having attribute 'SLAB' or 'Reserved' */ 106 /* kick pages having attribute 'SLAB' or 'Reserved' */
103 if( PageSlab(p) || PageReserved(p) ) 107 if (PageSlab(p) || PageReserved(p))
104 return ISOLATE_NG; 108 return ISOLATE_NG;
105 109
106 /* add attribute 'Reserved' and register the page */ 110 /* add attribute 'Reserved' and register the page */
@@ -122,10 +126,15 @@ mca_handler_bh(unsigned long paddr)
122 current->pid, current->comm); 126 current->pid, current->comm);
123 127
124 spin_lock(&mca_bh_lock); 128 spin_lock(&mca_bh_lock);
125 if (mca_page_isolate(paddr) == ISOLATE_OK) { 129 switch (mca_page_isolate(paddr)) {
130 case ISOLATE_OK:
126 printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr); 131 printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr);
127 } else { 132 break;
133 case ISOLATE_NG:
128 printk(KERN_DEBUG "Page isolation: ( %lx ) failure.\n", paddr); 134 printk(KERN_DEBUG "Page isolation: ( %lx ) failure.\n", paddr);
135 break;
136 default:
137 break;
129 } 138 }
130 spin_unlock(&mca_bh_lock); 139 spin_unlock(&mca_bh_lock);
131 140
@@ -139,10 +148,10 @@ mca_handler_bh(unsigned long paddr)
139 * @peidx: pointer to index of processor error section 148 * @peidx: pointer to index of processor error section
140 */ 149 */
141 150
142static void 151static void
143mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx) 152mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx)
144{ 153{
145 /* 154 /*
146 * calculate the start address of 155 * calculate the start address of
147 * "struct cpuid_info" and "sal_processor_static_info_t". 156 * "struct cpuid_info" and "sal_processor_static_info_t".
148 */ 157 */
@@ -164,7 +173,7 @@ mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx)
164} 173}
165 174
166/** 175/**
167 * mca_make_slidx - Make index of SAL error record 176 * mca_make_slidx - Make index of SAL error record
168 * @buffer: pointer to SAL error record 177 * @buffer: pointer to SAL error record
169 * @slidx: pointer to index of SAL error record 178 * @slidx: pointer to index of SAL error record
170 * 179 *
@@ -172,12 +181,12 @@ mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx)
172 * 1 if record has platform error / 0 if not 181 * 1 if record has platform error / 0 if not
173 */ 182 */
174#define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \ 183#define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \
175 { slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \ 184 {slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \
176 hl->hdr = ptr; \ 185 hl->hdr = ptr; \
177 list_add(&hl->list, &(sect)); \ 186 list_add(&hl->list, &(sect)); \
178 slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; } 187 slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; }
179 188
180static int 189static int
181mca_make_slidx(void *buffer, slidx_table_t *slidx) 190mca_make_slidx(void *buffer, slidx_table_t *slidx)
182{ 191{
183 int platform_err = 0; 192 int platform_err = 0;
@@ -214,28 +223,36 @@ mca_make_slidx(void *buffer, slidx_table_t *slidx)
214 sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos); 223 sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos);
215 if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) { 224 if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) {
216 LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp); 225 LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp);
217 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) { 226 } else if (!efi_guidcmp(sp->guid,
227 SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) {
218 platform_err = 1; 228 platform_err = 1;
219 LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp); 229 LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp);
220 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) { 230 } else if (!efi_guidcmp(sp->guid,
231 SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) {
221 platform_err = 1; 232 platform_err = 1;
222 LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp); 233 LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp);
223 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) { 234 } else if (!efi_guidcmp(sp->guid,
235 SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) {
224 platform_err = 1; 236 platform_err = 1;
225 LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp); 237 LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp);
226 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) { 238 } else if (!efi_guidcmp(sp->guid,
239 SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) {
227 platform_err = 1; 240 platform_err = 1;
228 LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp); 241 LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp);
229 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) { 242 } else if (!efi_guidcmp(sp->guid,
243 SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) {
230 platform_err = 1; 244 platform_err = 1;
231 LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp); 245 LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp);
232 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) { 246 } else if (!efi_guidcmp(sp->guid,
247 SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) {
233 platform_err = 1; 248 platform_err = 1;
234 LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp); 249 LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp);
235 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) { 250 } else if (!efi_guidcmp(sp->guid,
251 SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) {
236 platform_err = 1; 252 platform_err = 1;
237 LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp); 253 LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp);
238 } else if (!efi_guidcmp(sp->guid, SAL_PLAT_BUS_ERR_SECT_GUID)) { 254 } else if (!efi_guidcmp(sp->guid,
255 SAL_PLAT_BUS_ERR_SECT_GUID)) {
239 platform_err = 1; 256 platform_err = 1;
240 LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp); 257 LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp);
241 } else { 258 } else {
@@ -253,15 +270,16 @@ mca_make_slidx(void *buffer, slidx_table_t *slidx)
253 * Return value: 270 * Return value:
254 * 0 on Success / -ENOMEM on Failure 271 * 0 on Success / -ENOMEM on Failure
255 */ 272 */
256static int 273static int
257init_record_index_pools(void) 274init_record_index_pools(void)
258{ 275{
259 int i; 276 int i;
260 int rec_max_size; /* Maximum size of SAL error records */ 277 int rec_max_size; /* Maximum size of SAL error records */
261 int sect_min_size; /* Minimum size of SAL error sections */ 278 int sect_min_size; /* Minimum size of SAL error sections */
262 /* minimum size table of each section */ 279 /* minimum size table of each section */
263 static int sal_log_sect_min_sizes[] = { 280 static int sal_log_sect_min_sizes[] = {
264 sizeof(sal_log_processor_info_t) + sizeof(sal_processor_static_info_t), 281 sizeof(sal_log_processor_info_t)
282 + sizeof(sal_processor_static_info_t),
265 sizeof(sal_log_mem_dev_err_info_t), 283 sizeof(sal_log_mem_dev_err_info_t),
266 sizeof(sal_log_sel_dev_err_info_t), 284 sizeof(sal_log_sel_dev_err_info_t),
267 sizeof(sal_log_pci_bus_err_info_t), 285 sizeof(sal_log_pci_bus_err_info_t),
@@ -294,7 +312,8 @@ init_record_index_pools(void)
294 312
295 /* - 3 - */ 313 /* - 3 - */
296 slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1; 314 slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1;
297 slidx_pool.buffer = (slidx_list_t *) kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL); 315 slidx_pool.buffer = (slidx_list_t *)
316 kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL);
298 317
299 return slidx_pool.buffer ? 0 : -ENOMEM; 318 return slidx_pool.buffer ? 0 : -ENOMEM;
300} 319}
@@ -308,6 +327,7 @@ init_record_index_pools(void)
308 * is_mca_global - Check whether this MCA is global or not 327 * is_mca_global - Check whether this MCA is global or not
309 * @peidx: pointer of index of processor error section 328 * @peidx: pointer of index of processor error section
310 * @pbci: pointer to pal_bus_check_info_t 329 * @pbci: pointer to pal_bus_check_info_t
330 * @sos: pointer to hand off struct between SAL and OS
311 * 331 *
312 * Return value: 332 * Return value:
313 * MCA_IS_LOCAL / MCA_IS_GLOBAL 333 * MCA_IS_LOCAL / MCA_IS_GLOBAL
@@ -317,11 +337,12 @@ static mca_type_t
317is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci, 337is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci,
318 struct ia64_sal_os_state *sos) 338 struct ia64_sal_os_state *sos)
319{ 339{
320 pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); 340 pal_processor_state_info_t *psp =
341 (pal_processor_state_info_t*)peidx_psp(peidx);
321 342
322 /* 343 /*
323 * PAL can request a rendezvous, if the MCA has a global scope. 344 * PAL can request a rendezvous, if the MCA has a global scope.
324 * If "rz_always" flag is set, SAL requests MCA rendezvous 345 * If "rz_always" flag is set, SAL requests MCA rendezvous
325 * in spite of global MCA. 346 * in spite of global MCA.
326 * Therefore it is local MCA when rendezvous has not been requested. 347 * Therefore it is local MCA when rendezvous has not been requested.
327 * Failed to rendezvous, the system must be down. 348 * Failed to rendezvous, the system must be down.
@@ -381,13 +402,15 @@ is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci,
381 * @slidx: pointer of index of SAL error record 402 * @slidx: pointer of index of SAL error record
382 * @peidx: pointer of index of processor error section 403 * @peidx: pointer of index of processor error section
383 * @pbci: pointer of pal_bus_check_info 404 * @pbci: pointer of pal_bus_check_info
405 * @sos: pointer to hand off struct between SAL and OS
384 * 406 *
385 * Return value: 407 * Return value:
386 * 1 on Success / 0 on Failure 408 * 1 on Success / 0 on Failure
387 */ 409 */
388 410
389static int 411static int
390recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, 412recover_from_read_error(slidx_table_t *slidx,
413 peidx_table_t *peidx, pal_bus_check_info_t *pbci,
391 struct ia64_sal_os_state *sos) 414 struct ia64_sal_os_state *sos)
392{ 415{
393 sal_log_mod_error_info_t *smei; 416 sal_log_mod_error_info_t *smei;
@@ -453,24 +476,28 @@ recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_chec
453 * @slidx: pointer of index of SAL error record 476 * @slidx: pointer of index of SAL error record
454 * @peidx: pointer of index of processor error section 477 * @peidx: pointer of index of processor error section
455 * @pbci: pointer of pal_bus_check_info 478 * @pbci: pointer of pal_bus_check_info
479 * @sos: pointer to hand off struct between SAL and OS
456 * 480 *
457 * Return value: 481 * Return value:
458 * 1 on Success / 0 on Failure 482 * 1 on Success / 0 on Failure
459 */ 483 */
460 484
461static int 485static int
462recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, 486recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx,
487 pal_bus_check_info_t *pbci,
463 struct ia64_sal_os_state *sos) 488 struct ia64_sal_os_state *sos)
464{ 489{
465 int status = 0; 490 int status = 0;
466 pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); 491 pal_processor_state_info_t *psp =
492 (pal_processor_state_info_t*)peidx_psp(peidx);
467 493
468 if (psp->bc && pbci->eb && pbci->bsi == 0) { 494 if (psp->bc && pbci->eb && pbci->bsi == 0) {
469 switch(pbci->type) { 495 switch(pbci->type) {
470 case 1: /* partial read */ 496 case 1: /* partial read */
471 case 3: /* full line(cpu) read */ 497 case 3: /* full line(cpu) read */
472 case 9: /* I/O space read */ 498 case 9: /* I/O space read */
473 status = recover_from_read_error(slidx, peidx, pbci, sos); 499 status = recover_from_read_error(slidx, peidx, pbci,
500 sos);
474 break; 501 break;
475 case 0: /* unknown */ 502 case 0: /* unknown */
476 case 2: /* partial write */ 503 case 2: /* partial write */
@@ -481,7 +508,8 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_
481 case 8: /* write coalescing transactions */ 508 case 8: /* write coalescing transactions */
482 case 10: /* I/O space write */ 509 case 10: /* I/O space write */
483 case 11: /* inter-processor interrupt message(IPI) */ 510 case 11: /* inter-processor interrupt message(IPI) */
484 case 12: /* interrupt acknowledge or external task priority cycle */ 511 case 12: /* interrupt acknowledge or
512 external task priority cycle */
485 default: 513 default:
486 break; 514 break;
487 } 515 }
@@ -496,6 +524,7 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_
496 * @slidx: pointer of index of SAL error record 524 * @slidx: pointer of index of SAL error record
497 * @peidx: pointer of index of processor error section 525 * @peidx: pointer of index of processor error section
498 * @pbci: pointer of pal_bus_check_info 526 * @pbci: pointer of pal_bus_check_info
527 * @sos: pointer to hand off struct between SAL and OS
499 * 528 *
500 * Return value: 529 * Return value:
501 * 1 on Success / 0 on Failure 530 * 1 on Success / 0 on Failure
@@ -509,15 +538,17 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_
509 */ 538 */
510 539
511static int 540static int
512recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, 541recover_from_processor_error(int platform, slidx_table_t *slidx,
542 peidx_table_t *peidx, pal_bus_check_info_t *pbci,
513 struct ia64_sal_os_state *sos) 543 struct ia64_sal_os_state *sos)
514{ 544{
515 pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); 545 pal_processor_state_info_t *psp =
546 (pal_processor_state_info_t*)peidx_psp(peidx);
516 547
517 /* 548 /*
518 * We cannot recover errors with other than bus_check. 549 * We cannot recover errors with other than bus_check.
519 */ 550 */
520 if (psp->cc || psp->rc || psp->uc) 551 if (psp->cc || psp->rc || psp->uc)
521 return 0; 552 return 0;
522 553
523 /* 554 /*
@@ -546,10 +577,10 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *
546 * (e.g. a load from poisoned memory) 577 * (e.g. a load from poisoned memory)
547 * This means "there are some platform errors". 578 * This means "there are some platform errors".
548 */ 579 */
549 if (platform) 580 if (platform)
550 return recover_from_platform_error(slidx, peidx, pbci, sos); 581 return recover_from_platform_error(slidx, peidx, pbci, sos);
551 /* 582 /*
552 * On account of strange SAL error record, we cannot recover. 583 * On account of strange SAL error record, we cannot recover.
553 */ 584 */
554 return 0; 585 return 0;
555} 586}
@@ -557,14 +588,14 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *
557/** 588/**
558 * mca_try_to_recover - Try to recover from MCA 589 * mca_try_to_recover - Try to recover from MCA
559 * @rec: pointer to a SAL error record 590 * @rec: pointer to a SAL error record
591 * @sos: pointer to hand off struct between SAL and OS
560 * 592 *
561 * Return value: 593 * Return value:
562 * 1 on Success / 0 on Failure 594 * 1 on Success / 0 on Failure
563 */ 595 */
564 596
565static int 597static int
566mca_try_to_recover(void *rec, 598mca_try_to_recover(void *rec, struct ia64_sal_os_state *sos)
567 struct ia64_sal_os_state *sos)
568{ 599{
569 int platform_err; 600 int platform_err;
570 int n_proc_err; 601 int n_proc_err;
@@ -588,7 +619,8 @@ mca_try_to_recover(void *rec,
588 } 619 }
589 620
590 /* Make index of processor error section */ 621 /* Make index of processor error section */
591 mca_make_peidx((sal_log_processor_info_t*)slidx_first_entry(&slidx.proc_err)->hdr, &peidx); 622 mca_make_peidx((sal_log_processor_info_t*)
623 slidx_first_entry(&slidx.proc_err)->hdr, &peidx);
592 624
593 /* Extract Processor BUS_CHECK[0] */ 625 /* Extract Processor BUS_CHECK[0] */
594 *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0); 626 *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0);
@@ -598,7 +630,8 @@ mca_try_to_recover(void *rec,
598 return 0; 630 return 0;
599 631
600 /* Try to recover a processor error */ 632 /* Try to recover a processor error */
601 return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci, sos); 633 return recover_from_processor_error(platform_err, &slidx, &peidx,
634 &pbci, sos);
602} 635}
603 636
604/* 637/*
@@ -611,7 +644,7 @@ int __init mca_external_handler_init(void)
611 return -ENOMEM; 644 return -ENOMEM;
612 645
613 /* register external mca handlers */ 646 /* register external mca handlers */
614 if (ia64_reg_MCA_extension(mca_try_to_recover)){ 647 if (ia64_reg_MCA_extension(mca_try_to_recover)) {
615 printk(KERN_ERR "ia64_reg_MCA_extension failed.\n"); 648 printk(KERN_ERR "ia64_reg_MCA_extension failed.\n");
616 kfree(slidx_pool.buffer); 649 kfree(slidx_pool.buffer);
617 return -EFAULT; 650 return -EFAULT;