summaryrefslogtreecommitdiff
path: root/arch/mips/loongson64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/loongson64')
-rw-r--r--arch/mips/loongson64/Makefile1
-rw-r--r--arch/mips/loongson64/boardinfo.c48
-rw-r--r--arch/mips/loongson64/env.c10
-rw-r--r--arch/mips/loongson64/numa.c27
-rw-r--r--arch/mips/loongson64/smp.c126
5 files changed, 165 insertions, 47 deletions
diff --git a/arch/mips/loongson64/Makefile b/arch/mips/loongson64/Makefile
index 39c06f52b08f..cc76944b1a9d 100644
--- a/arch/mips/loongson64/Makefile
+++ b/arch/mips/loongson64/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_RS780_HPET) += hpet.o
obj-$(CONFIG_SUSPEND) += pm.o
obj-$(CONFIG_PCI_QUIRKS) += vbios_quirk.o
obj-$(CONFIG_CPU_LOONGSON3_CPUCFG_EMULATION) += cpucfg-emul.o
+obj-$(CONFIG_SYSFS) += boardinfo.o
diff --git a/arch/mips/loongson64/boardinfo.c b/arch/mips/loongson64/boardinfo.c
new file mode 100644
index 000000000000..280989c5a137
--- /dev/null
+++ b/arch/mips/loongson64/boardinfo.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kobject.h>
+#include <boot_param.h>
+
+static ssize_t boardinfo_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ char board_manufacturer[64] = {0};
+ char *tmp_board_manufacturer = board_manufacturer;
+ char bios_vendor[64] = {0};
+ char *tmp_bios_vendor = bios_vendor;
+
+ strcpy(board_manufacturer, eboard->name);
+ strcpy(bios_vendor, einter->description);
+
+ return sprintf(buf,
+ "Board Info\n"
+ "Manufacturer\t\t: %s\n"
+ "Board Name\t\t: %s\n"
+ "Family\t\t\t: LOONGSON3\n\n"
+ "BIOS Info\n"
+ "Vendor\t\t\t: %s\n"
+ "Version\t\t\t: %s\n"
+ "ROM Size\t\t: %d KB\n"
+ "Release Date\t\t: %s\n",
+ strsep(&tmp_board_manufacturer, "-"),
+ eboard->name,
+ strsep(&tmp_bios_vendor, "-"),
+ einter->description,
+ einter->size,
+ especial->special_name);
+}
+static struct kobj_attribute boardinfo_attr = __ATTR(boardinfo, 0444,
+ boardinfo_show, NULL);
+
+static int __init boardinfo_init(void)
+{
+ struct kobject *lefi_kobj;
+
+ lefi_kobj = kobject_create_and_add("lefi", firmware_kobj);
+ if (!lefi_kobj) {
+ pr_err("lefi: Firmware registration failed.\n");
+ return -ENOMEM;
+ }
+
+ return sysfs_create_file(lefi_kobj, &boardinfo_attr.attr);
+}
+late_initcall(boardinfo_init);
diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c
index 134cb8e9efc2..51a5d050a94c 100644
--- a/arch/mips/loongson64/env.c
+++ b/arch/mips/loongson64/env.c
@@ -28,6 +28,10 @@ EXPORT_SYMBOL(cpu_clock_freq);
struct efi_memory_map_loongson *loongson_memmap;
struct loongson_system_configuration loongson_sysconf;
+struct board_devices *eboard;
+struct interface_info *einter;
+struct loongson_special_attribute *especial;
+
u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
u64 loongson_chiptemp[MAX_PACKAGES];
u64 loongson_freqctrl[MAX_PACKAGES];
@@ -57,6 +61,12 @@ void __init prom_init_env(void)
((u64)loongson_p + loongson_p->system_offset);
ecpu = (struct efi_cpuinfo_loongson *)
((u64)loongson_p + loongson_p->cpu_offset);
+ eboard = (struct board_devices *)
+ ((u64)loongson_p + loongson_p->boarddev_table_offset);
+ einter = (struct interface_info *)
+ ((u64)loongson_p + loongson_p->interface_offset);
+ especial = (struct loongson_special_attribute *)
+ ((u64)loongson_p + loongson_p->special_offset);
eirq_source = (struct irq_source_routing_table *)
((u64)loongson_p + loongson_p->irq_offset);
loongson_memmap = (struct efi_memory_map_loongson *)
diff --git a/arch/mips/loongson64/numa.c b/arch/mips/loongson64/numa.c
index cf9459f79f9b..c6f0c48384f8 100644
--- a/arch/mips/loongson64/numa.c
+++ b/arch/mips/loongson64/numa.c
@@ -35,23 +35,6 @@ EXPORT_SYMBOL(__node_data);
cpumask_t __node_cpumask[MAX_NUMNODES];
EXPORT_SYMBOL(__node_cpumask);
-static void enable_lpa(void)
-{
- unsigned long value;
-
- value = __read_32bit_c0_register($16, 3);
- value |= 0x00000080;
- __write_32bit_c0_register($16, 3, value);
- value = __read_32bit_c0_register($16, 3);
- pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value);
-
- value = __read_32bit_c0_register($5, 1);
- value |= 0x20000000;
- __write_32bit_c0_register($5, 1, value);
- value = __read_32bit_c0_register($5, 1);
- pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value);
-}
-
static void cpu_node_probe(void)
{
int i;
@@ -168,6 +151,9 @@ static void __init node_mem_init(unsigned int node)
NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
if (node == 0) {
+ /* kernel start address */
+ unsigned long kernel_start_pfn = PFN_DOWN(__pa_symbol(&_text));
+
/* kernel end address */
unsigned long kernel_end_pfn = PFN_UP(__pa_symbol(&_end));
@@ -175,8 +161,8 @@ static void __init node_mem_init(unsigned int node)
max_low_pfn = end_pfn;
/* Reserve the kernel text/data/bss */
- memblock_reserve(start_pfn << PAGE_SHIFT,
- ((kernel_end_pfn - start_pfn) << PAGE_SHIFT));
+ memblock_reserve(kernel_start_pfn << PAGE_SHIFT,
+ ((kernel_end_pfn - kernel_start_pfn) << PAGE_SHIFT));
/* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */
if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT))
@@ -243,7 +229,8 @@ EXPORT_SYMBOL(pcibus_to_node);
void __init prom_init_numa_memory(void)
{
- enable_lpa();
+ pr_info("CP0_Config3: CP0 16.3 (0x%x)\n", read_c0_config3());
+ pr_info("CP0_PageGrain: CP0 5.1 (0x%x)\n", read_c0_pagegrain());
prom_meminit();
}
EXPORT_SYMBOL(prom_init_numa_memory);
diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c
index e744e1bee49e..b8c1fc3158fd 100644
--- a/arch/mips/loongson64/smp.c
+++ b/arch/mips/loongson64/smp.c
@@ -53,6 +53,29 @@ static uint32_t core0_c0count[NR_CPUS];
u32 (*ipi_read_clear)(int cpu);
void (*ipi_write_action)(int cpu, u32 action);
+void (*ipi_write_enable)(int cpu);
+void (*ipi_clear_buf)(int cpu);
+void (*ipi_write_buf)(int cpu, struct task_struct *idle);
+
+/* send mail via Mail_Send register for 3A4000+ CPU */
+static void csr_mail_send(uint64_t data, int cpu, int mailbox)
+{
+ uint64_t val;
+
+ /* send high 32 bits */
+ val = CSR_MAIL_SEND_BLOCK;
+ val |= (CSR_MAIL_SEND_BOX_HIGH(mailbox) << CSR_MAIL_SEND_BOX_SHIFT);
+ val |= (cpu << CSR_MAIL_SEND_CPU_SHIFT);
+ val |= (data & CSR_MAIL_SEND_H32_MASK);
+ csr_writeq(val, LOONGSON_CSR_MAIL_SEND);
+
+ /* send low 32 bits */
+ val = CSR_MAIL_SEND_BLOCK;
+ val |= (CSR_MAIL_SEND_BOX_LOW(mailbox) << CSR_MAIL_SEND_BOX_SHIFT);
+ val |= (cpu << CSR_MAIL_SEND_CPU_SHIFT);
+ val |= (data << CSR_MAIL_SEND_BUF_SHIFT);
+ csr_writeq(val, LOONGSON_CSR_MAIL_SEND);
+};
static u32 csr_ipi_read_clear(int cpu)
{
@@ -79,6 +102,35 @@ static void csr_ipi_write_action(int cpu, u32 action)
}
}
+static void csr_ipi_write_enable(int cpu)
+{
+ csr_writel(0xffffffff, LOONGSON_CSR_IPI_EN);
+}
+
+static void csr_ipi_clear_buf(int cpu)
+{
+ csr_writeq(0, LOONGSON_CSR_MAIL_BUF0);
+}
+
+static void csr_ipi_write_buf(int cpu, struct task_struct *idle)
+{
+ unsigned long startargs[4];
+
+ /* startargs[] are initial PC, SP and GP for secondary CPU */
+ startargs[0] = (unsigned long)&smp_bootstrap;
+ startargs[1] = (unsigned long)__KSTK_TOS(idle);
+ startargs[2] = (unsigned long)task_thread_info(idle);
+ startargs[3] = 0;
+
+ pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
+ cpu, startargs[0], startargs[1], startargs[2]);
+
+ csr_mail_send(startargs[3], cpu_logical_map(cpu), 3);
+ csr_mail_send(startargs[2], cpu_logical_map(cpu), 2);
+ csr_mail_send(startargs[1], cpu_logical_map(cpu), 1);
+ csr_mail_send(startargs[0], cpu_logical_map(cpu), 0);
+}
+
static u32 legacy_ipi_read_clear(int cpu)
{
u32 action;
@@ -96,14 +148,53 @@ static void legacy_ipi_write_action(int cpu, u32 action)
loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
}
+static void legacy_ipi_write_enable(int cpu)
+{
+ loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(cpu)]);
+}
+
+static void legacy_ipi_clear_buf(int cpu)
+{
+ loongson3_ipi_write64(0, ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
+}
+
+static void legacy_ipi_write_buf(int cpu, struct task_struct *idle)
+{
+ unsigned long startargs[4];
+
+ /* startargs[] are initial PC, SP and GP for secondary CPU */
+ startargs[0] = (unsigned long)&smp_bootstrap;
+ startargs[1] = (unsigned long)__KSTK_TOS(idle);
+ startargs[2] = (unsigned long)task_thread_info(idle);
+ startargs[3] = 0;
+
+ pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
+ cpu, startargs[0], startargs[1], startargs[2]);
+
+ loongson3_ipi_write64(startargs[3],
+ ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x18);
+ loongson3_ipi_write64(startargs[2],
+ ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x10);
+ loongson3_ipi_write64(startargs[1],
+ ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x8);
+ loongson3_ipi_write64(startargs[0],
+ ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
+}
+
static void csr_ipi_probe(void)
{
if (cpu_has_csr() && csr_readl(LOONGSON_CSR_FEATURES) & LOONGSON_CSRF_IPI) {
ipi_read_clear = csr_ipi_read_clear;
ipi_write_action = csr_ipi_write_action;
+ ipi_write_enable = csr_ipi_write_enable;
+ ipi_clear_buf = csr_ipi_clear_buf;
+ ipi_write_buf = csr_ipi_write_buf;
} else {
ipi_read_clear = legacy_ipi_read_clear;
ipi_write_action = legacy_ipi_write_action;
+ ipi_write_enable = legacy_ipi_write_enable;
+ ipi_clear_buf = legacy_ipi_clear_buf;
+ ipi_write_buf = legacy_ipi_write_buf;
}
}
@@ -347,9 +438,7 @@ static void loongson3_init_secondary(void)
/* Set interrupt mask, but don't enable */
change_c0_status(ST0_IM, imask);
-
- for (i = 0; i < num_possible_cpus(); i++)
- loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(i)]);
+ ipi_write_enable(cpu);
per_cpu(cpu_state, cpu) = CPU_ONLINE;
cpu_set_core(&cpu_data[cpu],
@@ -381,8 +470,8 @@ static void loongson3_smp_finish(void)
write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
local_irq_enable();
- loongson3_ipi_write64(0,
- ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
+ ipi_clear_buf(cpu);
+
pr_info("CPU#%d finished, CP0_ST=%x\n",
smp_processor_id(), read_c0_status());
}
@@ -420,6 +509,8 @@ static void __init loongson3_smp_setup(void)
ipi_status0_regs_init();
ipi_en0_regs_init();
ipi_mailbox_buf_init();
+ ipi_write_enable(0);
+
cpu_set_core(&cpu_data[0],
cpu_logical_map(0) % loongson_sysconf.cores_per_package);
cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;
@@ -439,27 +530,10 @@ static void __init loongson3_prepare_cpus(unsigned int max_cpus)
*/
static int loongson3_boot_secondary(int cpu, struct task_struct *idle)
{
- unsigned long startargs[4];
-
pr_info("Booting CPU#%d...\n", cpu);
- /* startargs[] are initial PC, SP and GP for secondary CPU */
- startargs[0] = (unsigned long)&smp_bootstrap;
- startargs[1] = (unsigned long)__KSTK_TOS(idle);
- startargs[2] = (unsigned long)task_thread_info(idle);
- startargs[3] = 0;
+ ipi_write_buf(cpu, idle);
- pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
- cpu, startargs[0], startargs[1], startargs[2]);
-
- loongson3_ipi_write64(startargs[3],
- ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x18);
- loongson3_ipi_write64(startargs[2],
- ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x10);
- loongson3_ipi_write64(startargs[1],
- ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x8);
- loongson3_ipi_write64(startargs[0],
- ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
return 0;
}
@@ -470,9 +544,6 @@ static int loongson3_cpu_disable(void)
unsigned long flags;
unsigned int cpu = smp_processor_id();
- if (cpu == 0)
- return -EBUSY;
-
set_cpu_online(cpu, false);
calculate_cpu_foreign_map();
local_irq_save(flags);
@@ -690,9 +761,10 @@ static void loongson3_type3_play_dead(int *state_addr)
"1: li %[count], 0x100 \n" /* wait for init loop */
"2: bnez %[count], 2b \n" /* limit mailbox access */
" addiu %[count], -1 \n"
- " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */
+ " lw %[initfunc], 0x20(%[base]) \n" /* check lower 32-bit as jump indicator */
" beqz %[initfunc], 1b \n"
" nop \n"
+ " ld %[initfunc], 0x20(%[base]) \n" /* get PC (whole 64-bit) via mailbox */
" ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */
" ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */
" ld $a1, 0x38(%[base]) \n"