in kernel/traps_64.c [1572:1757]
void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
{
struct cheetah_err_info local_snapshot, *p;
int recoverable, is_memory;
#ifdef CONFIG_PCI
/* Check for the special PCI poke sequence. */
if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
cheetah_flush_icache();
cheetah_flush_dcache();
/* Re-enable I-cache/D-cache */
__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
"or %%g1, %1, %%g1\n\t"
"stxa %%g1, [%%g0] %0\n\t"
"membar #Sync"
: /* no outputs */
: "i" (ASI_DCU_CONTROL_REG),
"i" (DCU_DC | DCU_IC)
: "g1");
/* Re-enable error reporting */
__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
"or %%g1, %1, %%g1\n\t"
"stxa %%g1, [%%g0] %0\n\t"
"membar #Sync"
: /* no outputs */
: "i" (ASI_ESTATE_ERROR_EN),
"i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
: "g1");
(void) cheetah_recheck_errors(NULL);
pci_poke_faulted = 1;
regs->tpc += 4;
regs->tnpc = regs->tpc + 4;
return;
}
#endif
p = cheetah_get_error_log(afsr);
if (!p) {
prom_printf("ERROR: Early deferred error afsr[%016lx] afar[%016lx]\n",
afsr, afar);
prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
prom_halt();
}
/* Grab snapshot of logged error. */
memcpy(&local_snapshot, p, sizeof(local_snapshot));
/* If the current trap snapshot does not match what the
* trap handler passed along into our args, big trouble.
* In such a case, mark the local copy as invalid.
*
* Else, it matches and we mark the afsr in the non-local
* copy as invalid so we may log new error traps there.
*/
if (p->afsr != afsr || p->afar != afar)
local_snapshot.afsr = CHAFSR_INVALID;
else
p->afsr = CHAFSR_INVALID;
is_memory = cheetah_check_main_memory(afar);
{
int flush_all, flush_line;
flush_all = flush_line = 0;
if ((afsr & CHAFSR_EDU) != 0UL) {
if ((afsr & cheetah_afsr_errors) == CHAFSR_EDU)
flush_line = 1;
else
flush_all = 1;
} else if ((afsr & CHAFSR_BERR) != 0UL) {
if ((afsr & cheetah_afsr_errors) == CHAFSR_BERR)
flush_line = 1;
else
flush_all = 1;
}
cheetah_flush_icache();
cheetah_flush_dcache();
/* Re-enable I/D caches */
__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
"or %%g1, %1, %%g1\n\t"
"stxa %%g1, [%%g0] %0\n\t"
"membar #Sync"
: /* no outputs */
: "i" (ASI_DCU_CONTROL_REG),
"i" (DCU_IC | DCU_DC)
: "g1");
if (flush_all)
cheetah_flush_ecache();
else if (flush_line)
cheetah_flush_ecache_line(afar);
}
/* Re-enable error reporting */
__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
"or %%g1, %1, %%g1\n\t"
"stxa %%g1, [%%g0] %0\n\t"
"membar #Sync"
: /* no outputs */
: "i" (ASI_ESTATE_ERROR_EN),
"i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
: "g1");
/* Decide if we can continue after handling this trap and
* logging the error.
*/
recoverable = 1;
if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
recoverable = 0;
/* Re-check AFSR/AFAR. What we are looking for here is whether a new
* error was logged while we had error reporting traps disabled.
*/
if (cheetah_recheck_errors(&local_snapshot)) {
unsigned long new_afsr = local_snapshot.afsr;
/* If we got a new asynchronous error, die... */
if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU |
CHAFSR_WDU | CHAFSR_CPU |
CHAFSR_IVU | CHAFSR_UE |
CHAFSR_BERR | CHAFSR_TO))
recoverable = 0;
}
/* Log errors. */
cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);
/* "Recoverable" here means we try to yank the page from ever
* being newly used again. This depends upon a few things:
* 1) Must be main memory, and AFAR must be valid.
* 2) If we trapped from user, OK.
* 3) Else, if we trapped from kernel we must find exception
* table entry (ie. we have to have been accessing user
* space).
*
* If AFAR is not in main memory, or we trapped from kernel
* and cannot find an exception table entry, it is unacceptable
* to try and continue.
*/
if (recoverable && is_memory) {
if ((regs->tstate & TSTATE_PRIV) == 0UL) {
/* OK, usermode access. */
recoverable = 1;
} else {
const struct exception_table_entry *entry;
entry = search_exception_tables(regs->tpc);
if (entry) {
/* OK, kernel access to userspace. */
recoverable = 1;
} else {
/* BAD, privileged state is corrupted. */
recoverable = 0;
}
if (recoverable) {
if (pfn_valid(afar >> PAGE_SHIFT))
get_page(pfn_to_page(afar >> PAGE_SHIFT));
else
recoverable = 0;
/* Only perform fixup if we still have a
* recoverable condition.
*/
if (recoverable) {
regs->tpc = entry->fixup;
regs->tnpc = regs->tpc + 4;
}
}
}
} else {
recoverable = 0;
}
if (!recoverable)
panic("Irrecoverable deferred error trap.\n");
}