|
1 | 1 | /* arch/sparc64/kernel/traps.c
|
2 | 2 | *
|
3 |
| - * Copyright (C) 1995,1997,2008,2009 David S. Miller (davem@davemloft.net) |
| 3 | + * Copyright (C) 1995,1997,2008,2009,2012 David S. Miller (davem@davemloft.net) |
4 | 4 | * Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com)
|
5 | 5 | */
|
6 | 6 |
|
|
18 | 18 | #include <linux/init.h>
|
19 | 19 | #include <linux/kdebug.h>
|
20 | 20 | #include <linux/ftrace.h>
|
| 21 | +#include <linux/reboot.h> |
21 | 22 | #include <linux/gfp.h>
|
22 | 23 |
|
23 | 24 | #include <asm/smp.h>
|
@@ -1760,85 +1761,223 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs)
|
1760 | 1761 | }
|
1761 | 1762 |
|
1762 | 1763 | struct sun4v_error_entry {
|
1763 |
| - u64 err_handle; |
1764 |
| - u64 err_stick; |
| 1764 | + /* Unique error handle */ |
| 1765 | +/*0x00*/u64 err_handle; |
1765 | 1766 |
|
1766 |
| - u32 err_type; |
| 1767 | + /* %stick value at the time of the error */ |
| 1768 | +/*0x08*/u64 err_stick; |
| 1769 | + |
| 1770 | +/*0x10*/u8 reserved_1[3]; |
| 1771 | + |
| 1772 | + /* Error type */ |
| 1773 | +/*0x13*/u8 err_type; |
1767 | 1774 | #define SUN4V_ERR_TYPE_UNDEFINED 0
|
1768 | 1775 | #define SUN4V_ERR_TYPE_UNCORRECTED_RES 1
|
1769 | 1776 | #define SUN4V_ERR_TYPE_PRECISE_NONRES 2
|
1770 | 1777 | #define SUN4V_ERR_TYPE_DEFERRED_NONRES 3
|
1771 |
| -#define SUN4V_ERR_TYPE_WARNING_RES 4 |
| 1778 | +#define SUN4V_ERR_TYPE_SHUTDOWN_RQST 4 |
| 1779 | +#define SUN4V_ERR_TYPE_DUMP_CORE 5 |
| 1780 | +#define SUN4V_ERR_TYPE_SP_STATE_CHANGE 6 |
| 1781 | +#define SUN4V_ERR_TYPE_NUM 7 |
1772 | 1782 |
|
1773 |
| - u32 err_attrs; |
| 1783 | + /* Error attributes */ |
| 1784 | +/*0x14*/u32 err_attrs; |
1774 | 1785 | #define SUN4V_ERR_ATTRS_PROCESSOR 0x00000001
|
1775 | 1786 | #define SUN4V_ERR_ATTRS_MEMORY 0x00000002
|
1776 | 1787 | #define SUN4V_ERR_ATTRS_PIO 0x00000004
|
1777 | 1788 | #define SUN4V_ERR_ATTRS_INT_REGISTERS 0x00000008
|
1778 | 1789 | #define SUN4V_ERR_ATTRS_FPU_REGISTERS 0x00000010
|
1779 |
| -#define SUN4V_ERR_ATTRS_USER_MODE 0x01000000 |
1780 |
| -#define SUN4V_ERR_ATTRS_PRIV_MODE 0x02000000 |
| 1790 | +#define SUN4V_ERR_ATTRS_SHUTDOWN_RQST 0x00000020 |
| 1791 | +#define SUN4V_ERR_ATTRS_ASR 0x00000040 |
| 1792 | +#define SUN4V_ERR_ATTRS_ASI 0x00000080 |
| 1793 | +#define SUN4V_ERR_ATTRS_PRIV_REG 0x00000100 |
| 1794 | +#define SUN4V_ERR_ATTRS_SPSTATE_MSK 0x00000600 |
| 1795 | +#define SUN4V_ERR_ATTRS_SPSTATE_SHFT 9 |
| 1796 | +#define SUN4V_ERR_ATTRS_MODE_MSK 0x03000000 |
| 1797 | +#define SUN4V_ERR_ATTRS_MODE_SHFT 24 |
1781 | 1798 | #define SUN4V_ERR_ATTRS_RES_QUEUE_FULL 0x80000000
|
1782 | 1799 |
|
1783 |
| - u64 err_raddr; |
1784 |
| - u32 err_size; |
1785 |
| - u16 err_cpu; |
1786 |
| - u16 err_pad; |
| 1800 | +#define SUN4V_ERR_SPSTATE_FAULTED 0 |
| 1801 | +#define SUN4V_ERR_SPSTATE_AVAILABLE 1 |
| 1802 | +#define SUN4V_ERR_SPSTATE_NOT_PRESENT 2 |
| 1803 | + |
| 1804 | +#define SUN4V_ERR_MODE_USER 1 |
| 1805 | +#define SUN4V_ERR_MODE_PRIV 2 |
| 1806 | + |
| 1807 | + /* Real address of the memory region or PIO transaction */ |
| 1808 | +/*0x18*/u64 err_raddr; |
| 1809 | + |
| 1810 | + /* Size of the operation triggering the error, in bytes */ |
| 1811 | +/*0x20*/u32 err_size; |
| 1812 | + |
| 1813 | + /* ID of the CPU */ |
| 1814 | +/*0x24*/u16 err_cpu; |
| 1815 | + |
| 1816 | + /* Grace periof for shutdown, in seconds */ |
| 1817 | +/*0x26*/u16 err_secs; |
| 1818 | + |
| 1819 | + /* Value of the %asi register */ |
| 1820 | +/*0x28*/u8 err_asi; |
| 1821 | + |
| 1822 | +/*0x29*/u8 reserved_2; |
| 1823 | + |
| 1824 | + /* Value of the ASR register number */ |
| 1825 | +/*0x2a*/u16 err_asr; |
| 1826 | +#define SUN4V_ERR_ASR_VALID 0x8000 |
| 1827 | + |
| 1828 | +/*0x2c*/u32 reserved_3; |
| 1829 | +/*0x30*/u64 reserved_4; |
| 1830 | +/*0x38*/u64 reserved_5; |
1787 | 1831 | };
|
1788 | 1832 |
|
1789 | 1833 | static atomic_t sun4v_resum_oflow_cnt = ATOMIC_INIT(0);
|
1790 | 1834 | static atomic_t sun4v_nonresum_oflow_cnt = ATOMIC_INIT(0);
|
1791 | 1835 |
|
1792 |
| -static const char *sun4v_err_type_to_str(u32 type) |
1793 |
| -{ |
1794 |
| - switch (type) { |
1795 |
| - case SUN4V_ERR_TYPE_UNDEFINED: |
1796 |
| - return "undefined"; |
1797 |
| - case SUN4V_ERR_TYPE_UNCORRECTED_RES: |
1798 |
| - return "uncorrected resumable"; |
1799 |
| - case SUN4V_ERR_TYPE_PRECISE_NONRES: |
1800 |
| - return "precise nonresumable"; |
1801 |
| - case SUN4V_ERR_TYPE_DEFERRED_NONRES: |
1802 |
| - return "deferred nonresumable"; |
1803 |
| - case SUN4V_ERR_TYPE_WARNING_RES: |
1804 |
| - return "warning resumable"; |
1805 |
| - default: |
1806 |
| - return "unknown"; |
| 1836 | +static const char *sun4v_err_type_to_str(u8 type) |
| 1837 | +{ |
| 1838 | + static const char *types[SUN4V_ERR_TYPE_NUM] = { |
| 1839 | + "undefined", |
| 1840 | + "uncorrected resumable", |
| 1841 | + "precise nonresumable", |
| 1842 | + "deferred nonresumable", |
| 1843 | + "shutdown request", |
| 1844 | + "dump core", |
| 1845 | + "SP state change", |
| 1846 | + }; |
| 1847 | + |
| 1848 | + if (type < SUN4V_ERR_TYPE_NUM) |
| 1849 | + return types[type]; |
| 1850 | + |
| 1851 | + return "unknown"; |
| 1852 | +} |
| 1853 | + |
| 1854 | +static void sun4v_emit_err_attr_strings(u32 attrs) |
| 1855 | +{ |
| 1856 | + static const char *attr_names[] = { |
| 1857 | + "processor", |
| 1858 | + "memory", |
| 1859 | + "PIO", |
| 1860 | + "int-registers", |
| 1861 | + "fpu-registers", |
| 1862 | + "shutdown-request", |
| 1863 | + "ASR", |
| 1864 | + "ASI", |
| 1865 | + "priv-reg", |
| 1866 | + }; |
| 1867 | + static const char *sp_states[] = { |
| 1868 | + "sp-faulted", |
| 1869 | + "sp-available", |
| 1870 | + "sp-not-present", |
| 1871 | + "sp-state-reserved", |
| 1872 | + }; |
| 1873 | + static const char *modes[] = { |
| 1874 | + "mode-reserved0", |
| 1875 | + "user", |
| 1876 | + "priv", |
| 1877 | + "mode-reserved1", |
| 1878 | + }; |
| 1879 | + u32 sp_state, mode; |
| 1880 | + int i; |
| 1881 | + |
| 1882 | + for (i = 0; i < ARRAY_SIZE(attr_names); i++) { |
| 1883 | + if (attrs & (1U << i)) { |
| 1884 | + const char *s = attr_names[i]; |
| 1885 | + |
| 1886 | + pr_cont("%s ", s); |
| 1887 | + } |
1807 | 1888 | }
|
| 1889 | + |
| 1890 | + sp_state = ((attrs & SUN4V_ERR_ATTRS_SPSTATE_MSK) >> |
| 1891 | + SUN4V_ERR_ATTRS_SPSTATE_SHFT); |
| 1892 | + pr_cont("%s ", sp_states[sp_state]); |
| 1893 | + |
| 1894 | + mode = ((attrs & SUN4V_ERR_ATTRS_MODE_MSK) >> |
| 1895 | + SUN4V_ERR_ATTRS_MODE_SHFT); |
| 1896 | + pr_cont("%s ", modes[mode]); |
| 1897 | + |
| 1898 | + if (attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) |
| 1899 | + pr_cont("res-queue-full "); |
1808 | 1900 | }
|
1809 | 1901 |
|
1810 |
| -static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt) |
| 1902 | +/* When the report contains a real-address of "-1" it means that the |
| 1903 | + * hardware did not provide the address. So we compute the effective |
| 1904 | + * address of the load or store instruction at regs->tpc and report |
| 1905 | + * that. Usually when this happens it's a PIO and in such a case we |
| 1906 | + * are using physical addresses with bypass ASIs anyways, so what we |
| 1907 | + * report here is exactly what we want. |
| 1908 | + */ |
| 1909 | +static void sun4v_report_real_raddr(const char *pfx, struct pt_regs *regs) |
1811 | 1910 | {
|
| 1911 | + unsigned int insn; |
| 1912 | + u64 addr; |
| 1913 | + |
| 1914 | + if (!(regs->tstate & TSTATE_PRIV)) |
| 1915 | + return; |
| 1916 | + |
| 1917 | + insn = *(unsigned int *) regs->tpc; |
| 1918 | + |
| 1919 | + addr = compute_effective_address(regs, insn, 0); |
| 1920 | + |
| 1921 | + printk("%s: insn effective address [0x%016llx]\n", |
| 1922 | + pfx, addr); |
| 1923 | +} |
| 1924 | + |
| 1925 | +static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, |
| 1926 | + int cpu, const char *pfx, atomic_t *ocnt) |
| 1927 | +{ |
| 1928 | + u64 *raw_ptr = (u64 *) ent; |
| 1929 | + u32 attrs; |
1812 | 1930 | int cnt;
|
1813 | 1931 |
|
1814 | 1932 | printk("%s: Reporting on cpu %d\n", pfx, cpu);
|
1815 |
| - printk("%s: err_handle[%llx] err_stick[%llx] err_type[%08x:%s]\n", |
1816 |
| - pfx, |
1817 |
| - ent->err_handle, ent->err_stick, |
1818 |
| - ent->err_type, |
1819 |
| - sun4v_err_type_to_str(ent->err_type)); |
1820 |
| - printk("%s: err_attrs[%08x:%s %s %s %s %s %s %s %s]\n", |
1821 |
| - pfx, |
1822 |
| - ent->err_attrs, |
1823 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_PROCESSOR) ? |
1824 |
| - "processor" : ""), |
1825 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_MEMORY) ? |
1826 |
| - "memory" : ""), |
1827 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_PIO) ? |
1828 |
| - "pio" : ""), |
1829 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_INT_REGISTERS) ? |
1830 |
| - "integer-regs" : ""), |
1831 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_FPU_REGISTERS) ? |
1832 |
| - "fpu-regs" : ""), |
1833 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_USER_MODE) ? |
1834 |
| - "user" : ""), |
1835 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_PRIV_MODE) ? |
1836 |
| - "privileged" : ""), |
1837 |
| - ((ent->err_attrs & SUN4V_ERR_ATTRS_RES_QUEUE_FULL) ? |
1838 |
| - "queue-full" : "")); |
1839 |
| - printk("%s: err_raddr[%016llx] err_size[%u] err_cpu[%u]\n", |
1840 |
| - pfx, |
1841 |
| - ent->err_raddr, ent->err_size, ent->err_cpu); |
| 1933 | + printk("%s: TPC [0x%016lx] <%pS>\n", |
| 1934 | + pfx, regs->tpc, (void *) regs->tpc); |
| 1935 | + |
| 1936 | + printk("%s: RAW [%016llx:%016llx:%016llx:%016llx\n", |
| 1937 | + pfx, raw_ptr[0], raw_ptr[1], raw_ptr[2], raw_ptr[3]); |
| 1938 | + printk("%s: %016llx:%016llx:%016llx:%016llx]\n", |
| 1939 | + pfx, raw_ptr[4], raw_ptr[5], raw_ptr[6], raw_ptr[7]); |
| 1940 | + |
| 1941 | + printk("%s: handle [0x%016llx] stick [0x%016llx]\n", |
| 1942 | + pfx, ent->err_handle, ent->err_stick); |
| 1943 | + |
| 1944 | + printk("%s: type [%s]\n", pfx, sun4v_err_type_to_str(ent->err_type)); |
| 1945 | + |
| 1946 | + attrs = ent->err_attrs; |
| 1947 | + printk("%s: attrs [0x%08x] < ", pfx, attrs); |
| 1948 | + sun4v_emit_err_attr_strings(attrs); |
| 1949 | + pr_cont(">\n"); |
| 1950 | + |
| 1951 | + /* Various fields in the error report are only valid if |
| 1952 | + * certain attribute bits are set. |
| 1953 | + */ |
| 1954 | + if (attrs & (SUN4V_ERR_ATTRS_MEMORY | |
| 1955 | + SUN4V_ERR_ATTRS_PIO | |
| 1956 | + SUN4V_ERR_ATTRS_ASI)) { |
| 1957 | + printk("%s: raddr [0x%016llx]\n", pfx, ent->err_raddr); |
| 1958 | + |
| 1959 | + if (ent->err_raddr == ~(u64)0) |
| 1960 | + sun4v_report_real_raddr(pfx, regs); |
| 1961 | + } |
| 1962 | + |
| 1963 | + if (attrs & (SUN4V_ERR_ATTRS_MEMORY | SUN4V_ERR_ATTRS_ASI)) |
| 1964 | + printk("%s: size [0x%x]\n", pfx, ent->err_size); |
| 1965 | + |
| 1966 | + if (attrs & (SUN4V_ERR_ATTRS_PROCESSOR | |
| 1967 | + SUN4V_ERR_ATTRS_INT_REGISTERS | |
| 1968 | + SUN4V_ERR_ATTRS_FPU_REGISTERS | |
| 1969 | + SUN4V_ERR_ATTRS_PRIV_REG)) |
| 1970 | + printk("%s: cpu[%u]\n", pfx, ent->err_cpu); |
| 1971 | + |
| 1972 | + if (attrs & SUN4V_ERR_ATTRS_ASI) |
| 1973 | + printk("%s: asi [0x%02x]\n", pfx, ent->err_asi); |
| 1974 | + |
| 1975 | + if ((attrs & (SUN4V_ERR_ATTRS_INT_REGISTERS | |
| 1976 | + SUN4V_ERR_ATTRS_FPU_REGISTERS | |
| 1977 | + SUN4V_ERR_ATTRS_PRIV_REG)) && |
| 1978 | + (ent->err_asr & SUN4V_ERR_ASR_VALID) != 0) |
| 1979 | + printk("%s: reg [0x%04x]\n", |
| 1980 | + pfx, ent->err_asr & ~SUN4V_ERR_ASR_VALID); |
1842 | 1981 |
|
1843 | 1982 | show_regs(regs);
|
1844 | 1983 |
|
@@ -1874,13 +2013,15 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
|
1874 | 2013 |
|
1875 | 2014 | put_cpu();
|
1876 | 2015 |
|
1877 |
| - if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) { |
1878 |
| - /* If err_type is 0x4, it's a powerdown request. Do |
1879 |
| - * not do the usual resumable error log because that |
1880 |
| - * makes it look like some abnormal error. |
| 2016 | + if (local_copy.err_type == SUN4V_ERR_TYPE_SHUTDOWN_RQST) { |
| 2017 | + /* We should really take the seconds field of |
| 2018 | + * the error report and use it for the shutdown |
| 2019 | + * invocation, but for now do the same thing we |
| 2020 | + * do for a DS shutdown request. |
1881 | 2021 | */
|
1882 |
| - printk(KERN_INFO "Power down request...\n"); |
1883 |
| - kill_cad_pid(SIGINT, 1); |
| 2022 | + pr_info("Shutdown request, %u seconds...\n", |
| 2023 | + local_copy.err_secs); |
| 2024 | + orderly_poweroff(true); |
1884 | 2025 | return;
|
1885 | 2026 | }
|
1886 | 2027 |
|
|
0 commit comments