aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/traps.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-02-08 05:53:50 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-03-20 04:12:01 -0500
commit5b0c0572fcd6204675c5f7ddfa572b5017f817dd (patch)
tree1075a61338e887bd6d4ecd4517646ef95dc09fbc /arch/sparc64/kernel/traps.c
parentac29c11d4cd4fa1fac968e99998a956405732f2f (diff)
[SPARC64]: Sun4v interrupt handling.
Sun4v has 4 interrupt queues: cpu, device, resumable errors, and non-resumable errors. A set of head/tail offset pointers help maintain a work queue in physical memory. The entries are 64-bytes in size. Each queue is allocated then registered with the hypervisor as we bring cpus up. The two error queues each get a kernel side buffer that we use to quickly empty the main interrupt queue before we call up to C code to log the event and possibly take evasive action. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/traps.c')
-rw-r--r--arch/sparc64/kernel/traps.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 8f3fce24359d..5417ff1b9345 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1668,6 +1668,186 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs)
1668 regs->tpc); 1668 regs->tpc);
1669} 1669}
1670 1670
1671struct sun4v_error_entry {
1672 u64 err_handle;
1673 u64 err_stick;
1674
1675 u32 err_type;
1676#define SUN4V_ERR_TYPE_UNDEFINED 0
1677#define SUN4V_ERR_TYPE_UNCORRECTED_RES 1
1678#define SUN4V_ERR_TYPE_PRECISE_NONRES 2
1679#define SUN4V_ERR_TYPE_DEFERRED_NONRES 3
1680#define SUN4V_ERR_TYPE_WARNING_RES 4
1681
1682 u32 err_attrs;
1683#define SUN4V_ERR_ATTRS_PROCESSOR 0x00000001
1684#define SUN4V_ERR_ATTRS_MEMORY 0x00000002
1685#define SUN4V_ERR_ATTRS_PIO 0x00000004
1686#define SUN4V_ERR_ATTRS_INT_REGISTERS 0x00000008
1687#define SUN4V_ERR_ATTRS_FPU_REGISTERS 0x00000010
1688#define SUN4V_ERR_ATTRS_USER_MODE 0x01000000
1689#define SUN4V_ERR_ATTRS_PRIV_MODE 0x02000000
1690#define SUN4V_ERR_ATTRS_RES_QUEUE_FULL 0x80000000
1691
1692 u64 err_raddr;
1693 u32 err_size;
1694 u16 err_cpu;
1695 u16 err_pad;
1696};
1697
1698static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0);
1699static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0);
1700
1701static const char *sun4v_err_type_to_str(u32 type)
1702{
1703 switch (type) {
1704 case SUN4V_ERR_TYPE_UNDEFINED:
1705 return "undefined";
1706 case SUN4V_ERR_TYPE_UNCORRECTED_RES:
1707 return "uncorrected resumable";
1708 case SUN4V_ERR_TYPE_PRECISE_NONRES:
1709 return "precise nonresumable";
1710 case SUN4V_ERR_TYPE_DEFERRED_NONRES:
1711 return "deferred nonresumable";
1712 case SUN4V_ERR_TYPE_WARNING_RES:
1713 return "warning resumable";
1714 default:
1715 return "unknown";
1716 };
1717}
1718
1719static void sun4v_log_error(struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt)
1720{
1721 int cnt;
1722
1723 printk("%s: Reporting on cpu %d\n", pfx, cpu);
1724 printk("%s: err_handle[%lx] err_stick[%lx] err_type[%08x:%s]\n",
1725 pfx,
1726 ent->err_handle, ent->err_stick,
1727 ent->err_type,
1728 sun4v_err_type_to_str(ent->err_type));
1729 printk("%s: err_attrs[%08x:%s %s %s %s %s %s %s %s]\n",
1730 pfx,
1731 ent->err_attrs,
1732 ((ent->err_attrs & SUN4V_ERR_ATTRS_PROCESSOR) ?
1733 "processor" : ""),
1734 ((ent->err_attrs & SUN4V_ERR_ATTRS_MEMORY) ?
1735 "memory" : ""),
1736 ((ent->err_attrs & SUN4V_ERR_ATTRS_PIO) ?
1737 "pio" : ""),
1738 ((ent->err_attrs & SUN4V_ERR_ATTRS_INT_REGISTERS) ?
1739 "integer-regs" : ""),
1740 ((ent->err_attrs & SUN4V_ERR_ATTRS_FPU_REGISTERS) ?
1741 "fpu-regs" : ""),
1742 ((ent->err_attrs & SUN4V_ERR_ATTRS_USER_MODE) ?
1743 "user" : ""),
1744 ((ent->err_attrs & SUN4V_ERR_ATTRS_PRIV_MODE) ?
1745 "privileged" : ""),
1746 ((ent->err_attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) ?
1747 "queue-full" : ""));
1748 printk("%s: err_raddr[%016lx] err_size[%u] err_cpu[%u]\n",
1749 pfx,
1750 ent->err_raddr, ent->err_size, ent->err_cpu);
1751
1752 if ((cnt = atomic_read(ocnt)) != 0) {
1753 atomic_set(ocnt, 0);
1754 wmb();
1755 printk("%s: Queue overflowed %d times.\n",
1756 pfx, cnt);
1757 }
1758}
1759
1760/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
1761 * Log the event and clear the first word of the entry.
1762 */
1763void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
1764{
1765 struct sun4v_error_entry *ent, local_copy;
1766 struct trap_per_cpu *tb;
1767 unsigned long paddr;
1768 int cpu;
1769
1770 cpu = get_cpu();
1771
1772 tb = &trap_block[cpu];
1773 paddr = tb->resum_kernel_buf_pa + offset;
1774 ent = __va(paddr);
1775
1776 memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry));
1777
1778 /* We have a local copy now, so release the entry. */
1779 ent->err_handle = 0;
1780 wmb();
1781
1782 put_cpu();
1783
1784 sun4v_log_error(&local_copy, cpu,
1785 KERN_ERR "RESUMABLE ERROR",
1786 &sun4v_resum_oflow_cnt);
1787}
1788
1789/* If we try to printk() we'll probably make matters worse, by trying
1790 * to retake locks this cpu already holds or causing more errors. So
1791 * just bump a counter, and we'll report these counter bumps above.
1792 */
1793void sun4v_resum_overflow(struct pt_regs *regs)
1794{
1795 atomic_inc(&sun4v_resum_oflow_cnt);
1796}
1797
1798/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
1799 * Log the event, clear the first word of the entry, and die.
1800 */
1801void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)
1802{
1803 struct sun4v_error_entry *ent, local_copy;
1804 struct trap_per_cpu *tb;
1805 unsigned long paddr;
1806 int cpu;
1807
1808 cpu = get_cpu();
1809
1810 tb = &trap_block[cpu];
1811 paddr = tb->nonresum_kernel_buf_pa + offset;
1812 ent = __va(paddr);
1813
1814 memcpy(&local_copy, ent, sizeof(struct sun4v_error_entry));
1815
1816 /* We have a local copy now, so release the entry. */
1817 ent->err_handle = 0;
1818 wmb();
1819
1820 put_cpu();
1821
1822#ifdef CONFIG_PCI
1823 /* Check for the special PCI poke sequence. */
1824 if (pci_poke_in_progress && pci_poke_cpu == cpu) {
1825 pci_poke_faulted = 1;
1826 regs->tpc += 4;
1827 regs->tnpc = regs->tpc + 4;
1828 return;
1829 }
1830#endif
1831
1832 sun4v_log_error(&local_copy, cpu,
1833 KERN_EMERG "NON-RESUMABLE ERROR",
1834 &sun4v_nonresum_oflow_cnt);
1835
1836 panic("Non-resumable error.");
1837}
1838
1839/* If we try to printk() we'll probably make matters worse, by trying
1840 * to retake locks this cpu already holds or causing more errors. So
1841 * just bump a counter, and we'll report these counter bumps above.
1842 */
1843void sun4v_nonresum_overflow(struct pt_regs *regs)
1844{
1845 /* XXX Actually even this can make not that much sense. Perhaps
1846 * XXX we should just pull the plug and panic directly from here?
1847 */
1848 atomic_inc(&sun4v_nonresum_oflow_cnt);
1849}
1850
1671void do_fpe_common(struct pt_regs *regs) 1851void do_fpe_common(struct pt_regs *regs)
1672{ 1852{
1673 if (regs->tstate & TSTATE_PRIV) { 1853 if (regs->tstate & TSTATE_PRIV) {
@@ -2190,8 +2370,12 @@ void __init trap_init(void)
2190 offsetof(struct trap_per_cpu, dev_mondo_pa)) || 2370 offsetof(struct trap_per_cpu, dev_mondo_pa)) ||
2191 (TRAP_PER_CPU_RESUM_MONDO_PA != 2371 (TRAP_PER_CPU_RESUM_MONDO_PA !=
2192 offsetof(struct trap_per_cpu, resum_mondo_pa)) || 2372 offsetof(struct trap_per_cpu, resum_mondo_pa)) ||
2373 (TRAP_PER_CPU_RESUM_KBUF_PA !=
2374 offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) ||
2193 (TRAP_PER_CPU_NONRESUM_MONDO_PA != 2375 (TRAP_PER_CPU_NONRESUM_MONDO_PA !=
2194 offsetof(struct trap_per_cpu, nonresum_mondo_pa)) || 2376 offsetof(struct trap_per_cpu, nonresum_mondo_pa)) ||
2377 (TRAP_PER_CPU_NONRESUM_KBUF_PA !=
2378 offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
2195 (TRAP_PER_CPU_FAULT_INFO != 2379 (TRAP_PER_CPU_FAULT_INFO !=
2196 offsetof(struct trap_per_cpu, fault_info))) 2380 offsetof(struct trap_per_cpu, fault_info)))
2197 trap_per_cpu_offsets_are_bolixed_dave(); 2381 trap_per_cpu_offsets_are_bolixed_dave();