summaryrefslogtreecommitdiff
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/etrap_64.S26
-rw-r--r--arch/sparc/kernel/head_64.S18
-rw-r--r--arch/sparc/kernel/hvapi.c2
-rw-r--r--arch/sparc/kernel/hvcalls.S11
-rw-r--r--arch/sparc/kernel/ldc.c2
-rw-r--r--arch/sparc/kernel/leon_pci_grpci1.c2
-rw-r--r--arch/sparc/kernel/leon_pci_grpci2.c2
-rw-r--r--arch/sparc/kernel/process_64.c7
-rw-r--r--arch/sparc/kernel/rtrap_64.S13
-rw-r--r--arch/sparc/kernel/setup_64.c6
-rw-r--r--arch/sparc/kernel/smp_64.c80
-rw-r--r--arch/sparc/kernel/traps_64.c51
-rw-r--r--arch/sparc/kernel/tsb.S2
-rw-r--r--arch/sparc/kernel/vio.c1
-rw-r--r--arch/sparc/kernel/viohs.c12
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S10
16 files changed, 225 insertions, 20 deletions
diff --git a/arch/sparc/kernel/etrap_64.S b/arch/sparc/kernel/etrap_64.S
index 1276ca2567ba..5c237467d156 100644
--- a/arch/sparc/kernel/etrap_64.S
+++ b/arch/sparc/kernel/etrap_64.S
@@ -38,7 +38,11 @@ etrap_syscall: TRAP_LOAD_THREAD_REG(%g6, %g1)
or %g1, %g3, %g1
bne,pn %xcc, 1f
sub %sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2
- wrpr %g0, 7, %cleanwin
+661: wrpr %g0, 7, %cleanwin
+ .section .fast_win_ctrl_1insn_patch, "ax"
+ .word 661b
+ .word 0x85880000 ! allclean
+ .previous
sethi %hi(TASK_REGOFF), %g2
sethi %hi(TSTATE_PEF), %g3
@@ -88,16 +92,30 @@ etrap_save: save %g2, -STACK_BIAS, %sp
bne,pn %xcc, 3f
mov PRIMARY_CONTEXT, %l4
- rdpr %canrestore, %g3
+661: rdpr %canrestore, %g3
+ .section .fast_win_ctrl_1insn_patch, "ax"
+ .word 661b
+ nop
+ .previous
+
rdpr %wstate, %g2
- wrpr %g0, 0, %canrestore
+661: wrpr %g0, 0, %canrestore
+ .section .fast_win_ctrl_1insn_patch, "ax"
+ .word 661b
+ nop
+ .previous
sll %g2, 3, %g2
/* Set TI_SYS_FPDEPTH to 1 and clear TI_SYS_NOERROR. */
mov 1, %l5
sth %l5, [%l6 + TI_SYS_NOERROR]
- wrpr %g3, 0, %otherwin
+661: wrpr %g3, 0, %otherwin
+ .section .fast_win_ctrl_1insn_patch, "ax"
+ .word 661b
+ .word 0x87880000 ! otherw
+ .previous
+
wrpr %g2, 0, %wstate
sethi %hi(sparc64_kern_pri_context), %g2
ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index 78e0211753d2..4de9fbd1a177 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -603,10 +603,10 @@ niagara_tlb_fixup:
be,pt %xcc, niagara4_patch
nop
cmp %g1, SUN4V_CHIP_SPARC_M7
- be,pt %xcc, niagara4_patch
+ be,pt %xcc, sparc_m7_patch
nop
cmp %g1, SUN4V_CHIP_SPARC_M8
- be,pt %xcc, niagara4_patch
+ be,pt %xcc, sparc_m7_patch
nop
cmp %g1, SUN4V_CHIP_SPARC_SN
be,pt %xcc, niagara4_patch
@@ -621,6 +621,18 @@ niagara_tlb_fixup:
ba,a,pt %xcc, 80f
nop
+
+sparc_m7_patch:
+ call m7_patch_copyops
+ nop
+ call m7_patch_bzero
+ nop
+ call m7_patch_pageops
+ nop
+
+ ba,a,pt %xcc, 80f
+ nop
+
niagara4_patch:
call niagara4_patch_copyops
nop
@@ -881,7 +893,6 @@ sparc64_boot_end:
#include "misctrap.S"
#include "syscalls.S"
#include "helpers.S"
-#include "hvcalls.S"
#include "sun4v_tlb_miss.S"
#include "sun4v_ivec.S"
#include "ktlb.S"
@@ -926,6 +937,7 @@ swapper_4m_tsb:
! 0x0000000000428000
+#include "hvcalls.S"
#include "systbls_64.S"
.data
diff --git a/arch/sparc/kernel/hvapi.c b/arch/sparc/kernel/hvapi.c
index 267731234ce8..d41ce33d87d6 100644
--- a/arch/sparc/kernel/hvapi.c
+++ b/arch/sparc/kernel/hvapi.c
@@ -189,7 +189,7 @@ void __init sun4v_hvapi_init(void)
group = HV_GRP_CORE;
major = 1;
- minor = 1;
+ minor = 6;
if (sun4v_hvapi_register(group, major, &minor))
goto bad;
diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S
index 4116ee5c7791..e57007ff7f8f 100644
--- a/arch/sparc/kernel/hvcalls.S
+++ b/arch/sparc/kernel/hvcalls.S
@@ -106,6 +106,17 @@ ENTRY(sun4v_cpu_yield)
nop
ENDPROC(sun4v_cpu_yield)
+ /* %o0: cpuid
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_cpu_poke)
+ mov HV_FAST_CPU_POKE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_cpu_poke)
+
/* %o0: type
* %o1: queue paddr
* %o2: num queue entries
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index 840e0b21bfe3..acffbc894ab0 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -1480,6 +1480,7 @@ int ldc_rx_reset(struct ldc_channel *lp)
{
return __set_rx_head(lp, lp->rx_tail);
}
+EXPORT_SYMBOL(ldc_rx_reset);
void __ldc_print(struct ldc_channel *lp, const char *caller)
{
@@ -1493,6 +1494,7 @@ void __ldc_print(struct ldc_channel *lp, const char *caller)
lp->tx_head, lp->tx_tail, lp->tx_num_entries,
lp->rcv_nxt, lp->snd_nxt);
}
+EXPORT_SYMBOL(__ldc_print);
static int write_raw(struct ldc_channel *lp, const void *buf, unsigned int size)
{
diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c
index 1e77128a8f88..83ba5005d44c 100644
--- a/arch/sparc/kernel/leon_pci_grpci1.c
+++ b/arch/sparc/kernel/leon_pci_grpci1.c
@@ -695,7 +695,7 @@ err1:
return err;
}
-static struct of_device_id grpci1_of_match[] = {
+static const struct of_device_id grpci1_of_match[] __initconst = {
{
.name = "GAISLER_PCIFBRG",
},
diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c
index f727c4de1316..ff0e5c90310f 100644
--- a/arch/sparc/kernel/leon_pci_grpci2.c
+++ b/arch/sparc/kernel/leon_pci_grpci2.c
@@ -886,7 +886,7 @@ err1:
return err;
}
-static struct of_device_id grpci2_of_match[] = {
+static const struct of_device_id grpci2_of_match[] __initconst = {
{
.name = "GAISLER_GRPCI2",
},
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index b96104da5bd6..44e5da405f96 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -77,8 +77,13 @@ void arch_cpu_idle(void)
: "=&r" (pstate)
: "i" (PSTATE_IE));
- if (!need_resched() && !cpu_is_offline(smp_processor_id()))
+ if (!need_resched() && !cpu_is_offline(smp_processor_id())) {
sun4v_cpu_yield();
+ /* If resumed by cpu_poke then we need to explicitly
+ * call scheduler_ipi().
+ */
+ scheduler_poke();
+ }
/* Re-enable interrupts. */
__asm__ __volatile__(
diff --git a/arch/sparc/kernel/rtrap_64.S b/arch/sparc/kernel/rtrap_64.S
index 709a82ebd294..dff86fad0a1f 100644
--- a/arch/sparc/kernel/rtrap_64.S
+++ b/arch/sparc/kernel/rtrap_64.S
@@ -224,10 +224,19 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
rdpr %otherwin, %l2
srl %l1, 3, %l1
- wrpr %l2, %g0, %canrestore
+661: wrpr %l2, %g0, %canrestore
+ .section .fast_win_ctrl_1insn_patch, "ax"
+ .word 661b
+ .word 0x89880000 ! normalw
+ .previous
+
wrpr %l1, %g0, %wstate
brnz,pt %l2, user_rtt_restore
- wrpr %g0, %g0, %otherwin
+661: wrpr %g0, %g0, %otherwin
+ .section .fast_win_ctrl_1insn_patch, "ax"
+ .word 661b
+ nop
+ .previous
ldx [%g6 + TI_FLAGS], %g3
wr %g0, ASI_AIUP, %asi
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 150ee7d4b059..db4c4d7e28a0 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -300,6 +300,11 @@ static void __init sun4v_patch(void)
break;
}
+ if (sun4v_chip_type != SUN4V_CHIP_NIAGARA1) {
+ sun4v_patch_1insn_range(&__fast_win_ctrl_1insn_patch,
+ &__fast_win_ctrl_1insn_patch_end);
+ }
+
sun4v_hvapi_init();
}
@@ -363,6 +368,7 @@ void __init start_early_boot(void)
check_if_starfire();
per_cpu_patch();
sun4v_patch();
+ smp_init_cpu_poke();
cpu = hard_smp_processor_id();
if (cpu >= NR_CPUS) {
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index 3218bc43302e..4898329970c5 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -74,6 +74,9 @@ EXPORT_SYMBOL(cpu_core_sib_cache_map);
static cpumask_t smp_commenced_mask;
+static DEFINE_PER_CPU(bool, poke);
+static bool cpu_poke;
+
void smp_info(struct seq_file *m)
{
int i;
@@ -1439,15 +1442,86 @@ void __init smp_cpus_done(unsigned int max_cpus)
{
}
+static void send_cpu_ipi(int cpu)
+{
+ xcall_deliver((u64) &xcall_receive_signal,
+ 0, 0, cpumask_of(cpu));
+}
+
+void scheduler_poke(void)
+{
+ if (!cpu_poke)
+ return;
+
+ if (!__this_cpu_read(poke))
+ return;
+
+ __this_cpu_write(poke, false);
+ set_softint(1 << PIL_SMP_RECEIVE_SIGNAL);
+}
+
+static unsigned long send_cpu_poke(int cpu)
+{
+ unsigned long hv_err;
+
+ per_cpu(poke, cpu) = true;
+ hv_err = sun4v_cpu_poke(cpu);
+ if (hv_err != HV_EOK) {
+ per_cpu(poke, cpu) = false;
+ pr_err_ratelimited("%s: sun4v_cpu_poke() fails err=%lu\n",
+ __func__, hv_err);
+ }
+
+ return hv_err;
+}
+
void smp_send_reschedule(int cpu)
{
if (cpu == smp_processor_id()) {
WARN_ON_ONCE(preemptible());
set_softint(1 << PIL_SMP_RECEIVE_SIGNAL);
- } else {
- xcall_deliver((u64) &xcall_receive_signal,
- 0, 0, cpumask_of(cpu));
+ return;
+ }
+
+ /* Use cpu poke to resume idle cpu if supported. */
+ if (cpu_poke && idle_cpu(cpu)) {
+ unsigned long ret;
+
+ ret = send_cpu_poke(cpu);
+ if (ret == HV_EOK)
+ return;
}
+
+ /* Use IPI in following cases:
+ * - cpu poke not supported
+ * - cpu not idle
+ * - send_cpu_poke() returns with error
+ */
+ send_cpu_ipi(cpu);
+}
+
+void smp_init_cpu_poke(void)
+{
+ unsigned long major;
+ unsigned long minor;
+ int ret;
+
+ if (tlb_type != hypervisor)
+ return;
+
+ ret = sun4v_hvapi_get(HV_GRP_CORE, &major, &minor);
+ if (ret) {
+ pr_debug("HV_GRP_CORE is not registered\n");
+ return;
+ }
+
+ if (major == 1 && minor >= 6) {
+ /* CPU POKE is registered. */
+ cpu_poke = true;
+ return;
+ }
+
+ pr_debug("CPU_POKE not supported\n");
}
void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index ad31af1dd726..c74f2dffcc13 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -265,6 +265,45 @@ void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
sun4v_insn_access_exception(regs, addr, type_ctx);
}
+bool is_no_fault_exception(struct pt_regs *regs)
+{
+ unsigned char asi;
+ u32 insn;
+
+ if (get_user(insn, (u32 __user *)regs->tpc) == -EFAULT)
+ return false;
+
+ /*
+ * Must do a little instruction decoding here in order to
+ * decide on a course of action. The bits of interest are:
+ * insn[31:30] = op, where 3 indicates the load/store group
+ * insn[24:19] = op3, which identifies individual opcodes
+ * insn[13] indicates an immediate offset
+ * op3[4]=1 identifies alternate space instructions
+ * op3[5:4]=3 identifies floating point instructions
+ * op3[2]=1 identifies stores
+ * See "Opcode Maps" in the appendix of any Sparc V9
+ * architecture spec for full details.
+ */
+ if ((insn & 0xc0800000) == 0xc0800000) { /* op=3, op3[4]=1 */
+ if (insn & 0x2000) /* immediate offset */
+ asi = (regs->tstate >> 24); /* saved %asi */
+ else
+ asi = (insn >> 5); /* immediate asi */
+ if ((asi & 0xf2) == ASI_PNF) {
+ if (insn & 0x1000000) { /* op3[5:4]=3 */
+ handle_ldf_stq(insn, regs);
+ return true;
+ } else if (insn & 0x200000) { /* op3[2], stores */
+ return false;
+ }
+ handle_ld_nf(insn, regs);
+ return true;
+ }
+ }
+ return false;
+}
+
void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
{
enum ctx_state prev_state = exception_enter();
@@ -296,6 +335,9 @@ void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, un
die_if_kernel("Dax", regs);
}
+ if (is_no_fault_exception(regs))
+ return;
+
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
@@ -352,6 +394,9 @@ void sun4v_data_access_exception(struct pt_regs *regs, unsigned long addr, unsig
regs->tpc &= 0xffffffff;
regs->tnpc &= 0xffffffff;
}
+ if (is_no_fault_exception(regs))
+ return;
+
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
@@ -2575,6 +2620,9 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo
kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
goto out;
}
+ if (is_no_fault_exception(regs))
+ return;
+
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
@@ -2597,6 +2645,9 @@ void sun4v_do_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_c
kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
return;
}
+ if (is_no_fault_exception(regs))
+ return;
+
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
diff --git a/arch/sparc/kernel/tsb.S b/arch/sparc/kernel/tsb.S
index db872dbfafe9..f74115364b1e 100644
--- a/arch/sparc/kernel/tsb.S
+++ b/arch/sparc/kernel/tsb.S
@@ -117,7 +117,7 @@ tsb_miss_page_table_walk_sun4v_fastpath:
/* Valid PTE is now in %g5. */
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
- sethi %uhi(_PAGE_PMD_HUGE), %g7
+ sethi %uhi(_PAGE_PMD_HUGE | _PAGE_PUD_HUGE), %g7
sllx %g7, 32, %g7
andcc %g5, %g7, %g0
diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c
index 1c8763c9c52b..da1ac3f22b24 100644
--- a/arch/sparc/kernel/vio.c
+++ b/arch/sparc/kernel/vio.c
@@ -246,6 +246,7 @@ u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev)
return node;
}
+EXPORT_SYMBOL(vio_vdev_node);
static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
struct vio_dev *vdev)
diff --git a/arch/sparc/kernel/viohs.c b/arch/sparc/kernel/viohs.c
index d4f13c037a40..dcd278f29573 100644
--- a/arch/sparc/kernel/viohs.c
+++ b/arch/sparc/kernel/viohs.c
@@ -814,15 +814,21 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
case VDEV_NETWORK_SWITCH:
case VDEV_DISK:
case VDEV_DISK_SERVER:
+ case VDEV_CONSOLE_CON:
break;
default:
return -EINVAL;
}
- if (!ops || !ops->send_attr || !ops->handle_attr ||
- !ops->handshake_complete)
- return -EINVAL;
+ if (dev_class == VDEV_NETWORK ||
+ dev_class == VDEV_NETWORK_SWITCH ||
+ dev_class == VDEV_DISK ||
+ dev_class == VDEV_DISK_SERVER) {
+ if (!ops || !ops->send_attr || !ops->handle_attr ||
+ !ops->handshake_complete)
+ return -EINVAL;
+ }
if (!ver_table || ver_table_size < 0)
return -EINVAL;
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 03b3d65d1266..d78847d56a4b 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -154,6 +154,16 @@ SECTIONS
*(.get_tick_patch)
__get_tick_patch_end = .;
}
+ .pud_huge_patch : {
+ __pud_huge_patch = .;
+ *(.pud_huge_patch)
+ __pud_huge_patch_end = .;
+ }
+ .fast_win_ctrl_1insn_patch : {
+ __fast_win_ctrl_1insn_patch = .;
+ *(.fast_win_ctrl_1insn_patch)
+ __fast_win_ctrl_1insn_patch_end = .;
+ }
PERCPU_SECTION(SMP_CACHE_BYTES)
#ifdef CONFIG_JUMP_LABEL