From 7653716bf989cf8be04c7bedcad6bb201b1df108 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Thu, 9 Jul 2015 10:51:36 +0200 Subject: MIPS: ath79: irq: IRQCHIP_DECLARE moved to linux/irqchip.h Remove the ugly cross tree include now that IRQCHIP_DECLARE moved to linux/irqchip.h. Signed-off-by: Alban Bedel Cc: linux-mips@linux-mips.org Cc: Thomas Gleixner Cc: Andrew Bresticker Cc: Qais Yousef Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10633/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/irq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index afb009603f7f..2021be20d9d9 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -17,7 +17,6 @@ #include #include #include -#include "../../../drivers/irqchip/irqchip.h" #include #include -- cgit v1.2.3-59-g8ed1b From 90b8baa2c1acb8c270aa31e75d00b44193fb306f Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:35 +0100 Subject: MIPS: Add MIPS I6400 PRid and cputype identifiers Add a Processor ID and CPU type for the MIPS I6400 core. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10634/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index e46e40602af3..5fa7b8ba48a9 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -120,6 +120,7 @@ #define PRID_IMP_PROAPTIV_MP 0xa300 #define PRID_IMP_M5150 0xa700 #define PRID_IMP_P5600 0xa800 +#define PRID_IMP_I6400 0xa900 /* * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE @@ -307,6 +308,7 @@ enum cpu_type_enum { CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150, + CPU_I6400, /* * MIPS64 class processors -- cgit v1.2.3-59-g8ed1b From 4e88a8621301b992e8e3422e08bfb604772f3338 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:36 +0100 Subject: MIPS: Add cases for CPU_I6400 Add a CPU_I6400 case to various switch statements, doing the same thing as for CPU_P5600. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10635/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-type.h | 4 ++++ arch/mips/kernel/idle.c | 1 + arch/mips/kernel/perf_event_mipsxx.c | 6 ++++++ arch/mips/kernel/pm-cps.c | 2 ++ arch/mips/kernel/spram.c | 1 + arch/mips/kernel/traps.c | 1 + arch/mips/mm/c-r4k.c | 1 + arch/mips/oprofile/common.c | 1 + arch/mips/oprofile/op_model_mipsxx.c | 4 ++++ 9 files changed, 21 insertions(+) diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index d41e8e284825..abee2bfd10dc 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h @@ -77,6 +77,10 @@ static inline int __pure __get_cpu_type(const int cpu_type) */ #endif +#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R6 + case CPU_I6400: +#endif + #ifdef CONFIG_SYS_HAS_CPU_R3000 case CPU_R2000: case CPU_R3000: diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index e4f62b7875d2..ab1478d5a4db 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -196,6 +196,7 @@ void __init check_wait(void) case CPU_INTERAPTIV: case CPU_M5150: case CPU_QEMU_GENERIC: + case CPU_I6400: cpu_wait = r4k_wait; if (read_c0_config7() & MIPS_CONF7_WII) cpu_wait = r4k_wait_irqoff; diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index cc1b6fadf089..d7b8dd43147a 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -1556,6 +1556,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) #endif break; case CPU_P5600: + case CPU_I6400: /* 8-bit event numbers */ raw_id = config & 0x1ff; base_id = raw_id & 0xff; @@ -1717,6 +1718,11 @@ init_hw_perf_events(void) mipspmu.general_event_map = &mipsxxcore_event_map2; mipspmu.cache_event_map = &mipsxxcore_cache_map2; break; + case CPU_I6400: + mipspmu.name = "mips/I6400"; + mipspmu.general_event_map = &mipsxxcore_event_map2; + mipspmu.cache_event_map = &mipsxxcore_cache_map2; + break; case CPU_1004K: mipspmu.name = "mips/1004K"; mipspmu.general_event_map = &mipsxxcore_event_map; diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 06147179a175..f63a289977cc 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -267,6 +267,7 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, /* CPUs which do not require the workaround */ case CPU_P5600: + case CPU_I6400: return 0; default: @@ -671,6 +672,7 @@ static int __init cps_pm_init(void) case CPU_PROAPTIV: case CPU_M5150: case CPU_P5600: + case CPU_I6400: stype_intervention = 0x2; stype_memory = 0x3; stype_ordering = 0x10; diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c index d1168d7c31e8..8489c88f9932 100644 --- a/arch/mips/kernel/spram.c +++ b/arch/mips/kernel/spram.c @@ -209,6 +209,7 @@ void spram_config(void) case CPU_PROAPTIV: case CPU_P5600: case CPU_QEMU_GENERIC: + case CPU_I6400: config0 = read_c0_config(); /* FIXME: addresses are Malta specific */ if (config0 & (1<<24)) { diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 8ea28e6ab37d..01da120d75c4 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1651,6 +1651,7 @@ static inline void parity_protection_init(void) case CPU_PROAPTIV: case CPU_P5600: case CPU_QEMU_GENERIC: + case CPU_I6400: { #define ERRCTL_PE 0x80000000 #define ERRCTL_L2P 0x00800000 diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index fbea4432f3f2..5d3a25e1cfae 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1276,6 +1276,7 @@ static void probe_pcache(void) case CPU_PROAPTIV: case CPU_M5150: case CPU_QEMU_GENERIC: + case CPU_I6400: if (!(read_c0_config7() & MIPS_CONF7_IAR) && (c->icache.waysize > PAGE_SIZE)) c->icache.flags |= MIPS_CACHE_ALIASES; diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 81f58958cf08..3c9ec3ddca84 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -91,6 +91,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case CPU_INTERAPTIV: case CPU_PROAPTIV: case CPU_P5600: + case CPU_I6400: case CPU_M5150: case CPU_LOONGSON1: case CPU_SB1: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 6a6e2cc55b89..8f988a61b7a8 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -392,6 +392,10 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.cpu_type = "mips/P5600"; break; + case CPU_I6400: + op_model_mipsxx_ops.cpu_type = "mips/I6400"; + break; + case CPU_M5150: op_model_mipsxx_ops.cpu_type = "mips/M5150"; break; -- cgit v1.2.3-59-g8ed1b From e57f9a2dcedc7f4847799e13a9987874a161d308 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:37 +0100 Subject: MIPS: Add MIPS I6400 probe support Add a case in cpu_probe_mips for the MIPS I6400 processor ID, which sets the CPU type to the new CPU_I6400. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10636/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dbe0792fc9c1..02b75127dad3 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1121,6 +1121,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_P5600; __cpu_name[cpu] = "MIPS P5600"; break; + case PRID_IMP_I6400: + c->cputype = CPU_I6400; + __cpu_name[cpu] = "MIPS I6400"; + break; case PRID_IMP_M5150: c->cputype = CPU_M5150; __cpu_name[cpu] = "MIPS M5150"; -- cgit v1.2.3-59-g8ed1b From 5676319c91c8d668635ac0b9b6d9145c4fa418ac Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:38 +0100 Subject: MIPS: Kconfig: Disable MIPS MT and SMP implementations for R6 R6 does not support the MIPS MT ASE and the CMP/SMP options so restrict them in order to prevent users from selecting incompatible SMP configuration for R6 cores. We also disable the CPS/SMP option because its support hasn't been added to the CPS code yet. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10637/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 199a8357838c..60d7ae76dd7e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2113,7 +2113,7 @@ config CPU_R4K_CACHE_TLB config MIPS_MT_SMP bool "MIPS MT SMP support (1 TC on each available VPE)" - depends on SYS_SUPPORTS_MULTITHREADING + depends on SYS_SUPPORTS_MULTITHREADING && !CPU_MIPSR6 select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select SYNC_R4K @@ -2214,7 +2214,7 @@ config MIPS_VPE_APSP_API_MT config MIPS_CMP bool "MIPS CMP framework support (DEPRECATED)" - depends on SYS_SUPPORTS_MIPS_CMP + depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6 select MIPS_GIC_IPI select SMP select SYNC_R4K @@ -2231,7 +2231,7 @@ config MIPS_CMP config MIPS_CPS bool "MIPS Coherent Processing System support" - depends on SYS_SUPPORTS_MIPS_CPS + depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6 select MIPS_CM select MIPS_CPC select MIPS_CPS_PM if HOTPLUG_CPU -- cgit v1.2.3-59-g8ed1b From 197e89e0984a2aaf1a5a998887b22e53051e3b6d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 10 Jul 2015 10:12:52 +0100 Subject: MIPS: mips-cm: Implement mips_cm_revision Provide a function to trivially return the version of the CM present in the system, or 0 if no CM is present. The mips_cm_revision() will be used later on to determine the CM register width, so it must not use the regular CM accessors to read the revision register since that will lead to build failures due to recursive inlines. Signed-off-by: Paul Burton Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10655/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index edc7ee95269e..c70ba21e62f0 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -189,6 +189,13 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_REV_MINOR_SHF 0 #define CM_GCR_REV_MINOR_MSK (_ULCAST_(0xff) << 0) +#define CM_ENCODE_REV(major, minor) \ + (((major) << CM_GCR_REV_MAJOR_SHF) | \ + ((minor) << CM_GCR_REV_MINOR_SHF)) + +#define CM_REV_CM2 CM_ENCODE_REV(6, 0) +#define CM_REV_CM3 CM_ENCODE_REV(8, 0) + /* GCR_ERROR_CAUSE register fields */ #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27) @@ -324,4 +331,18 @@ static inline int mips_cm_l2sync(void) return 0; } +/** + * mips_cm_revision() - return CM revision + * + * Return: The revision of the CM, from GCR_REV, or 0 if no CM is present. The + * return value should be checked against the CM_REV_* macros. + */ +static inline int mips_cm_revision(void) +{ + if (!mips_cm_present()) + return 0; + + return read_gcr_rev(); +} + #endif /* __MIPS_ASM_MIPS_CM_H__ */ -- cgit v1.2.3-59-g8ed1b From 0ba3c125aa0ff9f993c0f9629945a0dd18d42568 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 9 Jul 2015 10:40:40 +0100 Subject: MIPS: CM: Add GCR_L2_CONFIG register accessors Provide accessor functions for the GCR_L2_CONFIG register introduced with CM3, and define the bits included in the register. Signed-off-by: Paul Burton Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10639/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index c70ba21e62f0..ca3f2c963fbd 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -144,6 +144,7 @@ BUILD_CM_RW(reg3_base, MIPS_CM_GCB_OFS + 0xc0) BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8) BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0) BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0) +BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130) /* Core Local & Core Other register accessor functions */ BUILD_CM_Cx_RW(reset_release, 0x00) @@ -256,6 +257,16 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_CPC_STATUS_EX_SHF 0 #define CM_GCR_CPC_STATUS_EX_MSK (_ULCAST_(0x1) << 0) +/* GCR_L2_CONFIG register fields */ +#define CM_GCR_L2_CONFIG_BYPASS_SHF 20 +#define CM_GCR_L2_CONFIG_BYPASS_MSK (_ULCAST_(0x1) << 20) +#define CM_GCR_L2_CONFIG_SET_SIZE_SHF 12 +#define CM_GCR_L2_CONFIG_SET_SIZE_MSK (_ULCAST_(0xf) << 12) +#define CM_GCR_L2_CONFIG_LINE_SIZE_SHF 8 +#define CM_GCR_L2_CONFIG_LINE_SIZE_MSK (_ULCAST_(0xf) << 8) +#define CM_GCR_L2_CONFIG_ASSOC_SHF 0 +#define CM_GCR_L2_CONFIG_ASSOC_MSK (_ULCAST_(0xff) << 0) + /* GCR_Cx_COHERENCE register fields */ #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0 #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0) -- cgit v1.2.3-59-g8ed1b From 7d53e9c4cd21cbc82b7422c90852e56baaf7ddae Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 9 Jul 2015 10:40:42 +0100 Subject: MIPS: CM3: Add support for CM3 L2 cache. Detect the L2 cache configuration from GCR_L2_CONFIG when a CM3 is present in the system, rather than from Config2 which does not expose the L2 configuration on I6400. Signed-off-by: Paul Burton Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10641/ Signed-off-by: Ralf Baechle --- arch/mips/mm/sc-mips.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 4ceafd13870c..5fa452e8cff9 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -14,6 +14,7 @@ #include #include #include +#include /* * MIPS32/MIPS64 L2 cache handling @@ -94,6 +95,34 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) return 1; } +static int __init mips_sc_probe_cm3(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned long cfg = read_gcr_l2_config(); + unsigned long sets, line_sz, assoc; + + if (cfg & CM_GCR_L2_CONFIG_BYPASS_MSK) + return 0; + + sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK; + sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF; + c->scache.sets = 64 << sets; + + line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK; + line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF; + c->scache.linesz = 2 << line_sz; + + assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK; + assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF; + c->scache.ways = assoc + 1; + c->scache.waysize = c->scache.sets * c->scache.linesz; + c->scache.waybit = __ffs(c->scache.waysize); + + c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + + return 1; +} + static inline int __init mips_sc_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -103,6 +132,9 @@ static inline int __init mips_sc_probe(void) /* Mark as not present until probe completed */ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; + if (mips_cm_revision() >= CM_REV_CM3) + return mips_sc_probe_cm3(); + /* Ignore anything but MIPSxx processors */ if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | -- cgit v1.2.3-59-g8ed1b From c014d164f21dbdbe721a4ec7e5147591c4eed545 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:43 +0100 Subject: MIPS: Add platform callback before initializing the L2 cache Allow platforms to perform platform-specific steps before configuring the L2 cache. This is necessary for platforms with CM3 since the L2 parameters no longer live in the Config2 register. Signed-off-by: Markos Chandras Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10642/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 7 +++++++ arch/mips/mm/sc-mips.c | 10 ++++++++++ arch/mips/mti-malta/malta-init.c | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 85bbe9b96759..42602f30949f 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -81,6 +81,13 @@ int mips_cm_probe(void) phys_addr_t addr; u32 base_reg; + /* + * No need to probe again if we have already been + * here before. + */ + if (mips_cm_base) + return 0; + addr = mips_cm_phys_base(); BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr); if (!addr) diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 5fa452e8cff9..53ea8391f9bb 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -123,6 +123,10 @@ static int __init mips_sc_probe_cm3(void) return 1; } +void __weak platform_early_l2_init(void) +{ +} + static inline int __init mips_sc_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -132,6 +136,12 @@ static inline int __init mips_sc_probe(void) /* Mark as not present until probe completed */ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; + /* + * Do we need some platform specific probing before + * we configure L2? + */ + platform_early_l2_init(); + if (mips_cm_revision() >= CM_REV_CM3) return mips_sc_probe_cm3(); diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index cec3e187c48f..53c24784a2f7 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -303,3 +303,10 @@ mips_pci_controller: if (!register_vsmp_smp_ops()) return; } + +void platform_early_l2_init(void) +{ + /* L2 configuration lives in the CM3 */ + if (mips_cm_revision() >= CM_REV_CM3) + mips_cm_probe(); +} -- cgit v1.2.3-59-g8ed1b From c0b584a2691ccbc3c0d4e6cb1874bcf00a921371 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 14 Jul 2015 09:14:12 +0100 Subject: MIPS: mips-cm: Extend CM accessors for 64-bit CPUs Previously, the CM accessors were only accessing CM registers as u32 types instead of using the native CM register with. However, newer CMs may actually be 64-bit on MIPS64 cores. Fortunately, current 64-bit CMs (CM3) hold all the useful configuration bits in the lower half of the 64-bit registers (at least most of them) so they can still be accessed using the current 32-bit accessors. Signed-off-by: Markos Chandras Cc: Thomas Gleixner Cc: Jason Cooper Cc: Andrew Bresticker Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10707/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 48 +++++++++++++++++++++++++++++++++++++---- arch/mips/kernel/mips-cm.c | 4 ++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index ca3f2c963fbd..46cc0c69b77c 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -33,6 +33,20 @@ extern void __iomem *mips_cm_l2sync_base; */ extern phys_addr_t __mips_cm_phys_base(void); +/* + * mips_cm_is64 - determine CM register width + * + * The CM register width is processor and CM specific. A 64-bit processor + * usually has a 64-bit CM and a 32-bit one has a 32-bit CM but a 64-bit + * processor could come with a 32-bit CM. Moreover, accesses on 64-bit CMs + * can be done either using regular 64-bit load/store instructions, or 32-bit + * load/store instruction on 32-bit register pairs. We opt for using 64-bit + * accesses on 64-bit CMs and kernels and 32-bit in any other case. + * + * It's set to 0 for 32-bit accesses and 1 for 64-bit accesses. + */ +extern int mips_cm_is64; + /** * mips_cm_probe - probe for a Coherence Manager * @@ -90,20 +104,46 @@ static inline bool mips_cm_has_l2sync(void) /* Macros to ease the creation of register access functions */ #define BUILD_CM_R_(name, off) \ -static inline u32 __iomem *addr_gcr_##name(void) \ +static inline unsigned long __iomem *addr_gcr_##name(void) \ { \ - return (u32 __iomem *)(mips_cm_base + (off)); \ + return (unsigned long __iomem *)(mips_cm_base + (off)); \ } \ \ -static inline u32 read_gcr_##name(void) \ +static inline u32 read32_gcr_##name(void) \ { \ return __raw_readl(addr_gcr_##name()); \ +} \ + \ +static inline u64 read64_gcr_##name(void) \ +{ \ + return __raw_readq(addr_gcr_##name()); \ +} \ + \ +static inline unsigned long read_gcr_##name(void) \ +{ \ + if (mips_cm_is64) \ + return read64_gcr_##name(); \ + else \ + return read32_gcr_##name(); \ } #define BUILD_CM__W(name, off) \ -static inline void write_gcr_##name(u32 value) \ +static inline void write32_gcr_##name(u32 value) \ { \ __raw_writel(value, addr_gcr_##name()); \ +} \ + \ +static inline void write64_gcr_##name(u64 value) \ +{ \ + __raw_writeq(value, addr_gcr_##name()); \ +} \ + \ +static inline void write_gcr_##name(unsigned long value) \ +{ \ + if (mips_cm_is64) \ + write64_gcr_##name(value); \ + else \ + write32_gcr_##name(value); \ } #define BUILD_CM_RW(name, off) \ diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 42602f30949f..3d2cb6f47898 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -15,6 +15,7 @@ void __iomem *mips_cm_base; void __iomem *mips_cm_l2sync_base; +int mips_cm_is64; phys_addr_t __mips_cm_phys_base(void) { @@ -124,5 +125,8 @@ int mips_cm_probe(void) /* probe for an L2-only sync region */ mips_cm_probe_l2sync(); + /* determine register width for this CM */ + mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3); + return 0; } -- cgit v1.2.3-59-g8ed1b From 038b0f536e45d85038428d2edc169f1f4089c36d Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:45 +0100 Subject: MIPS: CM: The CMGCRBase register is 64-bit on 64 bit kernels. The CMGCRBase register (CP0, 15, 3) register is 64-bit on MIPS64 so we change its type to unsigned long. Signed-off-by: Markos Chandras Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10644/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 3d2cb6f47898..c390be1cecc9 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -20,7 +20,7 @@ int mips_cm_is64; phys_addr_t __mips_cm_phys_base(void) { u32 config3 = read_c0_config3(); - u32 cmgcr; + unsigned long cmgcr; /* Check the CMGCRBase register is implemented */ if (!(config3 & MIPS_CONF3_CMGCR)) -- cgit v1.2.3-59-g8ed1b From 391057d915f42d4942f0c65e7d55cec6662c8a54 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:46 +0100 Subject: MIPS: CPC: Fix type for GCR CPC base reg for 64-bit The GCR CPC base register is 64-bit on 64-bit processors so use the appropriate field. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10645/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 11964501c4b0..e05aca41e087 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -23,7 +23,7 @@ static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); phys_addr_t __weak mips_cpc_phys_base(void) { - u32 cpc_base; + unsigned long cpc_base; if (!mips_cm_present()) return 0; -- cgit v1.2.3-59-g8ed1b From 3885c2b463f6a236e47df22ef13d13433006b951 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:47 +0100 Subject: MIPS: CM: Add support for reporting CM cache errors The CM cache error reporting code is not Malta specific and as such it should live in the mips-cm.c file. Moreover, CM2 and CM3 differ in the way cache errors are being recorded to the registers so extend the previous code to add support for the CM3 as well. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10646/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 9 ++ arch/mips/kernel/mips-cm.c | 244 ++++++++++++++++++++++++++++++++++++++++ arch/mips/mti-malta/malta-int.c | 112 +----------------- 3 files changed, 254 insertions(+), 111 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 46cc0c69b77c..d75b75e78ebb 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -47,6 +47,15 @@ extern phys_addr_t __mips_cm_phys_base(void); */ extern int mips_cm_is64; +/** + * mips_cm_error_report - Report CM cache errors + */ +#ifdef CONFIG_MIPS_CM +extern void mips_cm_error_report(void); +#else +static inline void mips_cm_error_report(void) {} +#endif + /** * mips_cm_probe - probe for a Coherence Manager * diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index c390be1cecc9..b8ceee576cdf 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -17,6 +17,125 @@ void __iomem *mips_cm_base; void __iomem *mips_cm_l2sync_base; int mips_cm_is64; +static char *cm2_tr[8] = { + "mem", "gcr", "gic", "mmio", + "0x04", "cpc", "0x06", "0x07" +}; + +/* CM3 Tag ECC transation type */ +static char *cm3_tr[16] = { + [0x0] = "ReqNoData", + [0x1] = "0x1", + [0x2] = "ReqWData", + [0x3] = "0x3", + [0x4] = "IReqNoResp", + [0x5] = "IReqWResp", + [0x6] = "IReqNoRespDat", + [0x7] = "IReqWRespDat", + [0x8] = "RespNoData", + [0x9] = "RespDataFol", + [0xa] = "RespWData", + [0xb] = "RespDataOnly", + [0xc] = "IRespNoData", + [0xd] = "IRespDataFol", + [0xe] = "IRespWData", + [0xf] = "IRespDataOnly" +}; + +static char *cm2_cmd[32] = { + [0x00] = "0x00", + [0x01] = "Legacy Write", + [0x02] = "Legacy Read", + [0x03] = "0x03", + [0x04] = "0x04", + [0x05] = "0x05", + [0x06] = "0x06", + [0x07] = "0x07", + [0x08] = "Coherent Read Own", + [0x09] = "Coherent Read Share", + [0x0a] = "Coherent Read Discard", + [0x0b] = "Coherent Ready Share Always", + [0x0c] = "Coherent Upgrade", + [0x0d] = "Coherent Writeback", + [0x0e] = "0x0e", + [0x0f] = "0x0f", + [0x10] = "Coherent Copyback", + [0x11] = "Coherent Copyback Invalidate", + [0x12] = "Coherent Invalidate", + [0x13] = "Coherent Write Invalidate", + [0x14] = "Coherent Completion Sync", + [0x15] = "0x15", + [0x16] = "0x16", + [0x17] = "0x17", + [0x18] = "0x18", + [0x19] = "0x19", + [0x1a] = "0x1a", + [0x1b] = "0x1b", + [0x1c] = "0x1c", + [0x1d] = "0x1d", + [0x1e] = "0x1e", + [0x1f] = "0x1f" +}; + +/* CM3 Tag ECC command type */ +static char *cm3_cmd[16] = { + [0x0] = "Legacy Read", + [0x1] = "Legacy Write", + [0x2] = "Coherent Read Own", + [0x3] = "Coherent Read Share", + [0x4] = "Coherent Read Discard", + [0x5] = "Coherent Evicted", + [0x6] = "Coherent Upgrade", + [0x7] = "Coherent Upgrade for Store Conditional", + [0x8] = "Coherent Writeback", + [0x9] = "Coherent Write Invalidate", + [0xa] = "0xa", + [0xb] = "0xb", + [0xc] = "0xc", + [0xd] = "0xd", + [0xe] = "0xe", + [0xf] = "0xf" +}; + +/* CM3 Tag ECC command group */ +static char *cm3_cmd_group[8] = { + [0x0] = "Normal", + [0x1] = "Registers", + [0x2] = "TLB", + [0x3] = "0x3", + [0x4] = "L1I", + [0x5] = "L1D", + [0x6] = "L3", + [0x7] = "L2" +}; + +static char *cm2_core[8] = { + "Invalid/OK", "Invalid/Data", + "Shared/OK", "Shared/Data", + "Modified/OK", "Modified/Data", + "Exclusive/OK", "Exclusive/Data" +}; + +static char *cm2_causes[32] = { + "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", + "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", + "0x08", "0x09", "0x0a", "0x0b", + "0x0c", "0x0d", "0x0e", "0x0f", + "0x10", "0x11", "0x12", "0x13", + "0x14", "0x15", "0x16", "INTVN_WR_ERR", + "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", + "0x1c", "0x1d", "0x1e", "0x1f" +}; + +static char *cm3_causes[32] = { + "0x0", "MP_CORRECTABLE_ECC_ERR", "MP_REQUEST_DECODE_ERR", + "MP_UNCORRECTABLE_ECC_ERR", "MP_PARITY_ERR", "MP_COHERENCE_ERR", + "CMBIU_REQUEST_DECODE_ERR", "CMBIU_PARITY_ERR", "CMBIU_AXI_RESP_ERR", + "0x9", "RBI_BUS_ERR", "0xb", "0xc", "0xd", "0xe", "0xf", "0x10", + "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", + "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" +}; + phys_addr_t __mips_cm_phys_base(void) { u32 config3 = read_c0_config3(); @@ -130,3 +249,128 @@ int mips_cm_probe(void) return 0; } + +void mips_cm_error_report(void) +{ + unsigned long revision = mips_cm_revision(); + /* + * CM3 has a 64-bit Error cause register with 0:57 containing the error + * info and 63:58 the error type. For old CMs, everything is contained + * in a single 32-bit register (0:26 and 31:27 respectively). Even + * though the cm_error is u64, we will simply ignore the upper word + * for CM2. + */ + u64 cm_error = read_gcr_error_cause(); + int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + + ((revision >= CM_REV_CM3) ? 31 : 0); + unsigned long cm_addr = read_gcr_error_addr(); + unsigned long cm_other = read_gcr_error_mult(); + int ocause, cause; + char buf[256]; + + if (!mips_cm_present()) + return; + + cause = cm_error >> cm_error_cause_sft; + + if (!cause) + /* All good */ + return; + + ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; + if (revision < CM_REV_CM3) { /* CM2 */ + if (cause < 16) { + unsigned long cca_bits = (cm_error >> 15) & 7; + unsigned long tr_bits = (cm_error >> 12) & 7; + unsigned long cmd_bits = (cm_error >> 7) & 0x1f; + unsigned long stag_bits = (cm_error >> 3) & 15; + unsigned long sport_bits = (cm_error >> 0) & 7; + + snprintf(buf, sizeof(buf), + "CCA=%lu TR=%s MCmd=%s STag=%lu " + "SPort=%lu\n", cca_bits, cm2_tr[tr_bits], + cm2_cmd[cmd_bits], stag_bits, sport_bits); + } else { + /* glob state & sresp together */ + unsigned long c3_bits = (cm_error >> 18) & 7; + unsigned long c2_bits = (cm_error >> 15) & 7; + unsigned long c1_bits = (cm_error >> 12) & 7; + unsigned long c0_bits = (cm_error >> 9) & 7; + unsigned long sc_bit = (cm_error >> 8) & 1; + unsigned long cmd_bits = (cm_error >> 3) & 0x1f; + unsigned long sport_bits = (cm_error >> 0) & 7; + + snprintf(buf, sizeof(buf), + "C3=%s C2=%s C1=%s C0=%s SC=%s " + "MCmd=%s SPort=%lu\n", + cm2_core[c3_bits], cm2_core[c2_bits], + cm2_core[c1_bits], cm2_core[c0_bits], + sc_bit ? "True" : "False", + cm2_cmd[cmd_bits], sport_bits); + } + pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, + cm2_causes[cause], buf); + pr_err("CM_ADDR =%08lx\n", cm_addr); + pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]); + } else { /* CM3 */ + /* Used by cause == {1,2,3} */ + unsigned long core_id_bits = (cm_error >> 22) & 0xf; + unsigned long vp_id_bits = (cm_error >> 18) & 0xf; + unsigned long cmd_bits = (cm_error >> 14) & 0xf; + unsigned long cmd_group_bits = (cm_error >> 11) & 0xf; + unsigned long cm3_cca_bits = (cm_error >> 8) & 7; + unsigned long mcp_bits = (cm_error >> 5) & 0xf; + unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf; + unsigned long sched_bit = cm_error & 0x1; + + if (cause == 1 || cause == 3) { /* Tag ECC */ + unsigned long tag_ecc = (cm_error >> 57) & 0x1; + unsigned long tag_way_bits = (cm_error >> 29) & 0xffff; + unsigned long dword_bits = (cm_error >> 49) & 0xff; + unsigned long data_way_bits = (cm_error >> 45) & 0xf; + unsigned long data_sets_bits = (cm_error >> 29) & 0xfff; + unsigned long bank_bit = (cm_error >> 28) & 0x1; + snprintf(buf, sizeof(buf), + "%s ECC Error: Way=%lu (DWORD=%lu, Sets=%lu)" + "Bank=%lu CoreID=%lu VPID=%lu Command=%s" + "Command Group=%s CCA=%lu MCP=%d" + "Transaction type=%s Scheduler=%lu\n", + tag_ecc ? "TAG" : "DATA", + tag_ecc ? (unsigned long)ffs(tag_way_bits) - 1 : + data_way_bits, bank_bit, dword_bits, + data_sets_bits, + core_id_bits, vp_id_bits, + cm3_cmd[cmd_bits], + cm3_cmd_group[cmd_group_bits], + cm3_cca_bits, 1 << mcp_bits, + cm3_tr[cm3_tr_bits], sched_bit); + } else if (cause == 2) { + unsigned long data_error_type = (cm_error >> 41) & 0xfff; + unsigned long data_decode_cmd = (cm_error >> 37) & 0xf; + unsigned long data_decode_group = (cm_error >> 34) & 0x7; + unsigned long data_decode_destination_id = (cm_error >> 28) & 0x3f; + + snprintf(buf, sizeof(buf), + "Decode Request Error: Type=%lu, Command=%lu" + "Command Group=%lu Destination ID=%lu" + "CoreID=%lu VPID=%lu Command=%s" + "Command Group=%s CCA=%lu MCP=%d" + "Transaction type=%s Scheduler=%lu\n", + data_error_type, data_decode_cmd, + data_decode_group, data_decode_destination_id, + core_id_bits, vp_id_bits, + cm3_cmd[cmd_bits], + cm3_cmd_group[cmd_group_bits], + cm3_cca_bits, 1 << mcp_bits, + cm3_tr[cm3_tr_bits], sched_bit); + } + + pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, + cm3_causes[cause], buf); + pr_err("CM_ADDR =%lx\n", cm_addr); + pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]); + } + + /* reprime cause register */ + write_gcr_error_cause(0); +} diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index fa8f591f3713..c6a6c7afddab 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -382,122 +382,12 @@ void malta_be_init(void) /* Could change CM error mask register. */ } - -static char *tr[8] = { - "mem", "gcr", "gic", "mmio", - "0x04", "0x05", "0x06", "0x07" -}; - -static char *mcmd[32] = { - [0x00] = "0x00", - [0x01] = "Legacy Write", - [0x02] = "Legacy Read", - [0x03] = "0x03", - [0x04] = "0x04", - [0x05] = "0x05", - [0x06] = "0x06", - [0x07] = "0x07", - [0x08] = "Coherent Read Own", - [0x09] = "Coherent Read Share", - [0x0a] = "Coherent Read Discard", - [0x0b] = "Coherent Ready Share Always", - [0x0c] = "Coherent Upgrade", - [0x0d] = "Coherent Writeback", - [0x0e] = "0x0e", - [0x0f] = "0x0f", - [0x10] = "Coherent Copyback", - [0x11] = "Coherent Copyback Invalidate", - [0x12] = "Coherent Invalidate", - [0x13] = "Coherent Write Invalidate", - [0x14] = "Coherent Completion Sync", - [0x15] = "0x15", - [0x16] = "0x16", - [0x17] = "0x17", - [0x18] = "0x18", - [0x19] = "0x19", - [0x1a] = "0x1a", - [0x1b] = "0x1b", - [0x1c] = "0x1c", - [0x1d] = "0x1d", - [0x1e] = "0x1e", - [0x1f] = "0x1f" -}; - -static char *core[8] = { - "Invalid/OK", "Invalid/Data", - "Shared/OK", "Shared/Data", - "Modified/OK", "Modified/Data", - "Exclusive/OK", "Exclusive/Data" -}; - -static char *causes[32] = { - "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", - "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", - "0x08", "0x09", "0x0a", "0x0b", - "0x0c", "0x0d", "0x0e", "0x0f", - "0x10", "0x11", "0x12", "0x13", - "0x14", "0x15", "0x16", "INTVN_WR_ERR", - "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", - "0x1c", "0x1d", "0x1e", "0x1f" -}; - int malta_be_handler(struct pt_regs *regs, int is_fixup) { /* This duplicates the handling in do_be which seems wrong */ int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; - if (mips_cm_present()) { - unsigned long cm_error = read_gcr_error_cause(); - unsigned long cm_addr = read_gcr_error_addr(); - unsigned long cm_other = read_gcr_error_mult(); - unsigned long cause, ocause; - char buf[256]; - - cause = cm_error & CM_GCR_ERROR_CAUSE_ERRTYPE_MSK; - if (cause != 0) { - cause >>= CM_GCR_ERROR_CAUSE_ERRTYPE_SHF; - if (cause < 16) { - unsigned long cca_bits = (cm_error >> 15) & 7; - unsigned long tr_bits = (cm_error >> 12) & 7; - unsigned long cmd_bits = (cm_error >> 7) & 0x1f; - unsigned long stag_bits = (cm_error >> 3) & 15; - unsigned long sport_bits = (cm_error >> 0) & 7; - - snprintf(buf, sizeof(buf), - "CCA=%lu TR=%s MCmd=%s STag=%lu " - "SPort=%lu\n", - cca_bits, tr[tr_bits], mcmd[cmd_bits], - stag_bits, sport_bits); - } else { - /* glob state & sresp together */ - unsigned long c3_bits = (cm_error >> 18) & 7; - unsigned long c2_bits = (cm_error >> 15) & 7; - unsigned long c1_bits = (cm_error >> 12) & 7; - unsigned long c0_bits = (cm_error >> 9) & 7; - unsigned long sc_bit = (cm_error >> 8) & 1; - unsigned long cmd_bits = (cm_error >> 3) & 0x1f; - unsigned long sport_bits = (cm_error >> 0) & 7; - snprintf(buf, sizeof(buf), - "C3=%s C2=%s C1=%s C0=%s SC=%s " - "MCmd=%s SPort=%lu\n", - core[c3_bits], core[c2_bits], - core[c1_bits], core[c0_bits], - sc_bit ? "True" : "False", - mcmd[cmd_bits], sport_bits); - } - - ocause = (cm_other & CM_GCR_ERROR_MULT_ERR2ND_MSK) >> - CM_GCR_ERROR_MULT_ERR2ND_SHF; - - pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error, - causes[cause], buf); - pr_err("CM_ADDR =%08lx\n", cm_addr); - pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); - - /* reprime cause register */ - write_gcr_error_cause(0); - } - } + mips_cm_error_report(); return retval; } -- cgit v1.2.3-59-g8ed1b From c3f57f02e3a275d8b5c6dc692adb21525ccb392c Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 14 Jul 2015 10:26:09 +0100 Subject: IRQCHIP: irq-mips-gic: Extend GIC accessors for 64-bit CMs Previously, the GIC accessors were only accessing u32 registers but newer CMs may actually be 64-bit on MIPS64 cores. As a result of which, extended these accessors to support 64-bit reads and writes. Signed-off-by: Markos Chandras Cc: Thomas Gleixner Cc: Jason Cooper Cc: Andrew Bresticker Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10709/ Signed-off-by: Ralf Baechle --- drivers/irqchip/irq-mips-gic.c | 121 ++++++++++++++++++++++++--------------- include/linux/irqchip/mips-gic.h | 10 +++- 2 files changed, 84 insertions(+), 47 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index ff4be0515a0d..d8db854afded 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -42,20 +42,46 @@ static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; static void __gic_irq_dispatch(void); -static inline unsigned int gic_read(unsigned int reg) +static inline u32 gic_read32(unsigned int reg) { return __raw_readl(gic_base + reg); } -static inline void gic_write(unsigned int reg, unsigned int val) +static inline u64 gic_read64(unsigned int reg) { - __raw_writel(val, gic_base + reg); + return __raw_readq(gic_base + reg); } -static inline void gic_update_bits(unsigned int reg, unsigned int mask, - unsigned int val) +static inline unsigned long gic_read(unsigned int reg) { - unsigned int regval; + if (!mips_cm_is64) + return gic_read32(reg); + else + return gic_read64(reg); +} + +static inline void gic_write32(unsigned int reg, u32 val) +{ + return __raw_writel(val, gic_base + reg); +} + +static inline void gic_write64(unsigned int reg, u64 val) +{ + return __raw_writeq(val, gic_base + reg); +} + +static inline void gic_write(unsigned int reg, unsigned long val) +{ + if (!mips_cm_is64) + return gic_write32(reg, (u32)val); + else + return gic_write64(reg, (u64)val); +} + +static inline void gic_update_bits(unsigned int reg, unsigned long mask, + unsigned long val) +{ + unsigned long regval; regval = gic_read(reg); regval &= ~mask; @@ -66,40 +92,40 @@ static inline void gic_update_bits(unsigned int reg, unsigned int mask, static inline void gic_reset_mask(unsigned int intr) { gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr)); } static inline void gic_set_mask(unsigned int intr) { gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr)); } static inline void gic_set_polarity(unsigned int intr, unsigned int pol) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) + - GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), - pol << GIC_INTR_BIT(intr)); + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), + (unsigned long)pol << GIC_INTR_BIT(intr)); } static inline void gic_set_trigger(unsigned int intr, unsigned int trig) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) + - GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), - trig << GIC_INTR_BIT(intr)); + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), + (unsigned long)trig << GIC_INTR_BIT(intr)); } static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr), - dual << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr), + (unsigned long)dual << GIC_INTR_BIT(intr)); } static inline void gic_map_to_pin(unsigned int intr, unsigned int pin) { - gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + - GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); + gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + + GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); } static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe) @@ -115,9 +141,9 @@ cycle_t gic_read_count(void) unsigned int hi, hi2, lo; do { - hi = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); - lo = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); - hi2 = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); + hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); } while (hi2 != hi); return (((cycle_t) hi) << 32) + lo; @@ -136,9 +162,9 @@ unsigned int gic_get_count_width(void) void gic_write_compare(cycle_t cnt) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), (int)(cnt >> 32)); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), (int)(cnt & 0xffffffff)); } @@ -148,10 +174,10 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), (int)(cnt >> 32)); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), (int)(cnt & 0xffffffff)); local_irq_restore(flags); @@ -161,8 +187,8 @@ cycle_t gic_read_compare(void) { unsigned int hi, lo; - hi = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); - lo = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); + hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); + lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); return (((cycle_t) hi) << 32) + lo; } @@ -197,7 +223,7 @@ static bool gic_local_irq_is_routable(int intr) if (cpu_has_veic) return true; - vpe_ctl = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); + vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); switch (intr) { case GIC_LOCAL_INT_TIMER: return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK; @@ -263,7 +289,7 @@ int gic_get_c0_fdc_int(void) static void gic_handle_shared_int(bool chained) { - unsigned int i, intr, virq; + unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4; unsigned long *pcpu_mask; unsigned long pending_reg, intrmask_reg; DECLARE_BITMAP(pending, GIC_MAX_INTRS); @@ -278,8 +304,8 @@ static void gic_handle_shared_int(bool chained) for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) { pending[i] = gic_read(pending_reg); intrmask[i] = gic_read(intrmask_reg); - pending_reg += 0x4; - intrmask_reg += 0x4; + pending_reg += gic_reg_step; + intrmask_reg += gic_reg_step; } bitmap_and(pending, pending, intrmask, gic_shared_intrs); @@ -429,8 +455,8 @@ static void gic_handle_local_int(bool chained) unsigned long pending, masked; unsigned int intr, virq; - pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); - masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); + pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); + masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); @@ -453,14 +479,14 @@ static void gic_mask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); } static void gic_unmask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); } static struct irq_chip gic_local_irq_controller = { @@ -478,7 +504,7 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); } @@ -492,7 +518,7 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); } @@ -612,7 +638,7 @@ static void __init gic_basic_init(void) for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { if (!gic_local_irq_is_routable(j)) continue; - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); } } } @@ -657,27 +683,32 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, switch (intr) { case GIC_LOCAL_INT_WD: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); break; case GIC_LOCAL_INT_COMPARE: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), + val); break; case GIC_LOCAL_INT_TIMER: /* CONFIG_MIPS_CMP workaround (see __gic_init) */ val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin; - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), + val); break; case GIC_LOCAL_INT_PERFCTR: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), + val); break; case GIC_LOCAL_INT_SWINT0: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), + val); break; case GIC_LOCAL_INT_SWINT1: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), + val); break; case GIC_LOCAL_INT_FDC: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); break; default: pr_err("Invalid local IRQ %d\n", intr); @@ -782,7 +813,7 @@ static void __init __gic_init(unsigned long gic_base_addr, */ if (IS_ENABLED(CONFIG_MIPS_CMP) && gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { - timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL, + timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_TIMER_MAP)) & GIC_MAP_MSK; irq_set_chained_handler(MIPS_CPU_IRQ_BASE + diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index 9b1ad3734911..10e4a9073019 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -45,8 +45,14 @@ #define GIC_SH_REVISIONID_OFS 0x0020 /* Convert an interrupt number to a byte offset/bit for multi-word registers */ -#define GIC_INTR_OFS(intr) (((intr) / 32) * 4) -#define GIC_INTR_BIT(intr) ((intr) % 32) +#define GIC_INTR_OFS(intr) ({ \ + unsigned bits = mips_cm_is64 ? 64 : 32; \ + unsigned reg_idx = (intr) / bits; \ + unsigned reg_width = bits / 8; \ + \ + reg_idx * reg_width; \ +}) +#define GIC_INTR_BIT(intr) ((intr) % (mips_cm_is64 ? 64 : 32)) /* Polarity : Reset Value is always 0 */ #define GIC_SH_SET_POLARITY_OFS 0x0100 -- cgit v1.2.3-59-g8ed1b From 6f50c83529ac1fa3444ff4be5f5b0bf3d76db678 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:49 +0100 Subject: IRQCHIP: irq-mips-gic: Add support for CM3 64-bit timer irqs CM3 uses a 64-bit counter and compare registers so add support for them in the GIC counter interrupt. Signed-off-by: Markos Chandras Cc: Thomas Gleixner Cc: Jason Cooper Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10648/ Signed-off-by: Ralf Baechle --- drivers/irqchip/irq-mips-gic.c | 33 ++++++++++++++++++++++++--------- include/linux/irqchip/mips-gic.h | 4 ++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index d8db854afded..7d4616963b5a 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -140,6 +140,9 @@ cycle_t gic_read_count(void) { unsigned int hi, hi2, lo; + if (mips_cm_is64) + return (cycle_t)gic_read(GIC_REG(SHARED, GIC_SH_COUNTER)); + do { hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); @@ -162,10 +165,14 @@ unsigned int gic_get_count_width(void) void gic_write_compare(cycle_t cnt) { - gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); + if (mips_cm_is64) { + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt); + } else { + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); + } } void gic_write_cpu_compare(cycle_t cnt, int cpu) @@ -174,11 +181,16 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); - gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); - gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + + if (mips_cm_is64) { + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); + } else { + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); + } local_irq_restore(flags); } @@ -187,6 +199,9 @@ cycle_t gic_read_compare(void) { unsigned int hi, lo; + if (mips_cm_is64) + return (cycle_t)gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE)); + hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index 10e4a9073019..4e6861605050 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -41,6 +41,8 @@ /* Shared Global Counter */ #define GIC_SH_COUNTER_31_00_OFS 0x0010 +/* 64-bit counter register for CM3 */ +#define GIC_SH_COUNTER_OFS GIC_SH_COUNTER_31_00_OFS #define GIC_SH_COUNTER_63_32_OFS 0x0014 #define GIC_SH_REVISIONID_OFS 0x0020 @@ -104,6 +106,8 @@ #define GIC_VPE_WD_COUNT0_OFS 0x0094 #define GIC_VPE_WD_INITIAL0_OFS 0x0098 #define GIC_VPE_COMPARE_LO_OFS 0x00a0 +/* 64-bit Compare register on CM3 */ +#define GIC_VPE_COMPARE_OFS GIC_VPE_COMPARE_LO_OFS #define GIC_VPE_COMPARE_HI_OFS 0x00a4 #define GIC_VPE_EIC_SHADOW_SET_BASE_OFS 0x0100 -- cgit v1.2.3-59-g8ed1b From c982c6d6c48b48159db481581cadbb8773219677 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:50 +0100 Subject: MIPS: cpu-probe: Remove cp0 hazard barrier when enabling the FTLB We are so early in the boot process where we really don't want to stall and wait for CP0 FTLB related changes become visible so just drop the cp0 hazard barrier. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10649/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 02b75127dad3..dc057f37305b 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -385,7 +385,6 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) else /* Disable FTLB */ write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); - back_to_back_c0_hazard(); break; } } -- cgit v1.2.3-59-g8ed1b From 912708c26d673f8d043bc4a9552495fefd6ddf18 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:51 +0100 Subject: MIPS: Add default case for the FTLB enable/disable code Add a default case for the FTLB enable/disable code. This will be used to detect that something went wrong in the set_ftlb_enable() function either because that function knows nothing about the running core, or simply because the core can't turn its FTLB on/off. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10650/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dc057f37305b..6da5f2db6792 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -188,7 +188,7 @@ __setup("nohtw", htw_disable); static int mips_ftlb_disabled; static int mips_has_ftlb_configured; -static void set_ftlb_enable(struct cpuinfo_mips *c, int enable); +static int set_ftlb_enable(struct cpuinfo_mips *c, int enable); static int __init ftlb_disable(char *s) { @@ -202,7 +202,10 @@ static int __init ftlb_disable(char *s) return 1; /* Disable it in the boot cpu */ - set_ftlb_enable(&cpu_data[0], 0); + if (set_ftlb_enable(&cpu_data[0], 0)) { + pr_warn("Can't turn FTLB off\n"); + return 1; + } back_to_back_c0_hazard(); @@ -364,7 +367,7 @@ static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) return 3; } -static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) +static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) { unsigned int config6; @@ -386,7 +389,11 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) /* Disable FTLB */ write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); break; + default: + return 1; } + + return 0; } static inline unsigned int decode_config0(struct cpuinfo_mips *c) -- cgit v1.2.3-59-g8ed1b From e87569cd6c57cfe8c3fbbd20a5cf5cefb8b14156 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:52 +0100 Subject: MIPS: cpu-probe: Fix VTLB/FTLB configuration for R6 R6 has dropped the MMUExtDef field from the config4 register and it now returns 0. However, the return value means nothing in that case and the only supported configuration for R6 is the VTLB+FTLB (MMUextDef == 3). As a result, rework the code so that the correct value is set for R6 cores. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10651/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 6da5f2db6792..62dae429fe70 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -546,7 +546,16 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) if (cpu_has_tlb) { if (((config4 & MIPS_CONF4_IE) >> 29) == 2) c->options |= MIPS_CPU_TLBINV; - mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; + /* + * This is a bit ugly. R6 has dropped that field from + * config4 and the only valid configuration is VTLB+FTLB so + * set a good value for mmuextdef for that case. + */ + if (cpu_has_mips_r6) + mmuextdef = MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT; + else + mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; + switch (mmuextdef) { case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT: c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; -- cgit v1.2.3-59-g8ed1b From 20a7f7e5a6739a3521529a5f2bbfddf9f545fef9 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:53 +0100 Subject: MIPS: Set up FTLB probability for I6400 Set up the I6400 FTLB probability similar to P5600 and proAptiv. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10652/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 2 ++ arch/mips/kernel/cpu-probe.c | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index c5b0956a8530..723ee3c7849d 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -579,6 +579,8 @@ #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) #define MIPS_CONF7_AR (_ULCAST_(1) << 16) +/* FTLB probability bits for R6 */ +#define MIPS_CONF7_FTLBP_SHIFT (18) /* MAAR bit definitions */ #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 62dae429fe70..4e39b340f3b7 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -369,25 +369,33 @@ static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) { - unsigned int config6; + unsigned int config; /* It's implementation dependent how the FTLB can be enabled */ switch (c->cputype) { case CPU_PROAPTIV: case CPU_P5600: /* proAptiv & related cores use Config6 to enable the FTLB */ - config6 = read_c0_config6(); + config = read_c0_config6(); /* Clear the old probability value */ - config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); + config &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); if (enable) /* Enable FTLB */ - write_c0_config6(config6 | + write_c0_config6(config | (calculate_ftlb_probability(c) << MIPS_CONF6_FTLBP_SHIFT) | MIPS_CONF6_FTLBEN); else /* Disable FTLB */ - write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); + write_c0_config6(config & ~MIPS_CONF6_FTLBEN); + break; + case CPU_I6400: + /* I6400 & related cores use Config7 to configure FTLB */ + config = read_c0_config7(); + /* Clear the old probability value */ + config &= ~(3 << MIPS_CONF7_FTLBP_SHIFT); + write_c0_config7(config | (calculate_ftlb_probability(c) + << MIPS_CONF7_FTLBP_SHIFT)); break; default: return 1; -- cgit v1.2.3-59-g8ed1b From f058dc80d6f964fa466650f74290a964a7f91c92 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:53 +0000 Subject: MIPS: jz4740: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10695/ Signed-off-by: Ralf Baechle --- arch/mips/jz4740/gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c index 54c80d42a88d..77df1602f818 100644 --- a/arch/mips/jz4740/gpio.c +++ b/arch/mips/jz4740/gpio.c @@ -423,8 +423,8 @@ static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); chip->irq = JZ4740_IRQ_INTC_GPIO(id); - irq_set_handler_data(chip->irq, chip); - irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); + irq_set_chained_handler_and_data(chip->irq, + jz_gpio_irq_demux_handler, chip); gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base, chip->base, handle_level_irq); -- cgit v1.2.3-59-g8ed1b From 777fd18a71866f5057b27535c47c817973293498 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:55 +0000 Subject: MIPS: pci-ar71xx: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10696/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-ar71xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 283157f8dc64..ad35a5e6a56c 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -312,8 +312,8 @@ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) irq_set_chip_data(i, apc); } - irq_set_handler_data(apc->irq, apc); - irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); + irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler, + apc); } static void ar71xx_pci_reset(void) -- cgit v1.2.3-59-g8ed1b From 4d3f77d855090e11c9823fcb00864745adaf6fae Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:56 +0000 Subject: MIPS: pci-ar724x: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10697/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-ar724x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 0af362b5af92..907d11dd921b 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -321,8 +321,8 @@ static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc, irq_set_chip_data(i, apc); } - irq_set_handler_data(apc->irq, apc); - irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); + irq_set_chained_handler_and_data(apc->irq, ar724x_pci_irq_handler, + apc); } static int ar724x_pci_probe(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From 586134a84c0e3e503d2e65a117e2cb06f376aac8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:58 +0000 Subject: MIPS: pci-rt3883: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10698/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-rt3883.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index 80fafe646e74..c156f48912e8 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -225,8 +225,7 @@ static int rt3883_pci_irq_init(struct device *dev, return -ENODEV; } - irq_set_handler_data(irq, rpc); - irq_set_chained_handler(irq, rt3883_pci_irq_handler); + irq_set_chained_handler_and_data(irq, rt3883_pci_irq_handler, rpc); return 0; } -- cgit v1.2.3-59-g8ed1b From 5c1594224fffccb4adb76fb460871e1047accbbd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:45:59 +0000 Subject: MIPS: irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10699/ Signed-off-by: Ralf Baechle --- arch/mips/bcm63xx/irq.c | 2 +- arch/mips/cavium-octeon/octeon-irq.c | 14 ++++++++------ arch/mips/pmcs-msp71xx/msp_irq_cic.c | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index e3e808a6c542..02983b90826d 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -60,7 +60,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, if (m) enable &= cpumask_test_cpu(cpu, m); else if (irqd_affinity_was_set(d)) - enable &= cpumask_test_cpu(cpu, d->affinity); + enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d)); #endif return enable; } diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index d8124a3c5a85..18bf3dcb9d1b 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -225,13 +225,14 @@ static int next_cpu_for_irq(struct irq_data *data) #ifdef CONFIG_SMP int cpu; - int weight = cpumask_weight(data->affinity); + struct cpumask *mask = irq_data_get_affinity_mask(data); + int weight = cpumask_weight(mask); struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data); if (weight > 1) { cpu = cd->current_cpu; for (;;) { - cpu = cpumask_next(cpu, data->affinity); + cpu = cpumask_next(cpu, mask); if (cpu >= nr_cpu_ids) { cpu = -1; continue; @@ -240,7 +241,7 @@ static int next_cpu_for_irq(struct irq_data *data) } } } else if (weight == 1) { - cpu = cpumask_first(data->affinity); + cpu = cpumask_first(mask); } else { cpu = smp_processor_id(); } @@ -712,16 +713,17 @@ static void octeon_irq_cpu_offline_ciu(struct irq_data *data) { int cpu = smp_processor_id(); cpumask_t new_affinity; + struct cpumask *mask = irq_data_get_affinity_mask(data); - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, mask)) return; - if (cpumask_weight(data->affinity) > 1) { + if (cpumask_weight(mask) > 1) { /* * It has multi CPU affinity, just remove this CPU * from the affinity set. */ - cpumask_copy(&new_affinity, data->affinity); + cpumask_copy(&new_affinity, mask); cpumask_clear_cpu(cpu, &new_affinity); } else { /* Otherwise, put it on lowest numbered online CPU. */ diff --git a/arch/mips/pmcs-msp71xx/msp_irq_cic.c b/arch/mips/pmcs-msp71xx/msp_irq_cic.c index 1207ec4dfb77..8b9cf6463040 100644 --- a/arch/mips/pmcs-msp71xx/msp_irq_cic.c +++ b/arch/mips/pmcs-msp71xx/msp_irq_cic.c @@ -88,7 +88,8 @@ static void unmask_cic_irq(struct irq_data *d) * Make sure we have IRQ affinity. It may have changed while * we were processing the IRQ. */ - if (!cpumask_test_cpu(smp_processor_id(), d->affinity)) + if (!cpumask_test_cpu(smp_processor_id(), + irq_data_get_affinity_mask(d))) return; #endif -- cgit v1.2.3-59-g8ed1b From 5a06545008514ce4b9315284b4ddff31bfa9d77e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:01 +0000 Subject: MIPS: alchemy: Use irq_set_chip_handler_name_locked() Hand in irq_data and avoid the redundant lookup of irq_desc. Originally-from: Jiang Liu Signed-off-by: Thomas Gleixner Cc: LKML Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10700/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/common/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 6cb60abfdcc9..4c496c50edf6 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -491,7 +491,7 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) default: ret = -EINVAL; } - __irq_set_chip_handler_name_locked(d->irq, chip, handler, name); + irq_set_chip_handler_name_locked(d, chip, handler, name); wmb(); @@ -703,7 +703,7 @@ static int au1300_gpic_settype(struct irq_data *d, unsigned int type) return -EINVAL; } - __irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name); + irq_set_chip_handler_name_locked(d, &au1300_gpic, hdl, name); au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); -- cgit v1.2.3-59-g8ed1b From 9154566ee3edd0f6a7aa4ef8bed76d3cd57bcb88 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:02 +0000 Subject: MIPS: bcm63xx: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10701/ Signed-off-by: Ralf Baechle --- arch/mips/bcm63xx/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 02983b90826d..1a47ec2a0906 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -365,9 +365,9 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d, irqd_set_trigger_type(d, flow_type); if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return IRQ_SET_MASK_OK_NOCOPY; } -- cgit v1.2.3-59-g8ed1b From e0288a0a7bb8b28787453cb96f7aad272086def1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:04 +0000 Subject: MIPS: alchemy: Remove pointless irqdisable/enable bcsr_csc_handler() is a cascading interrupt handler. It has a disable_irq_nosync()/enable_irq() pair around the generic_handle_irq() call. The value of this disable/enable is zero because its a complete noop: disable_irq_nosync() merily increments the disable count without actually masking the interrupt. enable_irq() soleley decrements the disable count without touching the interrupt chip. The interrupt cannot arrive again because the complete call chain runs with interrupts disabled. Remove it. [ralf@linux-mips.org: Fold in followup fix from Thomas Gleixner.] Signed-off-by: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10702/ Patchwork: https://patchwork.linux-mips.org/patch/10708/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/devboards/bcsr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c index c98c9ea3372c..324ad72d7c36 100644 --- a/arch/mips/alchemy/devboards/bcsr.c +++ b/arch/mips/alchemy/devboards/bcsr.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -88,10 +89,11 @@ EXPORT_SYMBOL_GPL(bcsr_mod); static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) { unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT); + struct irq_chip *chip = irq_desc_get_chip(d); - disable_irq_nosync(irq); + chained_irq_enter(chip, d); generic_handle_irq(bcsr_csc_base + __ffs(bisr)); - enable_irq(irq); + chained_irq_exit(chip, d); } static void bcsr_irq_mask(struct irq_data *d) -- cgit v1.2.3-59-g8ed1b From 9d9a2fa7dcbd05a1608a6a38b6ec1a092e117c3c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:06 +0000 Subject: MIPS: ath91: Remove pointless irqdisable/enable The various interrupt flow handlers in ath79 are cascading interrupt handlers. They all have a disable_irq_nosync()/enable_irq() pair around the generic_handle_irq() call. The value of this disable/enable is zero because its a complete noop: disable_irq_nosync() merily increments the disable count without actually masking the interrupt. enable_irq() soleley decrements the disable count without touching the interrupt chip. The interrupt cannot arrive again because the complete call chain runs with interrupts disabled. Remove it. Signed-off-by: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10703/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/irq.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index 2021be20d9d9..807132b838b2 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -123,8 +123,6 @@ static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) { u32 status; - disable_irq_nosync(irq); - status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) { @@ -136,8 +134,6 @@ static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) } else { spurious_interrupt(); } - - enable_irq(irq); } static void ar934x_ip2_irq_init(void) @@ -156,14 +152,12 @@ static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) { u32 status; - disable_irq_nosync(irq); - status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL; if (status == 0) { spurious_interrupt(); - goto enable; + return; } if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) { @@ -175,17 +169,12 @@ static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) /* TODO: flush DDR? */ generic_handle_irq(ATH79_IP2_IRQ(1)); } - -enable: - enable_irq(irq); } static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) { u32 status; - disable_irq_nosync(irq); - status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); status &= QCA955X_EXT_INT_PCIE_RC2_ALL | QCA955X_EXT_INT_USB1 | @@ -193,7 +182,7 @@ static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) if (status == 0) { spurious_interrupt(); - goto enable; + return; } if (status & QCA955X_EXT_INT_USB1) { @@ -210,9 +199,6 @@ static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) /* TODO: flush DDR? */ generic_handle_irq(ATH79_IP3_IRQ(2)); } - -enable: - enable_irq(irq); } static void qca955x_irq_init(void) -- cgit v1.2.3-59-g8ed1b From 56a86c352b02ce2fe09a72771ef4334632a1f9c1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:07 +0000 Subject: MIPS: octeon: Replace the homebrewn flow handler The gpio interrupt handling of octeon contains a homebrewn flow handler which calls either handle_level_irq or handle_edge_irq depending on the trigger type. Thats an extra conditional and call in the interrupt handling path. The proper way to handle different types and therefor different flows is to update the handler in the irq_set_type() callback. Remove the extra indirection and add the handler update to octeon_irq_ciu_gpio_set_type(). At mapping time it defaults to handle_level_irq which gets updated if the device tree contains a different trigger type. Signed-off-by: Thomas Gleixner Cc: David Daney Cc: Jiang Liu Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10704/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/octeon-irq.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 18bf3dcb9d1b..f26c3c661cca 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -663,6 +663,11 @@ static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t) irqd_set_trigger_type(data, t); octeon_irq_gpio_setup(data); + if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(data, handle_edge_irq); + else + irq_set_handler_locked(data, handle_level_irq); + return IRQ_SET_MASK_OK; } @@ -697,16 +702,6 @@ static void octeon_irq_ciu_gpio_ack(struct irq_data *data) cvmx_write_csr(CVMX_GPIO_INT_CLR, mask); } -static void octeon_irq_handle_trigger(unsigned int irq, struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - - if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) - handle_edge_irq(irq, desc); - else - handle_level_irq(irq, desc); -} - #ifdef CONFIG_SMP static void octeon_irq_cpu_offline_ciu(struct irq_data *data) @@ -1229,8 +1224,13 @@ static int octeon_irq_gpio_map(struct irq_domain *d, octeon_irq_ciu_to_irq[line][bit] != 0) return -EINVAL; + /* + * Default to handle_level_irq. If the DT contains a different + * trigger type, it will call the irq_set_type callback and + * the handler gets updated. + */ r = octeon_irq_set_ciu_mapping(virq, line, bit, hw, - octeon_irq_gpio_chip, octeon_irq_handle_trigger); + octeon_irq_gpio_chip, handle_level_irq); return r; } -- cgit v1.2.3-59-g8ed1b From 31429d1a74c01875d7dad72a6a1d75d8eeca2bc6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:09 +0000 Subject: MIPS: netlogic: Prepare ipi handlers for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10705/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/common/smp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index f5fff228b347..0136b4f9c9cd 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -82,8 +82,9 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) } /* IRQ_IPI_SMP_FUNCTION Handler */ -void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) +void nlm_smp_function_ipi_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); clear_c0_eimr(irq); ack_c0_eirr(irq); generic_smp_call_function_interrupt(); @@ -91,8 +92,9 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) } /* IRQ_IPI_SMP_RESCHEDULE handler */ -void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) +void nlm_smp_resched_ipi_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); clear_c0_eimr(irq); ack_c0_eirr(irq); scheduler_ipi(); -- cgit v1.2.3-59-g8ed1b From e51395d2739d0bb4991b6b531e1066475aae9bfd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:10 +0000 Subject: MIPS: rt3883: Prepare rt3883_pci_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10706/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-rt3883.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index c156f48912e8..53c8efaf1572 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -129,7 +129,7 @@ static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc, rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA); } -static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) +static void rt3883_pci_irq_handler(unsigned int __irq, struct irq_desc *desc) { struct rt3883_pci_controller *rpc; u32 pending; @@ -145,7 +145,7 @@ static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) } while (pending) { - unsigned bit = __ffs(pending); + unsigned irq, bit = __ffs(pending); irq = irq_find_mapping(rpc->irq_domain, bit); generic_handle_irq(irq); -- cgit v1.2.3-59-g8ed1b From 2dca88da835616c3c65d1e4167288346fd67f02f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 13 Jul 2015 17:14:21 +0100 Subject: MIPS: ops-emma2rh: Drop nonsensical db_assert The db_assert call checks whether the bus_num pointer is non-NULL, but does so after said pointer has been dereferenced by the assignment on the previous line. Thus the check is pointless & likely to have been optimised out by the compiler anyway. The check_args function is static & only ever called from the local file with bus_num being a pointer to an on-stack variable, so the check seems somewhat overzealous anyway. Simply remove it. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10692/ Signed-off-by: Ralf Baechle --- arch/mips/pci/ops-emma2rh.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/mips/pci/ops-emma2rh.c b/arch/mips/pci/ops-emma2rh.c index 710aef5c070e..2dc97c45685e 100644 --- a/arch/mips/pci/ops-emma2rh.c +++ b/arch/mips/pci/ops-emma2rh.c @@ -25,7 +25,6 @@ #include #include -#include #include @@ -40,10 +39,9 @@ static int check_args(struct pci_bus *bus, u32 devfn, u32 * bus_num) { /* check if the bus is top-level */ - if (bus->parent != NULL) { + if (bus->parent != NULL) *bus_num = bus->number; - db_assert(bus_num != NULL); - } else + else *bus_num = 0; if (*bus_num == 0) { -- cgit v1.2.3-59-g8ed1b From 9b4685de77afd688407fd56cc350083a0a6a0516 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 13 Jul 2015 17:14:22 +0100 Subject: MIPS: Drop CONFIG_RUNTIME_DEBUG & debug.h The debug.h header provided some MIPS-specific debug macros, which are no longer used at all. Remove them. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10693/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig.debug | 9 -------- arch/mips/include/asm/debug.h | 48 ------------------------------------------- 2 files changed, 57 deletions(-) delete mode 100644 arch/mips/include/asm/debug.h diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 3a2b775e8458..e250524021ac 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -87,15 +87,6 @@ config SB1XXX_CORELIS Select compile flags that produce code that can be processed by the Corelis mksym utility and UDB Emulator. -config RUNTIME_DEBUG - bool "Enable run-time debugging" - depends on DEBUG_KERNEL - help - If you say Y here, some debugging macros will do run-time checking. - If you say N here, those macros will mostly turn to no-ops. See - arch/mips/include/asm/debug.h for debugging macros. - If unsure, say N. - config DEBUG_ZBOOT bool "Enable compressed kernel support debugging" depends on DEBUG_KERNEL && SYS_SUPPORTS_ZBOOT diff --git a/arch/mips/include/asm/debug.h b/arch/mips/include/asm/debug.h deleted file mode 100644 index 1fd5a2b39445..000000000000 --- a/arch/mips/include/asm/debug.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Debug macros for run-time debugging. - * Turned on/off with CONFIG_RUNTIME_DEBUG option. - * - * Copyright (C) 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef _ASM_DEBUG_H -#define _ASM_DEBUG_H - - -/* - * run-time macros for catching spurious errors. Eable CONFIG_RUNTIME_DEBUG in - * kernel hacking config menu to use them. - * - * Use them as run-time debugging aid. NEVER USE THEM AS ERROR HANDLING CODE!!! - */ - -#ifdef CONFIG_RUNTIME_DEBUG - -#include - -#define db_assert(x) if (!(x)) { \ - panic("assertion failed at %s:%d: %s", __FILE__, __LINE__, #x); } -#define db_warn(x) if (!(x)) { \ - printk(KERN_WARNING "warning at %s:%d: %s", __FILE__, __LINE__, #x); } -#define db_verify(x, y) db_assert(x y) -#define db_verify_warn(x, y) db_warn(x y) -#define db_run(x) do { x; } while (0) - -#else - -#define db_assert(x) -#define db_warn(x) -#define db_verify(x, y) x -#define db_verify_warn(x, y) x -#define db_run(x) - -#endif - -#endif /* _ASM_DEBUG_H */ -- cgit v1.2.3-59-g8ed1b From 8dedde6b289c51ba216fdf5467fc85a673775489 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:10:56 -0500 Subject: MIPS: CPC: Remove "weak" from mips_cpc_phys_base() and make it static There's only one implementation of mips_cpc_phys_base(), and it's only used within the same file, so it doesn't need to be weak, and it doesn't need an extern declaration. Remove the extern mips_cpc_phys_base() declaration and make it static. [ralf@linux-mips.org: Fixed conflict.] Signed-off-by: Bjorn Helgaas CC: linux-mips@linux-mips.org Cc: Andrew Bresticker Cc: James Hogan Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10681/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cpc.h | 10 ---------- arch/mips/kernel/mips-cpc.c | 9 ++++++++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index 1cebe8c79051..f386f32702f1 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -27,16 +27,6 @@ extern void __iomem *mips_cpc_base; */ extern phys_addr_t mips_cpc_default_phys_base(void); -/** - * mips_cpc_phys_base - retrieve the physical base address of the CPC - * - * This function returns the physical base address of the Cluster Power - * Controller memory mapped registers, or 0 if no Cluster Power Controller - * is present. It may be overriden by individual platforms which determine - * this address in a different way. - */ -extern phys_addr_t __weak mips_cpc_phys_base(void); - /** * mips_cpc_probe - probe for a Cluster Power Controller * diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index e05aca41e087..8af4d627b68b 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -21,7 +21,14 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); -phys_addr_t __weak mips_cpc_phys_base(void) +/** + * mips_cpc_phys_base - retrieve the physical base address of the CPC + * + * This function returns the physical base address of the Cluster Power + * Controller memory mapped registers, or 0 if no Cluster Power Controller + * is present. + */ +static phys_addr_t mips_cpc_phys_base(void) { unsigned long cpc_base; -- cgit v1.2.3-59-g8ed1b From 27d8d449ba7c553e9e004aaa07b225625b20fd2d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:04 -0500 Subject: MIPS: Remove "weak" from platform_maar_init() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). platform_maar_init() is defined in: - arch/mips/mm/init.c (where it is marked "weak") - arch/mips/mti-malta/malta-memory.c (without annotation) The "weak" attribute on the platform_maar_init() extern declaration applies to the platform-specific definition in arch/mips/mti-malta/malta-memory.c, so both definitions are weak, and which one we get depends on link order. Remove the "weak" attribute from the declaration. That makes the malta definition strong, so it will always be preferred if it is present. Signed-off-by: Bjorn Helgaas CC: linux-mips@linux-mips.org Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10682/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/maar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/maar.h b/arch/mips/include/asm/maar.h index 6c62b0f899c0..b02891f9caaf 100644 --- a/arch/mips/include/asm/maar.h +++ b/arch/mips/include/asm/maar.h @@ -26,7 +26,7 @@ * * Return: The number of MAAR pairs configured. */ -unsigned __weak platform_maar_init(unsigned num_pairs); +unsigned platform_maar_init(unsigned num_pairs); /** * write_maar_pair() - write to a pair of MAARs -- cgit v1.2.3-59-g8ed1b From 1c205b9cc6f66c5caa91fa2644dcf75254c3bfe1 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:12 -0500 Subject: MIPS: VPE: Exit vpe_release() early if vpe_run() isn't defined vpe_run() is a weak symbol. If there's no definition of it, its value is zero. If vpe_run is zero, return failure early. We're going to fail anyway, so there's no point in getting a VPE and attempting to load it. Signed-off-by: Bjorn Helgaas Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: James Hogan Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10683/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/vpe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 11da314565cc..72cae9f55460 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -821,13 +821,18 @@ static int vpe_release(struct inode *inode, struct file *filp) Elf_Ehdr *hdr; int ret = 0; + if (!vpe_run) { + pr_warn("VPE loader: ELF load failed.\n"); + return -ENOEXEC; + } + v = get_vpe(aprp_cpu_index()); if (v == NULL) return -ENODEV; hdr = (Elf_Ehdr *) v->pbuffer; if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { - if ((vpe_elfload(v) >= 0) && vpe_run) { + if (vpe_elfload(v) >= 0) { vpe_run(v); } else { pr_warn("VPE loader: ELF load failed.\n"); -- cgit v1.2.3-59-g8ed1b From c60f99445aed684b5a8d84dcb84f5a06c1f70430 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:20 -0500 Subject: MIPS: MT: Remove "weak" from vpe_run() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). That's not a problem for vpe_run() because Kconfig ensures there's never more than one definition: - vpe_run() is defined in arch/mips/kernel/vpe-mt.c if CONFIG_MIPS_VPE_LOADER_MT=y - vpe_run() is defined in arch/mips/mti-malta/malta-amon.c if CONFIG_MIPS_CMP=y - CONFIG_MIPS_VPE_LOADER_MT cannot be set if CONFIG_MIPS_CMP=y But it's simpler to verify correctness if we remove "weak" from the picture and test the config symbols directly. Remove "weak" from the vpe_run() declaration and use #if to test whether a definition should be present. Signed-off-by: Bjorn Helgaas Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: James Hogan Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10684/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/vpe.h | 2 +- arch/mips/kernel/vpe.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/vpe.h b/arch/mips/include/asm/vpe.h index 7849f3978fea..80e70dbd1f64 100644 --- a/arch/mips/include/asm/vpe.h +++ b/arch/mips/include/asm/vpe.h @@ -122,7 +122,7 @@ void release_vpe(struct vpe *v); void *alloc_progmem(unsigned long len); void release_progmem(void *ptr); -int __weak vpe_run(struct vpe *v); +int vpe_run(struct vpe *v); void cleanup_tc(struct tc *tc); int __init vpe_module_init(void); diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 72cae9f55460..9067b651c7a2 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -817,15 +817,11 @@ static int vpe_open(struct inode *inode, struct file *filp) static int vpe_release(struct inode *inode, struct file *filp) { +#if defined(CONFIG_MIPS_VPE_LOADER_MT) || defined(CONFIG_MIPS_VPE_LOADER_CMP) struct vpe *v; Elf_Ehdr *hdr; int ret = 0; - if (!vpe_run) { - pr_warn("VPE loader: ELF load failed.\n"); - return -ENOEXEC; - } - v = get_vpe(aprp_cpu_index()); if (v == NULL) return -ENODEV; @@ -855,6 +851,10 @@ static int vpe_release(struct inode *inode, struct file *filp) v->plen = 0; return ret; +#else + pr_warn("VPE loader: ELF load failed.\n"); + return -ENOEXEC; +#endif } static ssize_t vpe_write(struct file *file, const char __user *buffer, -- cgit v1.2.3-59-g8ed1b From 90996511187d6282db6d02d3f97006b4dbb5c457 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Aug 2015 15:42:35 -0700 Subject: MIPS: CPS: use 32b accesses to GCRs Commit b677bc03d757 ("MIPS: cps-vec: Use macros for various arithmetics and memory operations") replaced various load & store instructions through cps-vec.S with the PTR_L & PTR_S macros. However it was somewhat overzealous in doing so for CM GCR accesses, since the bit width of the CM doesn't necessarily match that of the CPU. The registers accessed (GCR_CL_COHERENCE & GCR_CL_ID) should be safe to simply always access using 32b instructions, so do so in order to avoid issues when using a 32b CM with a 64b CPU. Signed-off-by: Paul Burton Cc: Markos Chandras Cc: # 3.16+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: James Hogan Patchwork: https://patchwork.linux-mips.org/patch/10864/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cps-vec.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 1b6ca634e646..9f71c06aebf6 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -152,7 +152,7 @@ dcache_done: /* Enter the coherent domain */ li t0, 0xff - PTR_S t0, GCR_CL_COHERENCE_OFS(v1) + sw t0, GCR_CL_COHERENCE_OFS(v1) ehb /* Jump to kseg0 */ @@ -302,7 +302,7 @@ LEAF(mips_cps_boot_vpes) PTR_L t0, 0(t0) /* Calculate a pointer to this cores struct core_boot_config */ - PTR_L t0, GCR_CL_ID_OFS(t0) + lw t0, GCR_CL_ID_OFS(t0) li t1, COREBOOTCFG_SIZE mul t0, t0, t1 PTR_LA t1, mips_cps_core_bootcfg -- cgit v1.2.3-59-g8ed1b From 1cfa8de2880e5512f9037c7804ea47a79cc8232c Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sun, 3 May 2015 10:36:19 +0100 Subject: MIPS: pgtable-bits.h: Correct _PAGE_GLOBAL_SHIFT build failure Correct a build failure introduced by be0c37c9 [MIPS: Rearrange PTE bits into fixed positions.]: In file included from ./arch/mips/include/asm/io.h:27:0, from ./arch/mips/include/asm/page.h:176, from include/linux/mm_types.h:15, from include/linux/sched.h:27, from include/linux/ptrace.h:5, from arch/mips/kernel/cpu-probe.c:16: ./arch/mips/include/asm/pgtable-bits.h:164:0: error: "_PAGE_GLOBAL_SHIFT" redefined [-Werror] #define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) ^ ./arch/mips/include/asm/pgtable-bits.h:141:0: note: this is the location of the previous definition #define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) ^ cc1: all warnings being treated as errors make[2]: *** [arch/mips/kernel/cpu-probe.o] Error 1 for 64BIT/CPU_MIPSR1/MIPS_HUGE_TLB_SUPPORT configurations. Remove the scattered double `_PAGE_NO_EXEC_SHIFT' and `_PAGE_GLOBAL_SHIFT' macro definitions and rearrange them so that the respective macros these definitions are based on are also those used for guarding conditionals. [ralf@linux-mips.org: resolved conflicts and updated commments.] Signed-off-by: Maciej W. Rozycki Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9960/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable-bits.h | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index c28a8499aec7..46017419bb6e 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -133,20 +133,13 @@ #define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) #define _PAGE_SPLITTING_SHIFT (_PAGE_HUGE_SHIFT + 1) #define _PAGE_SPLITTING (1 << _PAGE_SPLITTING_SHIFT) - -/* Only R2 or newer cores have the XI bit */ -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) -#define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1) -#else -#define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ - #endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */ #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) /* XI - page cannot be executed */ -#ifndef _PAGE_NO_EXEC_SHIFT +#ifdef _PAGE_SPLITTING_SHIFT +#define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1) +#else #define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1) #endif #define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) @@ -156,14 +149,16 @@ #define _PAGE_READ (cpu_has_rixi ? 0 : (1 << _PAGE_READ_SHIFT)) #define _PAGE_NO_READ_SHIFT _PAGE_READ_SHIFT #define _PAGE_NO_READ (cpu_has_rixi ? (1 << _PAGE_READ_SHIFT) : 0) +#endif /* defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) */ +#if defined(_PAGE_NO_READ_SHIFT) #define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) - -#else /* !CONFIG_CPU_MIPSR2 && !CONFIG_CPU_MIPSR6 */ +#elif defined(_PAGE_SPLITTING_SHIFT) +#define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) +#else #define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) +#endif #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ #define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) #define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -- cgit v1.2.3-59-g8ed1b From ec0b9d35d1fbf7e3a3eccc662ad641794d3685a5 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:38 -0500 Subject: MIPS: Remove "weak" from get_c0_compare_int() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). get_c0_compare_int() is defined in several files. Each definition is weak, so I assume Kconfig prevents two or more from being included. The caller contains default code used when get_c0_compare_int() isn't defined at all. Add a weak get_c0_compare_int() definition with the default code and remove the weak annotation from the declaration. Then the platform implementations will be strong and will override the weak default. If multiple platforms are ever configured in, we'll get a link error instead of calling a random platform's implementation. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10686/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/time.h | 2 +- arch/mips/kernel/cevt-r4k.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index 8ab2874225c4..17d4cd20f18c 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h @@ -51,7 +51,7 @@ extern int __weak get_c0_perfcount_int(void); /* * Initialize the calling CPU's compare interrupt as clockevent device */ -extern unsigned int __weak get_c0_compare_int(void); +extern unsigned int get_c0_compare_int(void); extern int r4k_clockevent_init(void); static inline int mips_clockevent_init(void) diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index d70c4d893219..cc7cc46b58f7 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -174,6 +174,11 @@ int c0_compare_int_usable(void) return 1; } +unsigned int __weak get_c0_compare_int(void) +{ + return MIPS_CPU_IRQ_BASE + cp0_compare_irq; +} + int r4k_clockevent_init(void) { unsigned int cpu = smp_processor_id(); @@ -189,11 +194,9 @@ int r4k_clockevent_init(void) /* * With vectored interrupts things are getting platform specific. * get_c0_compare_int is a hook to allow a platform to return the - * interrupt number of it's liking. + * interrupt number of its liking. */ - irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; - if (get_c0_compare_int) - irq = get_c0_compare_int(); + irq = get_c0_compare_int(); cd = &per_cpu(mips_clockevent_device, cpu); -- cgit v1.2.3-59-g8ed1b From 770847bad0200b62af2d93808b4e69d82f14264e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:46 -0500 Subject: MIPS: Remove "weak" from get_c0_fdc_int() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). The most elegant solution is to have a weak default implementation and allow a strong function to override it. Then we don't have to test whether a definition is present, and if there are ever multiple strong definitions, we get a link error instead of calling a random definition. Add a weak get_c0_fdc_int() definition with the default code and remove the weak annotation from the declaration. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10687/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/irq.h | 2 +- drivers/tty/mips_ejtag_fdc.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index f0db99f8defe..15e0fecbc300 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -49,7 +49,7 @@ extern int cp0_compare_irq_shift; extern int cp0_perfcount_irq; extern int cp0_fdc_irq; -extern int __weak get_c0_fdc_int(void); +extern int get_c0_fdc_int(void); void arch_trigger_all_cpu_backtrace(bool); #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 358323c83b4f..a8c8cfd52a23 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -879,6 +879,11 @@ static const struct tty_operations mips_ejtag_fdc_tty_ops = { .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer, }; +int __weak get_c0_fdc_int(void) +{ + return -1; +} + static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) { int ret, nport; @@ -967,9 +972,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) wake_up_process(priv->thread); /* Look for an FDC IRQ */ - priv->irq = -1; - if (get_c0_fdc_int) - priv->irq = get_c0_fdc_int(); + priv->irq = get_c0_fdc_int(); /* Try requesting the IRQ */ if (priv->irq >= 0) { -- cgit v1.2.3-59-g8ed1b From e1d97497309867cdc1064ed6b10953abd1740b05 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:54 -0500 Subject: MIPS: Remove "weak" from mips_cdmm_phys_base() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). mips_cdmm_phys_base() is defined only in arch/mips/mti-malta/malta-memory.c so there's no problem with multiple definitions. But it works better to have a weak default implementation and allow a strong function to override it. Then we don't have to test whether a definition is present, and if there are ever multiple strong definitions, we get a link error instead of calling a random definition. Add a weak mips_cdmm_phys_base() definition and remove the weak annotation from the declaration in arch/mips/include/asm/cdmm.h. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10688/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cdmm.h | 4 ++-- drivers/bus/mips_cdmm.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/cdmm.h b/arch/mips/include/asm/cdmm.h index 16e22ce9719f..bece2064cc8c 100644 --- a/arch/mips/include/asm/cdmm.h +++ b/arch/mips/include/asm/cdmm.h @@ -53,7 +53,7 @@ struct mips_cdmm_driver { * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. * * Picking a suitable physical address at which to map the CDMM region is - * platform specific, so this weak function can be defined by platform code to + * platform specific, so this function can be defined by platform code to * pick a suitable value if none is configured by the bootloader. * * This address must be 32kB aligned, and the region occupies a maximum of 32kB @@ -61,7 +61,7 @@ struct mips_cdmm_driver { * * Returns: Physical base address for CDMM region, or 0 on failure. */ -phys_addr_t __weak mips_cdmm_phys_base(void); +phys_addr_t mips_cdmm_phys_base(void); extern struct bus_type mips_cdmm_bustype; void __iomem *mips_cdmm_early_probe(unsigned int dev_type); diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index ab3bde16ecb4..1c543effe062 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -331,6 +331,18 @@ static phys_addr_t mips_cdmm_cur_base(void) << MIPS_CDMMBASE_ADDR_START; } +/** + * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. + * + * Picking a suitable physical address at which to map the CDMM region is + * platform specific, so this weak function can be overridden by platform + * code to pick a suitable value if none is configured by the bootloader. + */ +phys_addr_t __weak mips_cdmm_phys_base(void) +{ + return 0; +} + /** * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable. * @bus: Pointer to bus information for current CPU. @@ -368,7 +380,7 @@ static int mips_cdmm_setup(struct mips_cdmm_bus *bus) if (!bus->phys) bus->phys = mips_cdmm_cur_base(); /* Otherwise, ask platform code for suggestions */ - if (!bus->phys && mips_cdmm_phys_base) + if (!bus->phys) bus->phys = mips_cdmm_phys_base(); /* Otherwise, copy what other CPUs have done */ if (!bus->phys) -- cgit v1.2.3-59-g8ed1b From b620c9720a0e18bc2067c65ad3b9020e813372eb Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:12:03 -0500 Subject: MIPS: Remove "__weak" definition from arch-specific linkage.h "__weak" is defined in include/linux/compiler-gcc.h. We shouldn't need an arch-specific definition. Remove the "__weak" definition from arch/mips/include/asm/linkage.h. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10689/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/linkage.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/include/asm/linkage.h b/arch/mips/include/asm/linkage.h index 2767dda9e309..99651b0ea7c7 100644 --- a/arch/mips/include/asm/linkage.h +++ b/arch/mips/include/asm/linkage.h @@ -5,7 +5,6 @@ #include #endif -#define __weak __attribute__((weak)) #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall") #define SYSCALL_ALIAS(alias, name) \ asm ( #alias " = " #name "\n\t.globl " #alias) -- cgit v1.2.3-59-g8ed1b From 6701ca2df4e22fb130330800b6cde687cb761637 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Mon, 22 Jun 2015 12:20:58 +0100 Subject: MIPS: Declare MSA MI10 instruction formats Declare a struct describing the MSA MI10 instruction format used for ld & st instructions, for use by subsequent patches. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Steven J. Hill Cc: linux-kernel@vger.kernel.org Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10571/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/inst.h | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index fc0cf5ac0cf7..3dce80e67948 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -26,7 +26,7 @@ enum major_op { cop0_op, cop1_op, cop2_op, cop1x_op, beql_op, bnel_op, blezl_op, bgtzl_op, daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op, - spec2_op, jalx_op, mdmx_op, spec3_op, + spec2_op, jalx_op, mdmx_op, msa_op = mdmx_op, spec3_op, lb_op, lh_op, lwl_op, lw_op, lbu_op, lhu_op, lwr_op, lwu_op, sb_op, sh_op, swl_op, sw_op, @@ -220,6 +220,24 @@ enum bshfl_func { seh_op = 0x18, }; +/* + * func field for MSA MI10 format. + */ +enum msa_mi10_func { + msa_ld_op = 8, + msa_st_op = 9, +}; + +/* + * MSA 2 bit format fields. + */ +enum msa_2b_fmt { + msa_fmt_b = 0, + msa_fmt_h = 1, + msa_fmt_w = 2, + msa_fmt_d = 3, +}; + /* * (microMIPS) Major opcodes. */ @@ -611,6 +629,16 @@ struct v_format { /* MDMX vector format */ ;))))))) }; +struct msa_mi10_format { /* MSA MI10 */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(signed int s10 : 10, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int wd : 5, + __BITFIELD_FIELD(unsigned int func : 4, + __BITFIELD_FIELD(unsigned int df : 2, + ;)))))) +}; + struct spec3_format { /* SPEC3 */ __BITFIELD_FIELD(unsigned int opcode:6, __BITFIELD_FIELD(unsigned int rs:5, @@ -888,6 +916,7 @@ union mips_instruction { struct p_format p_format; struct f_format f_format; struct ma_format ma_format; + struct msa_mi10_format msa_mi10_format; struct b_format b_format; struct ps_format ps_format; struct v_format v_format; -- cgit v1.2.3-59-g8ed1b From 6b35e11442db48638c9e9f2ff19f706484a73abe Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 22 Jun 2015 12:20:59 +0100 Subject: MIPS: Introduce accessors for MSA vector registers Introduce accessor functions allowing the kernel to access arbitrary vector registers using an arbitrary data format. The accessors are implemented in assembly, using macros to avoid massive duplication, in order to make use of the existing support for MSA with & without toolchain support. The accessors will be used in a later patch. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Cc: Manuel Lauss Patchwork: https://patchwork.linux-mips.org/patch/10572/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/asmmacro.h | 114 +++++++++++++++++++++++++++++++++++++++ arch/mips/include/asm/msa.h | 80 +++++++++++++++++++++++++++ arch/mips/kernel/r4k_fpu.S | 67 +++++++++++++++++++++++ 3 files changed, 261 insertions(+) diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 76317a70200d..867f924b05c7 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -232,6 +232,30 @@ .set pop .endm + .macro ld_b wd, off, base + .set push + .set mips32r2 + .set msa + ld.b $w\wd, \off(\base) + .set pop + .endm + + .macro ld_h wd, off, base + .set push + .set mips32r2 + .set msa + ld.h $w\wd, \off(\base) + .set pop + .endm + + .macro ld_w wd, off, base + .set push + .set mips32r2 + .set msa + ld.w $w\wd, \off(\base) + .set pop + .endm + .macro ld_d wd, off, base .set push .set mips32r2 @@ -241,6 +265,30 @@ .set pop .endm + .macro st_b wd, off, base + .set push + .set mips32r2 + .set msa + st.b $w\wd, \off(\base) + .set pop + .endm + + .macro st_h wd, off, base + .set push + .set mips32r2 + .set msa + st.h $w\wd, \off(\base) + .set pop + .endm + + .macro st_w wd, off, base + .set push + .set mips32r2 + .set msa + st.w $w\wd, \off(\base) + .set pop + .endm + .macro st_d wd, off, base .set push .set mips32r2 @@ -290,7 +338,13 @@ #ifdef CONFIG_CPU_MICROMIPS #define CFC_MSA_INSN 0x587e0056 #define CTC_MSA_INSN 0x583e0816 +#define LDB_MSA_INSN 0x58000807 +#define LDH_MSA_INSN 0x58000817 +#define LDW_MSA_INSN 0x58000827 #define LDD_MSA_INSN 0x58000837 +#define STB_MSA_INSN 0x5800080f +#define STH_MSA_INSN 0x5800081f +#define STW_MSA_INSN 0x5800082f #define STD_MSA_INSN 0x5800083f #define COPY_UW_MSA_INSN 0x58f00056 #define COPY_UD_MSA_INSN 0x58f80056 @@ -299,7 +353,13 @@ #else #define CFC_MSA_INSN 0x787e0059 #define CTC_MSA_INSN 0x783e0819 +#define LDB_MSA_INSN 0x78000820 +#define LDH_MSA_INSN 0x78000821 +#define LDW_MSA_INSN 0x78000822 #define LDD_MSA_INSN 0x78000823 +#define STB_MSA_INSN 0x78000824 +#define STH_MSA_INSN 0x78000825 +#define STW_MSA_INSN 0x78000826 #define STD_MSA_INSN 0x78000827 #define COPY_UW_MSA_INSN 0x78f00059 #define COPY_UD_MSA_INSN 0x78f80059 @@ -329,6 +389,33 @@ .set pop .endm + .macro ld_b wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word LDB_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro ld_h wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word LDH_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro ld_w wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word LDW_MSA_INSN | (\wd << 6) + .set pop + .endm + .macro ld_d wd, off, base .set push .set noat @@ -338,6 +425,33 @@ .set pop .endm + .macro st_b wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word STB_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro st_h wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word STH_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro st_w wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word STW_MSA_INSN | (\wd << 6) + .set pop + .endm + .macro st_d wd, off, base .set push .set noat diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index af5638b12c75..bbb85fe21642 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h @@ -14,10 +14,90 @@ #ifndef __ASSEMBLY__ +#include + extern void _save_msa(struct task_struct *); extern void _restore_msa(struct task_struct *); extern void _init_msa_upper(void); +extern void read_msa_wr_b(unsigned idx, union fpureg *to); +extern void read_msa_wr_h(unsigned idx, union fpureg *to); +extern void read_msa_wr_w(unsigned idx, union fpureg *to); +extern void read_msa_wr_d(unsigned idx, union fpureg *to); + +/** + * read_msa_wr() - Read a single MSA vector register + * @idx: The index of the vector register to read + * @to: The FPU register union to store the registers value in + * @fmt: The format of the data in the vector register + * + * Read the value of MSA vector register idx into the FPU register + * union to, using the format fmt. + */ +static inline void read_msa_wr(unsigned idx, union fpureg *to, + enum msa_2b_fmt fmt) +{ + switch (fmt) { + case msa_fmt_b: + read_msa_wr_b(idx, to); + break; + + case msa_fmt_h: + read_msa_wr_h(idx, to); + break; + + case msa_fmt_w: + read_msa_wr_w(idx, to); + break; + + case msa_fmt_d: + read_msa_wr_d(idx, to); + break; + + default: + BUG(); + } +} + +extern void write_msa_wr_b(unsigned idx, union fpureg *from); +extern void write_msa_wr_h(unsigned idx, union fpureg *from); +extern void write_msa_wr_w(unsigned idx, union fpureg *from); +extern void write_msa_wr_d(unsigned idx, union fpureg *from); + +/** + * write_msa_wr() - Write a single MSA vector register + * @idx: The index of the vector register to write + * @from: The FPU register union to take the registers value from + * @fmt: The format of the data in the vector register + * + * Write the value from the FPU register union from into MSA vector + * register idx, using the format fmt. + */ +static inline void write_msa_wr(unsigned idx, union fpureg *from, + enum msa_2b_fmt fmt) +{ + switch (fmt) { + case msa_fmt_b: + write_msa_wr_b(idx, from); + break; + + case msa_fmt_h: + write_msa_wr_h(idx, from); + break; + + case msa_fmt_w: + write_msa_wr_w(idx, from); + break; + + case msa_fmt_d: + write_msa_wr_d(idx, from); + break; + + default: + BUG(); + } +} + static inline void enable_msa(void) { if (cpu_has_msa) { diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 1d88af26ba82..ca887da1a48a 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -13,6 +13,7 @@ * Copyright (C) 1999, 2001 Silicon Graphics, Inc. */ #include +#include #include #include #include @@ -274,6 +275,72 @@ LEAF(_restore_fp_context32) END(_restore_fp_context32) #endif +#ifdef CONFIG_CPU_HAS_MSA + + .macro op_one_wr op, idx, base + .align 4 +\idx: \op \idx, 0, \base + jr ra + nop + .endm + + .macro op_msa_wr name, op +LEAF(\name) + .set push + .set noreorder + sll t0, a0, 4 + PTR_LA t1, 0f + PTR_ADDU t0, t0, t1 + jr t0 + nop + op_one_wr \op, 0, a1 + op_one_wr \op, 1, a1 + op_one_wr \op, 2, a1 + op_one_wr \op, 3, a1 + op_one_wr \op, 4, a1 + op_one_wr \op, 5, a1 + op_one_wr \op, 6, a1 + op_one_wr \op, 7, a1 + op_one_wr \op, 8, a1 + op_one_wr \op, 9, a1 + op_one_wr \op, 10, a1 + op_one_wr \op, 11, a1 + op_one_wr \op, 12, a1 + op_one_wr \op, 13, a1 + op_one_wr \op, 14, a1 + op_one_wr \op, 15, a1 + op_one_wr \op, 16, a1 + op_one_wr \op, 17, a1 + op_one_wr \op, 18, a1 + op_one_wr \op, 19, a1 + op_one_wr \op, 20, a1 + op_one_wr \op, 21, a1 + op_one_wr \op, 22, a1 + op_one_wr \op, 23, a1 + op_one_wr \op, 24, a1 + op_one_wr \op, 25, a1 + op_one_wr \op, 26, a1 + op_one_wr \op, 27, a1 + op_one_wr \op, 28, a1 + op_one_wr \op, 29, a1 + op_one_wr \op, 30, a1 + op_one_wr \op, 31, a1 + .set pop + END(\name) + .endm + + op_msa_wr read_msa_wr_b, st_b + op_msa_wr read_msa_wr_h, st_h + op_msa_wr read_msa_wr_w, st_w + op_msa_wr read_msa_wr_d, st_d + + op_msa_wr write_msa_wr_b, ld_b + op_msa_wr write_msa_wr_h, ld_h + op_msa_wr write_msa_wr_w, ld_w + op_msa_wr write_msa_wr_d, ld_d + +#endif /* CONFIG_CPU_HAS_MSA */ + .set reorder .type fault@function -- cgit v1.2.3-59-g8ed1b From e4aa1f153add29343eeb8b3bf0f64e7c6fc7e697 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Mon, 22 Jun 2015 12:21:00 +0100 Subject: MIPS: MSA unaligned memory access support The MSA architecture specification allows for hardware to not implement unaligned vector memory accesses in some or all cases. A typical example of this is the I6400 core which does not implement unaligned vector memory access when the memory crosses a page boundary. The architecture also requires that such memory accesses complete successfully as far as userland is concerned, so the kernel is required to emulate them. This patch implements support for emulating unaligned MSA ld & st instructions by copying between the user memory & the tasks FP context in struct thread_struct, updating hardware registers from there as appropriate in order to avoid saving & restoring the entire vector context for each unaligned memory access. Tested both using an I6400 CPU and with a QEMU build hacked to produce AdEL exceptions for unaligned vector memory accesses. [paul.burton@imgtec.com: - Remove #ifdef's - Move msa_op into enum major_op rather than #define - Replace msa_{to,from}_wd with {read,write}_msa_wr_{b,h,w,l} and the format-agnostic wrappers, removing the custom endian mangling for big endian systems. - Restructure the msa_op case in emulate_load_store_insn to share more code between the load & store cases. - Avoid the need for a temporary union fpureg on the stack by simply reusing the already suitably aligned context in struct thread_struct. - Use sizeof(*fpr) rather than hardcoding 16 as the size for user memory checks & copies. - Stop recalculating the address of the unaligned vector memory access and rely upon the value read from BadVAddr as we do for other unaligned memory access instructions. - Drop the now unused val8 & val16 fields in union fpureg. - Rewrite commit message. - General formatting cleanups.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Huacai Chen Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Jie Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10573/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/unaligned.c | 72 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index eb3efd137fd1..f55869c00ce4 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -891,6 +891,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, #ifdef CONFIG_EVA mm_segment_t seg; #endif + union fpureg *fpr; + enum msa_2b_fmt df; + unsigned int wd; origpc = (unsigned long)pc; orig31 = regs->regs[31]; @@ -1202,6 +1205,75 @@ static void emulate_load_store_insn(struct pt_regs *regs, break; return; + case msa_op: + if (!cpu_has_msa) + goto sigill; + + /* + * If we've reached this point then userland should have taken + * the MSA disabled exception & initialised vector context at + * some point in the past. + */ + BUG_ON(!thread_msa_context_live()); + + df = insn.msa_mi10_format.df; + wd = insn.msa_mi10_format.wd; + fpr = ¤t->thread.fpu.fpr[wd]; + + switch (insn.msa_mi10_format.func) { + case msa_ld_op: + if (!access_ok(VERIFY_READ, addr, sizeof(*fpr))) + goto sigbus; + + /* + * Disable preemption to avoid a race between copying + * state from userland, migrating to another CPU and + * updating the hardware vector register below. + */ + preempt_disable(); + + res = __copy_from_user_inatomic(fpr, addr, + sizeof(*fpr)); + if (res) + goto fault; + + /* + * Update the hardware register if it is in use by the + * task in this quantum, in order to avoid having to + * save & restore the whole vector context. + */ + if (test_thread_flag(TIF_USEDMSA)) + write_msa_wr(wd, fpr, df); + + preempt_enable(); + break; + + case msa_st_op: + if (!access_ok(VERIFY_WRITE, addr, sizeof(*fpr))) + goto sigbus; + + /* + * Update from the hardware register if it is in use by + * the task in this quantum, in order to avoid having to + * save & restore the whole vector context. + */ + preempt_disable(); + if (test_thread_flag(TIF_USEDMSA)) + read_msa_wr(wd, fpr, df); + preempt_enable(); + + res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr)); + if (res) + goto fault; + break; + + default: + goto sigbus; + } + + compute_return_epc(regs); + break; + #ifndef CONFIG_CPU_MIPSR6 /* * COP2 is available to implementor for application specific use. -- cgit v1.2.3-59-g8ed1b From cbd95a89996d1b5fadf411e9218c64e713a83099 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 10 Jul 2015 16:52:38 +0100 Subject: MIPS: mm: default platform_maar_init using bootmem data Introduce a default weak implementation of platform_maar_init which makes use of the data that platforms already provide to the bootmem allocator. This should hopefully cover the most common configurations, reduce the duplication of information provided by platforms & leaves platforms with the option of providing a custom implementation if required. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Paolo Bonzini Cc: Steven J. Hill Cc: linux-kernel@vger.kernel.org Cc: Ard Biesheuvel Patchwork: https://patchwork.linux-mips.org/patch/10676/ Signed-off-by: Ralf Baechle --- arch/mips/mm/init.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 198a3147dd7d..66d0f49c5bec 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -333,9 +334,40 @@ static inline void mem_init_free_highmem(void) #endif } -unsigned __weak platform_maar_init(unsigned num_maars) +unsigned __weak platform_maar_init(unsigned num_pairs) { - return 0; + struct maar_config cfg[BOOT_MEM_MAP_MAX]; + unsigned i, num_configured, num_cfg = 0; + phys_addr_t skip; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + case BOOT_MEM_INIT_RAM: + break; + default: + continue; + } + + skip = 0x10000 - (boot_mem_map.map[i].addr & 0xffff); + + cfg[num_cfg].lower = boot_mem_map.map[i].addr; + cfg[num_cfg].lower += skip; + + cfg[num_cfg].upper = cfg[num_cfg].lower; + cfg[num_cfg].upper += boot_mem_map.map[i].size - 1; + cfg[num_cfg].upper -= skip; + + cfg[num_cfg].attrs = MIPS_MAAR_S; + num_cfg++; + } + + num_configured = maar_config(cfg, num_cfg, num_pairs); + if (num_configured < num_cfg) + pr_warn("Not enough MAAR pairs (%u) for all bootmem regions (%u)\n", + num_pairs, num_cfg); + + return num_configured; } static void maar_init(void) -- cgit v1.2.3-59-g8ed1b From 570e5d26ff2e970e018343675bc64302420221d8 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 10 Jul 2015 16:52:39 +0100 Subject: MIPS: malta: Use generic platform_maar_init The default implementation of platform_maar_init is sufficient for Malta boards where we want to allow speculation in the regions of memory corresponding to DDR & disallow it elsewhere. Drop the custom implementation such that the default is used, reducing the duplication of information provided by the Malta platform code. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10677/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-memory.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c index b769657be4d4..dadeb8379182 100644 --- a/arch/mips/mti-malta/malta-memory.c +++ b/arch/mips/mti-malta/malta-memory.c @@ -179,31 +179,6 @@ void __init prom_free_prom_memory(void) } } -unsigned platform_maar_init(unsigned num_pairs) -{ - phys_addr_t mem_end = (physical_memsize & ~0xffffull) - 1; - struct maar_config cfg[] = { - /* DRAM preceding I/O */ - { 0x00000000, 0x0fffffff, MIPS_MAAR_S }, - - /* DRAM following I/O */ - { 0x20000000, mem_end, MIPS_MAAR_S }, - - /* DRAM alias in upper half of physical */ - { 0x80000000, 0x80000000 + mem_end, MIPS_MAAR_S }, - }; - unsigned i, num_cfg = ARRAY_SIZE(cfg); - - /* If DRAM fits before I/O, drop the region following it */ - if (physical_memsize <= 0x10000000) { - num_cfg--; - for (i = 1; i < num_cfg; i++) - cfg[i] = cfg[i + 1]; - } - - return maar_config(cfg, num_cfg, num_pairs); -} - phys_addr_t mips_cdmm_phys_base(void) { /* This address is "typically unused" */ -- cgit v1.2.3-59-g8ed1b From 82eb8f7342cf722a8bf3d42e9982f56bff166b85 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 15 Jul 2015 10:44:30 +1200 Subject: MIPS: Use unsigned int when reading CP0 registers Update __read_32bit_c0_register() and __read_32bit_c0_ctrl_register() to use "unsigned int res;" instead of "int res;". There is little reason to treat these register values as signed. They are either counters (which by definition are unsigned) or are made up of various bit fields to be interpreted as per the CPU datasheet. This has come up via u-boot[1] which sync's asm/mipsregs.h with the kernel. In u-boots case the value read from read_c0_count() is assigned to an unsigned long [2] which triggers a sign extension and causes a bug. U-boot should probably be more explicit about the types used for the timer_read_counter() API but that aside is there any reason to treat these values as signed integers? A quick grep around the arch/mips makes me thing that there may be some bugs lurking when read_c0_count() starts to yield a negative value but I haven't really explored any of them. [1] - http://lists.denx.de/pipermail/u-boot/2015-July/219086.html [2] - http://git.denx.de/?p=u-boot.git;a=blob;f=arch/mips/cpu/time.c#l11 Signed-off-by: Chris Packham Cc: linux-mips@linux-mips.org Cc: Daniel Schwierzeck Cc: Chris Packham Cc: Steven J. Hill Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Cc: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/10718/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 723ee3c7849d..07bf4e7109ac 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -934,7 +934,7 @@ do { \ */ #define __read_32bit_c0_register(source, sel) \ -({ int __res; \ +({ unsigned int __res; \ if (sel == 0) \ __asm__ __volatile__( \ "mfc0\t%0, " #source "\n\t" \ @@ -1016,7 +1016,7 @@ do { \ * On RM7000/RM9000 these are uses to access cop0 set 1 registers */ #define __read_32bit_c0_ctrl_register(source) \ -({ int __res; \ +({ unsigned int __res; \ __asm__ __volatile__( \ "cfc0\t%0, " #source "\n\t" \ : "=r" (__res)); \ -- cgit v1.2.3-59-g8ed1b From c46a2f01fb2bea6ae7e4e3f3f2aad65d8eda837d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 15 Jul 2015 11:48:15 +0200 Subject: MIPS: Treat CP1 control registers as unsigned ints. These are bitfields and treating them as signed values doesn't make any sense. Signed-off-by: Ralf Baechle Reported-by: Chris Packham --- arch/mips/include/asm/mipsregs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 07bf4e7109ac..b688c924a025 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1473,7 +1473,7 @@ do { \ */ #define _read_32bit_cp1_register(source, gas_hardfloat) \ ({ \ - int __res; \ + unsigned int __res; \ \ __asm__ __volatile__( \ " .set push \n" \ -- cgit v1.2.3-59-g8ed1b From 674d10e26dd4c1a1b9161e9dcce0667d1c5dd318 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 16 Jul 2015 13:24:46 +0100 Subject: MIPS: Kconfig: Drop the EXPERIMENTAL tag from MIPS R6 The MIPS R6 ISA support has been part of mainline since v4.0 and it should be in a good shape nowadays so it is not an experimental feature anymore. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10731/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 60d7ae76dd7e..52b7918da21a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1367,7 +1367,7 @@ config CPU_MIPS32_R2 otherwise CPU_MIPS32_R1 is a safe bet for any MIPS32 system. config CPU_MIPS32_R6 - bool "MIPS32 Release 6 (EXPERIMENTAL)" + bool "MIPS32 Release 6" depends on SYS_HAS_CPU_MIPS32_R6 select CPU_HAS_PREFETCH select CPU_SUPPORTS_32BIT_KERNEL @@ -1418,7 +1418,7 @@ config CPU_MIPS64_R2 otherwise CPU_MIPS64_R1 is a safe bet for any MIPS64 system. config CPU_MIPS64_R6 - bool "MIPS64 Release 6 (EXPERIMENTAL)" + bool "MIPS64 Release 6" depends on SYS_HAS_CPU_MIPS64_R6 select CPU_HAS_PREFETCH select CPU_SUPPORTS_32BIT_KERNEL -- cgit v1.2.3-59-g8ed1b From bbdd8147b1b9efb7268a7cad31e148d794363abe Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 16 Jul 2015 14:06:45 +0100 Subject: MIPS: cp1emu: Fix closing bracket for the d_fmt case The double format (d_fmt) case uses an opening bracket which then closes at the end of the word format (w_fmt). This can be rather confusing so add the closing bracket at the end of the d_fmt case and use another one for the w_fmt one. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10733/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 712f17a2ecf2..cd858953a783 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -2021,8 +2021,11 @@ dcopuop: break; } break; + } + + case w_fmt: { + union ieee754dp fs; - case w_fmt: switch (MIPSInst_FUNC(ir)) { case fcvts_op: /* convert word to single precision real */ -- cgit v1.2.3-59-g8ed1b From 166457436e38175e1d9891f98d9d6edbee100f32 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 16 Jul 2015 16:43:33 +0100 Subject: MIPS: math-emu: Fix indentation Fix indentation for the final 'else' blocks. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10735/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/ieee754int.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 05389d5e3a93..6383e2c5c1ad 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -65,8 +65,8 @@ static inline int ieee754_class_nan(int xc) vc = IEEE754_CLASS_INF; \ else if (vm & SP_MBIT(SP_FBITS-1)) \ vc = IEEE754_CLASS_SNAN; \ - else \ - vc = IEEE754_CLASS_QNAN; \ + else \ + vc = IEEE754_CLASS_QNAN; \ } else if (ve == SP_EMIN-1+SP_EBIAS) { \ if (vm) { \ ve = SP_EMIN; \ @@ -105,8 +105,8 @@ static inline int ieee754_class_nan(int xc) if (vm) { \ ve = DP_EMIN; \ vc = IEEE754_CLASS_DNORM; \ - } else \ - vc = IEEE754_CLASS_ZERO; \ + } else \ + vc = IEEE754_CLASS_ZERO; \ } else { \ ve -= DP_EBIAS; \ vm |= DP_HIDDEN_BIT; \ -- cgit v1.2.3-59-g8ed1b From e8f80cc1a6d80587136b015e989a12827e1fcfe5 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Fri, 17 Jul 2015 10:36:03 +0100 Subject: MIPS: math-emu: Allow m{f,t}hc emulation on MIPS R6 The mfhc/mthc instructions are supported on MIPS R6 so emulate them if needed. Signed-off-by: Markos Chandras Cc: # 4.0+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10737/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index cd858953a783..e78b1ae6dcdb 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1137,7 +1137,7 @@ emul: break; case mfhc_op: - if (!cpu_has_mips_r2) + if (!cpu_has_mips_r2_r6) goto sigill; /* copregister rd -> gpr[rt] */ @@ -1148,7 +1148,7 @@ emul: break; case mthc_op: - if (!cpu_has_mips_r2) + if (!cpu_has_mips_r2_r6) goto sigill; /* copregister rd <- gpr[rt] */ -- cgit v1.2.3-59-g8ed1b From c909ca718e8f50cf484ef06a8dd935e738e8e53d Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Fri, 17 Jul 2015 10:38:32 +0100 Subject: MIPS: math-emu: Emulate missing BC1{EQ,NE}Z instructions Commit c8a34581ec09 ("MIPS: Emulate the BC1{EQ,NE}Z FPU instructions") added support for emulating the new R6 BC1{EQ,NE}Z branches but it missed the case where the instruction that caused the exception was not on a DS. Signed-off-by: Markos Chandras Fixes: c8a34581ec09 ("MIPS: Emulate the BC1{EQ,NE}Z FPU instructions") Cc: # 4.0+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10738/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index e78b1ae6dcdb..8a5b0eb4ddef 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1181,6 +1181,24 @@ emul: } break; + case bc1eqz_op: + case bc1nez_op: + if (!cpu_has_mips_r6 || delay_slot(xcp)) + return SIGILL; + + cond = likely = 0; + switch (MIPSInst_RS(ir)) { + case bc1eqz_op: + if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1) + cond = 1; + break; + case bc1nez_op: + if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)) + cond = 1; + break; + } + goto branch_common; + case bc_op: if (delay_slot(xcp)) return SIGILL; @@ -1207,7 +1225,7 @@ emul: case bct_op: break; } - +branch_common: set_delay_slot(xcp); if (cond) { /* -- cgit v1.2.3-59-g8ed1b From 0f6ce77538c3f0628acdeee30738e4c8fe08d7e2 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:42 +0100 Subject: Documentation/sysrq.txt: Mention MIPS TLB dump (x) Commit d1e9a4f54735 ("MIPS: Add SysRq operation to dump TLBs on all CPUs") added the 'x' sysrq key for dumping MIPS TLB entries, but didn't document it in Documentation/sysrq.txt. Add mention of the MIPS use of the 'x' SysRq key. Reported-by: Maciej W. Rozycki Signed-off-by: James Hogan Acked-by: Jonathan Corbet Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Cc: linux-doc@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10720/ Signed-off-by: Ralf Baechle --- Documentation/sysrq.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index 0e307c94809a..267f39386f99 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt @@ -119,6 +119,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.: 'x' - Used by xmon interface on ppc/powerpc platforms. Show global PMU Registers on sparc64. + Dump all TLB entries on MIPS. 'y' - Show global CPU Registers [SPARC-64 specific] -- cgit v1.2.3-59-g8ed1b From 3c865dd9c1d64046877112451f13db2cb46d4d28 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:43 +0100 Subject: MIPS: Refactor dumping of TLB registers for r3k/r4k The TLB registers are dumped in a couble of places: - sysrq_tlbdump_single() - when dumping TLB state. - do_mcheck() - in response to a machine check error. The main TLB registers also differ between r3k and r4k, but r4k appears to be assumed. Refactor this code into a dump_tlb_regs() function, implemented for both r3k and r4k, and used by both of the above functions. Fixes: d1e9a4f54735 ("MIPS: Add SysRq operation to dump TLBs on all CPUs") Suggested-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10721/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/tlbdebug.h | 1 + arch/mips/kernel/sysrq.c | 14 +------------- arch/mips/kernel/traps.c | 16 ++-------------- arch/mips/lib/dump_tlb.c | 18 ++++++++++++++++++ arch/mips/lib/r3k_dump_tlb.c | 11 +++++++++++ arch/mips/mm/tlb-r3k.c | 2 +- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/arch/mips/include/asm/tlbdebug.h b/arch/mips/include/asm/tlbdebug.h index bb8f5c29c3d9..3a25a8780ac7 100644 --- a/arch/mips/include/asm/tlbdebug.h +++ b/arch/mips/include/asm/tlbdebug.h @@ -11,6 +11,7 @@ /* * TLB debugging functions: */ +extern void dump_tlb_regs(void); extern void dump_tlb_all(void); #endif /* __ASM_TLBDEBUG_H */ diff --git a/arch/mips/kernel/sysrq.c b/arch/mips/kernel/sysrq.c index 5b539f5fc9d9..5f055393092d 100644 --- a/arch/mips/kernel/sysrq.c +++ b/arch/mips/kernel/sysrq.c @@ -21,24 +21,12 @@ static DEFINE_SPINLOCK(show_lock); static void sysrq_tlbdump_single(void *dummy) { - const int field = 2 * sizeof(unsigned long); unsigned long flags; spin_lock_irqsave(&show_lock, flags); pr_info("CPU%d:\n", smp_processor_id()); - pr_info("Index : %0x\n", read_c0_index()); - pr_info("Pagemask: %0x\n", read_c0_pagemask()); - pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); - pr_info("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); - pr_info("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); - pr_info("Wired : %0x\n", read_c0_wired()); - pr_info("Pagegrain: %0x\n", read_c0_pagegrain()); - if (cpu_has_htw) { - pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); - pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); - pr_info("PWCtl : %0x\n", read_c0_pwctl()); - } + dump_tlb_regs(); pr_info("\n"); dump_tlb_all(); pr_info("\n"); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 01da120d75c4..da0b3189fe88 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1523,7 +1523,6 @@ asmlinkage void do_watch(struct pt_regs *regs) asmlinkage void do_mcheck(struct pt_regs *regs) { - const int field = 2 * sizeof(unsigned long); int multi_match = regs->cp0_status & ST0_TS; enum ctx_state prev_state; mm_segment_t old_fs = get_fs(); @@ -1532,19 +1531,8 @@ asmlinkage void do_mcheck(struct pt_regs *regs) show_regs(regs); if (multi_match) { - pr_err("Index : %0x\n", read_c0_index()); - pr_err("Pagemask: %0x\n", read_c0_pagemask()); - pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi()); - pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); - pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); - pr_err("Wired : %0x\n", read_c0_wired()); - pr_err("Pagegrain: %0x\n", read_c0_pagegrain()); - if (cpu_has_htw) { - pr_err("PWField : %0*lx\n", field, read_c0_pwfield()); - pr_err("PWSize : %0*lx\n", field, read_c0_pwsize()); - pr_err("PWCtl : %0x\n", read_c0_pwctl()); - } - pr_err("\n"); + dump_tlb_regs(); + pr_info("\n"); dump_tlb_all(); } diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 167f35634709..519ededbf9a4 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -13,6 +13,24 @@ #include #include +void dump_tlb_regs(void) +{ + const int field = 2 * sizeof(unsigned long); + + pr_info("Index : %0x\n", read_c0_index()); + pr_info("PageMask : %0x\n", read_c0_pagemask()); + pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); + pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); + pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); + pr_info("Wired : %0x\n", read_c0_wired()); + pr_info("PageGrain: %0x\n", read_c0_pagegrain()); + if (cpu_has_htw) { + pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); + pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); + pr_info("PWCtl : %0x\n", read_c0_pwctl()); + } +} + static inline const char *msk2str(unsigned int mask) { switch (mask) { diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index 8e0d3cff8ae4..cfcbb5218b59 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -14,6 +14,17 @@ #include #include +extern int r3k_have_wired_reg; + +void dump_tlb_regs(void) +{ + pr_info("Index : %0x\n", read_c0_index()); + pr_info("EntryHi : %0lx\n", read_c0_entryhi()); + pr_info("EntryLo : %0lx\n", read_c0_entrylo0()); + if (r3k_have_wired_reg) + pr_info("Wired : %0x\n", read_c0_wired()); +} + static void dump_tlb(int first, int last) { int i; diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index 2b75b8f880ed..b4f366f7c0f5 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c @@ -36,7 +36,7 @@ extern void build_tlb_refill_handler(void); "nop\n\t" \ ".set pop\n\t") -static int r3k_have_wired_reg; /* Should be in cpu_data? */ +int r3k_have_wired_reg; /* Should be in cpu_data? */ /* TLB operations. */ static void local_flush_tlb_from(int entry) -- cgit v1.2.3-59-g8ed1b From aaa7be48fdbf14836ff1bc61c72969960a5923c6 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:44 +0100 Subject: MIPS: Probe for small (1KiB) page support Probe Config3 for small page support. This will be useful to give clues as to whether the PageGrain register exists. Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10722/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-features.h | 4 ++++ arch/mips/include/asm/cpu.h | 1 + arch/mips/kernel/cpu-probe.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index f25de771f7ed..9801ac982655 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -411,4 +411,8 @@ # define cpu_has_cdmm (cpu_data[0].options & MIPS_CPU_CDMM) #endif +#ifndef cpu_has_small_pages +# define cpu_has_small_pages (cpu_data[0].options & MIPS_CPU_SP) +#endif + #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 5fa7b8ba48a9..cd89e9855775 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -384,6 +384,7 @@ enum cpu_type_enum { #define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */ #define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */ #define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */ +#define MIPS_CPU_SP 0x10000000000ull /* Small (1KB) page support */ /* * CPU ASE encodings diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 4e39b340f3b7..987036761fb6 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -538,6 +538,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) } if (config3 & MIPS_CONF3_CDMM) c->options |= MIPS_CPU_CDMM; + if (config3 & MIPS_CONF3_SP) + c->options |= MIPS_CPU_SP; return config3 & MIPS_CONF_M; } -- cgit v1.2.3-59-g8ed1b From 5d3c3c7d296d9622560558de96875cf694d96f58 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:45 +0100 Subject: MIPS: dump_tlb: Only dump PageGrain if interesting The PageGrain register may not exist if certain architectural features aren't present, therefore only print out its value when dumping the TLB registers if it is expected to contain fields relevant to the TLB. Fixes: d1e9a4f54735 ("MIPS: Add SysRq operation to dump TLBs on all CPUs") Reported-by: Joshua Kinard Reported-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Joshua Kinard Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10723/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 519ededbf9a4..2ab83be14ffa 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -23,7 +23,8 @@ void dump_tlb_regs(void) pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); pr_info("Wired : %0x\n", read_c0_wired()); - pr_info("PageGrain: %0x\n", read_c0_pagegrain()); + if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa) + pr_info("PageGrain: %0x\n", read_c0_pagegrain()); if (cpu_has_htw) { pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); -- cgit v1.2.3-59-g8ed1b From 9bd860cae3c46a83371ce899ae0d665b6e253687 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:46 +0100 Subject: MIPS: dump_tlb: Dump FrameMask register if exists The FrameMask register is relevant to the TLB so it should be dumped by dump_tlb_regs(), however it is only present in certain cores (r10000, r12000, r14000, r16000). Add dumping of it, conditional upon current_cpu_type(). Suggested-by: Joshua Kinard Suggested-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Joshua Kinard Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10724/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 2ab83be14ffa..64f90f626681 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -23,6 +23,14 @@ void dump_tlb_regs(void) pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); pr_info("Wired : %0x\n", read_c0_wired()); + switch (current_cpu_type()) { + case CPU_R10000: + case CPU_R12000: + case CPU_R14000: + case CPU_R16000: + pr_info("FrameMask: %0x\n", read_c0_framemask()); + break; + } if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa) pr_info("PageGrain: %0x\n", read_c0_pagegrain()); if (cpu_has_htw) { -- cgit v1.2.3-59-g8ed1b From bae637a2148c97882a1bbfdac08d7a5f4441cdb3 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:47 +0100 Subject: MIPS: Rearrange ENTRYLO field definitions The generic field definitions (i.e. present before MIPS32/MIPS64) in mipsregs.h are conventionally not prefixed with MIPS_, so rename the recently added MIPS_ENTRYLO_* definitions for the G, V, D, and C fields to ENTRYLO_*. Also rearrange to put the EntryLo and EntryHi definitions in the right place in the file. Fixes: 8ab6abcb6aa4 ("MIPS: mipsregs.h: Add EntryLo bit definitions") Reported-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10725/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 52 +++++++++++++++++++++------------------- arch/mips/lib/dump_tlb.c | 18 +++++++------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index b688c924a025..d3cd8eac81e3 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -112,6 +112,30 @@ #define CP0_TX39_CACHE $7 +/* Generic EntryLo bit definitions */ +#define ENTRYLO_G (_ULCAST_(1) << 0) +#define ENTRYLO_V (_ULCAST_(1) << 1) +#define ENTRYLO_D (_ULCAST_(1) << 2) +#define ENTRYLO_C_SHIFT 3 +#define ENTRYLO_C (_ULCAST_(7) << ENTRYLO_C_SHIFT) + +/* R3000 EntryLo bit definitions */ +#define R3K_ENTRYLO_G (_ULCAST_(1) << 8) +#define R3K_ENTRYLO_V (_ULCAST_(1) << 9) +#define R3K_ENTRYLO_D (_ULCAST_(1) << 10) +#define R3K_ENTRYLO_N (_ULCAST_(1) << 11) + +/* MIPS32/64 EntryLo bit definitions */ +#ifdef CONFIG_64BIT +/* as read by dmfc0 */ +#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 62) +#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 63) +#else +/* as read by mfc0 */ +#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 30) +#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 31) +#endif + /* * Values for PageMask register */ @@ -203,6 +227,9 @@ #define PG_ESP (_ULCAST_(1) << 28) #define PG_IEC (_ULCAST_(1) << 27) +/* MIPS32/64 EntryHI bit definitions */ +#define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) + /* * R4x00 interrupt enable / cause bits */ @@ -588,31 +615,6 @@ #define MIPS_MAAR_S (_ULCAST_(1) << 1) #define MIPS_MAAR_V (_ULCAST_(1) << 0) -/* EntryHI bit definition */ -#define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) - -/* R3000 EntryLo bit definitions */ -#define R3K_ENTRYLO_G (_ULCAST_(1) << 8) -#define R3K_ENTRYLO_V (_ULCAST_(1) << 9) -#define R3K_ENTRYLO_D (_ULCAST_(1) << 10) -#define R3K_ENTRYLO_N (_ULCAST_(1) << 11) - -/* R4000 compatible EntryLo bit definitions */ -#define MIPS_ENTRYLO_G (_ULCAST_(1) << 0) -#define MIPS_ENTRYLO_V (_ULCAST_(1) << 1) -#define MIPS_ENTRYLO_D (_ULCAST_(1) << 2) -#define MIPS_ENTRYLO_C_SHIFT 3 -#define MIPS_ENTRYLO_C (_ULCAST_(7) << MIPS_ENTRYLO_C_SHIFT) -#ifdef CONFIG_64BIT -/* as read by dmfc0 */ -#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 62) -#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 63) -#else -/* as read by mfc0 */ -#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 30) -#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 31) -#endif - /* CMGCRBase bit definitions */ #define MIPS_CMGCRB_BASE 11 #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 64f90f626681..92a37319efbe 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -114,7 +114,7 @@ static void dump_tlb(int first, int last) * leave only a single G bit set after a machine check exception * due to duplicate TLB entry. */ - if (!((entrylo0 | entrylo1) & MIPS_ENTRYLO_G) && + if (!((entrylo0 | entrylo1) & ENTRYLO_G) && (entryhi & 0xff) != asid) continue; @@ -123,8 +123,8 @@ static void dump_tlb(int first, int last) */ printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); - c0 = (entrylo0 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; - c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; + c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; + c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; printk("va=%0*lx asid=%02lx\n", vwidth, (entryhi & ~0x1fffUL), @@ -141,9 +141,9 @@ static void dump_tlb(int first, int last) (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", pwidth, pa, c0, - (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, - (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, - (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); + (entrylo0 & ENTRYLO_D) ? 1 : 0, + (entrylo0 & ENTRYLO_V) ? 1 : 0, + (entrylo0 & ENTRYLO_G) ? 1 : 0); /* RI/XI are in awkward places, so mask them off separately */ pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); if (xpa) @@ -155,9 +155,9 @@ static void dump_tlb(int first, int last) (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", pwidth, pa, c1, - (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, - (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, - (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); + (entrylo1 & ENTRYLO_D) ? 1 : 0, + (entrylo1 & ENTRYLO_V) ? 1 : 0, + (entrylo1 & ENTRYLO_G) ? 1 : 0); } printk("\n"); -- cgit v1.2.3-59-g8ed1b From 486fcde40d8f903dbd460fb0b5a35423528032e3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 08:58:20 +0200 Subject: MIPS: Sibyte: Move bus watcher from deprecated __initcall to device_initcall Signed-off-by: Ralf Baechle --- arch/mips/sibyte/common/bus_watcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/sibyte/common/bus_watcher.c b/arch/mips/sibyte/common/bus_watcher.c index 41a1d2242211..a4e55999ecb4 100644 --- a/arch/mips/sibyte/common/bus_watcher.c +++ b/arch/mips/sibyte/common/bus_watcher.c @@ -250,4 +250,4 @@ int __init sibyte_bus_watcher(void) return 0; } -__initcall(sibyte_bus_watcher); +device_initcall(sibyte_bus_watcher); -- cgit v1.2.3-59-g8ed1b From 8d6b591ce9b2706403b4c79d72c4483a7fbeda54 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 09:04:41 +0200 Subject: MIPS: unaligned: Move from deprecated __initcall to arch_initcall. Signed-off-by: Ralf Baechle --- arch/mips/kernel/unaligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index f55869c00ce4..990354dd6bde 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -2312,5 +2312,5 @@ static int __init debugfs_unaligned(void) return -ENOMEM; return 0; } -__initcall(debugfs_unaligned); +arch_initcall(debugfs_unaligned); #endif -- cgit v1.2.3-59-g8ed1b From 1bab0b627f6d9cd5af08f6be81288883d3b1aa9c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 09:09:40 +0200 Subject: MIPS: Lasat: Move from deprecated __initcall to arch_initcall. Signed-off-by: Ralf Baechle --- arch/mips/lasat/sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c index a57959e648a6..c710d969938d 100644 --- a/arch/mips/lasat/sysctl.c +++ b/arch/mips/lasat/sysctl.c @@ -270,4 +270,4 @@ static int __init lasat_register_sysctl(void) return 0; } -__initcall(lasat_register_sysctl); +arch_initcall(lasat_register_sysctl); -- cgit v1.2.3-59-g8ed1b From 1249ed3540809d30d1fe42c94276a9db2845d173 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 09:10:20 +0200 Subject: MIPS: math-emu: Move from deprecated __initcall to arch_initcall. Signed-off-by: Ralf Baechle --- arch/mips/math-emu/me-debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c index f308e0f05fc5..506a67a98cdf 100644 --- a/arch/mips/math-emu/me-debugfs.c +++ b/arch/mips/math-emu/me-debugfs.c @@ -65,4 +65,4 @@ do { \ return 0; } -__initcall(debugfs_fpuemu); +arch_initcall(debugfs_fpuemu); -- cgit v1.2.3-59-g8ed1b From f17c4ca33601f03f4b5f598f085ee356358932b7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 23 Jul 2015 12:02:09 +0200 Subject: MIPS: Kconfig: Separate 32BIT and 64BIT config block by blank line. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 52b7918da21a..efa3706beb54 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1968,6 +1968,7 @@ config 32BIT select TRAD_SIGNALS help Select this option if you want to build a 32-bit kernel. + config 64BIT bool "64-bit kernel" depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL -- cgit v1.2.3-59-g8ed1b From 3dcd7779ac4dada4a2c97e19a9ac3593891d89a0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:52 +0530 Subject: MIPS: Alchemy: Migrate to new 'set-state' interface Migrate alchemy driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: Manuel Lauss Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10599/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/common/time.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index 50e17e13c18b..f99d3ec17a45 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -69,11 +69,6 @@ static int au1x_rtcmatch2_set_next_event(unsigned long delta, return 0; } -static void au1x_rtcmatch2_set_mode(enum clock_event_mode mode, - struct clock_event_device *cd) -{ -} - static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id) { struct clock_event_device *cd = dev_id; @@ -86,7 +81,6 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = { .features = CLOCK_EVT_FEAT_ONESHOT, .rating = 1500, .set_next_event = au1x_rtcmatch2_set_next_event, - .set_mode = au1x_rtcmatch2_set_mode, .cpumask = cpu_all_mask, }; -- cgit v1.2.3-59-g8ed1b From 20a7835f8f3666eaaec599f8f9f1628c4e7e88dd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:53 +0530 Subject: MIPS: Jazz: Migrate to new 'set-state' interface Migrate jazz driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10600/ Signed-off-by: Ralf Baechle --- arch/mips/jazz/irq.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index e1ea4f625f7a..5d6828b2a750 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -110,18 +110,11 @@ asmlinkage void plat_irq_dispatch(void) } } -static void r4030_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - struct clock_event_device r4030_clockevent = { .name = "r4030", .features = CLOCK_EVT_FEAT_PERIODIC, .rating = 300, .irq = JAZZ_TIMER_IRQ, - .set_mode = r4030_set_mode, }; static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) -- cgit v1.2.3-59-g8ed1b From c87cbe06916868e1b14a0681e874b96cfab61083 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:54 +0530 Subject: MIPS: jz4740: Migrate to new 'set-state' interface Migrate jz4740 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Paul Burton Cc: Deng-Cheng Zhu Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10601/ Signed-off-by: Ralf Baechle --- arch/mips/jz4740/time.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c index 7ab47fee1be8..1f7ca2c9f262 100644 --- a/arch/mips/jz4740/time.c +++ b/arch/mips/jz4740/time.c @@ -58,7 +58,7 @@ static irqreturn_t jz4740_clockevent_irq(int irq, void *devid) jz4740_timer_ack_full(TIMER_CLOCKEVENT); - if (cd->mode != CLOCK_EVT_MODE_PERIODIC) + if (!clockevent_state_periodic(cd)) jz4740_timer_disable(TIMER_CLOCKEVENT); cd->event_handler(cd); @@ -66,24 +66,29 @@ static irqreturn_t jz4740_clockevent_irq(int irq, void *devid) return IRQ_HANDLED; } -static void jz4740_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *cd) +static int jz4740_clockevent_set_periodic(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); - jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); - case CLOCK_EVT_MODE_RESUME: - jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); - jz4740_timer_enable(TIMER_CLOCKEVENT); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_SHUTDOWN: - jz4740_timer_disable(TIMER_CLOCKEVENT); - break; - default: - break; - } + jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); + jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); + jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); + jz4740_timer_enable(TIMER_CLOCKEVENT); + + return 0; +} + +static int jz4740_clockevent_resume(struct clock_event_device *evt) +{ + jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); + jz4740_timer_enable(TIMER_CLOCKEVENT); + + return 0; +} + +static int jz4740_clockevent_shutdown(struct clock_event_device *evt) +{ + jz4740_timer_disable(TIMER_CLOCKEVENT); + + return 0; } static int jz4740_clockevent_set_next(unsigned long evt, @@ -100,7 +105,10 @@ static struct clock_event_device jz4740_clockevent = { .name = "jz4740-timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_next_event = jz4740_clockevent_set_next, - .set_mode = jz4740_clockevent_set_mode, + .set_state_shutdown = jz4740_clockevent_shutdown, + .set_state_periodic = jz4740_clockevent_set_periodic, + .set_state_oneshot = jz4740_clockevent_shutdown, + .tick_resume = jz4740_clockevent_resume, .rating = 200, #ifdef CONFIG_MACH_JZ4740 .irq = JZ4740_IRQ_TCU0, -- cgit v1.2.3-59-g8ed1b From 1edf907a09e1cad9032411d84679b637ab696593 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:55 +0530 Subject: MIPS: cevt-bcm1480: Migrate to new 'set-state' interface Migrate cevt-bcm1480 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Read operation on R_SCD_TIMER_CFG and R_SCD_TIMER_INIT registers isn't performed now for many modes as there returned values aren't used. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10602/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-bcm1480.c | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/mips/kernel/cevt-bcm1480.c b/arch/mips/kernel/cevt-bcm1480.c index 7976457184b1..940ac00e9129 100644 --- a/arch/mips/kernel/cevt-bcm1480.c +++ b/arch/mips/kernel/cevt-bcm1480.c @@ -40,8 +40,8 @@ * The general purpose timer ticks at 1MHz independent if * the rest of the system */ -static void sibyte_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) + +static int sibyte_set_periodic(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); void __iomem *cfg, *init; @@ -49,24 +49,22 @@ static void sibyte_set_mode(enum clock_event_mode mode, cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writeq(0, cfg); - __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - cfg); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* Stop the timer until we actually program a shot */ - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writeq(0, cfg); - break; - - case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ - case CLOCK_EVT_MODE_RESUME: - ; - } + __raw_writeq(0, cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); + return 0; +} + +static int sibyte_shutdown(struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *cfg; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + /* Stop the timer until we actually program a shot */ + __raw_writeq(0, cfg); + return 0; } static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) @@ -91,7 +89,7 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) void __iomem *cfg; unsigned long tmode; - if (cd->mode == CLOCK_EVT_MODE_PERIODIC) + if (clockevent_state_periodic(cd)) tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; else tmode = 0; @@ -130,7 +128,9 @@ void sb1480_clockevent_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = sibyte_next_event; - cd->set_mode = sibyte_set_mode; + cd->set_state_shutdown = sibyte_shutdown; + cd->set_state_periodic = sibyte_set_periodic; + cd->set_state_oneshot = sibyte_shutdown; clockevents_register_device(cd); bcm1480_mask_irq(cpu, irq); -- cgit v1.2.3-59-g8ed1b From 9f95618f9fe5fc902a3d8fecd10c98e482fab6c5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:56 +0530 Subject: MIPS: cevt-ds1287: Migrate to new 'set-state' interface Migrate cevt-ds1287 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10603/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-ds1287.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c index ff1f01b72270..77a5ddf53f57 100644 --- a/arch/mips/kernel/cevt-ds1287.c +++ b/arch/mips/kernel/cevt-ds1287.c @@ -59,27 +59,32 @@ static int ds1287_set_next_event(unsigned long delta, return -EINVAL; } -static void ds1287_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int ds1287_shutdown(struct clock_event_device *evt) { u8 val; spin_lock(&rtc_lock); val = CMOS_READ(RTC_REG_B); + val &= ~RTC_PIE; + CMOS_WRITE(val, RTC_REG_B); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - val |= RTC_PIE; - break; - default: - val &= ~RTC_PIE; - break; - } + spin_unlock(&rtc_lock); + return 0; +} +static int ds1287_set_periodic(struct clock_event_device *evt) +{ + u8 val; + + spin_lock(&rtc_lock); + + val = CMOS_READ(RTC_REG_B); + val |= RTC_PIE; CMOS_WRITE(val, RTC_REG_B); spin_unlock(&rtc_lock); + return 0; } static void ds1287_event_handler(struct clock_event_device *dev) @@ -87,11 +92,13 @@ static void ds1287_event_handler(struct clock_event_device *dev) } static struct clock_event_device ds1287_clockevent = { - .name = "ds1287", - .features = CLOCK_EVT_FEAT_PERIODIC, - .set_next_event = ds1287_set_next_event, - .set_mode = ds1287_set_mode, - .event_handler = ds1287_event_handler, + .name = "ds1287", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_next_event = ds1287_set_next_event, + .set_state_shutdown = ds1287_shutdown, + .set_state_periodic = ds1287_set_periodic, + .tick_resume = ds1287_shutdown, + .event_handler = ds1287_event_handler, }; static irqreturn_t ds1287_interrupt(int irq, void *dev_id) -- cgit v1.2.3-59-g8ed1b From c88f2fb4d81df3dbafd79d51b2cacefb356d466c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:57 +0530 Subject: MIPS: cevt-gt641xx: Migrate to new 'set-state' interface Migrate cevt-gt641xx driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10604/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-gt641xx.c | 57 ++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c index f069460751ab..66040051151d 100644 --- a/arch/mips/kernel/cevt-gt641xx.c +++ b/arch/mips/kernel/cevt-gt641xx.c @@ -64,8 +64,7 @@ static int gt641xx_timer0_set_next_event(unsigned long delta, return 0; } -static void gt641xx_timer0_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int gt641xx_timer0_shutdown(struct clock_event_device *evt) { u32 ctrl; @@ -73,21 +72,39 @@ static void gt641xx_timer0_set_mode(enum clock_event_mode mode, ctrl = GT_READ(GT_TC_CONTROL_OFS); ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); + + raw_spin_unlock(>641xx_timer_lock); + return 0; +} + +static int gt641xx_timer0_set_oneshot(struct clock_event_device *evt) +{ + u32 ctrl; + + raw_spin_lock(>641xx_timer_lock); + + ctrl = GT_READ(GT_TC_CONTROL_OFS); + ctrl &= ~GT_TC_CONTROL_SELTC0_MSK; + ctrl |= GT_TC_CONTROL_ENTC0_MSK; + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); + + raw_spin_unlock(>641xx_timer_lock); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; - break; - case CLOCK_EVT_MODE_ONESHOT: - ctrl |= GT_TC_CONTROL_ENTC0_MSK; - break; - default: - break; - } +static int gt641xx_timer0_set_periodic(struct clock_event_device *evt) +{ + u32 ctrl; + + raw_spin_lock(>641xx_timer_lock); + ctrl = GT_READ(GT_TC_CONTROL_OFS); + ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; GT_WRITE(GT_TC_CONTROL_OFS, ctrl); raw_spin_unlock(>641xx_timer_lock); + return 0; } static void gt641xx_timer0_event_handler(struct clock_event_device *dev) @@ -95,12 +112,16 @@ static void gt641xx_timer0_event_handler(struct clock_event_device *dev) } static struct clock_event_device gt641xx_timer0_clockevent = { - .name = "gt641xx-timer0", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .irq = GT641XX_TIMER0_IRQ, - .set_next_event = gt641xx_timer0_set_next_event, - .set_mode = gt641xx_timer0_set_mode, - .event_handler = gt641xx_timer0_event_handler, + .name = "gt641xx-timer0", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .irq = GT641XX_TIMER0_IRQ, + .set_next_event = gt641xx_timer0_set_next_event, + .set_state_shutdown = gt641xx_timer0_shutdown, + .set_state_periodic = gt641xx_timer0_set_periodic, + .set_state_oneshot = gt641xx_timer0_set_oneshot, + .tick_resume = gt641xx_timer0_shutdown, + .event_handler = gt641xx_timer0_event_handler, }; static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) -- cgit v1.2.3-59-g8ed1b From 877c61dc63c2eaa98515abfd89596f293b543342 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:58 +0530 Subject: MIPS: cevt-r4k: Migrate to new 'set-state' interface Migrate cevt-4k driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: James Hogan Cc: Andrew Bresticker Cc: Qais Yousef Cc: Jason Cooper Cc: Leonid Yegoshin Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10605/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cevt-r4k.h | 1 - arch/mips/kernel/cevt-r4k.c | 7 ------- 2 files changed, 8 deletions(-) diff --git a/arch/mips/include/asm/cevt-r4k.h b/arch/mips/include/asm/cevt-r4k.h index f0edf6fcd002..2e13a038d260 100644 --- a/arch/mips/include/asm/cevt-r4k.h +++ b/arch/mips/include/asm/cevt-r4k.h @@ -21,7 +21,6 @@ DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); void mips_event_handler(struct clock_event_device *dev); int c0_compare_int_usable(void); -void mips_set_clock_mode(enum clock_event_mode, struct clock_event_device *); irqreturn_t c0_compare_interrupt(int, void *); extern struct irqaction c0_compare_irqaction; diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index cc7cc46b58f7..8dfe6a6e1480 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -28,12 +28,6 @@ static int mips_next_event(unsigned long delta, return res; } -void mips_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); int cp0_timer_irq_installed; @@ -215,7 +209,6 @@ int r4k_clockevent_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = mips_next_event; - cd->set_mode = mips_set_clock_mode; cd->event_handler = mips_event_handler; clockevents_register_device(cd); -- cgit v1.2.3-59-g8ed1b From 57e148cabbb2f1e6770d6a506088486142b26b97 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:59 +0530 Subject: MIPS: cevt-sb1250: Migrate to new 'set-state' interface Migrate cevt-rsb1250 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10606/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-sb1250.c | 45 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/arch/mips/kernel/cevt-sb1250.c b/arch/mips/kernel/cevt-sb1250.c index 5ea6d6b1de15..3d860efd63b9 100644 --- a/arch/mips/kernel/cevt-sb1250.c +++ b/arch/mips/kernel/cevt-sb1250.c @@ -38,8 +38,20 @@ * The general purpose timer ticks at 1MHz independent if * the rest of the system */ -static void sibyte_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) + +static int sibyte_shutdown(struct clock_event_device *evt) +{ + void __iomem *cfg; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(smp_processor_id(), R_SCD_TIMER_CFG)); + + /* Stop the timer until we actually program a shot */ + __raw_writeq(0, cfg); + + return 0; +} + +static int sibyte_set_periodic(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); void __iomem *cfg, *init; @@ -47,24 +59,11 @@ static void sibyte_set_mode(enum clock_event_mode mode, cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writeq(0, cfg); - __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - cfg); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* Stop the timer until we actually program a shot */ - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writeq(0, cfg); - break; - - case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ - case CLOCK_EVT_MODE_RESUME: - ; - } + __raw_writeq(0, cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); + + return 0; } static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) @@ -89,7 +88,7 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) void __iomem *cfg; unsigned long tmode; - if (cd->mode == CLOCK_EVT_MODE_PERIODIC) + if (clockevent_state_periodic(cd)) tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; else tmode = 0; @@ -129,7 +128,9 @@ void sb1250_clockevent_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = sibyte_next_event; - cd->set_mode = sibyte_set_mode; + cd->set_state_shutdown = sibyte_shutdown; + cd->set_state_periodic = sibyte_set_periodic; + cd->set_state_oneshot = sibyte_shutdown; clockevents_register_device(cd); sb1250_mask_irq(cpu, irq); -- cgit v1.2.3-59-g8ed1b From d199da550da30e0946a7554f8a93ef75f66f8005 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:00 +0530 Subject: MIPS: cevt-txx9: Migrate to new 'set-state' interface Migrate cevt-txx9 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Deng-Cheng Zhu Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Cc: Viresh Kumar Patchwork: https://patchwork.linux-mips.org/patch/10607/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-txx9.c | 81 ++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c index 723932441ecc..537eefdf838f 100644 --- a/arch/mips/kernel/cevt-txx9.c +++ b/arch/mips/kernel/cevt-txx9.c @@ -85,36 +85,54 @@ static void txx9tmr_stop_and_clear(struct txx9_tmr_reg __iomem *tmrptr) __raw_writel(0, &tmrptr->tisr); } -static void txx9tmr_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int txx9tmr_set_state_periodic(struct clock_event_device *evt) { struct txx9_clock_event_device *txx9_cd = container_of(evt, struct txx9_clock_event_device, cd); struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; txx9tmr_stop_and_clear(tmrptr); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, - &tmrptr->itmr); - /* start timer */ - __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> - evt->shift, - &tmrptr->cpra); - __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - __raw_writel(0, &tmrptr->itmr); - break; - case CLOCK_EVT_MODE_ONESHOT: - __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); - break; - case CLOCK_EVT_MODE_RESUME: - __raw_writel(TIMER_CCD, &tmrptr->ccdr); - __raw_writel(0, &tmrptr->itmr); - break; - } + + __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, &tmrptr->itmr); + /* start timer */ + __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> evt->shift, + &tmrptr->cpra); + __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); + return 0; +} + +static int txx9tmr_set_state_oneshot(struct clock_event_device *evt) +{ + struct txx9_clock_event_device *txx9_cd = + container_of(evt, struct txx9_clock_event_device, cd); + struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; + + txx9tmr_stop_and_clear(tmrptr); + __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); + return 0; +} + +static int txx9tmr_set_state_shutdown(struct clock_event_device *evt) +{ + struct txx9_clock_event_device *txx9_cd = + container_of(evt, struct txx9_clock_event_device, cd); + struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; + + txx9tmr_stop_and_clear(tmrptr); + __raw_writel(0, &tmrptr->itmr); + return 0; +} + +static int txx9tmr_tick_resume(struct clock_event_device *evt) +{ + struct txx9_clock_event_device *txx9_cd = + container_of(evt, struct txx9_clock_event_device, cd); + struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; + + txx9tmr_stop_and_clear(tmrptr); + __raw_writel(TIMER_CCD, &tmrptr->ccdr); + __raw_writel(0, &tmrptr->itmr); + return 0; } static int txx9tmr_set_next_event(unsigned long delta, @@ -133,12 +151,15 @@ static int txx9tmr_set_next_event(unsigned long delta, static struct txx9_clock_event_device txx9_clock_event_device = { .cd = { - .name = "TXx9", - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_mode = txx9tmr_set_mode, - .set_next_event = txx9tmr_set_next_event, + .name = "TXx9", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_state_shutdown = txx9tmr_set_state_shutdown, + .set_state_periodic = txx9tmr_set_state_periodic, + .set_state_oneshot = txx9tmr_set_state_oneshot, + .tick_resume = txx9tmr_tick_resume, + .set_next_event = txx9tmr_set_next_event, }, }; -- cgit v1.2.3-59-g8ed1b From e3280b2a54b38406563d6422685a20172382d365 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:01 +0530 Subject: MIPS: loongson64/timer: Migrate to new 'set-state' interface Migrate loongson driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. [ralf@linux-mips.org: Folded in Viresh's followon fix.] Signed-off-by: Viresh Kumar Cc: Huacai Chen Cc: Michael Opdenacker Cc: Hongliang Tao Cc: Valentin Rothberg Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Cc: Viresh Kumar Patchwork: https://patchwork.linux-mips.org/patch/10608/ Patchwork: https://patchwork.linux-mips.org/patch/10883/ Signed-off-by: Ralf Baechle --- arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c | 46 ++++----- arch/mips/loongson64/loongson-3/hpet.c | 117 +++++++++++++--------- 2 files changed, 92 insertions(+), 71 deletions(-) diff --git a/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c index 875037063a80..da77d412514c 100644 --- a/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c +++ b/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c @@ -51,40 +51,36 @@ void enable_mfgpt0_counter(void) } EXPORT_SYMBOL(enable_mfgpt0_counter); -static void init_mfgpt_timer(enum clock_event_mode mode, - struct clock_event_device *evt) +static int mfgpt_timer_set_periodic(struct clock_event_device *evt) { raw_spin_lock(&mfgpt_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ - outw(0, MFGPT0_CNT); /* set counter to 0 */ - enable_mfgpt0_counter(); - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - if (evt->mode == CLOCK_EVT_MODE_PERIODIC || - evt->mode == CLOCK_EVT_MODE_ONESHOT) - disable_mfgpt0_counter(); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* The oneshot mode have very high deviation, Not use it! */ - break; - - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do here */ - break; - } + outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ + outw(0, MFGPT0_CNT); /* set counter to 0 */ + enable_mfgpt0_counter(); + raw_spin_unlock(&mfgpt_lock); + return 0; +} + +static int mfgpt_timer_shutdown(struct clock_event_device *evt) +{ + if (clockevent_state_periodic(evt) || clockevent_state_oneshot(evt)) { + raw_spin_lock(&mfgpt_lock); + disable_mfgpt0_counter(); + raw_spin_unlock(&mfgpt_lock); + } + + return 0; } static struct clock_event_device mfgpt_clockevent = { .name = "mfgpt", .features = CLOCK_EVT_FEAT_PERIODIC, - .set_mode = init_mfgpt_timer, + + /* The oneshot mode have very high deviation, don't use it! */ + .set_state_shutdown = mfgpt_timer_shutdown, + .set_state_periodic = mfgpt_timer_set_periodic, .irq = CS5536_MFGPT_INTR, }; diff --git a/arch/mips/loongson64/loongson-3/hpet.c b/arch/mips/loongson64/loongson-3/hpet.c index 5c21cd3bd339..bf9f1a77f0e5 100644 --- a/arch/mips/loongson64/loongson-3/hpet.c +++ b/arch/mips/loongson64/loongson-3/hpet.c @@ -78,55 +78,77 @@ static void hpet_enable_legacy_int(void) /* Do nothing on Loongson-3 */ } -static void hpet_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int hpet_set_state_periodic(struct clock_event_device *evt) { - int cfg = 0; + int cfg; spin_lock(&hpet_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - pr_info("set clock event to periodic mode!\n"); - /* stop counter */ - hpet_stop_counter(); - - /* enables the timer0 to generate a periodic interrupt */ - cfg = hpet_read(HPET_T0_CFG); - cfg &= ~HPET_TN_LEVEL; - cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | - HPET_TN_SETVAL | HPET_TN_32BIT; - hpet_write(HPET_T0_CFG, cfg); - - /* set the comparator */ - hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); - udelay(1); - hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); - - /* start counter */ - hpet_start_counter(); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - cfg = hpet_read(HPET_T0_CFG); - cfg &= ~HPET_TN_ENABLE; - hpet_write(HPET_T0_CFG, cfg); - break; - case CLOCK_EVT_MODE_ONESHOT: - pr_info("set clock event to one shot mode!\n"); - cfg = hpet_read(HPET_T0_CFG); - /* set timer0 type - * 1 : periodic interrupt - * 0 : non-periodic(oneshot) interrupt - */ - cfg &= ~HPET_TN_PERIODIC; - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; - hpet_write(HPET_T0_CFG, cfg); - break; - case CLOCK_EVT_MODE_RESUME: - hpet_enable_legacy_int(); - break; - } + + pr_info("set clock event to periodic mode!\n"); + /* stop counter */ + hpet_stop_counter(); + + /* enables the timer0 to generate a periodic interrupt */ + cfg = hpet_read(HPET_T0_CFG); + cfg &= ~HPET_TN_LEVEL; + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | + HPET_TN_32BIT; + hpet_write(HPET_T0_CFG, cfg); + + /* set the comparator */ + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); + udelay(1); + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); + + /* start counter */ + hpet_start_counter(); + + spin_unlock(&hpet_lock); + return 0; +} + +static int hpet_set_state_shutdown(struct clock_event_device *evt) +{ + int cfg; + + spin_lock(&hpet_lock); + + cfg = hpet_read(HPET_T0_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_write(HPET_T0_CFG, cfg); + spin_unlock(&hpet_lock); + return 0; +} + +static int hpet_set_state_oneshot(struct clock_event_device *evt) +{ + int cfg; + + spin_lock(&hpet_lock); + + pr_info("set clock event to one shot mode!\n"); + cfg = hpet_read(HPET_T0_CFG); + /* + * set timer0 type + * 1 : periodic interrupt + * 0 : non-periodic(oneshot) interrupt + */ + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_write(HPET_T0_CFG, cfg); + + spin_unlock(&hpet_lock); + return 0; +} + +static int hpet_tick_resume(struct clock_event_device *evt) +{ + spin_lock(&hpet_lock); + hpet_enable_legacy_int(); + spin_unlock(&hpet_lock); + + return 0; } static int hpet_next_event(unsigned long delta, @@ -206,7 +228,10 @@ void __init setup_hpet_timer(void) cd->name = "hpet"; cd->rating = 320; cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - cd->set_mode = hpet_set_mode; + cd->set_state_shutdown = hpet_set_state_shutdown; + cd->set_state_periodic = hpet_set_state_periodic; + cd->set_state_oneshot = hpet_set_state_oneshot; + cd->tick_resume = hpet_tick_resume; cd->set_next_event = hpet_next_event; cd->irq = HPET_T0_IRQ; cd->cpumask = cpumask_of(cpu); -- cgit v1.2.3-59-g8ed1b From 1fed884d5f3d615d56d3b3c07d5ef95f7b49b5f5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:02 +0530 Subject: MIPS: loongsoon32: Migrate to new 'set-state' interface Migrate loongsoon32 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Kelvin Cheung Cc: Huacai Chen Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10609/ Signed-off-by: Ralf Baechle --- arch/mips/loongson32/common/time.c | 57 +++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/arch/mips/loongson32/common/time.c b/arch/mips/loongson32/common/time.c index df0f850d6a5f..0996b025eeef 100644 --- a/arch/mips/loongson32/common/time.c +++ b/arch/mips/loongson32/common/time.c @@ -126,26 +126,34 @@ static irqreturn_t ls1x_clockevent_isr(int irq, void *devid) return IRQ_HANDLED; } -static void ls1x_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *cd) +static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) { raw_spin_lock(&ls1x_timer_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); - ls1x_pwmtimer_restart(); - case CLOCK_EVT_MODE_RESUME: - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, - timer_base + PWM_CTRL); - break; - default: - break; - } + ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); + ls1x_pwmtimer_restart(); + __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); + + return 0; +} + +static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) +{ + raw_spin_lock(&ls1x_timer_lock); + __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + raw_spin_unlock(&ls1x_timer_lock); + + return 0; +} + +static int ls1x_clockevent_set_state_shutdown(struct clock_event_device *cd) +{ + raw_spin_lock(&ls1x_timer_lock); + __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, + timer_base + PWM_CTRL); + raw_spin_unlock(&ls1x_timer_lock); + + return 0; } static int ls1x_clockevent_set_next(unsigned long evt, @@ -160,12 +168,15 @@ static int ls1x_clockevent_set_next(unsigned long evt, } static struct clock_event_device ls1x_clockevent = { - .name = "ls1x-pwmtimer", - .features = CLOCK_EVT_FEAT_PERIODIC, - .rating = 300, - .irq = LS1X_TIMER_IRQ, - .set_next_event = ls1x_clockevent_set_next, - .set_mode = ls1x_clockevent_set_mode, + .name = "ls1x-pwmtimer", + .features = CLOCK_EVT_FEAT_PERIODIC, + .rating = 300, + .irq = LS1X_TIMER_IRQ, + .set_next_event = ls1x_clockevent_set_next, + .set_state_shutdown = ls1x_clockevent_set_state_shutdown, + .set_state_periodic = ls1x_clockevent_set_state_periodic, + .set_state_oneshot = ls1x_clockevent_set_state_shutdown, + .tick_resume = ls1x_clockevent_tick_resume, }; static struct irqaction ls1x_pwmtimer_irqaction = { -- cgit v1.2.3-59-g8ed1b From 59113d93c2b483485cf62f0b057f896e420048c2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:03 +0530 Subject: MIPS: rt3352: Migrate to new 'set-state' interface Migrate ralink driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10610/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/cevt-rt3352.c | 59 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index 24bf057a3613..a8e70a9f274b 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -36,8 +36,8 @@ struct systick_device { int freq_scale; }; -static void systick_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt); +static int systick_set_oneshot(struct clock_event_device *evt); +static int systick_shutdown(struct clock_event_device *evt); static int systick_next_event(unsigned long delta, struct clock_event_device *evt) @@ -73,11 +73,12 @@ static struct systick_device systick = { * cevt-r4k uses 300, make sure systick * gets used if available */ - .rating = 310, - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = systick_next_event, - .set_mode = systick_set_clock_mode, - .event_handler = systick_event_handler, + .rating = 310, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = systick_next_event, + .set_state_shutdown = systick_shutdown, + .set_state_oneshot = systick_set_oneshot, + .event_handler = systick_event_handler, }, }; @@ -87,33 +88,33 @@ static struct irqaction systick_irqaction = { .dev_id = &systick.dev, }; -static void systick_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int systick_shutdown(struct clock_event_device *evt) { struct systick_device *sdev; sdev = container_of(evt, struct systick_device, dev); - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - if (!sdev->irq_requested) - setup_irq(systick.dev.irq, &systick_irqaction); - sdev->irq_requested = 1; - iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, - systick.membase + SYSTICK_CONFIG); - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - if (sdev->irq_requested) - free_irq(systick.dev.irq, &systick_irqaction); - sdev->irq_requested = 0; - iowrite32(0, systick.membase + SYSTICK_CONFIG); - break; - - default: - pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name); - break; - } + if (sdev->irq_requested) + free_irq(systick.dev.irq, &systick_irqaction); + sdev->irq_requested = 0; + iowrite32(0, systick.membase + SYSTICK_CONFIG); + + return 0; +} + +static int systick_set_oneshot(struct clock_event_device *evt) +{ + struct systick_device *sdev; + + sdev = container_of(evt, struct systick_device, dev); + + if (!sdev->irq_requested) + setup_irq(systick.dev.irq, &systick_irqaction); + sdev->irq_requested = 1; + iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, + systick.membase + SYSTICK_CONFIG); + + return 0; } static void __init ralink_systick_init(struct device_node *np) -- cgit v1.2.3-59-g8ed1b From 0c16240ab07ff8a0e611f676f86a92a4b513d15d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:04 +0530 Subject: MIPS: IP27: Migrate to new 'set-state' interface Migrate sgidriver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: Deng-Cheng Zhu Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10611/ Signed-off-by: Ralf Baechle --- arch/mips/sgi-ip27/ip27-timer.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index a6d10f607f34..42d6cb9f956e 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -64,12 +64,6 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt) return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; } -static void rt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - unsigned int rt_timer_irq; static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent); @@ -124,7 +118,6 @@ void hub_rt_clock_event_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = rt_next_event; - cd->set_mode = rt_set_mode; clockevents_register_device(cd); } -- cgit v1.2.3-59-g8ed1b From 397d08b006fc8bbb087615214400b86b64f8fe50 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:05 +0530 Subject: MIPS: sni: Migrate to new 'set-state' interface Migrate sni driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10612/ Signed-off-by: Ralf Baechle --- arch/mips/sni/time.c | 49 +++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index cf8ec568b9df..fb4b3520cdc6 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -14,44 +14,33 @@ #define SNI_COUNTER2_DIV 64 #define SNI_COUNTER0_DIV ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ) -static void a20r_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int a20r_set_periodic(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8; - wmb(); - - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8; - wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8; + wmb(); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - break; - case CLOCK_EVT_MODE_RESUME: - break; - } + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8; + wmb(); + return 0; } static struct clock_event_device a20r_clockevent_device = { - .name = "a20r-timer", - .features = CLOCK_EVT_FEAT_PERIODIC, + .name = "a20r-timer", + .features = CLOCK_EVT_FEAT_PERIODIC, /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ - .rating = 300, - .irq = SNI_A20R_IRQ_TIMER, - .set_mode = a20r_set_mode, + .rating = 300, + .irq = SNI_A20R_IRQ_TIMER, + .set_state_periodic = a20r_set_periodic, }; static irqreturn_t a20r_interrupt(int irq, void *dev_id) -- cgit v1.2.3-59-g8ed1b From 689ee8565c5b5af9369f4c34af04196f2d3fea83 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:13 -0700 Subject: MIPS: Simplify EVA FP context handling code The protected_{save,restore}_fp_context functions had effectively different implementations for EVA. Simplify & unify the code somewhat such that EVA configurations simply guarantee the FPU-not-owned path through the standard code path. Signed-off-by: Paul Burton Cc: Markos Chandras Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10787/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 6a28c792d862..796c7d856d7d 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -101,7 +101,14 @@ static int copy_fp_from_sigcontext(struct sigcontext __user *sc) static int protected_save_fp_context(struct sigcontext __user *sc) { int err; -#ifndef CONFIG_EVA + + /* + * EVA does not have userland equivalents of ldc1 or sdc1, so + * save to the kernel FP context & copy that to userland below. + */ + if (config_enabled(CONFIG_EVA)) + lose_fpu(1); + while (1) { lock_fpu_owner(); if (is_fpu_owner()) { @@ -120,21 +127,22 @@ static int protected_save_fp_context(struct sigcontext __user *sc) if (err) break; /* really bad sigcontext */ } -#else - /* - * EVA does not have FPU EVA instructions so saving fpu context directly - * does not work. - */ - lose_fpu(1); - err = save_fp_context(sc); /* this might fail */ -#endif + return err; } static int protected_restore_fp_context(struct sigcontext __user *sc) { int err, tmp __maybe_unused; -#ifndef CONFIG_EVA + + /* + * EVA does not have userland equivalents of ldc1 or sdc1, so we + * disable the FPU here such that the code below simply copies to + * the kernel FP context. + */ + if (config_enabled(CONFIG_EVA)) + lose_fpu(0); + while (1) { lock_fpu_owner(); if (is_fpu_owner()) { @@ -153,14 +161,7 @@ static int protected_restore_fp_context(struct sigcontext __user *sc) if (err) break; /* really bad sigcontext */ } -#else - /* - * EVA does not have FPU EVA instructions so restoring fpu context - * directly does not work. - */ - lose_fpu(0); - err = restore_fp_context(sc); /* this might fail */ -#endif + return err; } @@ -629,7 +630,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, } #ifdef CONFIG_SMP -#ifndef CONFIG_EVA static int smp_save_fp_context(struct sigcontext __user *sc) { return raw_cpu_has_fpu @@ -643,12 +643,10 @@ static int smp_restore_fp_context(struct sigcontext __user *sc) ? _restore_fp_context(sc) : copy_fp_from_sigcontext(sc); } -#endif /* CONFIG_EVA */ #endif static int signal_setup(void) { -#ifndef CONFIG_EVA #ifdef CONFIG_SMP /* For now just do the cpu_has_fpu check when the functions are invoked */ save_fp_context = smp_save_fp_context; @@ -662,10 +660,6 @@ static int signal_setup(void) restore_fp_context = copy_fp_from_sigcontext; } #endif /* CONFIG_SMP */ -#else - save_fp_context = copy_fp_to_sigcontext; - restore_fp_context = copy_fp_from_sigcontext; -#endif return 0; } -- cgit v1.2.3-59-g8ed1b From 778561006e5891801ac794ddf7b21148a5555e35 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:14 -0700 Subject: MIPS: Add offsets to sigcontext FP fields to struct mips_abi Add fields to struct mips_abi, which holds information regarding the kernel-userland ABI regarding signals, to specify the offsets to the FP related fields within the appropriate variant of struct sigcontext. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10788/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/abi.h | 4 ++++ arch/mips/kernel/signal.c | 6 +++++- arch/mips/kernel/signal32.c | 6 +++++- arch/mips/kernel/signal_n32.c | 6 +++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/abi.h b/arch/mips/include/asm/abi.h index 7186bb51b89b..37f84078e78a 100644 --- a/arch/mips/include/asm/abi.h +++ b/arch/mips/include/asm/abi.h @@ -20,6 +20,10 @@ struct mips_abi { struct pt_regs *regs, sigset_t *set); const unsigned long rt_signal_return_offset; const unsigned long restart; + + unsigned off_sc_fpregs; + unsigned off_sc_fpc_csr; + unsigned off_sc_used_math; }; #endif /* _ASM_ABI_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 796c7d856d7d..ddf83189fff8 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -521,7 +521,11 @@ struct mips_abi mips_abi = { .setup_rt_frame = setup_rt_frame, .rt_signal_return_offset = offsetof(struct mips_vdso, rt_signal_trampoline), - .restart = __NR_restart_syscall + .restart = __NR_restart_syscall, + + .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), + .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), + .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), }; static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 5d7f2634996f..da70ea5cf6ec 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -585,7 +585,11 @@ struct mips_abi mips_abi_32 = { .setup_rt_frame = setup_rt_frame_32, .rt_signal_return_offset = offsetof(struct mips_vdso, o32_rt_signal_trampoline), - .restart = __NR_O32_restart_syscall + .restart = __NR_O32_restart_syscall, + + .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), + .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), + .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), }; static int signal32_init(void) diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index f1d4751eead0..0d017fdcaf07 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -153,5 +153,9 @@ struct mips_abi mips_abi_n32 = { .setup_rt_frame = setup_rt_frame_n32, .rt_signal_return_offset = offsetof(struct mips_vdso, n32_rt_signal_trampoline), - .restart = __NR_N32_restart_syscall + .restart = __NR_N32_restart_syscall, + + .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), + .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), + .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), }; -- cgit v1.2.3-59-g8ed1b From 2db9ca0a355100c40d1bef2aae3b9d9cf199cd04 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:15 -0700 Subject: MIPS: Use struct mips_abi offsets to save FP context When saving FP state to struct sigcontext, make use of the offsets provided by struct mips_abi to obtain appropriate addresses for the sc_fpregs & sc_fpc_csr fields of the sigcontext. This is done only for the native struct sigcontext in this patch (ie. for O32 in CONFIG_32BIT kernels or for N64 in CONFIG_64BIT kernels) but is done in preparation for sharing this code with compat ABIs in further patches. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andy Lutomirski Cc: Markos Chandras Cc: Manuel Lauss Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10789/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/r4k_fpu.S | 151 +++++++++++++++++++++------------------ arch/mips/kernel/signal-common.h | 6 ++ arch/mips/kernel/signal.c | 85 +++++++++++++++------- 3 files changed, 145 insertions(+), 97 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index ca887da1a48a..b8044d612ad3 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -36,6 +36,14 @@ .set noreorder +/** + * _save_fp_context() - save FP context from the FPU + * @a0 - pointer to fpregs field of sigcontext + * @a1 - pointer to fpc_csr field of sigcontext + * + * Save FP context, including the 32 FP data registers and the FP + * control & status register, from the FPU to signal context. + */ LEAF(_save_fp_context) .set push SET_HARDFLOAT @@ -55,45 +63,45 @@ LEAF(_save_fp_context) nop #endif /* Store the 16 odd double precision registers */ - EX sdc1 $f1, SC_FPREGS+8(a0) - EX sdc1 $f3, SC_FPREGS+24(a0) - EX sdc1 $f5, SC_FPREGS+40(a0) - EX sdc1 $f7, SC_FPREGS+56(a0) - EX sdc1 $f9, SC_FPREGS+72(a0) - EX sdc1 $f11, SC_FPREGS+88(a0) - EX sdc1 $f13, SC_FPREGS+104(a0) - EX sdc1 $f15, SC_FPREGS+120(a0) - EX sdc1 $f17, SC_FPREGS+136(a0) - EX sdc1 $f19, SC_FPREGS+152(a0) - EX sdc1 $f21, SC_FPREGS+168(a0) - EX sdc1 $f23, SC_FPREGS+184(a0) - EX sdc1 $f25, SC_FPREGS+200(a0) - EX sdc1 $f27, SC_FPREGS+216(a0) - EX sdc1 $f29, SC_FPREGS+232(a0) - EX sdc1 $f31, SC_FPREGS+248(a0) + EX sdc1 $f1, 8(a0) + EX sdc1 $f3, 24(a0) + EX sdc1 $f5, 40(a0) + EX sdc1 $f7, 56(a0) + EX sdc1 $f9, 72(a0) + EX sdc1 $f11, 88(a0) + EX sdc1 $f13, 104(a0) + EX sdc1 $f15, 120(a0) + EX sdc1 $f17, 136(a0) + EX sdc1 $f19, 152(a0) + EX sdc1 $f21, 168(a0) + EX sdc1 $f23, 184(a0) + EX sdc1 $f25, 200(a0) + EX sdc1 $f27, 216(a0) + EX sdc1 $f29, 232(a0) + EX sdc1 $f31, 248(a0) 1: .set pop #endif .set push SET_HARDFLOAT /* Store the 16 even double precision registers */ - EX sdc1 $f0, SC_FPREGS+0(a0) - EX sdc1 $f2, SC_FPREGS+16(a0) - EX sdc1 $f4, SC_FPREGS+32(a0) - EX sdc1 $f6, SC_FPREGS+48(a0) - EX sdc1 $f8, SC_FPREGS+64(a0) - EX sdc1 $f10, SC_FPREGS+80(a0) - EX sdc1 $f12, SC_FPREGS+96(a0) - EX sdc1 $f14, SC_FPREGS+112(a0) - EX sdc1 $f16, SC_FPREGS+128(a0) - EX sdc1 $f18, SC_FPREGS+144(a0) - EX sdc1 $f20, SC_FPREGS+160(a0) - EX sdc1 $f22, SC_FPREGS+176(a0) - EX sdc1 $f24, SC_FPREGS+192(a0) - EX sdc1 $f26, SC_FPREGS+208(a0) - EX sdc1 $f28, SC_FPREGS+224(a0) - EX sdc1 $f30, SC_FPREGS+240(a0) - EX sw t1, SC_FPC_CSR(a0) + EX sdc1 $f0, 0(a0) + EX sdc1 $f2, 16(a0) + EX sdc1 $f4, 32(a0) + EX sdc1 $f6, 48(a0) + EX sdc1 $f8, 64(a0) + EX sdc1 $f10, 80(a0) + EX sdc1 $f12, 96(a0) + EX sdc1 $f14, 112(a0) + EX sdc1 $f16, 128(a0) + EX sdc1 $f18, 144(a0) + EX sdc1 $f20, 160(a0) + EX sdc1 $f22, 176(a0) + EX sdc1 $f24, 192(a0) + EX sdc1 $f26, 208(a0) + EX sdc1 $f28, 224(a0) + EX sdc1 $f30, 240(a0) + EX sw t1, 0(a1) jr ra li v0, 0 # success .set pop @@ -159,13 +167,16 @@ LEAF(_save_fp_context32) END(_save_fp_context32) #endif -/* - * Restore FPU state: - * - fp gp registers - * - cp1 status/control register +/** + * _restore_fp_context() - restore FP context to the FPU + * @a0 - pointer to fpregs field of sigcontext + * @a1 - pointer to fpc_csr field of sigcontext + * + * Restore FP context, including the 32 FP data registers and the FP + * control & status register, from signal context to the FPU. */ LEAF(_restore_fp_context) - EX lw t1, SC_FPC_CSR(a0) + EX lw t1, 0(a1) #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ defined(CONFIG_CPU_MIPS32_R6) @@ -179,42 +190,42 @@ LEAF(_restore_fp_context) bgez t0, 1f # skip loading odd if FR=0 nop #endif - EX ldc1 $f1, SC_FPREGS+8(a0) - EX ldc1 $f3, SC_FPREGS+24(a0) - EX ldc1 $f5, SC_FPREGS+40(a0) - EX ldc1 $f7, SC_FPREGS+56(a0) - EX ldc1 $f9, SC_FPREGS+72(a0) - EX ldc1 $f11, SC_FPREGS+88(a0) - EX ldc1 $f13, SC_FPREGS+104(a0) - EX ldc1 $f15, SC_FPREGS+120(a0) - EX ldc1 $f17, SC_FPREGS+136(a0) - EX ldc1 $f19, SC_FPREGS+152(a0) - EX ldc1 $f21, SC_FPREGS+168(a0) - EX ldc1 $f23, SC_FPREGS+184(a0) - EX ldc1 $f25, SC_FPREGS+200(a0) - EX ldc1 $f27, SC_FPREGS+216(a0) - EX ldc1 $f29, SC_FPREGS+232(a0) - EX ldc1 $f31, SC_FPREGS+248(a0) + EX ldc1 $f1, 8(a0) + EX ldc1 $f3, 24(a0) + EX ldc1 $f5, 40(a0) + EX ldc1 $f7, 56(a0) + EX ldc1 $f9, 72(a0) + EX ldc1 $f11, 88(a0) + EX ldc1 $f13, 104(a0) + EX ldc1 $f15, 120(a0) + EX ldc1 $f17, 136(a0) + EX ldc1 $f19, 152(a0) + EX ldc1 $f21, 168(a0) + EX ldc1 $f23, 184(a0) + EX ldc1 $f25, 200(a0) + EX ldc1 $f27, 216(a0) + EX ldc1 $f29, 232(a0) + EX ldc1 $f31, 248(a0) 1: .set pop #endif .set push SET_HARDFLOAT - EX ldc1 $f0, SC_FPREGS+0(a0) - EX ldc1 $f2, SC_FPREGS+16(a0) - EX ldc1 $f4, SC_FPREGS+32(a0) - EX ldc1 $f6, SC_FPREGS+48(a0) - EX ldc1 $f8, SC_FPREGS+64(a0) - EX ldc1 $f10, SC_FPREGS+80(a0) - EX ldc1 $f12, SC_FPREGS+96(a0) - EX ldc1 $f14, SC_FPREGS+112(a0) - EX ldc1 $f16, SC_FPREGS+128(a0) - EX ldc1 $f18, SC_FPREGS+144(a0) - EX ldc1 $f20, SC_FPREGS+160(a0) - EX ldc1 $f22, SC_FPREGS+176(a0) - EX ldc1 $f24, SC_FPREGS+192(a0) - EX ldc1 $f26, SC_FPREGS+208(a0) - EX ldc1 $f28, SC_FPREGS+224(a0) - EX ldc1 $f30, SC_FPREGS+240(a0) + EX ldc1 $f0, 0(a0) + EX ldc1 $f2, 16(a0) + EX ldc1 $f4, 32(a0) + EX ldc1 $f6, 48(a0) + EX ldc1 $f8, 64(a0) + EX ldc1 $f10, 80(a0) + EX ldc1 $f12, 96(a0) + EX ldc1 $f14, 112(a0) + EX ldc1 $f16, 128(a0) + EX ldc1 $f18, 144(a0) + EX ldc1 $f20, 160(a0) + EX ldc1 $f22, 176(a0) + EX ldc1 $f24, 192(a0) + EX ldc1 $f26, 208(a0) + EX ldc1 $f28, 224(a0) + EX ldc1 $f30, 240(a0) ctc1 t1, fcr31 .set pop jr ra diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 0b85f827cd18..96b0fd82f8b5 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -31,4 +31,10 @@ extern int fpcsr_pending(unsigned int __user *fpcsr); #define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); }) #define unlock_fpu_owner() ({ pagefault_enable(); preempt_enable(); }) +/* Assembly functions to move context to/from the FPU */ +extern asmlinkage int +_save_fp_context(void __user *fpregs, void __user *csr); +extern asmlinkage int +_restore_fp_context(void __user *fpregs, void __user *csr); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index ddf83189fff8..10f7dbc989c4 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -41,11 +41,8 @@ #include "signal-common.h" -static int (*save_fp_context)(struct sigcontext __user *sc); -static int (*restore_fp_context)(struct sigcontext __user *sc); - -extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); -extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); +static int (*save_fp_context)(void __user *sc); +static int (*restore_fp_context)(void __user *sc); struct sigframe { u32 sf_ass[4]; /* argument save space for o32 */ @@ -65,41 +62,71 @@ struct rt_sigframe { * Thread saved context copy to/from a signal context presumed to be on the * user stack, and therefore accessed with appropriate macros from uaccess.h. */ -static int copy_fp_to_sigcontext(struct sigcontext __user *sc) +static int copy_fp_to_sigcontext(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; for (i = 0; i < NUM_FPU_REGS; i++) { err |= __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), - &sc->sc_fpregs[i]); + &fpregs[i]); } - err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); + err |= __put_user(current->thread.fpu.fcr31, csr); return err; } -static int copy_fp_from_sigcontext(struct sigcontext __user *sc) +static int copy_fp_from_sigcontext(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; u64 fpr_val; for (i = 0; i < NUM_FPU_REGS; i++) { - err |= __get_user(fpr_val, &sc->sc_fpregs[i]); + err |= __get_user(fpr_val, &fpregs[i]); set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); } - err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); + err |= __get_user(current->thread.fpu.fcr31, csr); return err; } +/* + * Wrappers for the assembly _{save,restore}_fp_context functions. + */ +static int save_hw_fp_context(void __user *sc) +{ + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; + + return _save_fp_context(fpregs, csr); +} + +static int restore_hw_fp_context(void __user *sc) +{ + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; + + return _restore_fp_context(fpregs, csr); +} + /* * Helper routines */ -static int protected_save_fp_context(struct sigcontext __user *sc) +static int protected_save_fp_context(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int err; /* @@ -121,9 +148,9 @@ static int protected_save_fp_context(struct sigcontext __user *sc) if (likely(!err)) break; /* touch the sigcontext and try again */ - err = __put_user(0, &sc->sc_fpregs[0]) | - __put_user(0, &sc->sc_fpregs[31]) | - __put_user(0, &sc->sc_fpc_csr); + err = __put_user(0, &fpregs[0]) | + __put_user(0, &fpregs[31]) | + __put_user(0, csr); if (err) break; /* really bad sigcontext */ } @@ -131,8 +158,11 @@ static int protected_save_fp_context(struct sigcontext __user *sc) return err; } -static int protected_restore_fp_context(struct sigcontext __user *sc) +static int protected_restore_fp_context(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int err, tmp __maybe_unused; /* @@ -155,9 +185,9 @@ static int protected_restore_fp_context(struct sigcontext __user *sc) if (likely(!err)) break; /* touch the sigcontext and try again */ - err = __get_user(tmp, &sc->sc_fpregs[0]) | - __get_user(tmp, &sc->sc_fpregs[31]) | - __get_user(tmp, &sc->sc_fpc_csr); + err = __get_user(tmp, &fpregs[0]) | + __get_user(tmp, &fpregs[31]) | + __get_user(tmp, csr); if (err) break; /* really bad sigcontext */ } @@ -225,11 +255,12 @@ int fpcsr_pending(unsigned int __user *fpcsr) } static int -check_and_restore_fp_context(struct sigcontext __user *sc) +check_and_restore_fp_context(void __user *sc) { + struct mips_abi *abi = current->thread.abi; int err, sig; - err = sig = fpcsr_pending(&sc->sc_fpc_csr); + err = sig = fpcsr_pending(sc + abi->off_sc_fpc_csr); if (err > 0) err = 0; err |= protected_restore_fp_context(sc); @@ -634,17 +665,17 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, } #ifdef CONFIG_SMP -static int smp_save_fp_context(struct sigcontext __user *sc) +static int smp_save_fp_context(void __user *sc) { return raw_cpu_has_fpu - ? _save_fp_context(sc) + ? save_hw_fp_context(sc) : copy_fp_to_sigcontext(sc); } -static int smp_restore_fp_context(struct sigcontext __user *sc) +static int smp_restore_fp_context(void __user *sc) { return raw_cpu_has_fpu - ? _restore_fp_context(sc) + ? restore_hw_fp_context(sc) : copy_fp_from_sigcontext(sc); } #endif @@ -657,8 +688,8 @@ static int signal_setup(void) restore_fp_context = smp_restore_fp_context; #else if (cpu_has_fpu) { - save_fp_context = _save_fp_context; - restore_fp_context = _restore_fp_context; + save_fp_context = save_hw_fp_context; + restore_fp_context = restore_hw_fp_context; } else { save_fp_context = copy_fp_to_sigcontext; restore_fp_context = copy_fp_from_sigcontext; -- cgit v1.2.3-59-g8ed1b From 64243c2a945640392b59fe1dc66c30ee1ca04170 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:16 -0700 Subject: MIPS: Move FP usage checks into protected_{save, restore}_fp_context In preparation for sharing protected_{save,restore}_fp_context with compat ABIs, move the FP usage checks into said functions. This will both enable that code to be shared, and allow for extensions of it in further patches to also be shared. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10790/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 73 ++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 10f7dbc989c4..9c42c500134e 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -127,8 +127,15 @@ static int protected_save_fp_context(void __user *sc) struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; + uint32_t __user *used_math = sc + abi->off_sc_used_math; + unsigned int used; int err; + used = !!used_math(); + err = __put_user(used, used_math); + if (err || !used) + return err; + /* * EVA does not have userland equivalents of ldc1 or sdc1, so * save to the kernel FP context & copy that to userland below. @@ -163,7 +170,25 @@ static int protected_restore_fp_context(void __user *sc) struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; - int err, tmp __maybe_unused; + uint32_t __user *used_math = sc + abi->off_sc_used_math; + unsigned int used; + int err, sig, tmp __maybe_unused; + + err = __get_user(used, used_math); + conditional_used_math(used); + + /* + * The signal handler may have used FPU; give it up if the program + * doesn't want it following sigreturn. + */ + if (err || !used) { + lose_fpu(0); + return err; + } + + err = sig = fpcsr_pending(csr); + if (err < 0) + return err; /* * EVA does not have userland equivalents of ldc1 or sdc1, so we @@ -192,14 +217,13 @@ static int protected_restore_fp_context(void __user *sc) break; /* really bad sigcontext */ } - return err; + return err ?: sig; } int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { int err = 0; int i; - unsigned int used_math; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -222,16 +246,13 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); } - used_math = !!used_math(); - err |= __put_user(used_math, &sc->sc_used_math); - if (used_math) { - /* - * Save FPU state to signal context. Signal handler - * will "inherit" current FPU state. - */ - err |= protected_save_fp_context(sc); - } + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + err |= protected_save_fp_context(sc); + return err; } @@ -254,22 +275,8 @@ int fpcsr_pending(unsigned int __user *fpcsr) return err ?: sig; } -static int -check_and_restore_fp_context(void __user *sc) -{ - struct mips_abi *abi = current->thread.abi; - int err, sig; - - err = sig = fpcsr_pending(sc + abi->off_sc_fpc_csr); - if (err > 0) - err = 0; - err |= protected_restore_fp_context(sc); - return err ?: sig; -} - int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { - unsigned int used_math; unsigned long treg; int err = 0; int i; @@ -297,19 +304,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) for (i = 1; i < 32; i++) err |= __get_user(regs->regs[i], &sc->sc_regs[i]); - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - if (used_math) { - /* restore fpu context if we have used it before */ - if (!err) - err = check_and_restore_fp_context(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(0); - } - - return err; + return err ?: protected_restore_fp_context(sc); } void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, -- cgit v1.2.3-59-g8ed1b From 6f0aba63bfb3eb33b68cf746c44b6ab302599180 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:17 -0700 Subject: MIPS: Skip odd double FP registers when copying FP32 sigcontext When a task uses 32 bit floating point, the odd indexed 32b register values are stored in bits 63:32 of the preceding even indexed 64b FP register field in saved context. Thus there is no point in preserving the odd indexed 64b register fields since they hold no valid context. This patch will cause them to be skipped, as is already done in arch/mips/kernel/signal32.c. [ralf@linux-mips.org: Fixed reject.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Cc: Andrew Morton Patchwork: https://patchwork.linux-mips.org/patch/10791/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9c42c500134e..cc3a01f5c5af 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -69,8 +69,9 @@ static int copy_fp_to_sigcontext(void __user *sc) uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; + int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - for (i = 0; i < NUM_FPU_REGS; i++) { + for (i = 0; i < NUM_FPU_REGS; i += inc) { err |= __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), &fpregs[i]); @@ -87,9 +88,10 @@ static int copy_fp_from_sigcontext(void __user *sc) uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; + int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; u64 fpr_val; - for (i = 0; i < NUM_FPU_REGS; i++) { + for (i = 0; i < NUM_FPU_REGS; i += inc) { err |= __get_user(fpr_val, &fpregs[i]); set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); } -- cgit v1.2.3-59-g8ed1b From d02a40aff6e043bae1cd6e6416e9048990928b1d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:18 -0700 Subject: MIPS: Use common FP sigcontext code for O32 compat Make use of the common FP sigcontext code for O32 binaries running on MIPS64 kernels now that it is taking appropriate offsets into struct sigcontext(32) from struct mips_abi. [ralf@linux-mips.org: Fixed reject.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andrew Morton Cc: Andy Lutomirski Cc: Markos Chandras Cc: Manuel Lauss Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10792/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/signal.h | 3 + arch/mips/kernel/asm-offsets.c | 11 --- arch/mips/kernel/r4k_fpu.S | 114 ------------------------------- arch/mips/kernel/signal.c | 4 +- arch/mips/kernel/signal32.c | 150 ++--------------------------------------- 5 files changed, 11 insertions(+), 271 deletions(-) diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h index 8efe5a9e2c3e..003e273eff4c 100644 --- a/arch/mips/include/asm/signal.h +++ b/arch/mips/include/asm/signal.h @@ -23,4 +23,7 @@ #define __ARCH_HAS_IRIX_SIGACTION +extern int protected_save_fp_context(void __user *sc); +extern int protected_restore_fp_context(void __user *sc); + #endif /* _ASM_SIGNAL_H */ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 072fab13645d..3706091b6351 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -245,17 +245,6 @@ void output_sc_defines(void) } #endif -#ifdef CONFIG_MIPS32_COMPAT -void output_sc32_defines(void) -{ - COMMENT("Linux 32-bit sigcontext offsets."); - OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs); - OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr); - OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir); - BLANK(); -} -#endif - void output_signal_defined(void) { COMMENT("Linux signal numbers."); diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index b8044d612ad3..0ed139889245 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -107,66 +107,6 @@ LEAF(_save_fp_context) .set pop END(_save_fp_context) -#ifdef CONFIG_MIPS32_COMPAT - /* Save 32-bit process floating point context */ -LEAF(_save_fp_context32) - .set push - .set MIPS_ISA_ARCH_LEVEL_RAW - SET_HARDFLOAT - cfc1 t1, fcr31 - -#ifndef CONFIG_CPU_MIPS64_R6 - mfc0 t0, CP0_STATUS - sll t0, t0, 5 - bgez t0, 1f # skip storing odd if FR=0 - nop -#endif - - /* Store the 16 odd double precision registers */ - EX sdc1 $f1, SC32_FPREGS+8(a0) - EX sdc1 $f3, SC32_FPREGS+24(a0) - EX sdc1 $f5, SC32_FPREGS+40(a0) - EX sdc1 $f7, SC32_FPREGS+56(a0) - EX sdc1 $f9, SC32_FPREGS+72(a0) - EX sdc1 $f11, SC32_FPREGS+88(a0) - EX sdc1 $f13, SC32_FPREGS+104(a0) - EX sdc1 $f15, SC32_FPREGS+120(a0) - EX sdc1 $f17, SC32_FPREGS+136(a0) - EX sdc1 $f19, SC32_FPREGS+152(a0) - EX sdc1 $f21, SC32_FPREGS+168(a0) - EX sdc1 $f23, SC32_FPREGS+184(a0) - EX sdc1 $f25, SC32_FPREGS+200(a0) - EX sdc1 $f27, SC32_FPREGS+216(a0) - EX sdc1 $f29, SC32_FPREGS+232(a0) - EX sdc1 $f31, SC32_FPREGS+248(a0) - - /* Store the 16 even double precision registers */ -1: EX sdc1 $f0, SC32_FPREGS+0(a0) - EX sdc1 $f2, SC32_FPREGS+16(a0) - EX sdc1 $f4, SC32_FPREGS+32(a0) - EX sdc1 $f6, SC32_FPREGS+48(a0) - EX sdc1 $f8, SC32_FPREGS+64(a0) - EX sdc1 $f10, SC32_FPREGS+80(a0) - EX sdc1 $f12, SC32_FPREGS+96(a0) - EX sdc1 $f14, SC32_FPREGS+112(a0) - EX sdc1 $f16, SC32_FPREGS+128(a0) - EX sdc1 $f18, SC32_FPREGS+144(a0) - EX sdc1 $f20, SC32_FPREGS+160(a0) - EX sdc1 $f22, SC32_FPREGS+176(a0) - EX sdc1 $f24, SC32_FPREGS+192(a0) - EX sdc1 $f26, SC32_FPREGS+208(a0) - EX sdc1 $f28, SC32_FPREGS+224(a0) - EX sdc1 $f30, SC32_FPREGS+240(a0) - EX sw t1, SC32_FPC_CSR(a0) - cfc1 t0, $0 # implementation/version - EX sw t0, SC32_FPC_EIR(a0) - .set pop - - jr ra - li v0, 0 # success - END(_save_fp_context32) -#endif - /** * _restore_fp_context() - restore FP context to the FPU * @a0 - pointer to fpregs field of sigcontext @@ -232,60 +172,6 @@ LEAF(_restore_fp_context) li v0, 0 # success END(_restore_fp_context) -#ifdef CONFIG_MIPS32_COMPAT -LEAF(_restore_fp_context32) - /* Restore an o32 sigcontext. */ - .set push - SET_HARDFLOAT - EX lw t1, SC32_FPC_CSR(a0) - -#ifndef CONFIG_CPU_MIPS64_R6 - mfc0 t0, CP0_STATUS - sll t0, t0, 5 - bgez t0, 1f # skip loading odd if FR=0 - nop -#endif - - EX ldc1 $f1, SC32_FPREGS+8(a0) - EX ldc1 $f3, SC32_FPREGS+24(a0) - EX ldc1 $f5, SC32_FPREGS+40(a0) - EX ldc1 $f7, SC32_FPREGS+56(a0) - EX ldc1 $f9, SC32_FPREGS+72(a0) - EX ldc1 $f11, SC32_FPREGS+88(a0) - EX ldc1 $f13, SC32_FPREGS+104(a0) - EX ldc1 $f15, SC32_FPREGS+120(a0) - EX ldc1 $f17, SC32_FPREGS+136(a0) - EX ldc1 $f19, SC32_FPREGS+152(a0) - EX ldc1 $f21, SC32_FPREGS+168(a0) - EX ldc1 $f23, SC32_FPREGS+184(a0) - EX ldc1 $f25, SC32_FPREGS+200(a0) - EX ldc1 $f27, SC32_FPREGS+216(a0) - EX ldc1 $f29, SC32_FPREGS+232(a0) - EX ldc1 $f31, SC32_FPREGS+248(a0) - -1: EX ldc1 $f0, SC32_FPREGS+0(a0) - EX ldc1 $f2, SC32_FPREGS+16(a0) - EX ldc1 $f4, SC32_FPREGS+32(a0) - EX ldc1 $f6, SC32_FPREGS+48(a0) - EX ldc1 $f8, SC32_FPREGS+64(a0) - EX ldc1 $f10, SC32_FPREGS+80(a0) - EX ldc1 $f12, SC32_FPREGS+96(a0) - EX ldc1 $f14, SC32_FPREGS+112(a0) - EX ldc1 $f16, SC32_FPREGS+128(a0) - EX ldc1 $f18, SC32_FPREGS+144(a0) - EX ldc1 $f20, SC32_FPREGS+160(a0) - EX ldc1 $f22, SC32_FPREGS+176(a0) - EX ldc1 $f24, SC32_FPREGS+192(a0) - EX ldc1 $f26, SC32_FPREGS+208(a0) - EX ldc1 $f28, SC32_FPREGS+224(a0) - EX ldc1 $f30, SC32_FPREGS+240(a0) - ctc1 t1, fcr31 - jr ra - li v0, 0 # success - .set pop - END(_restore_fp_context32) -#endif - #ifdef CONFIG_CPU_HAS_MSA .macro op_one_wr op, idx, base diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index cc3a01f5c5af..08f521567d64 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -124,7 +124,7 @@ static int restore_hw_fp_context(void __user *sc) /* * Helper routines */ -static int protected_save_fp_context(void __user *sc) +int protected_save_fp_context(void __user *sc) { struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; @@ -167,7 +167,7 @@ static int protected_save_fp_context(void __user *sc) return err; } -static int protected_restore_fp_context(void __user *sc) +int protected_restore_fp_context(void __user *sc) { struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index da70ea5cf6ec..7c45cb3e075a 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -36,12 +36,6 @@ #include "signal-common.h" -static int (*save_fp_context32)(struct sigcontext32 __user *sc); -static int (*restore_fp_context32)(struct sigcontext32 __user *sc); - -extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); -extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); - /* * Including would give use the 64-bit syscall numbers ... */ @@ -74,99 +68,11 @@ struct rt_sigframe32 { struct ucontext32 rs_uc; }; -/* - * Thread saved context copy to/from a signal context presumed to be on the - * user stack, and therefore accessed with appropriate macros from uaccess.h. - */ -static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc) -{ - int i; - int err = 0; - int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - - for (i = 0; i < NUM_FPU_REGS; i += inc) { - err |= - __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), - &sc->sc_fpregs[i]); - } - err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); - - return err; -} - -static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc) -{ - int i; - int err = 0; - int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - u64 fpr_val; - - for (i = 0; i < NUM_FPU_REGS; i += inc) { - err |= __get_user(fpr_val, &sc->sc_fpregs[i]); - set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); - } - err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); - - return err; -} - -/* - * sigcontext handlers - */ -static int protected_save_fp_context32(struct sigcontext32 __user *sc) -{ - int err; - while (1) { - lock_fpu_owner(); - if (is_fpu_owner()) { - err = save_fp_context32(sc); - unlock_fpu_owner(); - } else { - unlock_fpu_owner(); - err = copy_fp_to_sigcontext32(sc); - } - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __put_user(0, &sc->sc_fpregs[0]) | - __put_user(0, &sc->sc_fpregs[31]) | - __put_user(0, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - -static int protected_restore_fp_context32(struct sigcontext32 __user *sc) -{ - int err, tmp __maybe_unused; - while (1) { - lock_fpu_owner(); - if (is_fpu_owner()) { - err = restore_fp_context32(sc); - unlock_fpu_owner(); - } else { - unlock_fpu_owner(); - err = copy_fp_from_sigcontext32(sc); - } - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __get_user(tmp, &sc->sc_fpregs[0]) | - __get_user(tmp, &sc->sc_fpregs[31]) | - __get_user(tmp, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - static int setup_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { int err = 0; int i; - u32 used_math; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -186,35 +92,18 @@ static int setup_sigcontext32(struct pt_regs *regs, err |= __put_user(mflo3(), &sc->sc_lo3); } - used_math = !!used_math(); - err |= __put_user(used_math, &sc->sc_used_math); + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + err |= protected_save_fp_context(sc); - if (used_math) { - /* - * Save FPU state to signal context. Signal handler - * will "inherit" current FPU state. - */ - err |= protected_save_fp_context32(sc); - } return err; } -static int -check_and_restore_fp_context32(struct sigcontext32 __user *sc) -{ - int err, sig; - - err = sig = fpcsr_pending(&sc->sc_fpc_csr); - if (err > 0) - err = 0; - err |= protected_restore_fp_context32(sc); - return err ?: sig; -} - static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { - u32 used_math; int err = 0; s32 treg; int i; @@ -238,19 +127,7 @@ static int restore_sigcontext32(struct pt_regs *regs, for (i = 1; i < 32; i++) err |= __get_user(regs->regs[i], &sc->sc_regs[i]); - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - if (used_math) { - /* restore fpu context if we have used it before */ - if (!err) - err = check_and_restore_fp_context32(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(0); - } - - return err; + return err ?: protected_restore_fp_context(sc); } /* @@ -591,18 +468,3 @@ struct mips_abi mips_abi_32 = { .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), }; - -static int signal32_init(void) -{ - if (cpu_has_fpu) { - save_fp_context32 = _save_fp_context32; - restore_fp_context32 = _restore_fp_context32; - } else { - save_fp_context32 = copy_fp_to_sigcontext32; - restore_fp_context32 = copy_fp_from_sigcontext32; - } - - return 0; -} - -arch_initcall(signal32_init); -- cgit v1.2.3-59-g8ed1b From 6a24432cf9cfb6e071fb3566144a3a5ace9d3c0d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:19 -0700 Subject: MIPS: Remove unused {get,put}_sigset functions These functions are never called & thus dead code. Remove them. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Andrew Morton Patchwork: https://patchwork.linux-mips.org/patch/10793/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal32.c | 51 --------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 7c45cb3e075a..f7e89524e316 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -130,57 +130,6 @@ static int restore_sigcontext32(struct pt_regs *regs, return err ?: protected_restore_fp_context(sc); } -/* - * - */ -extern void __put_sigset_unknown_nsig(void); -extern void __get_sigset_unknown_nsig(void); - -static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) -{ - int err = 0; - - if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) - return -EFAULT; - - switch (_NSIG_WORDS) { - default: - __put_sigset_unknown_nsig(); - case 2: - err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); - err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); - case 1: - err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); - err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); - } - - return err; -} - -static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) -{ - int err = 0; - unsigned long sig[4]; - - if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) - return -EFAULT; - - switch (_NSIG_WORDS) { - default: - __get_sigset_unknown_nsig(); - case 2: - err |= __get_user(sig[3], &ubuf->sig[3]); - err |= __get_user(sig[2], &ubuf->sig[2]); - kbuf->sig[1] = sig[2] | (sig[3] << 32); - case 1: - err |= __get_user(sig[1], &ubuf->sig[1]); - err |= __get_user(sig[0], &ubuf->sig[0]); - kbuf->sig[0] = sig[0] | (sig[1] << 32); - } - - return err; -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ -- cgit v1.2.3-59-g8ed1b From 0d071fa3772b85fe5d81032fbc011c623570d2fc Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:20 -0700 Subject: MIPS: Indicate FP mode in sigcontext sc_used_math The sc_used_math field of struct sigcontext & its variants has traditionally been used as a boolean value indicating only whether or not floating point context is saved within the sigcontext. With various supported FP modes & the ability to switch between them this information will no longer be enough to decode the meaning of the data stored in the sc_fpregs fields of struct sigcontext. To make that possible 3 bits are defined within sc_used_math: - Bit 0 (USED_FP) represents whether FP was used, essentially providing the boolean flag which sc_used_math as a whole provided previously. - Bit 1 (USED_FR1) provides the value of the Status.FR bit at the time the FP context was saved. - Bit 2 (USED_HYBRID_FPRS) indicates whether the FP context was saved under the hybrid FPR scheme. Essentially, when set the odd singles are located in bits 63:32 of the preceding even indexed sc_fpregs element. Any userland that tests whether the sc_used_math field is zero or non-zero will continue to function as expected. Having said that, I could not find any userland which uses the sc_used_math field at all. [ralf@linux-mips.org: Fixed rejects.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10794/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/sigcontext.h | 9 +++++++++ arch/mips/kernel/signal.c | 15 +++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/uapi/asm/sigcontext.h b/arch/mips/include/uapi/asm/sigcontext.h index 9081d88ae44f..28f51bb47046 100644 --- a/arch/mips/include/uapi/asm/sigcontext.h +++ b/arch/mips/include/uapi/asm/sigcontext.h @@ -12,6 +12,15 @@ #include #include +/* scalar FP context was used */ +#define USED_FP (1 << 0) + +/* the value of Status.FR when context was saved */ +#define USED_FR1 (1 << 1) + +/* FR=1, but with odd singles in bits 63:32 of preceding even double */ +#define USED_HYBRID_FPRS (1 << 2) + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 08f521567d64..9cb75e9519c5 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -133,9 +133,16 @@ int protected_save_fp_context(void __user *sc) unsigned int used; int err; - used = !!used_math(); + used = used_math() ? USED_FP : 0; + if (used) { + if (!test_thread_flag(TIF_32BIT_FPREGS)) + used |= USED_FR1; + if (test_thread_flag(TIF_HYBRID_FPREGS)) + used |= USED_HYBRID_FPRS; + } + err = __put_user(used, used_math); - if (err || !used) + if (err || !(used & USED_FP)) return err; /* @@ -177,13 +184,13 @@ int protected_restore_fp_context(void __user *sc) int err, sig, tmp __maybe_unused; err = __get_user(used, used_math); - conditional_used_math(used); + conditional_used_math(used & USED_FP); /* * The signal handler may have used FPU; give it up if the program * doesn't want it following sigreturn. */ - if (err || !used) { + if (err || !(used & USED_FP)) { lose_fpu(0); return err; } -- cgit v1.2.3-59-g8ed1b From f1fe2d21f4e1aca8644cea888dc618f0183ad671 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:21 -0700 Subject: MIPS: Add definitions for extended context The context introduced by MSA needs to be saved around signals. However, we can't increase the size of struct sigcontext because that will change the offset of the signal mask in struct sigframe or struct ucontext. This patch instead places the new context immediately after the struct sigframe for traditional signals, or similarly after struct ucontext for RT signals. The layout of struct sigframe & struct ucontext is identical from their sigcontext fields onwards, so the offset from the sigcontext to the extended context will always be the same regardless of the type of signal. Userland will be able to search through the extended context by using the magic values to detect which types of context are present. Any unrecognised context can be skipped over using the size field of struct extcontext. Once the magic value END_EXTCONTEXT_MAGIC is seen it is known that there are no further extended context structures to examine. This approach is somewhat similar to that taken by ARM to save VFP & other context at the end of struct ucontext. Userland can determine whether extended context is present by checking for the USED_EXTCONTEXT bit in the sc_used_math field of struct sigcontext. Whilst this could potentially change the historic semantics of sc_used_math if further extended context which does not imply FP context were to be introduced in the future, I have been unable to find any userland code making use of sc_used_math at all. Using one of the fields described as unused in struct sigcontext was considered, but the kernel does not already write to those fields so there would be no guarantee of the field being clear on older kernels. Other alternatives would be to have userland check the kernel version, or to have a HWCAP bit indicating presence of extended context. However there is a desire to have the context & information required to decode it be self contained such that, for example, debuggers could decode the saved context easily. [ralf@linux-mips.org: Fixed conflict.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Peter Zijlstra Cc: Zubair Lutfullah Kakakhel Cc: Alex Smith Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andrew Morton Cc: Andy Lutomirski Cc: Michael Ellerman Cc: Markos Chandras Cc: Daniel Borkmann Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10795/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/Kbuild | 1 - arch/mips/include/uapi/asm/sigcontext.h | 3 ++ arch/mips/include/uapi/asm/ucontext.h | 65 +++++++++++++++++++++++++++++++++ arch/mips/kernel/signal.c | 13 +++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 arch/mips/include/uapi/asm/ucontext.h diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 1f8546081d20..40ec4ca3f946 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -16,6 +16,5 @@ generic-y += sections.h generic-y += segment.h generic-y += serial.h generic-y += trace_clock.h -generic-y += ucontext.h generic-y += user.h generic-y += xor.h diff --git a/arch/mips/include/uapi/asm/sigcontext.h b/arch/mips/include/uapi/asm/sigcontext.h index 28f51bb47046..5cbd9ae6421f 100644 --- a/arch/mips/include/uapi/asm/sigcontext.h +++ b/arch/mips/include/uapi/asm/sigcontext.h @@ -21,6 +21,9 @@ /* FR=1, but with odd singles in bits 63:32 of preceding even double */ #define USED_HYBRID_FPRS (1 << 2) +/* extended context was used, see struct extcontext for details */ +#define USED_EXTCONTEXT (1 << 3) + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* diff --git a/arch/mips/include/uapi/asm/ucontext.h b/arch/mips/include/uapi/asm/ucontext.h new file mode 100644 index 000000000000..2320144ce858 --- /dev/null +++ b/arch/mips/include/uapi/asm/ucontext.h @@ -0,0 +1,65 @@ +#ifndef __MIPS_UAPI_ASM_UCONTEXT_H +#define __MIPS_UAPI_ASM_UCONTEXT_H + +/** + * struct extcontext - extended context header structure + * @magic: magic value identifying the type of extended context + * @size: the size in bytes of the enclosing structure + * + * Extended context structures provide context which does not fit within struct + * sigcontext. They are placed sequentially in memory at the end of struct + * ucontext and struct sigframe, with each extended context structure beginning + * with a header defined by this struct. The type of context represented is + * indicated by the magic field. Userland may check each extended context + * structure against magic values that it recognises. The size field allows any + * unrecognised context to be skipped, allowing for future expansion. The end + * of the extended context data is indicated by the magic value + * END_EXTCONTEXT_MAGIC. + */ +struct extcontext { + unsigned int magic; + unsigned int size; +}; + +/** + * struct msa_extcontext - MSA extended context structure + * @ext: the extended context header, with magic == MSA_EXTCONTEXT_MAGIC + * @wr: the most significant 64 bits of each MSA vector register + * @csr: the value of the MSA control & status register + * + * If MSA context is live for a task at the time a signal is delivered to it, + * this structure will hold the MSA context of the task as it was prior to the + * signal delivery. + */ +struct msa_extcontext { + struct extcontext ext; +#define MSA_EXTCONTEXT_MAGIC 0x784d5341 /* xMSA */ + + unsigned long long wr[32]; + unsigned int csr; +}; + +#define END_EXTCONTEXT_MAGIC 0x78454e44 /* xEND */ + +/** + * struct ucontext - user context structure + * @uc_flags: + * @uc_link: + * @uc_stack: + * @uc_mcontext: holds basic processor state + * @uc_sigmask: + * @uc_extcontext: holds extended processor state + */ +struct ucontext { + /* Historic fields matching asm-generic */ + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; + + /* Extended context structures may follow ucontext */ + unsigned long long uc_extcontext[0]; +}; + +#endif /* __MIPS_UAPI_ASM_UCONTEXT_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9cb75e9519c5..3101bafd3a9c 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -47,8 +47,11 @@ static int (*restore_fp_context)(void __user *sc); struct sigframe { u32 sf_ass[4]; /* argument save space for o32 */ u32 sf_pad[2]; /* Was: signal trampoline */ + + /* Matches struct ucontext from its uc_mcontext field onwards */ struct sigcontext sf_sc; sigset_t sf_mask; + unsigned long long sf_extcontext[0]; }; struct rt_sigframe { @@ -686,6 +689,16 @@ static int smp_restore_fp_context(void __user *sc) static int signal_setup(void) { + /* + * The offset from sigcontext to extended context should be the same + * regardless of the type of signal, such that userland can always know + * where to look if it wishes to find the extended context structures. + */ + BUILD_BUG_ON((offsetof(struct sigframe, sf_extcontext) - + offsetof(struct sigframe, sf_sc)) != + (offsetof(struct rt_sigframe, rs_uc.uc_extcontext) - + offsetof(struct rt_sigframe, rs_uc.uc_mcontext))); + #ifdef CONFIG_SMP /* For now just do the cpu_has_fpu check when the functions are invoked */ save_fp_context = smp_save_fp_context; -- cgit v1.2.3-59-g8ed1b From bf82cb30c7e58b3a9742f0a45962ebdf51befac7 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:22 -0700 Subject: MIPS: Save MSA extended context around signals It is desirable for signal handlers to be allowed to make use of MSA, particularly if auto vectorisation is used when compiling a program. The MSA context must therefore be saved & restored before & after invoking the signal handler. Make use of the extended context structs defined in the preceding patch to save MSA context after the sigframe when appropriate. [ralf@linux-mips.org: Fixed conflicts.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andrew Morton Cc: Andy Lutomirski Cc: Markos Chandras Cc: Manuel Lauss Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10796/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/r4k_fpu.S | 118 ++++++++++++++++++++ arch/mips/kernel/signal-common.h | 3 + arch/mips/kernel/signal.c | 227 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 333 insertions(+), 15 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 0ed139889245..f09546ee2cdc 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -236,6 +236,124 @@ LEAF(\name) op_msa_wr write_msa_wr_w, ld_w op_msa_wr write_msa_wr_d, ld_d +#endif /* CONFIG_CPU_HAS_MSA */ + +#ifdef CONFIG_CPU_HAS_MSA + + .macro save_msa_upper wr, off, base + .set push + .set noat +#ifdef CONFIG_64BIT + copy_u_d \wr, 1 + EX sd $1, \off(\base) +#elif defined(CONFIG_CPU_LITTLE_ENDIAN) + copy_u_w \wr, 2 + EX sw $1, \off(\base) + copy_u_w \wr, 3 + EX sw $1, (\off+4)(\base) +#else /* CONFIG_CPU_BIG_ENDIAN */ + copy_u_w \wr, 2 + EX sw $1, (\off+4)(\base) + copy_u_w \wr, 3 + EX sw $1, \off(\base) +#endif + .set pop + .endm + +LEAF(_save_msa_all_upper) + save_msa_upper 0, 0x00, a0 + save_msa_upper 1, 0x08, a0 + save_msa_upper 2, 0x10, a0 + save_msa_upper 3, 0x18, a0 + save_msa_upper 4, 0x20, a0 + save_msa_upper 5, 0x28, a0 + save_msa_upper 6, 0x30, a0 + save_msa_upper 7, 0x38, a0 + save_msa_upper 8, 0x40, a0 + save_msa_upper 9, 0x48, a0 + save_msa_upper 10, 0x50, a0 + save_msa_upper 11, 0x58, a0 + save_msa_upper 12, 0x60, a0 + save_msa_upper 13, 0x68, a0 + save_msa_upper 14, 0x70, a0 + save_msa_upper 15, 0x78, a0 + save_msa_upper 16, 0x80, a0 + save_msa_upper 17, 0x88, a0 + save_msa_upper 18, 0x90, a0 + save_msa_upper 19, 0x98, a0 + save_msa_upper 20, 0xa0, a0 + save_msa_upper 21, 0xa8, a0 + save_msa_upper 22, 0xb0, a0 + save_msa_upper 23, 0xb8, a0 + save_msa_upper 24, 0xc0, a0 + save_msa_upper 25, 0xc8, a0 + save_msa_upper 26, 0xd0, a0 + save_msa_upper 27, 0xd8, a0 + save_msa_upper 28, 0xe0, a0 + save_msa_upper 29, 0xe8, a0 + save_msa_upper 30, 0xf0, a0 + save_msa_upper 31, 0xf8, a0 + jr ra + li v0, 0 + END(_save_msa_all_upper) + + .macro restore_msa_upper wr, off, base + .set push + .set noat +#ifdef CONFIG_64BIT + EX ld $1, \off(\base) + insert_d \wr, 1 +#elif defined(CONFIG_CPU_LITTLE_ENDIAN) + EX lw $1, \off(\base) + insert_w \wr, 2 + EX lw $1, (\off+4)(\base) + insert_w \wr, 3 +#else /* CONFIG_CPU_BIG_ENDIAN */ + EX lw $1, (\off+4)(\base) + insert_w \wr, 2 + EX lw $1, \off(\base) + insert_w \wr, 3 +#endif + .set pop + .endm + +LEAF(_restore_msa_all_upper) + restore_msa_upper 0, 0x00, a0 + restore_msa_upper 1, 0x08, a0 + restore_msa_upper 2, 0x10, a0 + restore_msa_upper 3, 0x18, a0 + restore_msa_upper 4, 0x20, a0 + restore_msa_upper 5, 0x28, a0 + restore_msa_upper 6, 0x30, a0 + restore_msa_upper 7, 0x38, a0 + restore_msa_upper 8, 0x40, a0 + restore_msa_upper 9, 0x48, a0 + restore_msa_upper 10, 0x50, a0 + restore_msa_upper 11, 0x58, a0 + restore_msa_upper 12, 0x60, a0 + restore_msa_upper 13, 0x68, a0 + restore_msa_upper 14, 0x70, a0 + restore_msa_upper 15, 0x78, a0 + restore_msa_upper 16, 0x80, a0 + restore_msa_upper 17, 0x88, a0 + restore_msa_upper 18, 0x90, a0 + restore_msa_upper 19, 0x98, a0 + restore_msa_upper 20, 0xa0, a0 + restore_msa_upper 21, 0xa8, a0 + restore_msa_upper 22, 0xb0, a0 + restore_msa_upper 23, 0xb8, a0 + restore_msa_upper 24, 0xc0, a0 + restore_msa_upper 25, 0xc8, a0 + restore_msa_upper 26, 0xd0, a0 + restore_msa_upper 27, 0xd8, a0 + restore_msa_upper 28, 0xe0, a0 + restore_msa_upper 29, 0xe8, a0 + restore_msa_upper 30, 0xf0, a0 + restore_msa_upper 31, 0xf8, a0 + jr ra + li v0, 0 + END(_restore_msa_all_upper) + #endif /* CONFIG_CPU_HAS_MSA */ .set reorder diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 96b0fd82f8b5..f50d48435c68 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -37,4 +37,7 @@ _save_fp_context(void __user *fpregs, void __user *csr); extern asmlinkage int _restore_fp_context(void __user *fpregs, void __user *csr); +extern asmlinkage int _save_msa_all_upper(void __user *buf); +extern asmlinkage int _restore_msa_all_upper(void __user *buf); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 3101bafd3a9c..fa13a52713df 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "signal-common.h" @@ -124,6 +125,168 @@ static int restore_hw_fp_context(void __user *sc) return _restore_fp_context(fpregs, csr); } +/* + * Extended context handling. + */ + +static inline void __user *sc_to_extcontext(void __user *sc) +{ + struct ucontext __user *uc; + + /* + * We can just pretend the sigcontext is always embedded in a struct + * ucontext here, because the offset from sigcontext to extended + * context is the same in the struct sigframe case. + */ + uc = container_of(sc, struct ucontext, uc_mcontext); + return &uc->uc_extcontext; +} + +static int save_msa_extcontext(void __user *buf) +{ + struct msa_extcontext __user *msa = buf; + uint64_t val; + int i, err; + + if (!thread_msa_context_live()) + return 0; + + /* + * Ensure that we can't lose the live MSA context between checking + * for it & writing it to memory. + */ + preempt_disable(); + + if (is_msa_enabled()) { + /* + * There are no EVA versions of the vector register load/store + * instructions, so MSA context has to be saved to kernel memory + * and then copied to user memory. The save to kernel memory + * should already have been done when handling scalar FP + * context. + */ + BUG_ON(config_enabled(CONFIG_EVA)); + + err = __put_user(read_msa_csr(), &msa->csr); + err |= _save_msa_all_upper(&msa->wr); + + preempt_enable(); + } else { + preempt_enable(); + + err = __put_user(current->thread.fpu.msacsr, &msa->csr); + + for (i = 0; i < NUM_FPU_REGS; i++) { + val = get_fpr64(¤t->thread.fpu.fpr[i], 1); + err |= __put_user(val, &msa->wr[i]); + } + } + + err |= __put_user(MSA_EXTCONTEXT_MAGIC, &msa->ext.magic); + err |= __put_user(sizeof(*msa), &msa->ext.size); + + return err ? -EFAULT : sizeof(*msa); +} + +static int restore_msa_extcontext(void __user *buf, unsigned int size) +{ + struct msa_extcontext __user *msa = buf; + unsigned long long val; + unsigned int csr; + int i, err; + + if (size != sizeof(*msa)) + return -EINVAL; + + err = get_user(csr, &msa->csr); + if (err) + return err; + + preempt_disable(); + + if (is_msa_enabled()) { + /* + * There are no EVA versions of the vector register load/store + * instructions, so MSA context has to be copied to kernel + * memory and later loaded to registers. The same is true of + * scalar FP context, so FPU & MSA should have already been + * disabled whilst handling scalar FP context. + */ + BUG_ON(config_enabled(CONFIG_EVA)); + + write_msa_csr(csr); + err |= _restore_msa_all_upper(&msa->wr); + preempt_enable(); + } else { + preempt_enable(); + + current->thread.fpu.msacsr = csr; + + for (i = 0; i < NUM_FPU_REGS; i++) { + err |= __get_user(val, &msa->wr[i]); + set_fpr64(¤t->thread.fpu.fpr[i], 1, val); + } + } + + return err; +} + +static int save_extcontext(void __user *buf) +{ + int sz; + + sz = save_msa_extcontext(buf); + if (sz < 0) + return sz; + buf += sz; + + /* If no context was saved then trivially return */ + if (!sz) + return 0; + + /* Write the end marker */ + if (__put_user(END_EXTCONTEXT_MAGIC, (u32 *)buf)) + return -EFAULT; + + sz += sizeof(((struct extcontext *)NULL)->magic); + return sz; +} + +static int restore_extcontext(void __user *buf) +{ + struct extcontext ext; + int err; + + while (1) { + err = __get_user(ext.magic, (unsigned int *)buf); + if (err) + return err; + + if (ext.magic == END_EXTCONTEXT_MAGIC) + return 0; + + err = __get_user(ext.size, (unsigned int *)(buf + + offsetof(struct extcontext, size))); + if (err) + return err; + + switch (ext.magic) { + case MSA_EXTCONTEXT_MAGIC: + err = restore_msa_extcontext(buf, ext.size); + break; + + default: + err = -EINVAL; + break; + } + + if (err) + return err; + + buf += ext.size; + } +} + /* * Helper routines */ @@ -133,20 +296,17 @@ int protected_save_fp_context(void __user *sc) uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; uint32_t __user *used_math = sc + abi->off_sc_used_math; - unsigned int used; + unsigned int used, ext_sz; int err; used = used_math() ? USED_FP : 0; - if (used) { - if (!test_thread_flag(TIF_32BIT_FPREGS)) - used |= USED_FR1; - if (test_thread_flag(TIF_HYBRID_FPREGS)) - used |= USED_HYBRID_FPRS; - } + if (!used) + goto fp_done; - err = __put_user(used, used_math); - if (err || !(used & USED_FP)) - return err; + if (!test_thread_flag(TIF_32BIT_FPREGS)) + used |= USED_FR1; + if (test_thread_flag(TIF_HYBRID_FPREGS)) + used |= USED_HYBRID_FPRS; /* * EVA does not have userland equivalents of ldc1 or sdc1, so @@ -171,10 +331,16 @@ int protected_save_fp_context(void __user *sc) __put_user(0, &fpregs[31]) | __put_user(0, csr); if (err) - break; /* really bad sigcontext */ + return err; /* really bad sigcontext */ } - return err; +fp_done: + ext_sz = err = save_extcontext(sc_to_extcontext(sc)); + if (err < 0) + return err; + used |= ext_sz ? USED_EXTCONTEXT : 0; + + return __put_user(used, used_math); } int protected_restore_fp_context(void __user *sc) @@ -184,7 +350,7 @@ int protected_restore_fp_context(void __user *sc) uint32_t __user *csr = sc + abi->off_sc_fpc_csr; uint32_t __user *used_math = sc + abi->off_sc_used_math; unsigned int used; - int err, sig, tmp __maybe_unused; + int err, sig = 0, tmp __maybe_unused; err = __get_user(used, used_math); conditional_used_math(used & USED_FP); @@ -193,10 +359,12 @@ int protected_restore_fp_context(void __user *sc) * The signal handler may have used FPU; give it up if the program * doesn't want it following sigreturn. */ - if (err || !(used & USED_FP)) { + if (err || !(used & USED_FP)) lose_fpu(0); + if (err) return err; - } + if (!(used & USED_FP)) + goto fp_done; err = sig = fpcsr_pending(csr); if (err < 0) @@ -229,6 +397,10 @@ int protected_restore_fp_context(void __user *sc) break; /* really bad sigcontext */ } +fp_done: + if (used & USED_EXTCONTEXT) + err |= restore_extcontext(sc_to_extcontext(sc)); + return err ?: sig; } @@ -268,6 +440,28 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) return err; } +static size_t extcontext_max_size(void) +{ + size_t sz = 0; + + /* + * The assumption here is that between this point & the point at which + * the extended context is saved the size of the context should only + * ever be able to shrink (if the task is preempted), but never grow. + * That is, what this function returns is an upper bound on the size of + * the extended context for the current task at the current time. + */ + + if (thread_msa_context_live()) + sz += sizeof(struct msa_extcontext); + + /* If any context is saved then we'll append the end marker */ + if (sz) + sz += sizeof(((struct extcontext *)NULL)->magic); + + return sz; +} + int fpcsr_pending(unsigned int __user *fpcsr) { int err, sig = 0; @@ -324,6 +518,9 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, { unsigned long sp; + /* Leave space for potential extended context */ + frame_size += extcontext_max_size(); + /* Default to using normal stack */ sp = regs->regs[29]; -- cgit v1.2.3-59-g8ed1b From e14f1db7a61f016d74393ca9e8fc49a91d27f603 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:23 -0700 Subject: MIPS: AT_HWCAP aux vector infrastructure In order for userland to determine whether various features are safe to use, it will need to know both that the hardware supports those features and that the kernel is recent enough & configured appropriately to support them. For example under the O32 modeless FP proposal the dynamic linker & ifunc resolvers will need this information. The kernel is the only thing in a position to know availability accurately, so the kernel needs to provide the information to userland. This patch introduces the infrastructure to provide the AT_HWCAP aux vector to userland in order to provide that information. It also defines the 2 currently specified flags, which indicate MIPSr6 & MSA support. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Kees Cook Cc: Huacai Chen Cc: Maciej W. Rozycki Cc: Alex Smith Cc: linux-kernel@vger.kernel.org Cc: Leonid Yegoshin Cc: Markos Chandras Cc: Ingo Molnar Patchwork: https://patchwork.linux-mips.org/patch/10797/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/elf.h | 4 +++- arch/mips/include/uapi/asm/hwcap.h | 8 ++++++++ arch/mips/kernel/cpu-probe.c | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 arch/mips/include/uapi/asm/hwcap.h diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index f19e890b99d2..53b26933b12c 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -382,7 +382,9 @@ do { \ instruction set this cpu supports. This could be done in userspace, but it's not easy, and we've already done it here. */ -#define ELF_HWCAP (0) +#define ELF_HWCAP (elf_hwcap) +extern unsigned int elf_hwcap; +#include /* * This yields a string that ld.so will use to load implementation diff --git a/arch/mips/include/uapi/asm/hwcap.h b/arch/mips/include/uapi/asm/hwcap.h new file mode 100644 index 000000000000..c7484a7ca686 --- /dev/null +++ b/arch/mips/include/uapi/asm/hwcap.h @@ -0,0 +1,8 @@ +#ifndef _UAPI_ASM_HWCAP_H +#define _UAPI_ASM_HWCAP_H + +/* HWCAP flags */ +#define HWCAP_MIPS_R6 (1 << 0) +#define HWCAP_MIPS_MSA (1 << 1) + +#endif /* _UAPI_ASM_HWCAP_H */ diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 987036761fb6..b6c1feed8b7b 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -32,6 +32,9 @@ #include #include +/* Hardware capabilities */ +unsigned int elf_hwcap __read_mostly; + /* * Get the FPU Implementation/Revision. */ -- cgit v1.2.3-59-g8ed1b From 4c0630346e2fcfe68eac8fa31d38daf04570e671 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:24 -0700 Subject: MIPS: Advertise MIPSr6 via HWCAP when appropriate When running on a CPU implementing the release 6 of the MIPS32 or MIPS64 ISA, advertise that to userland via the appropriate HWCAP bit. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Huacai Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10798/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b6c1feed8b7b..380a14b8772e 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1524,6 +1524,9 @@ void cpu_probe(void) else c->srsets = 1; + if (cpu_has_mips_r6) + elf_hwcap |= HWCAP_MIPS_R6; + if (cpu_has_msa) { c->msa_id = cpu_get_msa_id(); WARN(c->msa_id & MSA_IR_WRPF, -- cgit v1.2.3-59-g8ed1b From 3cc9fa7fb3e38e83e59977c8bc5c355687232362 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:25 -0700 Subject: MIPS: Advertise MSA support via HWCAP when present If MSA is supported by both the hardware & the kernel then advertise that support to userland via the AT_HWCAP aux vector. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Huacai Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10799/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 380a14b8772e..571a8e6ea5bd 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1531,6 +1531,7 @@ void cpu_probe(void) c->msa_id = cpu_get_msa_id(); WARN(c->msa_id & MSA_IR_WRPF, "Vector register partitioning unimplemented!"); + elf_hwcap |= HWCAP_MIPS_MSA; } cpu_probe_vmbits(c); -- cgit v1.2.3-59-g8ed1b From 0ce3417e84825155e2d74ac65e133bf7ba995a74 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:27 -0700 Subject: MIPS: Drop EXPERIMENTAL tag from O32+FP64 & MSA CONFIG_MIPS_O32_FP64_SUPPORT and CONFIG_CPU_HAS_MSA are in pretty good shape these days, and in much wider use than they once were. Stop referring to them as EXPERIMENTAL. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10801/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index efa3706beb54..3c2e4c87d489 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2307,7 +2307,7 @@ config CPU_MICROMIPS endchoice config CPU_HAS_MSA - bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)" + bool "Support for the MIPS SIMD Architecture" depends on CPU_SUPPORTS_MSA depends on 64BIT || MIPS_O32_FP64_SUPPORT help @@ -2647,7 +2647,7 @@ config SECCOMP If unsure, say Y. Only embedded should say N here. config MIPS_O32_FP64_SUPPORT - bool "Support for O32 binaries using 64-bit FP (EXPERIMENTAL)" + bool "Support for O32 binaries using 64-bit FP" depends on 32BIT || MIPS32_O32 help When this is enabled, the kernel will support use of 64-bit floating -- cgit v1.2.3-59-g8ed1b From c4687b15a8487e8ef028814a301a88958baf72bc Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 24 Jul 2015 16:16:10 +0100 Subject: MIPS: Fix definition of pgprot_writecombine() If pgprot_writecombine is not #defined, asm-generic/pgtable.h will try to provide a default implementation by #defining it to pgprot_noncached. However our implementation is an inline function rather than a #define, so it was never actually used because of the #define in generic code. Add "#define pgprot_writecombine pgprot_writecombine" to prevent generic code from re-defining it. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10767/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index ae8569475264..8957f15e21ec 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -393,6 +393,8 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot) return __pgprot(prot); } +#define pgprot_writecombine pgprot_writecombine + static inline pgprot_t pgprot_writecombine(pgprot_t _prot) { unsigned long prot = pgprot_val(_prot); -- cgit v1.2.3-59-g8ed1b From 8c172467be36f7c9591e59b647e4cd342ce2ef41 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 30 Jul 2015 12:03:42 +0100 Subject: MIPS: Add implementation of dma_map_ops.mmap() The generic implementation of dma_map_ops.mmap(), dma_common_mmap(), is not correct for non-coherent devices. It expects to be passed a virtual address previously returned by dma_alloc_coherent(), which for a non-coherent device will return a KSEG1 address. It then attempts to convert that virtual address to a physical address using virt_to_page() which will yield an incorrect address. Also, dma_common_mmap() does not handle the DMA_ATTR_WRITE_COMBINE attribute, and therefore dma_mmap_writecombine() will not actually set the appropriate pgprot_t flags for write combining. This patch adds an implementation of dma_map_ops.mmap() that correctly handles KSEG1 addresses, and enables write combining when requested. Signed-off-by: Alex Smith Cc: Sadegh Abbasi Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10808/ Signed-off-by: Ralf Baechle --- arch/mips/mm/dma-default.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index eeaf0245c3b1..8f23cf08f4ba 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -194,6 +194,40 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, __free_pages(page, get_order(size)); } +static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) +{ + unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; + unsigned long addr = (unsigned long)cpu_addr; + unsigned long off = vma->vm_pgoff; + unsigned long pfn; + int ret = -ENXIO; + + if (!plat_device_is_coherent(dev) && !hw_coherentio) + addr = CAC_ADDR(addr); + + pfn = page_to_pfn(virt_to_page((void *)addr)); + + if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs)) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) + return ret; + + if (off < count && user_count <= (count - off)) { + ret = remap_pfn_range(vma, vma->vm_start, + pfn + off, + user_count << PAGE_SHIFT, + vma->vm_page_prot); + } + + return ret; +} + static inline void __dma_sync_virtual(void *addr, size_t size, enum dma_data_direction direction) { @@ -380,6 +414,7 @@ EXPORT_SYMBOL(dma_cache_sync); static struct dma_map_ops mips_default_dma_map_ops = { .alloc = mips_dma_alloc_coherent, .free = mips_dma_free_coherent, + .mmap = mips_dma_mmap, .map_page = mips_dma_map_page, .unmap_page = mips_dma_unmap_page, .map_sg = mips_dma_map_sg, -- cgit v1.2.3-59-g8ed1b From f1f5e414851fdb69a3200e5c15799ea4788d423e Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 24 Jul 2015 16:16:12 +0100 Subject: MIPS: Use Ingenic-specific write combine attribute on all Ingenic platforms The Ingenic-specific write combining cache attribute was defined based on CONFIG_MACH_JZ4740 and therefore not used on JZ4780. Change this to CONFIG_MACH_INGENIC so that it gets used on all Ingenic platforms. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10769/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable-bits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index c28a8499aec7..002eeb224733 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -249,7 +249,7 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) #define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* LOONGSON */ #define _CACHE_CACHABLE_COHERENT (3<<_CACHE_SHIFT) /* LOONGSON-3 */ -#elif defined(CONFIG_MACH_JZ4740) +#elif defined(CONFIG_MACH_INGENIC) /* Ingenic uses the WA bit to achieve write-combine memory writes */ #define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) -- cgit v1.2.3-59-g8ed1b From f51246efee2b6bc72e86bc1d16599fc7c455b986 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 29 Jul 2015 12:14:42 +0200 Subject: MIPS: Get rid of finish_arch_switch(). MIPS was using finish_arch_switch() as a hook to restore and initialize CPU context for all threads, even newly created kernel and user threads. This is however entirely solvable within switch_to() so get rid of finish_arch_switch() which is in the way of scheduler cleanups. Signed-off-by: Ralf Baechle --- arch/mips/include/asm/switch_to.h | 48 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index 7163cd7fdd69..9733cd0266e4 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -83,45 +83,43 @@ do { if (cpu_has_rw_llb) { \ } \ } while (0) +/* + * For newly created kernel threads switch_to() will return to + * ret_from_kernel_thread, newly created user threads to ret_from_fork. + * That is, everything following resume() will be skipped for new threads. + * So everything that matters to new threads should be placed before resume(). + */ #define switch_to(prev, next, last) \ do { \ - u32 __c0_stat; \ s32 __fpsave = FP_SAVE_NONE; \ __mips_mt_fpaff_switch_to(prev); \ - if (cpu_has_dsp) \ + if (cpu_has_dsp) { \ __save_dsp(prev); \ - if (cop2_present && (KSTK_STATUS(prev) & ST0_CU2)) { \ - if (cop2_lazy_restore) \ - KSTK_STATUS(prev) &= ~ST0_CU2; \ - __c0_stat = read_c0_status(); \ - write_c0_status(__c0_stat | ST0_CU2); \ - cop2_save(prev); \ - write_c0_status(__c0_stat & ~ST0_CU2); \ + __restore_dsp(next); \ + } \ + if (cop2_present) { \ + set_c0_status(ST0_CU2); \ + if ((KSTK_STATUS(prev) & ST0_CU2)) { \ + if (cop2_lazy_restore) \ + KSTK_STATUS(prev) &= ~ST0_CU2; \ + cop2_save(prev); \ + } \ + if (KSTK_STATUS(next) & ST0_CU2 && \ + !cop2_lazy_restore) { \ + cop2_restore(next); \ + } \ + clear_c0_status(ST0_CU2); \ } \ __clear_software_ll_bit(); \ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU)) \ __fpsave = FP_SAVE_SCALAR; \ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA)) \ __fpsave = FP_SAVE_VECTOR; \ - (last) = resume(prev, next, task_thread_info(next), __fpsave); \ -} while (0) - -#define finish_arch_switch(prev) \ -do { \ - u32 __c0_stat; \ - if (cop2_present && !cop2_lazy_restore && \ - (KSTK_STATUS(current) & ST0_CU2)) { \ - __c0_stat = read_c0_status(); \ - write_c0_status(__c0_stat | ST0_CU2); \ - cop2_restore(current); \ - write_c0_status(__c0_stat & ~ST0_CU2); \ - } \ - if (cpu_has_dsp) \ - __restore_dsp(current); \ if (cpu_has_userlocal) \ - write_c0_userlocal(current_thread_info()->tp_value); \ + write_c0_userlocal(task_thread_info(next)->tp_value); \ __restore_watch(); \ disable_msa(); \ + (last) = resume(prev, next, task_thread_info(next), __fpsave); \ } while (0) #endif /* _ASM_SWITCH_TO_H */ -- cgit v1.2.3-59-g8ed1b From 5fac4f7ac067b2eee3aaf19eff8bd1d7d8e9a91e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 30 Jul 2015 08:16:10 -0700 Subject: MIPS: Select CONFIG_ARCH_USE_CMPXCHG_LOCKREF for MIPS64 On MIPS64 we have spinlocks that are 32b in size and an efficient cmpxchg64 implementation, so we qualify to make use of cmpxchg backed lockrefs. Select the ARCH_USE_CMPXCHG_LOCKREF Kconfig symbol and provide a trivial implementation of arch_spin_value_unlocked to satisfy the lockref code. Using Linus' simple testcase from http://article.gmane.org/gmane.linux.file-systems/77466 on a dual core system with an in-development MIPS64 CPU running on FPGA I see around an 8% gain: Pre-patch: Total loops: 252698 Total loops: 251482 Total loops: 250806 Total loops: 252885 Total loops: 251666 Post-patch: Total loops: 273728 Total loops: 269932 Total loops: 269341 Total loops: 275004 Total loops: 270208 [ralf@linux-mips.org: Fixed conflict.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Steven J. Hill Cc: linux-kernel@vger.kernel.org Cc: Maciej W. Rozycki Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10810/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/include/asm/spinlock.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3c2e4c87d489..449f840d5a7f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -3,6 +3,7 @@ config MIPS default y select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO + select ARCH_USE_CMPXCHG_LOCKREF if 64BIT select HAVE_CONTEXT_TRACKING select HAVE_GENERIC_DMA_COHERENT select HAVE_IDE diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index 9de4ba43dcd1..40196bebe849 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h @@ -42,6 +42,11 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lock) return ((counters >> 16) ^ counters) & 0xffff; } +static inline int arch_spin_value_unlocked(arch_spinlock_t lock) +{ + return lock.h.serving_now == lock.h.ticket; +} + #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) #define arch_spin_unlock_wait(x) \ while (arch_spin_is_locked(x)) { cpu_relax(); } -- cgit v1.2.3-59-g8ed1b From f689332b19fa1120de1bd84988a7bd0c08bd9b7b Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Fri, 3 Jul 2015 11:11:48 +0200 Subject: MIPS: Ath79: Remove the unused GPIO function API To prepare moving the GPIO driver to drivers/gpio remove the platform specific pinmux API. As it is not used by any board, and such functionality should better be implemented using the pinmux subsystem just removing it seems to be the best option. Signed-off-by: Alban Bedel Acked-by: Linus Walleij Cc: linux-gpio@vger.kernel.org Cc: Alexandre Courbot Cc: Gabor Juhos Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10596/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/common.h | 3 --- arch/mips/ath79/gpio.c | 43 ------------------------------------------- 2 files changed, 46 deletions(-) diff --git a/arch/mips/ath79/common.h b/arch/mips/ath79/common.h index e5ea71277f0c..ca7cc19adfea 100644 --- a/arch/mips/ath79/common.h +++ b/arch/mips/ath79/common.h @@ -25,9 +25,6 @@ unsigned long ath79_get_sys_clk_rate(const char *id); void ath79_ddr_ctrl_init(void); void ath79_ddr_wb_flush(unsigned int reg); -void ath79_gpio_function_enable(u32 mask); -void ath79_gpio_function_disable(u32 mask); -void ath79_gpio_function_setup(u32 set, u32 clear); void ath79_gpio_init(void); #endif /* __ATH79_COMMON_H */ diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index f59ccb26520a..c3c92eb56e04 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -24,8 +24,6 @@ #include #include -#include -#include "common.h" static void __iomem *ath79_gpio_base; static u32 ath79_gpio_count; @@ -139,47 +137,6 @@ static struct gpio_chip ath79_gpio_chip = { .base = 0, }; -static void __iomem *ath79_gpio_get_function_reg(void) -{ - u32 reg = 0; - - if (soc_is_ar71xx() || - soc_is_ar724x() || - soc_is_ar913x() || - soc_is_ar933x()) - reg = AR71XX_GPIO_REG_FUNC; - else if (soc_is_ar934x()) - reg = AR934X_GPIO_REG_FUNC; - else - BUG(); - - return ath79_gpio_base + reg; -} - -void ath79_gpio_function_setup(u32 set, u32 clear) -{ - void __iomem *reg = ath79_gpio_get_function_reg(); - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - __raw_writel((__raw_readl(reg) & ~clear) | set, reg); - /* flush write */ - __raw_readl(reg); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); -} - -void ath79_gpio_function_enable(u32 mask) -{ - ath79_gpio_function_setup(mask, 0); -} - -void ath79_gpio_function_disable(u32 mask) -{ - ath79_gpio_function_setup(0, mask); -} - static const struct of_device_id ath79_gpio_of_match[] = { { .compatible = "qca,ar7100-gpio" }, { .compatible = "qca,ar9340-gpio" }, -- cgit v1.2.3-59-g8ed1b From 1d473c2cb9fe25fc6bad30b0eb8d92e384496042 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Fri, 3 Jul 2015 11:11:49 +0200 Subject: MIPS: ath79: Move the GPIO driver to drivers/gpio GPIO drivers should be in drivers/gpio Signed-off-by: Alban Bedel Acked-by: Linus Walleij Cc: linux-gpio@vger.kernel.org Cc: Alexandre Courbot Cc: Gabor Juhos Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10597/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/Makefile | 2 +- arch/mips/ath79/gpio.c | 236 ---------------------------------------------- drivers/gpio/Makefile | 1 + drivers/gpio/gpio-ath79.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 237 deletions(-) delete mode 100644 arch/mips/ath79/gpio.c create mode 100644 drivers/gpio/gpio-ath79.c diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile index 5c9ff692ff3c..fcc382cfc770 100644 --- a/arch/mips/ath79/Makefile +++ b/arch/mips/ath79/Makefile @@ -8,7 +8,7 @@ # under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. -obj-y := prom.o setup.o irq.o common.o clock.o gpio.o +obj-y := prom.o setup.o irq.o common.o clock.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c deleted file mode 100644 index c3c92eb56e04..000000000000 --- a/arch/mips/ath79/gpio.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Atheros AR71XX/AR724X/AR913X GPIO API support - * - * Copyright (C) 2010-2011 Jaiganesh Narayanan - * Copyright (C) 2008-2011 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static void __iomem *ath79_gpio_base; -static u32 ath79_gpio_count; -static DEFINE_SPINLOCK(ath79_gpio_lock); - -static void __ath79_gpio_set_value(unsigned gpio, int value) -{ - void __iomem *base = ath79_gpio_base; - - if (value) - __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET); - else - __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR); -} - -static int __ath79_gpio_get_value(unsigned gpio) -{ - return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; -} - -static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) -{ - return __ath79_gpio_get_value(offset); -} - -static void ath79_gpio_set_value(struct gpio_chip *chip, - unsigned offset, int value) -{ - __ath79_gpio_set_value(offset, value); -} - -static int ath79_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - void __iomem *base = ath79_gpio_base; - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), - base + AR71XX_GPIO_REG_OE); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); - - return 0; -} - -static int ath79_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - void __iomem *base = ath79_gpio_base; - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - if (value) - __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); - else - __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); - - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), - base + AR71XX_GPIO_REG_OE); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); - - return 0; -} - -static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *base = ath79_gpio_base; - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), - base + AR71XX_GPIO_REG_OE); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); - - return 0; -} - -static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - void __iomem *base = ath79_gpio_base; - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - if (value) - __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); - else - __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); - - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), - base + AR71XX_GPIO_REG_OE); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); - - return 0; -} - -static struct gpio_chip ath79_gpio_chip = { - .label = "ath79", - .get = ath79_gpio_get_value, - .set = ath79_gpio_set_value, - .direction_input = ath79_gpio_direction_input, - .direction_output = ath79_gpio_direction_output, - .base = 0, -}; - -static const struct of_device_id ath79_gpio_of_match[] = { - { .compatible = "qca,ar7100-gpio" }, - { .compatible = "qca,ar9340-gpio" }, - {}, -}; - -static int ath79_gpio_probe(struct platform_device *pdev) -{ - struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data; - struct device_node *np = pdev->dev.of_node; - struct resource *res; - bool oe_inverted; - int err; - - if (np) { - err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); - if (err) { - dev_err(&pdev->dev, "ngpios property is not valid\n"); - return err; - } - if (ath79_gpio_count >= 32) { - dev_err(&pdev->dev, "ngpios must be less than 32\n"); - return -EINVAL; - } - oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); - } else if (pdata) { - ath79_gpio_count = pdata->ngpios; - oe_inverted = pdata->oe_inverted; - } else { - dev_err(&pdev->dev, "No DT node or platform data found\n"); - return -EINVAL; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ath79_gpio_base = devm_ioremap_nocache( - &pdev->dev, res->start, resource_size(res)); - if (!ath79_gpio_base) - return -ENOMEM; - - ath79_gpio_chip.dev = &pdev->dev; - ath79_gpio_chip.ngpio = ath79_gpio_count; - if (oe_inverted) { - ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; - ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; - } - - err = gpiochip_add(&ath79_gpio_chip); - if (err) { - dev_err(&pdev->dev, - "cannot add AR71xx GPIO chip, error=%d", err); - return err; - } - - return 0; -} - -static struct platform_driver ath79_gpio_driver = { - .driver = { - .name = "ath79-gpio", - .of_match_table = ath79_gpio_of_match, - }, - .probe = ath79_gpio_probe, -}; - -module_platform_driver(ath79_gpio_driver); - -int gpio_get_value(unsigned gpio) -{ - if (gpio < ath79_gpio_count) - return __ath79_gpio_get_value(gpio); - - return __gpio_get_value(gpio); -} -EXPORT_SYMBOL(gpio_get_value); - -void gpio_set_value(unsigned gpio, int value) -{ - if (gpio < ath79_gpio_count) - __ath79_gpio_set_value(gpio, value); - else - __gpio_set_value(gpio, value); -} -EXPORT_SYMBOL(gpio_set_value); - -int gpio_to_irq(unsigned gpio) -{ - /* FIXME */ - return -EINVAL; -} -EXPORT_SYMBOL(gpio_to_irq); - -int irq_to_gpio(unsigned irq) -{ - /* FIXME */ - return -EINVAL; -} -EXPORT_SYMBOL(irq_to_gpio); diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f82cd678ce08..2b64f6177e33 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c new file mode 100644 index 000000000000..c3c92eb56e04 --- /dev/null +++ b/drivers/gpio/gpio-ath79.c @@ -0,0 +1,236 @@ +/* + * Atheros AR71XX/AR724X/AR913X GPIO API support + * + * Copyright (C) 2010-2011 Jaiganesh Narayanan + * Copyright (C) 2008-2011 Gabor Juhos + * Copyright (C) 2008 Imre Kaloz + * + * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static void __iomem *ath79_gpio_base; +static u32 ath79_gpio_count; +static DEFINE_SPINLOCK(ath79_gpio_lock); + +static void __ath79_gpio_set_value(unsigned gpio, int value) +{ + void __iomem *base = ath79_gpio_base; + + if (value) + __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET); + else + __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR); +} + +static int __ath79_gpio_get_value(unsigned gpio) +{ + return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1; +} + +static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + return __ath79_gpio_get_value(offset); +} + +static void ath79_gpio_set_value(struct gpio_chip *chip, + unsigned offset, int value) +{ + __ath79_gpio_set_value(offset, value); +} + +static int ath79_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static int ath79_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + if (value) + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); + else + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + void __iomem *base = ath79_gpio_base; + unsigned long flags; + + spin_lock_irqsave(&ath79_gpio_lock, flags); + + if (value) + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); + else + __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); + + __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), + base + AR71XX_GPIO_REG_OE); + + spin_unlock_irqrestore(&ath79_gpio_lock, flags); + + return 0; +} + +static struct gpio_chip ath79_gpio_chip = { + .label = "ath79", + .get = ath79_gpio_get_value, + .set = ath79_gpio_set_value, + .direction_input = ath79_gpio_direction_input, + .direction_output = ath79_gpio_direction_output, + .base = 0, +}; + +static const struct of_device_id ath79_gpio_of_match[] = { + { .compatible = "qca,ar7100-gpio" }, + { .compatible = "qca,ar9340-gpio" }, + {}, +}; + +static int ath79_gpio_probe(struct platform_device *pdev) +{ + struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; + struct resource *res; + bool oe_inverted; + int err; + + if (np) { + err = of_property_read_u32(np, "ngpios", &ath79_gpio_count); + if (err) { + dev_err(&pdev->dev, "ngpios property is not valid\n"); + return err; + } + if (ath79_gpio_count >= 32) { + dev_err(&pdev->dev, "ngpios must be less than 32\n"); + return -EINVAL; + } + oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio"); + } else if (pdata) { + ath79_gpio_count = pdata->ngpios; + oe_inverted = pdata->oe_inverted; + } else { + dev_err(&pdev->dev, "No DT node or platform data found\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ath79_gpio_base = devm_ioremap_nocache( + &pdev->dev, res->start, resource_size(res)); + if (!ath79_gpio_base) + return -ENOMEM; + + ath79_gpio_chip.dev = &pdev->dev; + ath79_gpio_chip.ngpio = ath79_gpio_count; + if (oe_inverted) { + ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; + ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; + } + + err = gpiochip_add(&ath79_gpio_chip); + if (err) { + dev_err(&pdev->dev, + "cannot add AR71xx GPIO chip, error=%d", err); + return err; + } + + return 0; +} + +static struct platform_driver ath79_gpio_driver = { + .driver = { + .name = "ath79-gpio", + .of_match_table = ath79_gpio_of_match, + }, + .probe = ath79_gpio_probe, +}; + +module_platform_driver(ath79_gpio_driver); + +int gpio_get_value(unsigned gpio) +{ + if (gpio < ath79_gpio_count) + return __ath79_gpio_get_value(gpio); + + return __gpio_get_value(gpio); +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned gpio, int value) +{ + if (gpio < ath79_gpio_count) + __ath79_gpio_set_value(gpio, value); + else + __gpio_set_value(gpio, value); +} +EXPORT_SYMBOL(gpio_set_value); + +int gpio_to_irq(unsigned gpio) +{ + /* FIXME */ + return -EINVAL; +} +EXPORT_SYMBOL(gpio_to_irq); + +int irq_to_gpio(unsigned irq) +{ + /* FIXME */ + return -EINVAL; +} +EXPORT_SYMBOL(irq_to_gpio); -- cgit v1.2.3-59-g8ed1b From 832f5dacfa0bb081a3b3b979a36a132b28ffacf3 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Sun, 2 Aug 2015 18:30:11 +0200 Subject: MIPS: Remove all the uses of custom gpio.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently CONFIG_ARCH_HAVE_CUSTOM_GPIO_H is defined for all MIPS machines, and each machine type provides its own gpio.h. However only a handful really implement the GPIO API, most just forward everythings to gpiolib. The Alchemy machine is notable as it provides a system to allow implementing the GPIO API at the board level. But it is not used by any board currently supported, so it can also be removed. For most machine types we can just remove the custom gpio.h, as well as the custom wrappers if some exists. Some of the code found in the wrappers must be moved to the respective GPIO driver. A few more fixes are need in some drivers as they rely on linux/gpio.h to provides some machine specific definitions, or used asm/gpio.h instead of linux/gpio.h for the gpio API. Signed-off-by: Alban Bedel Reviewed-by: Linus Walleij Cc: linux-mips@linux-mips.org Cc: Hauke Mehrtens Cc: RafaÅ‚ MiÅ‚ecki Cc: Bartlomiej Zolnierkiewicz Cc: Tejun Heo Cc: Alexandre Courbot Cc: Dmitry Torokhov Cc: Florian Fainelli Cc: Manuel Lauss Cc: Joe Perches Cc: Daniel Walter Cc: Sergey Ryazanov Cc: Huacai Chen Cc: James Hartley Cc: Andrew Bresticker Cc: Paul Burton Cc: Jiri Kosina Cc: Bjorn Helgaas Cc: Wolfram Sang Cc: Randy Dunlap Cc: Varka Bhadram Cc: Masanari Iida Cc: Tomi Valkeinen Cc: Michael Buesch Cc: abdoulaye berthe Cc: linux-kernel@vger.kernel.org Cc: linux-ide@vger.kernel.org Cc: linux-gpio@vger.kernel.org Cc: linux-input@vger.kernel.org Cc: netdev@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10828/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 - arch/mips/alchemy/Kconfig | 7 -- arch/mips/alchemy/board-gpr.c | 1 + arch/mips/alchemy/board-mtx1.c | 1 + arch/mips/alchemy/common/Makefile | 7 +- arch/mips/alchemy/devboards/db1000.c | 1 + arch/mips/alchemy/devboards/db1300.c | 1 + arch/mips/alchemy/devboards/db1550.c | 1 + arch/mips/alchemy/devboards/pm.c | 2 +- arch/mips/ar7/gpio.c | 5 +- arch/mips/ar7/platform.c | 1 - arch/mips/ar7/setup.c | 1 - arch/mips/include/asm/gpio.h | 6 - arch/mips/include/asm/mach-ar7/ar7.h | 4 + arch/mips/include/asm/mach-ar7/gpio.h | 41 ------- arch/mips/include/asm/mach-ath25/gpio.h | 16 --- arch/mips/include/asm/mach-ath79/gpio.h | 26 ----- arch/mips/include/asm/mach-au1x00/gpio-au1000.h | 148 ++---------------------- arch/mips/include/asm/mach-au1x00/gpio.h | 86 -------------- arch/mips/include/asm/mach-bcm47xx/gpio.h | 17 --- arch/mips/include/asm/mach-bcm63xx/gpio.h | 15 --- arch/mips/include/asm/mach-cavium-octeon/gpio.h | 21 ---- arch/mips/include/asm/mach-generic/gpio.h | 21 ---- arch/mips/include/asm/mach-jz4740/gpio.h | 2 - arch/mips/include/asm/mach-lantiq/gpio.h | 13 --- arch/mips/include/asm/mach-loongson64/gpio.h | 36 ------ arch/mips/include/asm/mach-pistachio/gpio.h | 21 ---- arch/mips/include/asm/mach-rc32434/gpio.h | 12 -- arch/mips/jz4740/gpio.c | 20 ++-- arch/mips/pci/pci-lantiq.c | 1 - arch/mips/rb532/devices.c | 1 + arch/mips/rb532/gpio.c | 6 + arch/mips/txx9/generic/setup.c | 16 --- drivers/ata/pata_rb532_cf.c | 3 +- drivers/gpio/gpio-ath79.c | 32 ----- drivers/input/misc/rb532_button.c | 1 + drivers/net/ethernet/ti/cpmac.c | 2 + 37 files changed, 45 insertions(+), 551 deletions(-) delete mode 100644 arch/mips/include/asm/gpio.h delete mode 100644 arch/mips/include/asm/mach-ar7/gpio.h delete mode 100644 arch/mips/include/asm/mach-ath25/gpio.h delete mode 100644 arch/mips/include/asm/mach-ath79/gpio.h delete mode 100644 arch/mips/include/asm/mach-au1x00/gpio.h delete mode 100644 arch/mips/include/asm/mach-bcm47xx/gpio.h delete mode 100644 arch/mips/include/asm/mach-bcm63xx/gpio.h delete mode 100644 arch/mips/include/asm/mach-cavium-octeon/gpio.h delete mode 100644 arch/mips/include/asm/mach-generic/gpio.h delete mode 100644 arch/mips/include/asm/mach-lantiq/gpio.h delete mode 100644 arch/mips/include/asm/mach-loongson64/gpio.h delete mode 100644 arch/mips/include/asm/mach-pistachio/gpio.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 449f840d5a7f..06c5957917d3 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -14,7 +14,6 @@ config MIPS select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_BPF_JIT if !CPU_MICROMIPS - select ARCH_HAVE_CUSTOM_GPIO_H select HAVE_FUNCTION_TRACER select HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig index b9628983d620..7fa24881b708 100644 --- a/arch/mips/alchemy/Kconfig +++ b/arch/mips/alchemy/Kconfig @@ -6,13 +6,6 @@ config ALCHEMY_GPIOINT_AU1000 config ALCHEMY_GPIOINT_AU1300 bool -# select this in your board config if you don't want to use the gpio -# namespace as documented in the manuals. In this case however you need -# to create the necessary gpio_* functions in your board code/headers! -# see arch/mips/include/asm/mach-au1x00/gpio.h for more information. -config ALCHEMY_GPIO_INDIRECT - def_bool n - choice prompt "Machine type" depends on MIPS_ALCHEMY diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c index acf9a2a37f5a..79efe4c6e636 100644 --- a/arch/mips/alchemy/board-gpr.c +++ b/arch/mips/alchemy/board-gpr.c @@ -34,6 +34,7 @@ #include #include #include +#include #include const char *get_system_type(void) diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c index 1e3b102389ef..85bb75669b0d 100644 --- a/arch/mips/alchemy/board-mtx1.c +++ b/arch/mips/alchemy/board-mtx1.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index f64744f3b59f..23800b8e67e5 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile @@ -5,10 +5,5 @@ # Makefile for the Alchemy Au1xx0 CPUs, generic files. # -obj-y += prom.o time.o clock.o platform.o power.o \ +obj-y += prom.o time.o clock.o platform.o power.o gpiolib.o \ setup.o sleeper.o dma.o dbdma.o vss.o irq.o usb.o - -# optional gpiolib support -ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) - obj-$(CONFIG_GPIOLIB) += gpiolib.o -endif diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c index 001102e197f1..bdeed9d13c6f 100644 --- a/arch/mips/alchemy/devboards/db1000.c +++ b/arch/mips/alchemy/devboards/db1000.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index 1c64fdbe4c81..b58077008a53 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c index 0fd5177e35ab..5740bcfdfc7f 100644 --- a/arch/mips/alchemy/devboards/db1550.c +++ b/arch/mips/alchemy/devboards/db1550.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/pm.c b/arch/mips/alchemy/devboards/pm.c index bfeb8f3c0be6..93024dc6b314 100644 --- a/arch/mips/alchemy/devboards/pm.c +++ b/arch/mips/alchemy/devboards/pm.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include /* diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c index d8dbd8f0c1d2..f4930456eb8e 100644 --- a/arch/mips/ar7/gpio.c +++ b/arch/mips/ar7/gpio.c @@ -21,7 +21,10 @@ #include #include -#include +#include + +#define AR7_GPIO_MAX 32 +#define TITAN_GPIO_MAX 51 struct ar7_gpio_chip { void __iomem *regs; diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index be9ff1673ded..462a252ea6e6 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -39,7 +39,6 @@ #include #include -#include #include /***************************************************************************** diff --git a/arch/mips/ar7/setup.c b/arch/mips/ar7/setup.c index 820b7a313d9b..7bb9a670bb73 100644 --- a/arch/mips/ar7/setup.c +++ b/arch/mips/ar7/setup.c @@ -23,7 +23,6 @@ #include #include #include -#include static void ar7_machine_restart(char *command) { diff --git a/arch/mips/include/asm/gpio.h b/arch/mips/include/asm/gpio.h deleted file mode 100644 index 06e46faf862d..000000000000 --- a/arch/mips/include/asm/gpio.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_MIPS_GPIO_H -#define __ASM_MIPS_GPIO_H - -#include - -#endif /* __ASM_MIPS_GPIO_H */ diff --git a/arch/mips/include/asm/mach-ar7/ar7.h b/arch/mips/include/asm/mach-ar7/ar7.h index a47ea0c85248..468cbd61b906 100644 --- a/arch/mips/include/asm/mach-ar7/ar7.h +++ b/arch/mips/include/asm/mach-ar7/ar7.h @@ -203,4 +203,8 @@ static inline void ar7_device_off(u32 bit) int __init ar7_gpio_init(void); void __init ar7_init_clocks(void); +/* Board specific GPIO functions */ +int ar7_gpio_enable(unsigned gpio); +int ar7_gpio_disable(unsigned gpio); + #endif /* __AR7_H__ */ diff --git a/arch/mips/include/asm/mach-ar7/gpio.h b/arch/mips/include/asm/mach-ar7/gpio.h deleted file mode 100644 index c177cd1eed25..000000000000 --- a/arch/mips/include/asm/mach-ar7/gpio.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007-2009 Florian Fainelli - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __AR7_GPIO_H__ -#define __AR7_GPIO_H__ - -#include - -#define AR7_GPIO_MAX 32 -#define TITAN_GPIO_MAX 51 -#define NR_BUILTIN_GPIO TITAN_GPIO_MAX - -#define gpio_to_irq(gpio) -1 - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep - -/* Board specific GPIO functions */ -int ar7_gpio_enable(unsigned gpio); -int ar7_gpio_disable(unsigned gpio); - -#include - -#endif diff --git a/arch/mips/include/asm/mach-ath25/gpio.h b/arch/mips/include/asm/mach-ath25/gpio.h deleted file mode 100644 index 713564b8e8ef..000000000000 --- a/arch/mips/include/asm/mach-ath25/gpio.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __ASM_MACH_ATH25_GPIO_H -#define __ASM_MACH_ATH25_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#define gpio_to_irq __gpio_to_irq - -static inline int irq_to_gpio(unsigned irq) -{ - return -EINVAL; -} - -#endif /* __ASM_MACH_ATH25_GPIO_H */ diff --git a/arch/mips/include/asm/mach-ath79/gpio.h b/arch/mips/include/asm/mach-ath79/gpio.h deleted file mode 100644 index 60dcb62785b4..000000000000 --- a/arch/mips/include/asm/mach-ath79/gpio.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Atheros AR71XX/AR724X/AR913X GPIO API definitions - * - * Copyright (C) 2008-2010 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - */ - -#ifndef __ASM_MACH_ATH79_GPIO_H -#define __ASM_MACH_ATH79_GPIO_H - -#define ARCH_NR_GPIOS 64 -#include - -int gpio_to_irq(unsigned gpio); -int irq_to_gpio(unsigned irq); -int gpio_get_value(unsigned gpio); -void gpio_set_value(unsigned gpio, int value); - -#define gpio_cansleep __gpio_cansleep - -#endif /* __ASM_MACH_ATH79_GPIO_H */ diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h index 9785e4ebb450..adde1fa5097e 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h @@ -266,6 +266,17 @@ static inline int alchemy_gpio1_to_irq(int gpio) return -ENXIO; } +/* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before + * SYS_PININPUTEN is written to at least once. On Au1550/Au1200/Au1300 this + * register enables use of GPIOs as wake source. + */ +static inline void alchemy_gpio1_input_enable(void) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); + __raw_writel(0, base + 0x110); /* the write op is key */ + wmb(); +} + /* * GPIO2 block macros for common linux GPIO functions. The 'gpio' * parameter must be in range of ALCHEMY_GPIO2_BASE..ALCHEMY_GPIO2_MAX. @@ -518,141 +529,4 @@ static inline int alchemy_irq_to_gpio(int irq) return -ENXIO; } -/**********************************************************************/ - -/* Linux gpio framework integration. - * - * 4 use cases of Au1000-Au1200 GPIOS: - *(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y: - * Board must register gpiochips. - *(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n: - * 2 (1 for Au1000) gpio_chips are registered. - * - *(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y: - * the boards' gpio.h must provide the linux gpio wrapper functions, - * - *(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n: - * inlinable gpio functions are provided which enable access to the - * Au1000 gpios only by using the numbers straight out of the data- - * sheets. - - * Cases 1 and 3 are intended for boards which want to provide their own - * GPIO namespace and -operations (i.e. for example you have 8 GPIOs - * which are in part provided by spare Au1000 GPIO pins and in part by - * an external FPGA but you still want them to be accssible in linux - * as gpio0-7. The board can of course use the alchemy_gpioX_* functions - * as required). - */ - -#ifndef CONFIG_GPIOLIB - -#ifdef CONFIG_ALCHEMY_GPIOINT_AU1000 - -#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT /* case (4) */ - -static inline int gpio_direction_input(int gpio) -{ - return alchemy_gpio_direction_input(gpio); -} - -static inline int gpio_direction_output(int gpio, int v) -{ - return alchemy_gpio_direction_output(gpio, v); -} - -static inline int gpio_get_value(int gpio) -{ - return alchemy_gpio_get_value(gpio); -} - -static inline void gpio_set_value(int gpio, int v) -{ - alchemy_gpio_set_value(gpio, v); -} - -static inline int gpio_get_value_cansleep(unsigned gpio) -{ - return gpio_get_value(gpio); -} - -static inline void gpio_set_value_cansleep(unsigned gpio, int value) -{ - gpio_set_value(gpio, value); -} - -static inline int gpio_is_valid(int gpio) -{ - return alchemy_gpio_is_valid(gpio); -} - -static inline int gpio_cansleep(int gpio) -{ - return alchemy_gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(int gpio) -{ - return alchemy_gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(int irq) -{ - return alchemy_irq_to_gpio(irq); -} - -static inline int gpio_request(unsigned gpio, const char *label) -{ - return 0; -} - -static inline int gpio_request_one(unsigned gpio, - unsigned long flags, const char *label) -{ - return 0; -} - -static inline int gpio_request_array(struct gpio *array, size_t num) -{ - return 0; -} - -static inline void gpio_free(unsigned gpio) -{ -} - -static inline void gpio_free_array(struct gpio *array, size_t num) -{ -} - -static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) -{ - return -ENOSYS; -} - -static inline int gpio_export(unsigned gpio, bool direction_may_change) -{ - return -ENOSYS; -} - -static inline int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) -{ - return -ENOSYS; -} - -static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) -{ - return -ENOSYS; -} - -static inline void gpio_unexport(unsigned gpio) -{ -} - -#endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ - -#endif /* CONFIG_ALCHEMY_GPIOINT_AU1000 */ - -#endif /* !CONFIG_GPIOLIB */ - #endif /* _ALCHEMY_GPIO_AU1000_H_ */ diff --git a/arch/mips/include/asm/mach-au1x00/gpio.h b/arch/mips/include/asm/mach-au1x00/gpio.h deleted file mode 100644 index 22e7ff17fc48..000000000000 --- a/arch/mips/include/asm/mach-au1x00/gpio.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Alchemy GPIO support. - * - * With CONFIG_GPIOLIB=y different types of on-chip GPIO can be supported within - * the same kernel image. - * With CONFIG_GPIOLIB=n, your board must select ALCHEMY_GPIOINT_AU1XXX for the - * appropriate CPU type (AU1000 currently). - */ - -#ifndef _ALCHEMY_GPIO_H_ -#define _ALCHEMY_GPIO_H_ - -#include -#include -#include - -/* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before - * SYS_PININPUTEN is written to at least once. On Au1550/Au1200/Au1300 this - * register enables use of GPIOs as wake source. - */ -static inline void alchemy_gpio1_input_enable(void) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); - __raw_writel(0, base + 0x110); /* the write op is key */ - wmb(); -} - - -/* Linux gpio framework integration. -* -* 4 use cases of Alchemy GPIOS: -*(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y: -* Board must register gpiochips. -*(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n: -* A gpiochip for the 75 GPIOs is registered. -* -*(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y: -* the boards' gpio.h must provide the linux gpio wrapper functions, -* -*(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n: -* inlinable gpio functions are provided which enable access to the -* Au1300 gpios only by using the numbers straight out of the data- -* sheets. - -* Cases 1 and 3 are intended for boards which want to provide their own -* GPIO namespace and -operations (i.e. for example you have 8 GPIOs -* which are in part provided by spare Au1300 GPIO pins and in part by -* an external FPGA but you still want them to be accssible in linux -* as gpio0-7. The board can of course use the alchemy_gpioX_* functions -* as required). -*/ - -#ifdef CONFIG_GPIOLIB - -/* wraps the cpu-dependent irq_to_gpio functions */ -/* FIXME: gpiolib needs an irq_to_gpio hook */ -static inline int __au_irq_to_gpio(unsigned int irq) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000...ALCHEMY_CPU_AU1200: - return alchemy_irq_to_gpio(irq); - case ALCHEMY_CPU_AU1300: - return au1300_irq_to_gpio(irq); - } - return -EINVAL; -} - - -/* using gpiolib to provide up to 2 gpio_chips for on-chip gpios */ -#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT /* case (2) */ - -/* get everything through gpiolib */ -#define gpio_to_irq __gpio_to_irq -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#define irq_to_gpio __au_irq_to_gpio - -#include - -#endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ - - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ALCHEMY_GPIO_H_ */ diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h deleted file mode 100644 index 90daefa24a4d..000000000000 --- a/arch/mips/include/asm/mach-bcm47xx/gpio.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __ASM_MIPS_MACH_BCM47XX_GPIO_H -#define __ASM_MIPS_MACH_BCM47XX_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep -#define gpio_to_irq __gpio_to_irq - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif diff --git a/arch/mips/include/asm/mach-bcm63xx/gpio.h b/arch/mips/include/asm/mach-bcm63xx/gpio.h deleted file mode 100644 index 1eb534de8e3b..000000000000 --- a/arch/mips/include/asm/mach-bcm63xx/gpio.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __ASM_MIPS_MACH_BCM63XX_GPIO_H -#define __ASM_MIPS_MACH_BCM63XX_GPIO_H - -#include - -#define gpio_to_irq(gpio) -1 - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep - -#include - -#endif /* __ASM_MIPS_MACH_BCM63XX_GPIO_H */ diff --git a/arch/mips/include/asm/mach-cavium-octeon/gpio.h b/arch/mips/include/asm/mach-cavium-octeon/gpio.h deleted file mode 100644 index 34e9f7aabab4..000000000000 --- a/arch/mips/include/asm/mach-cavium-octeon/gpio.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __ASM_MACH_CAVIUM_OCTEON_GPIO_H -#define __ASM_MACH_CAVIUM_OCTEON_GPIO_H - -#ifdef CONFIG_GPIOLIB -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#else -int gpio_request(unsigned gpio, const char *label); -void gpio_free(unsigned gpio); -int gpio_direction_input(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); -int gpio_get_value(unsigned gpio); -void gpio_set_value(unsigned gpio, int value); -#endif - -#include - -#define gpio_to_irq __gpio_to_irq - -#endif /* __ASM_MACH_GENERIC_GPIO_H */ diff --git a/arch/mips/include/asm/mach-generic/gpio.h b/arch/mips/include/asm/mach-generic/gpio.h deleted file mode 100644 index b4e70208da64..000000000000 --- a/arch/mips/include/asm/mach-generic/gpio.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __ASM_MACH_GENERIC_GPIO_H -#define __ASM_MACH_GENERIC_GPIO_H - -#ifdef CONFIG_GPIOLIB -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#else -int gpio_request(unsigned gpio, const char *label); -void gpio_free(unsigned gpio); -int gpio_direction_input(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); -int gpio_get_value(unsigned gpio); -void gpio_set_value(unsigned gpio, int value); -#endif -int gpio_to_irq(unsigned gpio); -int irq_to_gpio(unsigned irq); - -#include /* cansleep wrappers */ - -#endif /* __ASM_MACH_GENERIC_GPIO_H */ diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h index eaacba79cf18..bf8c3e1860e7 100644 --- a/arch/mips/include/asm/mach-jz4740/gpio.h +++ b/arch/mips/include/asm/mach-jz4740/gpio.h @@ -73,8 +73,6 @@ int jz_gpio_port_direction_output(int port, uint32_t mask); void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask); uint32_t jz_gpio_port_get_value(int port, uint32_t mask); -#include - #define JZ_GPIO_PORTA(x) ((x) + 32 * 0) #define JZ_GPIO_PORTB(x) ((x) + 32 * 1) #define JZ_GPIO_PORTC(x) ((x) + 32 * 2) diff --git a/arch/mips/include/asm/mach-lantiq/gpio.h b/arch/mips/include/asm/mach-lantiq/gpio.h deleted file mode 100644 index 9ba1caebca5f..000000000000 --- a/arch/mips/include/asm/mach-lantiq/gpio.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __ASM_MIPS_MACH_LANTIQ_GPIO_H -#define __ASM_MIPS_MACH_LANTIQ_GPIO_H - -#define gpio_to_irq __gpio_to_irq - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep - -#include - -#endif diff --git a/arch/mips/include/asm/mach-loongson64/gpio.h b/arch/mips/include/asm/mach-loongson64/gpio.h deleted file mode 100644 index b3b216904a9a..000000000000 --- a/arch/mips/include/asm/mach-loongson64/gpio.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Loongson GPIO Support - * - * Copyright (c) 2008 Richard Liu, STMicroelectronics - * Copyright (c) 2008-2010 Arnaud Patard - * Copyright (c) 2014 Huacai Chen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __LOONGSON_GPIO_H -#define __LOONGSON_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep - -/* The chip can do interrupt - * but it has not been tested and doc not clear - */ -static inline int gpio_to_irq(int gpio) -{ - return -EINVAL; -} - -static inline int irq_to_gpio(int gpio) -{ - return -EINVAL; -} - -#endif /* __LOONGSON_GPIO_H */ diff --git a/arch/mips/include/asm/mach-pistachio/gpio.h b/arch/mips/include/asm/mach-pistachio/gpio.h deleted file mode 100644 index 6c1649c27b8d..000000000000 --- a/arch/mips/include/asm/mach-pistachio/gpio.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Pistachio IRQ setup - * - * Copyright (C) 2014 Google, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ - -#ifndef __ASM_MACH_PISTACHIO_GPIO_H -#define __ASM_MACH_PISTACHIO_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#define gpio_to_irq __gpio_to_irq - -#endif /* __ASM_MACH_PISTACHIO_GPIO_H */ diff --git a/arch/mips/include/asm/mach-rc32434/gpio.h b/arch/mips/include/asm/mach-rc32434/gpio.h index 4dee0a34250c..db211212ce79 100644 --- a/arch/mips/include/asm/mach-rc32434/gpio.h +++ b/arch/mips/include/asm/mach-rc32434/gpio.h @@ -13,18 +13,6 @@ #ifndef _RC32434_GPIO_H_ #define _RC32434_GPIO_H_ -#include -#include - -#define NR_BUILTIN_GPIO 32 - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep - -#define gpio_to_irq(gpio) (8 + 4 * 32 + gpio) -#define irq_to_gpio(irq) (irq - (8 + 4 * 32)) - struct rb532_gpio_reg { u32 gpiofunc; /* GPIO Function Register * gpiofunc[x]==0 bit = gpio diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c index 77df1602f818..6cd69fdaa1c5 100644 --- a/arch/mips/jz4740/gpio.c +++ b/arch/mips/jz4740/gpio.c @@ -231,6 +231,13 @@ static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) return 0; } +static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + struct jz_gpio_chip *jz_gpio = gpio_chip_to_jz_gpio_chip(chip); + + return jz_gpio->irq_base + gpio; +} + int jz_gpio_port_direction_input(int port, uint32_t mask) { writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR)); @@ -262,18 +269,6 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask) } EXPORT_SYMBOL(jz_gpio_port_get_value); -int gpio_to_irq(unsigned gpio) -{ - return JZ4740_IRQ_GPIO(0) + gpio; -} -EXPORT_SYMBOL_GPL(gpio_to_irq); - -int irq_to_gpio(unsigned irq) -{ - return irq - JZ4740_IRQ_GPIO(0); -} -EXPORT_SYMBOL_GPL(irq_to_gpio); - #define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f) static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq) @@ -403,6 +398,7 @@ static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on) .get = jz_gpio_get_value, \ .direction_output = jz_gpio_direction_output, \ .direction_input = jz_gpio_direction_input, \ + .to_irq = jz_gpio_to_irq, \ .base = JZ4740_GPIO_BASE_ ## _bank, \ .ngpio = JZ4740_GPIO_NUM_ ## _bank, \ }, \ diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index c5347d99cf3a..6a15dbd085aa 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -20,7 +20,6 @@ #include #include -#include #include #include diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index e31e8cdcb296..9bd7a2de0765 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index 5aa3df853082..650d5d39f34d 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c @@ -140,6 +140,11 @@ static int rb532_gpio_direction_output(struct gpio_chip *chip, return 0; } +static int rb532_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + return 8 + 4 * 32 + gpio; +} + static struct rb532_gpio_chip rb532_gpio_chip[] = { [0] = { .chip = { @@ -148,6 +153,7 @@ static struct rb532_gpio_chip rb532_gpio_chip[] = { .direction_output = rb532_gpio_direction_output, .get = rb532_gpio_get, .set = rb532_gpio_set, + .to_irq = rb532_gpio_to_irq, .base = 0, .ngpio = 32, }, diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 2791b8641df6..9d9962ab7d25 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -117,22 +117,6 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); -/* GPIO support */ - -#ifdef CONFIG_GPIOLIB -int gpio_to_irq(unsigned gpio) -{ - return -EINVAL; -} -EXPORT_SYMBOL(gpio_to_irq); - -int irq_to_gpio(unsigned irq) -{ - return -EINVAL; -} -EXPORT_SYMBOL(irq_to_gpio); -#endif - #define BOARD_VEC(board) extern struct txx9_board_vec board; #include #undef BOARD_VEC diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 6d08446b877c..12fe0f3bb7e9 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -27,12 +27,11 @@ #include #include #include +#include #include #include -#include - #define DRV_NAME "pata-rb532-cf" #define DRV_VERSION "0.1.0" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index c3c92eb56e04..03b995304ad6 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -202,35 +202,3 @@ static struct platform_driver ath79_gpio_driver = { }; module_platform_driver(ath79_gpio_driver); - -int gpio_get_value(unsigned gpio) -{ - if (gpio < ath79_gpio_count) - return __ath79_gpio_get_value(gpio); - - return __gpio_get_value(gpio); -} -EXPORT_SYMBOL(gpio_get_value); - -void gpio_set_value(unsigned gpio, int value) -{ - if (gpio < ath79_gpio_count) - __ath79_gpio_set_value(gpio, value); - else - __gpio_set_value(gpio, value); -} -EXPORT_SYMBOL(gpio_set_value); - -int gpio_to_irq(unsigned gpio) -{ - /* FIXME */ - return -EINVAL; -} -EXPORT_SYMBOL(gpio_to_irq); - -int irq_to_gpio(unsigned irq) -{ - /* FIXME */ - return -EINVAL; -} -EXPORT_SYMBOL(irq_to_gpio); diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index e956e81cd4e6..62c5814c796b 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index dd9430043536..cba3d9fcb465 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -41,6 +41,8 @@ #include #include +#include + MODULE_AUTHOR("Eugene Konev "); MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 325f0a1833c41d2d399fda161866923b72592cc9 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Sat, 1 Aug 2015 17:44:20 +0530 Subject: MIPS: Netlogic: Use chip_data for irq_chip methods Update mips/netlogic/common/irq.c and mips/pci/msi-xlp.c to use chip_data to store interrupt controller data pointer. It uses handler_data now, and that causes errors when an API (like the GPIO subsystem) tries to use the handler data. Signed-off-by: Kamlakant Patel Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10817/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/common/irq.c | 12 ++++++------ arch/mips/pci/msi-xlp.c | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 5f5d18b0e94d..3660dc67d544 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -87,7 +87,7 @@ struct nlm_pic_irq { static void xlp_pic_enable(struct irq_data *d) { unsigned long flags; - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); BUG_ON(!pd); spin_lock_irqsave(&pd->node->piclock, flags); @@ -97,7 +97,7 @@ static void xlp_pic_enable(struct irq_data *d) static void xlp_pic_disable(struct irq_data *d) { - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); unsigned long flags; BUG_ON(!pd); @@ -108,7 +108,7 @@ static void xlp_pic_disable(struct irq_data *d) static void xlp_pic_mask_ack(struct irq_data *d) { - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); clear_c0_eimr(pd->picirq); ack_c0_eirr(pd->picirq); @@ -116,7 +116,7 @@ static void xlp_pic_mask_ack(struct irq_data *d) static void xlp_pic_unmask(struct irq_data *d) { - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); BUG_ON(!pd); @@ -193,7 +193,7 @@ void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) pic_data->picirq = picirq; pic_data->node = nlm_get_node(node); irq_set_chip_and_handler(xirq, &xlp_pic, handle_level_irq); - irq_set_handler_data(xirq, pic_data); + irq_set_chip_data(xirq, pic_data); } void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) @@ -202,7 +202,7 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) int xirq; xirq = nlm_irq_to_xirq(node, irq); - pic_data = irq_get_handler_data(xirq); + pic_data = irq_get_chip_data(xirq); if (WARN_ON(!pic_data)) return; pic_data->extra_ack = xack; diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c index 3407495fcbe2..bb14335f804b 100644 --- a/arch/mips/pci/msi-xlp.c +++ b/arch/mips/pci/msi-xlp.c @@ -131,7 +131,7 @@ struct xlp_msi_data { */ static void xlp_msi_enable(struct irq_data *d) { - struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); unsigned long flags; int vec; @@ -148,7 +148,7 @@ static void xlp_msi_enable(struct irq_data *d) static void xlp_msi_disable(struct irq_data *d) { - struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); unsigned long flags; int vec; @@ -165,7 +165,7 @@ static void xlp_msi_disable(struct irq_data *d) static void xlp_msi_mask_ack(struct irq_data *d) { - struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); int link, vec; link = nlm_irq_msilink(d->irq); @@ -211,7 +211,7 @@ static void xlp_msix_mask_ack(struct irq_data *d) msixvec = nlm_irq_msixvec(d->irq); link = nlm_irq_msixlink(msixvec); pci_msi_mask_irq(d); - md = irq_data_get_irq_handler_data(d); + md = irq_data_get_irq_chip_data(d); /* Ack MSI on bridge */ if (cpu_is_xlp9xx()) { @@ -302,7 +302,7 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link, /* Get MSI data for the link */ lirq = PIC_PCIE_LINK_MSI_IRQ(link); xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); - md = irq_get_handler_data(xirq); + md = irq_get_chip_data(xirq); msiaddr = MSI_LINK_ADDR(node, link); spin_lock_irqsave(&md->msi_lock, flags); @@ -409,7 +409,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link, /* Get MSI data for the link */ lirq = PIC_PCIE_MSIX_IRQ(link); xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); - md = irq_get_handler_data(xirq); + md = irq_get_chip_data(xirq); msixaddr = MSIX_LINK_ADDR(node, link); spin_lock_irqsave(&md->msi_lock, flags); @@ -485,7 +485,7 @@ void __init xlp_init_node_msi_irqs(int node, int link) irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq); - irq_set_handler_data(i, md); + irq_set_chip_data(i, md); } for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) { @@ -508,7 +508,7 @@ void __init xlp_init_node_msi_irqs(int node, int link) /* Initialize MSI-X extended irq space for the link */ irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); - irq_set_handler_data(irq, md); + irq_set_chip_data(irq, md); } } @@ -520,7 +520,7 @@ void nlm_dispatch_msi(int node, int lirq) link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); - md = irq_get_handler_data(irqbase); + md = irq_get_chip_data(irqbase); if (cpu_is_xlp9xx()) status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & md->msi_enabled_mask; @@ -550,7 +550,7 @@ void nlm_dispatch_msix(int node, int lirq) link = lirq - PIC_PCIE_MSIX_IRQ_BASE; irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); - md = irq_get_handler_data(irqbase); + md = irq_get_chip_data(irqbase); if (cpu_is_xlp9xx()) status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); else -- cgit v1.2.3-59-g8ed1b From a8a747764a970fc4c4f39f554c7dc08a4ca67db8 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Sat, 1 Aug 2015 17:44:21 +0530 Subject: MIPS: Netlogic: add device tree entry for XLP GPIO Add GPIO entries to the Netlogic XLP device tree files. Signed-off-by: Kamlakant Patel Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10819/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/netlogic/xlp_evp.dts | 12 ++++++++++++ arch/mips/boot/dts/netlogic/xlp_fvp.dts | 12 ++++++++++++ arch/mips/boot/dts/netlogic/xlp_gvp.dts | 11 +++++++++++ arch/mips/boot/dts/netlogic/xlp_rvp.dts | 11 +++++++++++ arch/mips/boot/dts/netlogic/xlp_svp.dts | 12 ++++++++++++ 5 files changed, 58 insertions(+) diff --git a/arch/mips/boot/dts/netlogic/xlp_evp.dts b/arch/mips/boot/dts/netlogic/xlp_evp.dts index 89ad04808c02..ec16ec2d8d02 100644 --- a/arch/mips/boot/dts/netlogic/xlp_evp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_evp.dts @@ -110,6 +110,18 @@ read-only; }; }; + + gpio: xlp_gpio@34100 { + compatible = "netlogic,xlp832-gpio"; + reg = <0 0x34100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_fvp.dts b/arch/mips/boot/dts/netlogic/xlp_fvp.dts index 63e62b7bd758..4bcebe641d8e 100644 --- a/arch/mips/boot/dts/netlogic/xlp_fvp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_fvp.dts @@ -110,6 +110,18 @@ read-only; }; }; + + gpio: xlp_gpio@34100 { + compatible = "netlogic,xlp208-gpio"; + reg = <0 0x34100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_gvp.dts b/arch/mips/boot/dts/netlogic/xlp_gvp.dts index bb4ecd1d47fc..b3ccb82ad7e4 100644 --- a/arch/mips/boot/dts/netlogic/xlp_gvp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_gvp.dts @@ -69,6 +69,17 @@ }; }; + gpio: xlp_gpio@114100 { + compatible = "netlogic,xlp980-gpio"; + reg = <0 0x114100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_rvp.dts b/arch/mips/boot/dts/netlogic/xlp_rvp.dts index 7188aed2ea2e..3783639a318a 100644 --- a/arch/mips/boot/dts/netlogic/xlp_rvp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_rvp.dts @@ -69,6 +69,17 @@ }; }; + gpio: xlp_gpio@114100 { + compatible = "netlogic,xlp532-gpio"; + reg = <0 0x114100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_svp.dts b/arch/mips/boot/dts/netlogic/xlp_svp.dts index 1ebd00edaacc..44d6640c1441 100644 --- a/arch/mips/boot/dts/netlogic/xlp_svp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_svp.dts @@ -110,6 +110,18 @@ read-only; }; }; + + gpio: xlp_gpio@34100 { + compatible = "netlogic,xlp316-gpio"; + reg = <0 0x34100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { -- cgit v1.2.3-59-g8ed1b From 079e31600786b1ef8cab15ac6345605ad9150daf Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Sat, 1 Aug 2015 17:44:22 +0530 Subject: MIPS: Netlogic: set ARCH_REQUIRE_GPIOLIB for XLP platform This is needed to enable GPIO framework support for Netlogic XLP platform. Signed-off-by: Kamlakant Patel Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10818/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 06c5957917d3..7e182424f119 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -898,6 +898,7 @@ config NLM_XLP_BOARD select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select ARCH_PHYS_ADDR_T_64BIT + select ARCH_REQUIRE_GPIOLIB select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_HIGHMEM -- cgit v1.2.3-59-g8ed1b From 8c576912e4708144cbaa28228cc910746f39bafd Mon Sep 17 00:00:00 2001 From: Subhendu Sekhar Behera Date: Sat, 1 Aug 2015 17:44:23 +0530 Subject: MIPS: Netlogic: NAND IRQ mapping Add NAND IRQ mapping for XLP9xx processor. Signed-off-by: Subhendu Sekhar Behera Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10820/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/xlp/nlm_hal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index a8f4144a0297..80ec929747c3 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -91,6 +91,8 @@ static int xlp9xx_irq_to_irt(int irq) return 134; case PIC_SATA_IRQ: return 143; + case PIC_NAND_IRQ: + return 151; case PIC_SPI_IRQ: return 152; case PIC_MMC_IRQ: -- cgit v1.2.3-59-g8ed1b From e3b28831c18c6c95c51b6bb717fa116d2b658ba9 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 28 Jul 2015 20:37:43 +0200 Subject: MIPS: Set trap_no field in thread_struct on exception. This reverts commit 7281cd22973008a782860e48ed8d85d00204168c and adds actual functionality to use the field. --- arch/mips/include/asm/processor.h | 2 ++ arch/mips/kernel/asm-offsets.c | 1 + arch/mips/kernel/traps.c | 28 ++++++++++++++-------------- arch/mips/mm/fault.c | 8 ++++---- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 9b3b48e21c22..59ee6dcf6eed 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -275,6 +275,7 @@ struct thread_struct { unsigned long cp0_badvaddr; /* Last user fault */ unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ unsigned long error_code; + unsigned long trap_nr; #ifdef CONFIG_CPU_CAVIUM_OCTEON struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); @@ -341,6 +342,7 @@ struct thread_struct { .cp0_badvaddr = 0, \ .cp0_baduaddr = 0, \ .error_code = 0, \ + .trap_nr = 0, \ /* \ * Platform specific cop2 registers(null if no COP2) \ */ \ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 3706091b6351..154e2039ea5e 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -128,6 +128,7 @@ void output_thread_defines(void) thread.cp0_baduaddr); OFFSET(THREAD_ECODE, task_struct, \ thread.error_code); + OFFSET(THREAD_TRAPNO, task_struct, thread.trap_nr); BLANK(); } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index da0b3189fe88..cea964daf400 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -370,11 +370,6 @@ void show_registers(struct pt_regs *regs) set_fs(old_fs); } -static int regs_to_trapnr(struct pt_regs *regs) -{ - return (regs->cp0_cause >> 2) & 0x1f; -} - static DEFINE_RAW_SPINLOCK(die_lock); void __noreturn die(const char *str, struct pt_regs *regs) @@ -384,7 +379,7 @@ void __noreturn die(const char *str, struct pt_regs *regs) oops_enter(); - if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) sig = 0; @@ -470,7 +465,7 @@ asmlinkage void do_be(struct pt_regs *regs) printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", data ? "Data" : "Instruction", field, regs->cp0_epc, field, regs->regs[31]); - if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_OOPS, "bus error", regs, 0, current->thread.trap_nr, SIGBUS) == NOTIFY_STOP) goto out; @@ -826,7 +821,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) int sig; prev_state = exception_enter(); - if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_FP, "FP exception", regs, 0, current->thread.trap_nr, SIGFPE) == NOTIFY_STOP) goto out; @@ -882,11 +877,12 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code, char b[40]; #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP - if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) + if (kgdb_ll_trap(DIE_TRAP, str, regs, code, current->thread.trap_nr, + SIGTRAP) == NOTIFY_STOP) return; #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ - if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), + if (notify_die(DIE_TRAP, str, regs, code, current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) return; @@ -948,6 +944,7 @@ asmlinkage void do_bp(struct pt_regs *regs) set_fs(KERNEL_DS); prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; if (get_isa16_mode(regs->cp0_epc)) { u16 instr[2]; @@ -989,13 +986,13 @@ asmlinkage void do_bp(struct pt_regs *regs) switch (bcode) { case BRK_KPROBE_BP: if (notify_die(DIE_BREAK, "debug", regs, bcode, - regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) goto out; else break; case BRK_KPROBE_SSTEPBP: if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, - regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) goto out; else break; @@ -1028,6 +1025,7 @@ asmlinkage void do_tr(struct pt_regs *regs) set_fs(get_ds()); prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; if (get_isa16_mode(regs->cp0_epc)) { if (__get_user(instr[0], (u16 __user *)(epc + 0)) || __get_user(instr[1], (u16 __user *)(epc + 2))) @@ -1094,8 +1092,9 @@ asmlinkage void do_ri(struct pt_regs *regs) no_r2_instr: prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; - if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_RI, "RI Fault", regs, 0, current->thread.trap_nr, SIGILL) == NOTIFY_STOP) goto out; @@ -1444,8 +1443,9 @@ asmlinkage void do_msa_fpe(struct pt_regs *regs, unsigned int msacsr) enum ctx_state prev_state; prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; if (notify_die(DIE_MSAFP, "MSA FP exception", regs, 0, - regs_to_trapnr(regs), SIGFPE) == NOTIFY_STOP) + current->thread.trap_nr, SIGFPE) == NOTIFY_STOP) goto out; /* Clear MSACSR.Cause before enabling interrupts */ diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 852a41c6da45..4b88fa031891 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -57,12 +57,10 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write, #ifdef CONFIG_KPROBES /* - * This is to notify the fault handler of the kprobes. The - * exception code is redundant as it is also carried in REGS, - * but we pass it anyhow. + * This is to notify the fault handler of the kprobes. */ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, - (regs->cp0_cause >> 2) & 0x1f, SIGSEGV) == NOTIFY_STOP) + current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) return; #endif @@ -224,6 +222,7 @@ bad_area_nosemaphore: print_vma_addr(" ", regs->regs[31]); pr_info("\n"); } + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; info.si_signo = SIGSEGV; info.si_errno = 0; /* info.si_code has been set above */ @@ -282,6 +281,7 @@ do_sigbus: field, (unsigned long) regs->cp0_epc, field, (unsigned long) regs->regs[31]); #endif + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; tsk->thread.cp0_badvaddr = address; info.si_signo = SIGBUS; info.si_errno = 0; -- cgit v1.2.3-59-g8ed1b From 40e084a506eba78310cd5e8ab700fd1226c6130a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 29 Jul 2015 22:44:53 +0200 Subject: MIPS: Add uprobes support. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 + arch/mips/include/asm/kdebug.h | 4 +- arch/mips/include/asm/ptrace.h | 80 +++++++++ arch/mips/include/asm/thread_info.h | 5 +- arch/mips/include/asm/uprobes.h | 58 ++++++ arch/mips/include/uapi/asm/break.h | 2 + arch/mips/kernel/Makefile | 1 + arch/mips/kernel/ptrace.c | 88 ++++++++++ arch/mips/kernel/signal.c | 4 + arch/mips/kernel/traps.c | 12 ++ arch/mips/kernel/uprobes.c | 341 ++++++++++++++++++++++++++++++++++++ 11 files changed, 597 insertions(+), 2 deletions(-) create mode 100644 arch/mips/include/asm/uprobes.h create mode 100644 arch/mips/kernel/uprobes.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7e182424f119..7a9a2554fa00 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1,6 +1,7 @@ config MIPS bool default y + select ARCH_SUPPORTS_UPROBES select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select ARCH_USE_CMPXCHG_LOCKREF if 64BIT @@ -1041,6 +1042,9 @@ config FW_CFE config ARCH_DMA_ADDR_T_64BIT def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT +config ARCH_SUPPORTS_UPROBES + bool + config DMA_MAYBE_COHERENT select DMA_NONCOHERENT bool diff --git a/arch/mips/include/asm/kdebug.h b/arch/mips/include/asm/kdebug.h index cba22ab7ad4d..8e3d08e739c1 100644 --- a/arch/mips/include/asm/kdebug.h +++ b/arch/mips/include/asm/kdebug.h @@ -11,7 +11,9 @@ enum die_val { DIE_PAGE_FAULT, DIE_BREAK, DIE_SSTEPBP, - DIE_MSAFP + DIE_MSAFP, + DIE_UPROBE, + DIE_UPROBE_XOL, }; #endif /* _ASM_MIPS_KDEBUG_H */ diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index ffc320389f40..f6fc6aac5496 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -14,11 +14,16 @@ #include #include #include +#include +#include #include /* * This struct defines the way the registers are stored on the stack during a * system call/exception. As usual the registers k0/k1 aren't being saved. + * + * If you add a register here, also add it to regoffset_table[] in + * arch/mips/kernel/ptrace.c. */ struct pt_regs { #ifdef CONFIG_32BIT @@ -43,8 +48,83 @@ struct pt_regs { unsigned long long mpl[6]; /* MTM{0-5} */ unsigned long long mtp[6]; /* MTP{0-5} */ #endif + unsigned long __last[0]; } __aligned(8); +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + return regs->regs[31]; +} + +/* + * Don't use asm-generic/ptrace.h it defines FP accessors that don't make + * sense on MIPS. We rather want an error if they get invoked. + */ + +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + regs->cp0_epc = val; +} + +/* Query offset/name of register from its name/offset */ +extern int regs_query_register_offset(const char *name); +#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) + +/** + * regs_get_register() - get register value from its offset + * @regs: pt_regs from which register value is gotten. + * @offset: offset number of the register. + * + * regs_get_register returns the value of a register. The @offset is the + * offset of the register in struct pt_regs address which specified by @regs. + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. + */ +static inline unsigned long regs_get_register(struct pt_regs *regs, + unsigned int offset) +{ + if (unlikely(offset > MAX_REG_OFFSET)) + return 0; + + return *(unsigned long *)((unsigned long)regs + offset); +} + +/** + * regs_within_kernel_stack() - check the address in the stack + * @regs: pt_regs which contains kernel stack pointer. + * @addr: address which is checked. + * + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). + * If @addr is within the kernel stack, it returns true. If not, returns false. + */ +static inline int regs_within_kernel_stack(struct pt_regs *regs, + unsigned long addr) +{ + return ((addr & ~(THREAD_SIZE - 1)) == + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs: pt_regs which contains kernel stack pointer. + * @n: stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + unsigned int n) +{ + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); + + addr += n; + if (regs_within_kernel_stack(regs, (unsigned long)addr)) + return *addr; + else + return 0; +} + struct task_struct; extern int ptrace_getregs(struct task_struct *child, diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 9c0014e87c17..e309d8fcb516 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -99,6 +99,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ #define TIF_SECCOMP 4 /* secure computing */ #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ +#define TIF_UPROBE 6 /* breakpointed or singlestepping */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ @@ -122,6 +123,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_AUDIT (1< +#include + +#include +#include + +/* + * We want this to be defined as union mips_instruction but that makes the + * generic code blow up. + */ +typedef u32 uprobe_opcode_t; + +/* + * Classic MIPS (note this implementation doesn't consider microMIPS yet) + * instructions are always 4 bytes but in order to deal with branches and + * their delay slots, we treat instructions as having 8 bytes maximum. + */ +#define MAX_UINSN_BYTES 8 +#define UPROBE_XOL_SLOT_BYTES 128 /* Max. cache line size */ + +#define UPROBE_BRK_UPROBE 0x000d000d /* break 13 */ +#define UPROBE_BRK_UPROBE_XOL 0x000e000d /* break 14 */ + +#define UPROBE_SWBP_INSN UPROBE_BRK_UPROBE +#define UPROBE_SWBP_INSN_SIZE 4 + +struct arch_uprobe { + unsigned long resume_epc; + u32 insn[2]; + u32 ixol[2]; + union mips_instruction orig_inst[MAX_UINSN_BYTES / 4]; +}; + +struct arch_uprobe_task { + unsigned long saved_trap_nr; +}; + +extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, + struct mm_struct *mm, unsigned long addr); +extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); +extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); +extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); +extern int arch_uprobe_exception_notify(struct notifier_block *self, + unsigned long val, void *data); +extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, + struct pt_regs *regs); +extern unsigned long arch_uretprobe_hijack_return_addr( + unsigned long trampoline_vaddr, struct pt_regs *regs); + +#endif /* __ASM_UPROBES_H */ diff --git a/arch/mips/include/uapi/asm/break.h b/arch/mips/include/uapi/asm/break.h index 002c39ea20c3..9c4265cbf151 100644 --- a/arch/mips/include/uapi/asm/break.h +++ b/arch/mips/include/uapi/asm/break.h @@ -21,6 +21,8 @@ #define BRK_DIVZERO 7 /* Divide by zero check */ #define BRK_RANGE 8 /* Range error check */ #define BRK_BUG 12 /* Used by BUG() */ +#define BRK_UPROBE 13 /* See */ +#define BRK_UPROBE_XOL 14 /* See */ #define BRK_MEMU 514 /* Used by FPU emulator */ #define BRK_KPROBE_BP 515 /* Kprobe break */ #define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 3f5cf8aff6f3..a61435b1ceb1 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o +obj-$(CONFIG_UPROBES) += uprobes.o obj-$(CONFIG_MIPS_CM) += mips-cm.o obj-$(CONFIG_MIPS_CPC) += mips-cpc.o diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index e933a309f2ea..4f0ac78d17f1 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -490,6 +491,93 @@ enum mips_regset { REGSET_FPR, }; +struct pt_regs_offset { + const char *name; + int offset; +}; + +#define REG_OFFSET_NAME(reg, r) { \ + .name = #reg, \ + .offset = offsetof(struct pt_regs, r) \ +} + +#define REG_OFFSET_END { \ + .name = NULL, \ + .offset = 0 \ +} + +static const struct pt_regs_offset regoffset_table[] = { + REG_OFFSET_NAME(r0, regs[0]), + REG_OFFSET_NAME(r1, regs[1]), + REG_OFFSET_NAME(r2, regs[2]), + REG_OFFSET_NAME(r3, regs[3]), + REG_OFFSET_NAME(r4, regs[4]), + REG_OFFSET_NAME(r5, regs[5]), + REG_OFFSET_NAME(r6, regs[6]), + REG_OFFSET_NAME(r7, regs[7]), + REG_OFFSET_NAME(r8, regs[8]), + REG_OFFSET_NAME(r9, regs[9]), + REG_OFFSET_NAME(r10, regs[10]), + REG_OFFSET_NAME(r11, regs[11]), + REG_OFFSET_NAME(r12, regs[12]), + REG_OFFSET_NAME(r13, regs[13]), + REG_OFFSET_NAME(r14, regs[14]), + REG_OFFSET_NAME(r15, regs[15]), + REG_OFFSET_NAME(r16, regs[16]), + REG_OFFSET_NAME(r17, regs[17]), + REG_OFFSET_NAME(r18, regs[18]), + REG_OFFSET_NAME(r19, regs[19]), + REG_OFFSET_NAME(r20, regs[20]), + REG_OFFSET_NAME(r21, regs[21]), + REG_OFFSET_NAME(r22, regs[22]), + REG_OFFSET_NAME(r23, regs[23]), + REG_OFFSET_NAME(r24, regs[24]), + REG_OFFSET_NAME(r25, regs[25]), + REG_OFFSET_NAME(r26, regs[26]), + REG_OFFSET_NAME(r27, regs[27]), + REG_OFFSET_NAME(r28, regs[28]), + REG_OFFSET_NAME(r29, regs[29]), + REG_OFFSET_NAME(r30, regs[30]), + REG_OFFSET_NAME(r31, regs[31]), + REG_OFFSET_NAME(c0_status, cp0_status), + REG_OFFSET_NAME(hi, hi), + REG_OFFSET_NAME(lo, lo), +#ifdef CONFIG_CPU_HAS_SMARTMIPS + REG_OFFSET_NAME(acx, acx), +#endif + REG_OFFSET_NAME(c0_badvaddr, cp0_badvaddr), + REG_OFFSET_NAME(c0_cause, cp0_cause), + REG_OFFSET_NAME(c0_epc, cp0_epc), +#ifdef CONFIG_MIPS_MT_SMTC + REG_OFFSET_NAME(c0_tcstatus, cp0_tcstatus), +#endif +#ifdef CONFIG_CPU_CAVIUM_OCTEON + REG_OFFSET_NAME(mpl0, mpl[0]), + REG_OFFSET_NAME(mpl1, mpl[1]), + REG_OFFSET_NAME(mpl2, mpl[2]), + REG_OFFSET_NAME(mtp0, mtp[0]), + REG_OFFSET_NAME(mtp1, mtp[1]), + REG_OFFSET_NAME(mtp2, mtp[2]), +#endif + REG_OFFSET_END, +}; + +/** + * regs_query_register_offset() - query register offset from its name + * @name: the name of a register + * + * regs_query_register_offset() returns the offset of a register in struct + * pt_regs from its name. If the name is invalid, this returns -EINVAL; + */ +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_offset *roff; + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + return -EINVAL; +} + #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) static const struct user_regset mips_regsets[] = { diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index fa13a52713df..2fec67bfc457 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -856,6 +857,9 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, user_exit(); + if (thread_info_flags & _TIF_UPROBE) + uprobe_notify_resume(regs); + /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index cea964daf400..fdb392b27e81 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -984,6 +984,18 @@ asmlinkage void do_bp(struct pt_regs *regs) * pertain to them. */ switch (bcode) { + case BRK_UPROBE: + if (notify_die(DIE_UPROBE, "uprobe", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; + case BRK_UPROBE_XOL: + if (notify_die(DIE_UPROBE_XOL, "uprobe_xol", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; case BRK_KPROBE_BP: if (notify_die(DIE_BREAK, "debug", regs, bcode, current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c new file mode 100644 index 000000000000..8452d933a645 --- /dev/null +++ b/arch/mips/kernel/uprobes.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static inline int insn_has_delay_slot(const union mips_instruction insn) +{ + switch (insn.i_format.opcode) { + /* + * jr and jalr are in r_format format. + */ + case spec_op: + switch (insn.r_format.func) { + case jalr_op: + case jr_op: + return 1; + } + break; + + /* + * This group contains: + * bltz_op, bgez_op, bltzl_op, bgezl_op, + * bltzal_op, bgezal_op, bltzall_op, bgezall_op. + */ + case bcond_op: + switch (insn.i_format.rt) { + case bltz_op: + case bltzl_op: + case bgez_op: + case bgezl_op: + case bltzal_op: + case bltzall_op: + case bgezal_op: + case bgezall_op: + case bposge32_op: + return 1; + } + break; + + /* + * These are unconditional and in j_format. + */ + case jal_op: + case j_op: + case beq_op: + case beql_op: + case bne_op: + case bnel_op: + case blez_op: /* not really i_format */ + case blezl_op: + case bgtz_op: + case bgtzl_op: + return 1; + + /* + * And now the FPA/cp1 branch instructions. + */ + case cop1_op: +#ifdef CONFIG_CPU_CAVIUM_OCTEON + case lwc2_op: /* This is bbit0 on Octeon */ + case ldc2_op: /* This is bbit032 on Octeon */ + case swc2_op: /* This is bbit1 on Octeon */ + case sdc2_op: /* This is bbit132 on Octeon */ +#endif + return 1; + } + + return 0; +} + +/** + * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. + * @mm: the probed address space. + * @arch_uprobe: the probepoint information. + * @addr: virtual address at which to install the probepoint + * Return 0 on success or a -ve number on error. + */ +int arch_uprobe_analyze_insn(struct arch_uprobe *aup, + struct mm_struct *mm, unsigned long addr) +{ + union mips_instruction inst; + + /* + * For the time being this also blocks attempts to use uprobes with + * MIPS16 and microMIPS. + */ + if (addr & 0x03) + return -EINVAL; + + inst.word = aup->insn[0]; + aup->ixol[0] = aup->insn[insn_has_delay_slot(inst)]; + aup->ixol[1] = UPROBE_BRK_UPROBE_XOL; /* NOP */ + + return 0; +} + +/** + * is_trap_insn - check if the instruction is a trap variant + * @insn: instruction to be checked. + * Returns true if @insn is a trap variant. + * + * This definition overrides the weak definition in kernel/events/uprobes.c. + * and is needed for the case where an architecture has multiple trap + * instructions (like PowerPC or MIPS). We treat BREAK just like the more + * modern conditional trap instructions. + */ +bool is_trap_insn(uprobe_opcode_t *insn) +{ + union mips_instruction inst; + + inst.word = *insn; + + switch (inst.i_format.opcode) { + case spec_op: + switch (inst.r_format.func) { + case break_op: + case teq_op: + case tge_op: + case tgeu_op: + case tlt_op: + case tltu_op: + case tne_op: + return 1; + } + break; + + case bcond_op: /* Yes, really ... */ + switch (inst.u_format.rt) { + case teqi_op: + case tgei_op: + case tgeiu_op: + case tlti_op: + case tltiu_op: + case tnei_op: + return 1; + } + break; + } + + return 0; +} + +#define UPROBE_TRAP_NR ULONG_MAX + +/* + * arch_uprobe_pre_xol - prepare to execute out of line. + * @auprobe: the probepoint information. + * @regs: reflects the saved user state of current task. + */ +int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + union mips_instruction insn; + + /* + * Now find the EPC where to resume after the breakpoint has been + * dealt with. This may require emulation of a branch. + */ + aup->resume_epc = regs->cp0_epc + 4; + if (insn_has_delay_slot((union mips_instruction) aup->insn[0])) { + unsigned long epc; + + epc = regs->cp0_epc; + __compute_return_epc_for_insn(regs, insn); + aup->resume_epc = regs->cp0_epc; + } + + utask->autask.saved_trap_nr = current->thread.trap_nr; + current->thread.trap_nr = UPROBE_TRAP_NR; + regs->cp0_epc = current->utask->xol_vaddr; + + return 0; +} + +int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + current->thread.trap_nr = utask->autask.saved_trap_nr; + regs->cp0_epc = aup->resume_epc; + + return 0; +} + +/* + * If xol insn itself traps and generates a signal(Say, + * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped + * instruction jumps back to its own address. It is assumed that anything + * like do_page_fault/do_trap/etc sets thread.trap_nr != -1. + * + * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr, + * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to + * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol(). + */ +bool arch_uprobe_xol_was_trapped(struct task_struct *tsk) +{ + if (tsk->thread.trap_nr != UPROBE_TRAP_NR) + return true; + + return false; +} + +int arch_uprobe_exception_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct die_args *args = data; + struct pt_regs *regs = args->regs; + + /* regs == NULL is a kernel bug */ + if (WARN_ON(!regs)) + return NOTIFY_DONE; + + /* We are only interested in userspace traps */ + if (!user_mode(regs)) + return NOTIFY_DONE; + + switch (val) { + case DIE_BREAK: + if (uprobe_pre_sstep_notifier(regs)) + return NOTIFY_STOP; + break; + case DIE_UPROBE_XOL: + if (uprobe_post_sstep_notifier(regs)) + return NOTIFY_STOP; + default: + break; + } + + return 0; +} + +/* + * This function gets called when XOL instruction either gets trapped or + * the thread has a fatal signal. Reset the instruction pointer to its + * probed address for the potential restart or for post mortem analysis. + */ +void arch_uprobe_abort_xol(struct arch_uprobe *aup, + struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + instruction_pointer_set(regs, utask->vaddr); +} + +unsigned long arch_uretprobe_hijack_return_addr( + unsigned long trampoline_vaddr, struct pt_regs *regs) +{ + unsigned long ra; + + ra = regs->regs[31]; + + /* Replace the return address with the trampoline address */ + regs->regs[31] = ra; + + return ra; +} + +/** + * set_swbp - store breakpoint at a given address. + * @auprobe: arch specific probepoint information. + * @mm: the probed process address space. + * @vaddr: the virtual address to insert the opcode. + * + * For mm @mm, store the breakpoint instruction at @vaddr. + * Return 0 (success) or a negative errno. + * + * This version overrides the weak version in kernel/events/uprobes.c. + * It is required to handle MIPS16 and microMIPS. + */ +int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long vaddr) +{ + return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN); +} + +/** + * set_orig_insn - Restore the original instruction. + * @mm: the probed process address space. + * @auprobe: arch specific probepoint information. + * @vaddr: the virtual address to insert the opcode. + * + * For mm @mm, restore the original opcode (opcode) at @vaddr. + * Return 0 (success) or a negative errno. + * + * This overrides the weak version in kernel/events/uprobes.c. + */ +int set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long vaddr) +{ + return uprobe_write_opcode(mm, vaddr, + *(uprobe_opcode_t *)&auprobe->orig_inst[0].word); +} + +void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, + void *src, unsigned long len) +{ + void *kaddr; + + /* Initialize the slot */ + kaddr = kmap_atomic(page); + memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len); + kunmap_atomic(kaddr); + + /* + * The MIPS version of flush_icache_range will operate safely on + * user space addresses and more importantly, it doesn't require a + * VMA argument. + */ + flush_icache_range(vaddr, vaddr + len); +} + +/** + * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs + * @regs: Reflects the saved state of the task after it has hit a breakpoint + * instruction. + * Return the address of the breakpoint instruction. + * + * This overrides the weak version in kernel/events/uprobes.c. + */ +unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) +{ + return instruction_pointer(regs); +} + +/* + * See if the instruction can be emulated. + * Returns true if instruction was emulated, false otherwise. + * + * For now we always emulate so this function just returns 0. + */ +bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + return 0; +} -- cgit v1.2.3-59-g8ed1b From b7565cc3321987e46d1f65f5b5eb3fb48268fdc2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 29 Jul 2015 23:17:00 +0200 Subject: Documentation: MIPS now supports uprobes. Signed-off-by: Ralf Baechle --- Documentation/features/debug/uprobes/arch-support.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/features/debug/uprobes/arch-support.txt b/Documentation/features/debug/uprobes/arch-support.txt index 4efe36c3ace9..d605c3fc38fd 100644 --- a/Documentation/features/debug/uprobes/arch-support.txt +++ b/Documentation/features/debug/uprobes/arch-support.txt @@ -22,7 +22,7 @@ | m68k: | TODO | | metag: | TODO | | microblaze: | TODO | - | mips: | TODO | + | mips: | ok | | mn10300: | TODO | | nios2: | TODO | | openrisc: | TODO | -- cgit v1.2.3-59-g8ed1b From 23eb6f4016758b756b54704b359e3c51d425d6ab Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Tue, 28 Apr 2015 13:11:25 +0200 Subject: MIPS: Netlogic: Fix 0x0x prefixes. Fix the 0x0x prefix in integer constants, in this case the registers interval is actually 0x8065 .. 0x80A4 as confirmed some lines above in the code. Signed-off-by: Antonio Ospite Cc: linux-mips@linux-mips.org Cc: Jiri Kosina Patchwork: https://patchwork.linux-mips.org/patch/9908/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/xlp/ahci-init-xlp2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/netlogic/xlp/ahci-init-xlp2.c b/arch/mips/netlogic/xlp/ahci-init-xlp2.c index 7b066a44e679..c11b9c7dc7c8 100644 --- a/arch/mips/netlogic/xlp/ahci-init-xlp2.c +++ b/arch/mips/netlogic/xlp/ahci-init-xlp2.c @@ -152,7 +152,7 @@ static const u8 sata_phy_config1[] = { 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 }; -/* SATA PHY config for register block 2 0x0x8065 .. 0x0x80A4 */ +/* SATA PHY config for register block 2 0x8065 .. 0x80A4 */ static const u8 sata_phy_config2[] = { 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, -- cgit v1.2.3-59-g8ed1b From 1a3d59579b9f436da038f377309cf2270c76318e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 3 Aug 2015 08:49:30 -0700 Subject: MIPS: Tidy up FPU context switching Rather than saving the scalar FP or vector context in the assembly resume function, reuse the existing C code we have in fpu.h to do exactly that. This reduces duplication, results in a much easier to read resume function & should allow the compiler to optimise out more MSA code due to is_msa_enabled()/cpu_has_msa being known-zero at compile time for kernels without MSA support. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Cc: Manuel Lauss Patchwork: https://patchwork.linux-mips.org/patch/10830/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/fpu.h | 21 ++++++++++++-------- arch/mips/include/asm/switch_to.h | 21 ++++---------------- arch/mips/kernel/r4k_switch.S | 41 +-------------------------------------- 3 files changed, 18 insertions(+), 65 deletions(-) diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 1b0625189835..9cbf383b8834 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -164,25 +164,30 @@ static inline int own_fpu(int restore) return ret; } -static inline void lose_fpu(int save) +static inline void lose_fpu_inatomic(int save, struct task_struct *tsk) { - preempt_disable(); if (is_msa_enabled()) { if (save) { - save_msa(current); - current->thread.fpu.fcr31 = + save_msa(tsk); + tsk->thread.fpu.fcr31 = read_32bit_cp1_register(CP1_STATUS); } disable_msa(); - clear_thread_flag(TIF_USEDMSA); + clear_tsk_thread_flag(tsk, TIF_USEDMSA); __disable_fpu(); } else if (is_fpu_owner()) { if (save) - _save_fp(current); + _save_fp(tsk); __disable_fpu(); } - KSTK_STATUS(current) &= ~ST0_CU1; - clear_thread_flag(TIF_USEDFPU); + KSTK_STATUS(tsk) &= ~ST0_CU1; + clear_tsk_thread_flag(tsk, TIF_USEDFPU); +} + +static inline void lose_fpu(int save) +{ + preempt_disable(); + lose_fpu_inatomic(save, current); preempt_enable(); } diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index 9733cd0266e4..28b5d84a5022 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -16,29 +16,21 @@ #include #include #include -#include +#include struct task_struct; -enum { - FP_SAVE_NONE = 0, - FP_SAVE_VECTOR = -1, - FP_SAVE_SCALAR = 1, -}; - /** * resume - resume execution of a task * @prev: The task previously executed. * @next: The task to begin executing. * @next_ti: task_thread_info(next). - * @fp_save: Which, if any, FP context to save for prev. * * This function is used whilst scheduling to save the context of prev & load * the context of next. Returns prev. */ extern asmlinkage struct task_struct *resume(struct task_struct *prev, - struct task_struct *next, struct thread_info *next_ti, - s32 fp_save); + struct task_struct *next, struct thread_info *next_ti); extern unsigned int ll_bit; extern struct task_struct *ll_task; @@ -91,8 +83,8 @@ do { if (cpu_has_rw_llb) { \ */ #define switch_to(prev, next, last) \ do { \ - s32 __fpsave = FP_SAVE_NONE; \ __mips_mt_fpaff_switch_to(prev); \ + lose_fpu_inatomic(1, prev); \ if (cpu_has_dsp) { \ __save_dsp(prev); \ __restore_dsp(next); \ @@ -111,15 +103,10 @@ do { \ clear_c0_status(ST0_CU2); \ } \ __clear_software_ll_bit(); \ - if (test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU)) \ - __fpsave = FP_SAVE_SCALAR; \ - if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA)) \ - __fpsave = FP_SAVE_VECTOR; \ if (cpu_has_userlocal) \ write_c0_userlocal(task_thread_info(next)->tp_value); \ __restore_watch(); \ - disable_msa(); \ - (last) = resume(prev, next, task_thread_info(next), __fpsave); \ + (last) = resume(prev, next, task_thread_info(next)); \ } while (0) #endif /* _ASM_SWITCH_TO_H */ diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 04cbbde3521b..92cd0516ecf5 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -34,7 +34,7 @@ #ifndef USE_ALTERNATE_RESUME_IMPL /* * task_struct *resume(task_struct *prev, task_struct *next, - * struct thread_info *next_ti, s32 fp_save) + * struct thread_info *next_ti) */ .align 5 LEAF(resume) @@ -43,45 +43,6 @@ cpu_save_nonscratch a0 LONG_S ra, THREAD_REG31(a0) - /* - * Check whether we need to save any FP context. FP context is saved - * iff the process has used the context with the scalar FPU or the MSA - * ASE in the current time slice, as indicated by _TIF_USEDFPU and - * _TIF_USEDMSA respectively. switch_to will have set fp_save - * accordingly to an FP_SAVE_ enum value. - */ - beqz a3, 2f - - /* - * We do. Clear the saved CU1 bit for prev, such that next time it is - * scheduled it will start in userland with the FPU disabled. If the - * task uses the FPU then it will be enabled again via the do_cpu trap. - * This allows us to lazily restore the FP context. - */ - PTR_L t3, TASK_THREAD_INFO(a0) - LONG_L t0, ST_OFF(t3) - li t1, ~ST0_CU1 - and t0, t0, t1 - LONG_S t0, ST_OFF(t3) - - /* Check whether we're saving scalar or vector context. */ - bgtz a3, 1f - - /* Save 128b MSA vector context + scalar FP control & status. */ - .set push - SET_HARDFLOAT - cfc1 t1, fcr31 - msa_save_all a0 - .set pop /* SET_HARDFLOAT */ - - sw t1, THREAD_FCR31(a0) - b 2f - -1: /* Save 32b/64b scalar FP context. */ - fpu_save_double a0 t0 t1 # c0_status passed in t0 - # clobbers t1 -2: - #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) PTR_LA t8, __stack_chk_guard LONG_L t9, TASK_STACK_CANARY(a1) -- cgit v1.2.3-59-g8ed1b From eb811c73b69f18cefb7a63f22fe07212c6575650 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:12 +0100 Subject: CLOCKSOURCE: mips-gic: Enable the clock before using it For the clock to be used (e.g. get its rate through clk_get_rate) it should be prepared and enabled first. Also, while the clock is enabled the driver must hold a reference to it, so let's remove the call to clk_put. Reviewed-by: Andrew Bresticker Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10779/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index b81ed1a5342d..913585d93466 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -158,8 +158,13 @@ static void __init gic_clocksource_of_init(struct device_node *node) clk = of_clk_get(node, 0); if (!IS_ERR(clk)) { + if (clk_prepare_enable(clk) < 0) { + pr_err("GIC failed to enable clock\n"); + clk_put(clk); + return; + } + gic_frequency = clk_get_rate(clk); - clk_put(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { pr_err("GIC frequency not specified.\n"); -- cgit v1.2.3-59-g8ed1b From f95ac8558b88a5e9ae2b1d580a5cc55bffa512fa Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:13 +0100 Subject: CLOCKSOURCE: mips-gic: Add missing error returns checks This commit adds the required checks on the functions that return an error. Some of them are not critical, so only a warning is printed. Signed-off-by: Ezequiel Garcia Reviewed-by: Andrew Bresticker Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10780/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 913585d93466..c4352f078492 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -100,12 +100,18 @@ static struct notifier_block gic_cpu_nb = { static int gic_clockevent_init(void) { + int ret; + if (!cpu_has_counter || !gic_frequency) return -ENXIO; - setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + if (ret < 0) + return ret; - register_cpu_notifier(&gic_cpu_nb); + ret = register_cpu_notifier(&gic_cpu_nb); + if (ret < 0) + pr_warn("GIC: Unable to register CPU notifier\n"); gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); @@ -125,13 +131,17 @@ static struct clocksource gic_clocksource = { static void __init __gic_clocksource_init(void) { + int ret; + /* Set clocksource mask. */ gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); /* Calculate a somewhat reasonable rating value. */ gic_clocksource.rating = 200 + gic_frequency / 10000000; - clocksource_register_hz(&gic_clocksource, gic_frequency); + ret = clocksource_register_hz(&gic_clocksource, gic_frequency); + if (ret < 0) + pr_warn("GIC: Unable to register clocksource\n"); gic_clockevent_init(); -- cgit v1.2.3-59-g8ed1b From 67d4e669c1e504a491e44737f3561eaba919b304 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:14 +0100 Subject: CLOCKSOURCE: mips-gic: Split clocksource and clockevent initialization This is preparation work for the introduction of clockevent frequency update with a clock notifier. This is only possible when the device is passed a clk struct, so let's split the legacy and devicetree initialization. Reviewed-by: Andrew Bresticker Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10781/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index c4352f078492..22a4daf5f0c8 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -142,11 +142,6 @@ static void __init __gic_clocksource_init(void) ret = clocksource_register_hz(&gic_clocksource, gic_frequency); if (ret < 0) pr_warn("GIC: Unable to register clocksource\n"); - - gic_clockevent_init(); - - /* And finally start the counter */ - gic_start_count(); } void __init gic_clocksource_init(unsigned int frequency) @@ -156,6 +151,10 @@ void __init gic_clocksource_init(unsigned int frequency) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } static void __init gic_clocksource_of_init(struct device_node *node) @@ -187,6 +186,10 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); -- cgit v1.2.3-59-g8ed1b From 42b002ab73e00b24356be4f01954fa961fea4d82 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 22 Aug 2015 02:40:41 -0700 Subject: MIPS: Kconfig: Enable common clock framework for Malta and SEAD3 Now that we're ready to enable COMMON_CLK for GIC platforms do so for Malta and SEAD3. The only other user of the GIC Pistachio does already do so. [ralf@linux-mips.org: Rewrite the commit message because applied in the right order there is no breakage thus no fix required.] Signed-off-by: Guenter Roeck Cc: Ezequiel Garcia Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11038/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7a9a2554fa00..8083ef9c80d4 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -409,6 +409,7 @@ config MIPS_MALTA select CEVT_R4K select CSRC_R4K select CLKSRC_MIPS_GIC + select COMMON_CLK select DMA_MAYBE_COHERENT select GENERIC_ISA_DMA select HAVE_PCSPKR_PLATFORM @@ -459,6 +460,7 @@ config MIPS_SEAD3 select CEVT_R4K select CSRC_R4K select CLKSRC_MIPS_GIC + select COMMON_CLK select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select DMA_NONCOHERENT -- cgit v1.2.3-59-g8ed1b From fc6a6772f888ee8ab4c5428854f7f1d3abda13df Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:15 +0100 Subject: CLOCKSOURCE: mips-gic: Update clockevent frequency on clock rate changes This commit introduces the clockevent frequency update, using a clock notifier. It will be used to support CPUFreq on platforms using MIPS GIC based clockevents. Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: Andrew Bresticker Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10782/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 22a4daf5f0c8..a155bec06d18 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -79,6 +79,13 @@ static void gic_clockevent_cpu_exit(struct clock_event_device *cd) disable_percpu_irq(gic_timer_irq); } +static void gic_update_frequency(void *data) +{ + unsigned long rate = (unsigned long)data; + + clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); +} + static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -94,10 +101,26 @@ static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } +static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct clk_notifier_data *cnd = data; + + if (action == POST_RATE_CHANGE) + on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); + + return NOTIFY_OK; +} + + static struct notifier_block gic_cpu_nb = { .notifier_call = gic_cpu_notifier, }; +static struct notifier_block gic_clk_nb = { + .notifier_call = gic_clk_notifier, +}; + static int gic_clockevent_init(void) { int ret; @@ -160,6 +183,7 @@ void __init gic_clocksource_init(unsigned int frequency) static void __init gic_clocksource_of_init(struct device_node *node) { struct clk *clk; + int ret; if (WARN_ON(!gic_present || !node->parent || !of_device_is_compatible(node->parent, "mti,gic"))) @@ -186,7 +210,12 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); - gic_clockevent_init(); + + ret = gic_clockevent_init(); + if (!ret && !IS_ERR(clk)) { + if (clk_notifier_register(clk, &gic_clk_nb) < 0) + pr_warn("GIC: Unable to register clock notifier\n"); + } /* And finally start the counter */ gic_start_count(); -- cgit v1.2.3-59-g8ed1b From d6ed2b9b60cb03091e0c84c270d145a475606297 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:02:33 +0100 Subject: Documentation: dt: Add Pistachio SoC general purpose timer binding document Add a device-tree binding document for the clocksource driver provided by Pistachio SoC general purpose timers. Signed-off-by: Ezequiel Garcia Reviewed-by: Andrew Bresticker Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Daniel Lezcano Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10783/ Signed-off-by: Ralf Baechle --- .../bindings/timer/img,pistachio-gptimer.txt | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt diff --git a/Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt b/Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt new file mode 100644 index 000000000000..7afce80bf6a0 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt @@ -0,0 +1,28 @@ +* Pistachio general-purpose timer based clocksource + +Required properties: + - compatible: "img,pistachio-gptimer". + - reg: Address range of the timer registers. + - interrupts: An interrupt for each of the four timers + - clocks: Should contain a clock specifier for each entry in clock-names + - clock-names: Should contain the following entries: + "sys", interface clock + "slow", slow counter clock + "fast", fast counter clock + - img,cr-periph: Must contain a phandle to the peripheral control + syscon node. + +Example: + timer: timer@18102000 { + compatible = "img,pistachio-gptimer"; + reg = <0x18102000 0x100>; + interrupts = , + , + , + ; + clocks = <&clk_periph PERIPH_CLK_COUNTER_FAST>, + <&clk_periph PERIPH_CLK_COUNTER_SLOW>, + <&cr_periph SYS_CLK_TIMER>; + clock-names = "fast", "slow", "sys"; + img,cr-periph = <&cr_periph>; + }; -- cgit v1.2.3-59-g8ed1b From 84583983c31983068429d82e6f9262009d584549 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 7 Aug 2015 16:39:31 +0100 Subject: CLOCKSOURCE: Add Pistachio clocksource-only driver The Pistachio SoC provides four general purpose timers, and allow to implement a clocksource driver. This driver can be used as a replacement for the MIPS GIC and MIPS R4K clocksources and sched clocks, which are clocked from the CPU clock. Given the general purpose timers are clocked from an independent clock, this new clocksource driver will be useful to introduce CPUFreq support for Pistachio machines. Signed-off-by: Ezequiel Garcia Signed-off-by: Govindraj Raja Reviewed-by: Thomas Gleixner Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Andrew Bresticker Cc: James Hartley Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10899/ Signed-off-by: Ralf Baechle --- drivers/clocksource/Kconfig | 4 + drivers/clocksource/Makefile | 1 + drivers/clocksource/time-pistachio.c | 217 +++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 drivers/clocksource/time-pistachio.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4e57730e0be4..74e002e80fd3 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -111,6 +111,10 @@ config CLKSRC_LPC32XX select CLKSRC_MMIO select CLKSRC_OF +config CLKSRC_PISTACHIO + bool + select CLKSRC_OF + config CLKSRC_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32 depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index f228354961ca..066337e24737 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o +obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c new file mode 100644 index 000000000000..18d4266c2986 --- /dev/null +++ b/drivers/clocksource/time-pistachio.c @@ -0,0 +1,217 @@ +/* + * Pistachio clocksource based on general-purpose timers + * + * Copyright (C) 2015 Imagination Technologies + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Top level reg */ +#define CR_TIMER_CTRL_CFG 0x00 +#define TIMER_ME_GLOBAL BIT(0) +#define CR_TIMER_REV 0x10 + +/* Timer specific registers */ +#define TIMER_CFG 0x20 +#define TIMER_ME_LOCAL BIT(0) +#define TIMER_RELOAD_VALUE 0x24 +#define TIMER_CURRENT_VALUE 0x28 +#define TIMER_CURRENT_OVERFLOW_VALUE 0x2C +#define TIMER_IRQ_STATUS 0x30 +#define TIMER_IRQ_CLEAR 0x34 +#define TIMER_IRQ_MASK 0x38 + +#define PERIP_TIMER_CONTROL 0x90 + +/* Timer specific configuration Values */ +#define RELOAD_VALUE 0xffffffff + +struct pistachio_clocksource { + void __iomem *base; + raw_spinlock_t lock; + struct clocksource cs; +}; + +static struct pistachio_clocksource pcs_gpt; + +#define to_pistachio_clocksource(cs) \ + container_of(cs, struct pistachio_clocksource, cs) + +static inline u32 gpt_readl(void __iomem *base, u32 offset, u32 gpt_id) +{ + return readl(base + 0x20 * gpt_id + offset); +} + +static inline void gpt_writel(void __iomem *base, u32 value, u32 offset, + u32 gpt_id) +{ + writel(value, base + 0x20 * gpt_id + offset); +} + +static cycle_t pistachio_clocksource_read_cycles(struct clocksource *cs) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 counter, overflw; + unsigned long flags; + + /* + * The counter value is only refreshed after the overflow value is read. + * And they must be read in strict order, hence raw spin lock added. + */ + + raw_spin_lock_irqsave(&pcs->lock, flags); + overflw = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0); + counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0); + raw_spin_unlock_irqrestore(&pcs->lock, flags); + + return ~(cycle_t)counter; +} + +static u64 notrace pistachio_read_sched_clock(void) +{ + return pistachio_clocksource_read_cycles(&pcs_gpt.cs); +} + +static void pistachio_clksrc_set_mode(struct clocksource *cs, int timeridx, + int enable) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 val; + + val = gpt_readl(pcs->base, TIMER_CFG, timeridx); + if (enable) + val |= TIMER_ME_LOCAL; + else + val &= ~TIMER_ME_LOCAL; + + gpt_writel(pcs->base, val, TIMER_CFG, timeridx); +} + +static void pistachio_clksrc_enable(struct clocksource *cs, int timeridx) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + + /* Disable GPT local before loading reload value */ + pistachio_clksrc_set_mode(cs, timeridx, false); + gpt_writel(pcs->base, RELOAD_VALUE, TIMER_RELOAD_VALUE, timeridx); + pistachio_clksrc_set_mode(cs, timeridx, true); +} + +static void pistachio_clksrc_disable(struct clocksource *cs, int timeridx) +{ + /* Disable GPT local */ + pistachio_clksrc_set_mode(cs, timeridx, false); +} + +static int pistachio_clocksource_enable(struct clocksource *cs) +{ + pistachio_clksrc_enable(cs, 0); + return 0; +} + +static void pistachio_clocksource_disable(struct clocksource *cs) +{ + pistachio_clksrc_disable(cs, 0); +} + +/* Desirable clock source for pistachio platform */ +static struct pistachio_clocksource pcs_gpt = { + .cs = { + .name = "gptimer", + .rating = 300, + .enable = pistachio_clocksource_enable, + .disable = pistachio_clocksource_disable, + .read = pistachio_clocksource_read_cycles, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | + CLOCK_SOURCE_SUSPEND_NONSTOP, + }, +}; + +static void __init pistachio_clksrc_of_init(struct device_node *node) +{ + struct clk *sys_clk, *fast_clk; + struct regmap *periph_regs; + unsigned long rate; + int ret; + + pcs_gpt.base = of_iomap(node, 0); + if (!pcs_gpt.base) { + pr_err("cannot iomap\n"); + return; + } + + periph_regs = syscon_regmap_lookup_by_phandle(node, "img,cr-periph"); + if (IS_ERR(periph_regs)) { + pr_err("cannot get peripheral regmap (%lu)\n", + PTR_ERR(periph_regs)); + return; + } + + /* Switch to using the fast counter clock */ + ret = regmap_update_bits(periph_regs, PERIP_TIMER_CONTROL, + 0xf, 0x0); + if (ret) + return; + + sys_clk = of_clk_get_by_name(node, "sys"); + if (IS_ERR(sys_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(sys_clk)); + return; + } + + fast_clk = of_clk_get_by_name(node, "fast"); + if (IS_ERR(fast_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk)); + return; + } + + ret = clk_prepare_enable(sys_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + return; + } + + ret = clk_prepare_enable(fast_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + clk_disable_unprepare(sys_clk); + return; + } + + rate = clk_get_rate(fast_clk); + + /* Disable irq's for clocksource usage */ + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 0); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 1); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 2); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 3); + + /* Enable timer block */ + writel(TIMER_ME_GLOBAL, pcs_gpt.base); + + raw_spin_lock_init(&pcs_gpt.lock); + sched_clock_register(pistachio_read_sched_clock, 32, rate); + clocksource_register_hz(&pcs_gpt.cs, rate); +} +CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", + pistachio_clksrc_of_init); -- cgit v1.2.3-59-g8ed1b From af0cfb2c44ee5cd3c86d1ffd054d318f536cb6dd Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 6 Aug 2015 12:22:43 +0100 Subject: MIPS: pistachio: Allow to enable the external timer based clocksource This commit introduces a new config, so the user can choose to enable the General Purpose Timer based clocksource. This option is required to have CPUFreq support. Signed-off-by: Ezequiel Garcia Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Daniel Lezcano Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: Andrew Bresticker Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Cc: Ezequiel Garcia Patchwork: http://patchwork.linux-mips.org/patch/10887/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/pistachio/Kconfig | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 arch/mips/pistachio/Kconfig diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8083ef9c80d4..233d338c24b4 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -951,6 +951,7 @@ source "arch/mips/jazz/Kconfig" source "arch/mips/jz4740/Kconfig" source "arch/mips/lantiq/Kconfig" source "arch/mips/lasat/Kconfig" +source "arch/mips/pistachio/Kconfig" source "arch/mips/pmcs-msp71xx/Kconfig" source "arch/mips/ralink/Kconfig" source "arch/mips/sgi-ip27/Kconfig" diff --git a/arch/mips/pistachio/Kconfig b/arch/mips/pistachio/Kconfig new file mode 100644 index 000000000000..97731ea94322 --- /dev/null +++ b/arch/mips/pistachio/Kconfig @@ -0,0 +1,13 @@ +config PISTACHIO_GPTIMER_CLKSRC + bool "Enable General Purpose Timer based clocksource" + depends on MACH_PISTACHIO + select CLKSRC_PISTACHIO + select MIPS_EXTERNAL_TIMER + help + This option enables a clocksource driver based on a Pistachio + SoC General Purpose external timer. + + If you want to enable the CPUFreq, you need to enable + this option. + + If you don't want to enable CPUFreq, you can leave this disabled. -- cgit v1.2.3-59-g8ed1b From c0034c30ed301e28c72dc516156baabf5840ce5f Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:33 +0300 Subject: MIPS: Octeon: Fix CN6880 hang on XAUI init Some CN68XX series Octeon II chips seem to hang if a reset is issued on XAUI initialization. Avoid the hang by disabling the reset on affected models. Tested on Cavium EBB6800 evaluation board and Kontron S1901 board. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: http://patchwork.linux-mips.org/patch/10970/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c index 7653b7e92197..323a784f7071 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c @@ -151,7 +151,12 @@ int __cvmx_helper_xaui_enable(int interface) /* (4)c Aply reset sequence */ xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); xauiCtl.s.lo_pwr = 0; - xauiCtl.s.reset = 1; + + /* Issuing a reset here seems to hang some CN68XX chips. */ + if (!OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) && + !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X)) + xauiCtl.s.reset = 1; + cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); /* Wait for PCS to come out of reset */ -- cgit v1.2.3-59-g8ed1b From 2c8c3f0201333f430b632c6b62a5b81456284884 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:34 +0300 Subject: MIPS: Octeon: Support additional interfaces on CN68XX CN68XX has 9 interfaces. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10968/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index 7e5cf7a5e2f3..ed4816c283f0 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -83,6 +83,8 @@ static cvmx_helper_link_info_t */ int cvmx_helper_get_number_of_interfaces(void) { + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return 9; if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) return 4; else -- cgit v1.2.3-59-g8ed1b From fce0af1dc34e2765357dfbd21dd923c89254bcdb Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:35 +0300 Subject: MIPS: Octeon: Support all PIP input ports on CN68XX CN68XX has 48 PIP input ports. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10969/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/octeon/cvmx-pip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/octeon/cvmx-pip.h b/arch/mips/include/asm/octeon/cvmx-pip.h index df69bfd2b006..c210154ad941 100644 --- a/arch/mips/include/asm/octeon/cvmx-pip.h +++ b/arch/mips/include/asm/octeon/cvmx-pip.h @@ -37,7 +37,7 @@ #include #include -#define CVMX_PIP_NUM_INPUT_PORTS 40 +#define CVMX_PIP_NUM_INPUT_PORTS 48 #define CVMX_PIP_NUM_WATCHERS 4 /* -- cgit v1.2.3-59-g8ed1b From 4397564542c18d2fee904b1e2c09ae15a871d853 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:36 +0300 Subject: MIPS: Octeon: Configure XAUI pkinds Configure the pkinds of XAUI interfaces on Octeon models that have them. This simple configuration uses 1:1 mapping between the PIP input port number and the selected pkind. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10971/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c index 323a784f7071..a56ee590de1f 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c @@ -124,6 +124,13 @@ int __cvmx_helper_xaui_enable(int interface) union cvmx_gmxx_tx_int_en gmx_tx_int_en; union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; + /* Setup PKND */ + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); + gmx_cfg.s.pknd = cvmx_helper_get_ipd_port(interface, 0); + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); + } + /* (1) Interface has already been enabled. */ /* (2) Disable GMX. */ -- cgit v1.2.3-59-g8ed1b From b92084ba545b73933ca179d46fe11801f7f9d349 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:37 +0300 Subject: MIPS: Octeon: Configure minimum PKO packet sizes on CN68XX CN68XX has common minimum packet size filters that need to be configured for the traffic to work. Just set them to a default value. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10963/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index ed4816c283f0..376701f41cc2 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -658,6 +658,21 @@ static int __cvmx_helper_global_setup_pko(void) fau_to.s.tout_val = 0xfff; fau_to.s.tout_enb = 0; cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64); + + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + union cvmx_pko_reg_min_pkt min_pkt; + + min_pkt.u64 = 0; + min_pkt.s.size1 = 59; + min_pkt.s.size2 = 59; + min_pkt.s.size3 = 59; + min_pkt.s.size4 = 59; + min_pkt.s.size5 = 59; + min_pkt.s.size6 = 59; + min_pkt.s.size7 = 59; + cvmx_write_csr(CVMX_PKO_REG_MIN_PKT, min_pkt.u64); + } + return 0; } -- cgit v1.2.3-59-g8ed1b From 70b4e2ed4343f03bd7d64d6a58801ff28d231d34 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:38 +0300 Subject: MIPS: Octeon: Add definitions for setting up SSO Some Octeon II models have SSO instead of POW and use a different register for setting the interrupt thresholds. Add the necessary definitions for configuring the interrupts also on those models. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10972/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/octeon/cvmx-pow-defs.h | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/mips/include/asm/octeon/cvmx-pow-defs.h b/arch/mips/include/asm/octeon/cvmx-pow-defs.h index 9020ef443736..6a3db4b068ff 100644 --- a/arch/mips/include/asm/octeon/cvmx-pow-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pow-defs.h @@ -52,6 +52,12 @@ #define CVMX_POW_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000000080ull) + ((offset) & 15) * 8) #define CVMX_POW_WS_PCX(offset) (CVMX_ADD_IO_SEG(0x0001670000000280ull) + ((offset) & 15) * 8) +#define CVMX_SSO_WQ_INT (CVMX_ADD_IO_SEG(0x0001670000001000ull)) +#define CVMX_SSO_WQ_IQ_DIS (CVMX_ADD_IO_SEG(0x0001670000001010ull)) +#define CVMX_SSO_WQ_INT_PC (CVMX_ADD_IO_SEG(0x0001670000001020ull)) +#define CVMX_SSO_PPX_GRP_MSK(offset) (CVMX_ADD_IO_SEG(0x0001670000006000ull) + ((offset) & 31) * 8) +#define CVMX_SSO_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000007000ull) + ((offset) & 63) * 8) + union cvmx_pow_bist_stat { uint64_t u64; struct cvmx_pow_bist_stat_s { @@ -1286,4 +1292,27 @@ union cvmx_pow_ws_pcx { struct cvmx_pow_ws_pcx_s cnf71xx; }; +union cvmx_sso_wq_int_thrx { + uint64_t u64; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_33_63:31; + uint64_t tc_en:1; + uint64_t tc_thr:4; + uint64_t reserved_26_27:2; + uint64_t ds_thr:12; + uint64_t reserved_12_13:2; + uint64_t iq_thr:12; +#else + uint64_t iq_thr:12; + uint64_t reserved_12_13:2; + uint64_t ds_thr:12; + uint64_t reserved_26_27:2; + uint64_t tc_thr:4; + uint64_t tc_en:1; + uint64_t reserved_33_63:31; +#endif + } s; +}; + #endif -- cgit v1.2.3-59-g8ed1b From bcbb13964dd4174f3a512d6a4460173c5c252199 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 13 Aug 2015 16:21:39 +0300 Subject: STAGING: Octeon: Properly enable/disable SSO WQE interrupts The Octeon models with SSO instead of POW need to use a different register for configuring the WQE interrupt thresholds. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10964/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet-rx.c | 54 ++++++++++++++++++++++++++---------- drivers/staging/octeon/ethernet.c | 5 +++- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 22853d33da05..1636bd9a5bc0 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -195,12 +195,19 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) prefetch(work); did_work_request = 0; if (work == NULL) { - union cvmx_pow_wq_int wq_int; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + cvmx_write_csr(CVMX_SSO_WQ_IQ_DIS, + 1ull << pow_receive_group); + cvmx_write_csr(CVMX_SSO_WQ_INT, + 1ull << pow_receive_group); + } else { + union cvmx_pow_wq_int wq_int; - wq_int.u64 = 0; - wq_int.s.iq_dis = 1 << pow_receive_group; - wq_int.s.wq_int = 1 << pow_receive_group; - cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); + wq_int.u64 = 0; + wq_int.s.iq_dis = 1 << pow_receive_group; + wq_int.s.wq_int = 1 << pow_receive_group; + cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); + } break; } pskb = (struct sk_buff **)(cvm_oct_get_buffer_ptr(work->packet_ptr) - @@ -422,8 +429,6 @@ void cvm_oct_rx_initialize(void) { int i; struct net_device *dev_for_napi = NULL; - union cvmx_pow_wq_int_thrx int_thr; - union cvmx_pow_wq_int_pc int_pc; for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) { if (cvm_oct_device[i]) { @@ -449,15 +454,34 @@ void cvm_oct_rx_initialize(void) disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group); - int_thr.u64 = 0; - int_thr.s.tc_en = 1; - int_thr.s.tc_thr = 1; /* Enable POW interrupt when our port has at least one packet */ - cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), int_thr.u64); - - int_pc.u64 = 0; - int_pc.s.pc_thr = 5; - cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + union cvmx_sso_wq_int_thrx int_thr; + union cvmx_pow_wq_int_pc int_pc; + + int_thr.u64 = 0; + int_thr.s.tc_en = 1; + int_thr.s.tc_thr = 1; + cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), + int_thr.u64); + + int_pc.u64 = 0; + int_pc.s.pc_thr = 5; + cvmx_write_csr(CVMX_SSO_WQ_INT_PC, int_pc.u64); + } else { + union cvmx_pow_wq_int_thrx int_thr; + union cvmx_pow_wq_int_pc int_pc; + + int_thr.u64 = 0; + int_thr.s.tc_en = 1; + int_thr.s.tc_thr = 1; + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), + int_thr.u64); + + int_pc.u64 = 0; + int_pc.s.pc_thr = 5; + cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); + } /* Schedule NAPI now. This will indirectly enable the interrupt. */ napi_schedule(&cvm_oct_napi); diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index f9dba23a3759..363742a0f6ee 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -859,7 +859,10 @@ static int cvm_oct_remove(struct platform_device *pdev) int port; /* Disable POW interrupt */ - cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), 0); + else + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); cvmx_ipd_disable(); -- cgit v1.2.3-59-g8ed1b From f5cfc8db28e63d992d293d5b49d7cb8ec5214c56 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 13 Aug 2015 16:21:40 +0300 Subject: STAGING: Octeon: Set SSO group mask properly on CN68XX CN68XX uses SSO instead of POW. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10966/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet-rx.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 1636bd9a5bc0..abfe9344e197 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -172,9 +172,16 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } /* Only allow work for our group (and preserve priorities) */ - old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), - (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + old_group_mask = cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); + cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), + 1ull << pow_receive_group); + cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ + } else { + old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), + (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); + } if (USE_ASYNC_IOBDMA) { cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT); @@ -397,7 +404,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } } /* Restore the original POW group mask */ - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), old_group_mask); + cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ + } else { + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); + } + if (USE_ASYNC_IOBDMA) { /* Restore the scratch area */ cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); -- cgit v1.2.3-59-g8ed1b From d5f9bc7360fc130b6f26e7c0684bc61df29deb6a Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:41 +0300 Subject: STAGING: Octeon: Increase output command buffers The Octeon II models have more interfaces and thus require more output command buffers. Increase the allocation to support these models. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10965/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 363742a0f6ee..fbde4191e717 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -152,7 +152,7 @@ static void cvm_oct_configure_common_hw(void) num_packet_buffers); if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024); #ifdef __LITTLE_ENDIAN { -- cgit v1.2.3-59-g8ed1b From f8023da8ae40c275403568d6f9fc9b585c7f6fab Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:42 +0300 Subject: STAGING: Octeon: Support CN68XX style WQE CN68XX has a bit different WQE structure. This patch provides the new definitions and converts the code to use the proper variant based on the actual model. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10973/ Signed-off-by: Ralf Baechle --- .../cavium-octeon/executive/cvmx-helper-util.c | 8 +- arch/mips/include/asm/octeon/cvmx-pow.h | 9 +- arch/mips/include/asm/octeon/cvmx-wqe.h | 308 +++++++++++++++++---- drivers/staging/octeon/ethernet-rx.c | 58 ++-- drivers/staging/octeon/ethernet-tx.c | 19 +- 5 files changed, 304 insertions(+), 98 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c index 453d7f66459a..402959605276 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c @@ -95,9 +95,9 @@ int cvmx_helper_dump_packet(cvmx_wqe_t *work) uint8_t *data_address; uint8_t *end_of_data; - cvmx_dprintf("Packet Length: %u\n", work->len); - cvmx_dprintf(" Input Port: %u\n", work->ipprt); - cvmx_dprintf(" QoS: %u\n", work->qos); + cvmx_dprintf("Packet Length: %u\n", work->word1.len); + cvmx_dprintf(" Input Port: %u\n", cvmx_wqe_get_port(work)); + cvmx_dprintf(" QoS: %u\n", cvmx_wqe_get_qos(work)); cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); if (work->word2.s.bufs == 0) { @@ -127,7 +127,7 @@ int cvmx_helper_dump_packet(cvmx_wqe_t *work) } } else buffer_ptr = work->packet_ptr; - remaining_bytes = work->len; + remaining_bytes = work->word1.len; while (remaining_bytes) { start_of_buffer = diff --git a/arch/mips/include/asm/octeon/cvmx-pow.h b/arch/mips/include/asm/octeon/cvmx-pow.h index d5565d758ddd..51531563f8dc 100644 --- a/arch/mips/include/asm/octeon/cvmx-pow.h +++ b/arch/mips/include/asm/octeon/cvmx-pow.h @@ -1810,10 +1810,11 @@ static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag, cvmx_addr_t ptr; cvmx_pow_tag_req_t tag_req; - wqp->qos = qos; - wqp->tag = tag; - wqp->tag_type = tag_type; - wqp->grp = grp; + wqp->word1.tag = tag; + wqp->word1.tag_type = tag_type; + + cvmx_wqe_set_qos(wqp, qos); + cvmx_wqe_set_grp(wqp, grp); tag_req.u64 = 0; tag_req.s.op = CVMX_POW_TAG_OP_ADDWQ; diff --git a/arch/mips/include/asm/octeon/cvmx-wqe.h b/arch/mips/include/asm/octeon/cvmx-wqe.h index 2d6d0c7127a7..0d697aa786d4 100644 --- a/arch/mips/include/asm/octeon/cvmx-wqe.h +++ b/arch/mips/include/asm/octeon/cvmx-wqe.h @@ -193,6 +193,53 @@ typedef union { uint64_t bufs:8; #endif } s; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t bufs:8; + uint64_t ip_offset:8; + uint64_t vlan_valid:1; + uint64_t vlan_stacked:1; + uint64_t unassigned:1; + uint64_t vlan_cfi:1; + uint64_t vlan_id:12; + uint64_t port:12; /* MAC/PIP port number. */ + uint64_t dec_ipcomp:1; + uint64_t tcp_or_udp:1; + uint64_t dec_ipsec:1; + uint64_t is_v6:1; + uint64_t software:1; + uint64_t L4_error:1; + uint64_t is_frag:1; + uint64_t IP_exc:1; + uint64_t is_bcast:1; + uint64_t is_mcast:1; + uint64_t not_IP:1; + uint64_t rcv_error:1; + uint64_t err_code:8; +#else + uint64_t err_code:8; + uint64_t rcv_error:1; + uint64_t not_IP:1; + uint64_t is_mcast:1; + uint64_t is_bcast:1; + uint64_t IP_exc:1; + uint64_t is_frag:1; + uint64_t L4_error:1; + uint64_t software:1; + uint64_t is_v6:1; + uint64_t dec_ipsec:1; + uint64_t tcp_or_udp:1; + uint64_t dec_ipcomp:1; + uint64_t port:12; + uint64_t vlan_id:12; + uint64_t vlan_cfi:1; + uint64_t unassigned:1; + uint64_t vlan_stacked:1; + uint64_t vlan_valid:1; + uint64_t ip_offset:8; + uint64_t bufs:8; +#endif + } s_cn68xx; /* use this to get at the 16 vlan bits */ struct { @@ -355,6 +402,146 @@ typedef union { } cvmx_pip_wqe_word2; +union cvmx_pip_wqe_word0 { + struct { +#ifdef __BIG_ENDIAN_BITFIELD + /** + * raw chksum result generated by the HW + */ + uint16_t hw_chksum; + /** + * Field unused by hardware - available for software + */ + uint8_t unused; + /** + * Next pointer used by hardware for list maintenance. + * May be written/read by HW before the work queue + * entry is scheduled to a PP (Only 36 bits used in + * Octeon 1) + */ + uint64_t next_ptr:40; +#else + uint64_t next_ptr:40; + uint8_t unused; + uint16_t hw_chksum; +#endif + } cn38xx; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t l4ptr:8; /* 56..63 */ + uint64_t unused0:8; /* 48..55 */ + uint64_t l3ptr:8; /* 40..47 */ + uint64_t l2ptr:8; /* 32..39 */ + uint64_t unused1:18; /* 14..31 */ + uint64_t bpid:6; /* 8..13 */ + uint64_t unused2:2; /* 6..7 */ + uint64_t pknd:6; /* 0..5 */ +#else + uint64_t pknd:6; /* 0..5 */ + uint64_t unused2:2; /* 6..7 */ + uint64_t bpid:6; /* 8..13 */ + uint64_t unused1:18; /* 14..31 */ + uint64_t l2ptr:8; /* 32..39 */ + uint64_t l3ptr:8; /* 40..47 */ + uint64_t unused0:8; /* 48..55 */ + uint64_t l4ptr:8; /* 56..63 */ +#endif + } cn68xx; +}; + +union cvmx_wqe_word0 { + uint64_t u64; + union cvmx_pip_wqe_word0 pip; +}; + +union cvmx_wqe_word1 { + uint64_t u64; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t len:16; + uint64_t varies:14; + /** + * the type of the tag (ORDERED, ATOMIC, NULL) + */ + uint64_t tag_type:2; + uint64_t tag:32; +#else + uint64_t tag:32; + uint64_t tag_type:2; + uint64_t varies:14; + uint64_t len:16; +#endif + }; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t len:16; + uint64_t zero_0:1; + /** + * HW sets this to what it thought the priority of + * the input packet was + */ + uint64_t qos:3; + + uint64_t zero_1:1; + /** + * the group that the work queue entry will be scheduled to + */ + uint64_t grp:6; + uint64_t zero_2:3; + uint64_t tag_type:2; + uint64_t tag:32; +#else + uint64_t tag:32; + uint64_t tag_type:2; + uint64_t zero_2:3; + uint64_t grp:6; + uint64_t zero_1:1; + uint64_t qos:3; + uint64_t zero_0:1; + uint64_t len:16; +#endif + } cn68xx; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + /** + * HW sets to the total number of bytes in the packet + */ + uint64_t len:16; + /** + * HW sets this to input physical port + */ + uint64_t ipprt:6; + + /** + * HW sets this to what it thought the priority of + * the input packet was + */ + uint64_t qos:3; + + /** + * the group that the work queue entry will be scheduled to + */ + uint64_t grp:4; + /** + * the type of the tag (ORDERED, ATOMIC, NULL) + */ + uint64_t tag_type:3; + /** + * the synchronization/ordering tag + */ + uint64_t tag:32; +#else + uint64_t tag:32; + uint64_t tag_type:2; + uint64_t zero_2:1; + uint64_t grp:4; + uint64_t qos:3; + uint64_t ipprt:6; + uint64_t len:16; +#endif + } cn38xx; +}; + /** * Work queue entry format * @@ -366,70 +553,13 @@ typedef struct { * WORD 0 * HW WRITE: the following 64 bits are filled by HW when a packet arrives */ - -#ifdef __BIG_ENDIAN_BITFIELD - /** - * raw chksum result generated by the HW - */ - uint16_t hw_chksum; - /** - * Field unused by hardware - available for software - */ - uint8_t unused; - /** - * Next pointer used by hardware for list maintenance. - * May be written/read by HW before the work queue - * entry is scheduled to a PP - * (Only 36 bits used in Octeon 1) - */ - uint64_t next_ptr:40; -#else - uint64_t next_ptr:40; - uint8_t unused; - uint16_t hw_chksum; -#endif + union cvmx_wqe_word0 word0; /***************************************************************** * WORD 1 * HW WRITE: the following 64 bits are filled by HW when a packet arrives */ - -#ifdef __BIG_ENDIAN_BITFIELD - /** - * HW sets to the total number of bytes in the packet - */ - uint64_t len:16; - /** - * HW sets this to input physical port - */ - uint64_t ipprt:6; - - /** - * HW sets this to what it thought the priority of the input packet was - */ - uint64_t qos:3; - - /** - * the group that the work queue entry will be scheduled to - */ - uint64_t grp:4; - /** - * the type of the tag (ORDERED, ATOMIC, NULL) - */ - uint64_t tag_type:3; - /** - * the synchronization/ordering tag - */ - uint64_t tag:32; -#else - uint64_t tag:32; - uint64_t tag_type:2; - uint64_t zero_2:1; - uint64_t grp:4; - uint64_t qos:3; - uint64_t ipprt:6; - uint64_t len:16; -#endif + union cvmx_wqe_word1 word1; /** * WORD 2 HW WRITE: the following 64-bits are filled in by @@ -465,4 +595,64 @@ typedef struct { } CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; +static inline int cvmx_wqe_get_port(cvmx_wqe_t *work) +{ + int port; + + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + port = work->word2.s_cn68xx.port; + else + port = work->word1.cn38xx.ipprt; + + return port; +} + +static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word2.s_cn68xx.port = port; + else + work->word1.cn38xx.ipprt = port; +} + +static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work) +{ + int grp; + + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + grp = work->word1.cn68xx.grp; + else + grp = work->word1.cn38xx.grp; + + return grp; +} + +static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word1.cn68xx.grp = grp; + else + work->word1.cn38xx.grp = grp; +} + +static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work) +{ + int qos; + + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + qos = work->word1.cn68xx.qos; + else + qos = work->word1.cn38xx.qos; + + return qos; +} + +static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word1.cn68xx.qos = qos; + else + work->word1.cn38xx.qos = qos; +} + #endif /* __CVMX_WQE_H__ */ diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index abfe9344e197..d1a33a927f6d 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -70,7 +70,14 @@ static irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id) */ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) { - if ((work->word2.snoip.err_code == 10) && (work->len <= 64)) { + int port; + + if (octeon_has_feature(OCTEON_FEATURE_PKND)) + port = work->word0.pip.cn68xx.pknd; + else + port = work->word1.cn38xx.ipprt; + + if ((work->word2.snoip.err_code == 10) && (work->word1.len <= 64)) { /* * Ignore length errors on min size packets. Some * equipment incorrectly pads packets to 64+4FCS @@ -87,8 +94,8 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) * packet to determine if we can remove a non spec * preamble and generate a correct packet. */ - int interface = cvmx_helper_get_interface_num(work->ipprt); - int index = cvmx_helper_get_interface_index_num(work->ipprt); + int interface = cvmx_helper_get_interface_num(port); + int index = cvmx_helper_get_interface_index_num(port); union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; gmxx_rxx_frm_ctl.u64 = @@ -99,7 +106,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) cvmx_phys_to_ptr(work->packet_ptr.s.addr); int i = 0; - while (i < work->len - 1) { + while (i < work->word1.len - 1) { if (*ptr != 0x55) break; ptr++; @@ -109,18 +116,18 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) if (*ptr == 0xd5) { /* printk_ratelimited("Port %d received 0xd5 preamble\n", - work->ipprt); + port); */ work->packet_ptr.s.addr += i + 1; - work->len -= i + 5; + work->word1.len -= i + 5; } else if ((*ptr & 0xf) == 0xd) { /* printk_ratelimited("Port %d received 0x?d preamble\n", - work->ipprt); + port); */ work->packet_ptr.s.addr += i; - work->len -= i + 4; - for (i = 0; i < work->len; i++) { + work->word1.len -= i + 4; + for (i = 0; i < work->word1.len; i++) { *ptr = ((*ptr & 0xf0) >> 4) | ((*(ptr + 1) & 0xf) << 4); @@ -128,7 +135,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) } } else { printk_ratelimited("Port %d unknown preamble, packet dropped\n", - work->ipprt); + port); /* cvmx_helper_dump_packet(work); */ @@ -138,7 +145,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) } } else { printk_ratelimited("Port %d receive error code %d, packet dropped\n", - work->ipprt, work->word2.snoip.err_code); + port, work->word2.snoip.err_code); cvm_oct_free_work(work); return 1; } @@ -193,6 +200,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) struct sk_buff **pskb = NULL; int skb_in_hw; cvmx_wqe_t *work; + int port; if (USE_ASYNC_IOBDMA && did_work_request) work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH); @@ -234,7 +242,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) prefetch(&skb->head); prefetch(&skb->len); } - prefetch(cvm_oct_device[work->ipprt]); + + if (octeon_has_feature(OCTEON_FEATURE_PKND)) + port = work->word0.pip.cn68xx.pknd; + else + port = work->word1.cn38xx.ipprt; + + prefetch(cvm_oct_device[port]); /* Immediately throw away all packets with receive errors */ if (unlikely(work->word2.snoip.rcv_error)) { @@ -251,7 +265,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) skb->data = skb->head + work->packet_ptr.s.addr - cvmx_ptr_to_phys(skb->head); prefetch(skb->data); - skb->len = work->len; + skb->len = work->word1.len; skb_set_tail_pointer(skb, skb->len); packet_not_copied = 1; } else { @@ -259,7 +273,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) * We have to copy the packet. First allocate * an skbuff for it. */ - skb = dev_alloc_skb(work->len); + skb = dev_alloc_skb(work->word1.len); if (!skb) { cvm_oct_free_work(work); continue; @@ -282,13 +296,14 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) else ptr += 6; } - memcpy(skb_put(skb, work->len), ptr, work->len); + memcpy(skb_put(skb, work->word1.len), ptr, + work->word1.len); /* No packet buffers to free */ } else { int segments = work->word2.s.bufs; union cvmx_buf_ptr segment_ptr = work->packet_ptr; - int len = work->len; + int len = work->word1.len; while (segments--) { union cvmx_buf_ptr next_ptr = @@ -324,10 +339,9 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } packet_not_copied = 0; } - - if (likely((work->ipprt < TOTAL_NUMBER_OF_PORTS) && - cvm_oct_device[work->ipprt])) { - struct net_device *dev = cvm_oct_device[work->ipprt]; + if (likely((port < TOTAL_NUMBER_OF_PORTS) && + cvm_oct_device[port])) { + struct net_device *dev = cvm_oct_device[port]; struct octeon_ethernet *priv = netdev_priv(dev); /* @@ -347,7 +361,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) skb->ip_summed = CHECKSUM_UNNECESSARY; /* Increment RX stats for virtual ports */ - if (work->ipprt >= CVMX_PIP_NUM_INPUT_PORTS) { + if (port >= CVMX_PIP_NUM_INPUT_PORTS) { #ifdef CONFIG_64BIT atomic64_add(1, (atomic64_t *)&priv->stats.rx_packets); @@ -382,7 +396,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) * doesn't exist. */ printk_ratelimited("Port %d not controlled by Linux, packet dropped\n", - work->ipprt); + port); dev_kfree_skb_irq(skb); } /* diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 7c1c1b052b7d..588354756c57 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -589,13 +589,14 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) * Fill in some of the work queue fields. We may need to add * more if the software at the other end needs them. */ - work->hw_chksum = skb->csum; - work->len = skb->len; - work->ipprt = priv->port; - work->qos = priv->port & 0x7; - work->grp = pow_send_group; - work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - work->tag = pow_send_group; /* FIXME */ + if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) + work->word0.pip.cn38xx.hw_chksum = skb->csum; + work->word1.len = skb->len; + cvmx_wqe_set_port(work, priv->port); + cvmx_wqe_set_qos(work, priv->port & 0x7); + cvmx_wqe_set_grp(work, pow_send_group); + work->word1.tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + work->word1.tag = pow_send_group; /* FIXME */ /* Default to zero. Sets of zero later are commented out */ work->word2.u64 = 0; work->word2.s.bufs = 1; @@ -675,8 +676,8 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) } /* Submit the packet to the POW */ - cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, - work->grp); + cvmx_pow_work_submit(work, work->word1.tag, work->word1.tag_type, + cvmx_wqe_get_qos(work), cvmx_wqe_get_grp(work)); priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; dev_consume_skb_any(skb); -- cgit v1.2.3-59-g8ed1b From 153bfe381356226ed4c330bb2dff957a6e6c3986 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:43 +0300 Subject: MIPS: Octeon: Initialize CN68XX PKO CN68XX requires a different PKO configuration. This patch provides just enough setup to get the XAUI interfaces on CN6880 working with default parameters. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10974/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-pko.c | 149 ++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 5 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c index 008b881cdf64..87be167a7a6a 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-pko.c +++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c @@ -39,6 +39,143 @@ * Internal state of packet output */ +static int __cvmx_pko_int(int interface, int index) +{ + switch (interface) { + case 0: + return index; + case 1: + return 4; + case 2: + return index + 0x08; + case 3: + return index + 0x0c; + case 4: + return index + 0x10; + case 5: + return 0x1c; + case 6: + return 0x1d; + case 7: + return 0x1e; + case 8: + return 0x1f; + default: + return -1; + } +} + +static void __cvmx_pko_iport_config(int pko_port) +{ + int queue; + const int num_queues = 1; + const int base_queue = pko_port; + const int static_priority_end = 1; + const int static_priority_base = 1; + + for (queue = 0; queue < num_queues; queue++) { + union cvmx_pko_mem_iqueue_ptrs config; + cvmx_cmd_queue_result_t cmd_res; + uint64_t *buf_ptr; + + config.u64 = 0; + config.s.index = queue; + config.s.qid = base_queue + queue; + config.s.ipid = pko_port; + config.s.tail = (queue == (num_queues - 1)); + config.s.s_tail = (queue == static_priority_end); + config.s.static_p = (static_priority_base >= 0); + config.s.static_q = (queue <= static_priority_end); + config.s.qos_mask = 0xff; + + cmd_res = cvmx_cmd_queue_initialize( + CVMX_CMD_QUEUE_PKO(base_queue + queue), + CVMX_PKO_MAX_QUEUE_DEPTH, + CVMX_FPA_OUTPUT_BUFFER_POOL, + (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - + CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8)); + + WARN(cmd_res, + "%s: cmd_res=%d pko_port=%d base_queue=%d num_queues=%d queue=%d\n", + __func__, (int)cmd_res, pko_port, base_queue, + num_queues, queue); + + buf_ptr = (uint64_t *)cvmx_cmd_queue_buffer( + CVMX_CMD_QUEUE_PKO(base_queue + queue)); + config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7; + CVMX_SYNCWS; + cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); + } +} + +static void __cvmx_pko_queue_alloc_o68(void) +{ + int port; + + for (port = 0; port < 48; port++) + __cvmx_pko_iport_config(port); +} + +static void __cvmx_pko_port_map_o68(void) +{ + int port; + int interface, index; + cvmx_helper_interface_mode_t mode; + union cvmx_pko_mem_iport_ptrs config; + + /* + * Initialize every iport with the invalid eid. + */ + config.u64 = 0; + config.s.eid = 31; /* Invalid */ + for (port = 0; port < 128; port++) { + config.s.ipid = port; + cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); + } + + /* + * Set up PKO_MEM_IPORT_PTRS + */ + for (port = 0; port < 48; port++) { + interface = cvmx_helper_get_interface_num(port); + index = cvmx_helper_get_interface_index_num(port); + mode = cvmx_helper_interface_get_mode(interface); + if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED) + continue; + + config.s.ipid = port; + config.s.qos_mask = 0xff; + config.s.crc = 1; + config.s.min_pkt = 1; + config.s.intr = __cvmx_pko_int(interface, index); + config.s.eid = config.s.intr; + config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ? + index : port; + cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); + } +} + +static void __cvmx_pko_chip_init(void) +{ + int i; + + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + __cvmx_pko_port_map_o68(); + __cvmx_pko_queue_alloc_o68(); + return; + } + + /* + * Initialize queues + */ + for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) { + const uint64_t priority = 8; + + cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, + &priority); + } +} + /** * Call before any other calls to initialize the packet * output system. This does chip global config, and should only be @@ -47,8 +184,6 @@ void cvmx_pko_initialize_global(void) { - int i; - uint64_t priority = 8; union cvmx_pko_reg_cmd_buf config; /* @@ -62,9 +197,10 @@ void cvmx_pko_initialize_global(void) cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); - for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) - cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, - &priority); + /* + * Chip-specific setup. + */ + __cvmx_pko_chip_init(); /* * If we aren't using all of the queues optimize PKO's @@ -212,6 +348,9 @@ cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, int static_priority_base = -1; int static_priority_end = -1; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return CVMX_PKO_SUCCESS; + if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", -- cgit v1.2.3-59-g8ed1b From 85847d8033b66c2f36e9a992ff3873fb10d72b80 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:44 +0300 Subject: MIPS: Octeon: Set up 1:1 mapping between CN68XX PKO queues and ports Use the internal port number also as the queue number on CN68XX. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10962/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/octeon/cvmx-pko.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/include/asm/octeon/cvmx-pko.h b/arch/mips/include/asm/octeon/cvmx-pko.h index 3da59bb8ce24..5f47f76ed510 100644 --- a/arch/mips/include/asm/octeon/cvmx-pko.h +++ b/arch/mips/include/asm/octeon/cvmx-pko.h @@ -542,6 +542,9 @@ static inline int cvmx_pko_get_base_queue_per_core(int port, int core) */ static inline int cvmx_pko_get_base_queue(int port) { + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return port; + return cvmx_pko_get_base_queue_per_core(port, 0); } -- cgit v1.2.3-59-g8ed1b From 31705376a2fd71f5c5b596fb2d3b2c6232a6268a Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:45 +0300 Subject: MIPS: Octeon: Support interfaces 4 and 5 Add the support for mapping between interface/port numbers and IPD port numbers also for the additional interfaces some Octeon II models have. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10967/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-util.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c index 402959605276..b45b2975746d 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c @@ -382,6 +382,10 @@ int cvmx_helper_get_ipd_port(int interface, int port) return port + 32; case 3: return port + 36; + case 4: + return port + 40; + case 5: + return port + 44; } return -1; } @@ -404,6 +408,10 @@ int cvmx_helper_get_interface_num(int ipd_port) return 2; else if (ipd_port < 40) return 3; + else if (ipd_port < 44) + return 4; + else if (ipd_port < 48) + return 5; else cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD " "port number\n"); @@ -428,6 +436,10 @@ int cvmx_helper_get_interface_index_num(int ipd_port) return ipd_port & 3; else if (ipd_port < 40) return ipd_port & 3; + else if (ipd_port < 44) + return ipd_port & 3; + else if (ipd_port < 48) + return ipd_port & 3; else cvmx_dprintf("cvmx_helper_get_interface_index_num: " "Illegal IPD port number\n"); -- cgit v1.2.3-59-g8ed1b From 1d39a5e4ce09172358a5435a3411a46e76a04bb4 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:46 +0300 Subject: STAGING: Octeon: Use common helpers for determining interface and port Currently the Octeon Ethernet driver hardcodes the mapping between interface/port and IPD port number. Since we have generic helpers for the very same purpose, we might as well use them instead. This prevents having the same information in multiple places. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10975/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet-util.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h index 1ba789a7741b..45f024bc5e33 100644 --- a/drivers/staging/octeon/ethernet-util.h +++ b/drivers/staging/octeon/ethernet-util.h @@ -8,6 +8,10 @@ * published by the Free Software Foundation. */ +#include +#include +#include + /** * cvm_oct_get_buffer_ptr - convert packet data address to pointer * @packet_ptr: Packet data hardware address @@ -28,14 +32,12 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr) */ static inline int INTERFACE(int ipd_port) { - if (ipd_port < 32) /* Interface 0 or 1 for RGMII,GMII,SPI, etc */ - return ipd_port >> 4; - else if (ipd_port < 36) /* Interface 2 for NPI */ - return 2; - else if (ipd_port < 40) /* Interface 3 for loopback */ - return 3; - else if (ipd_port == 40) /* Non existent interface for POW0 */ - return 4; + int interface = cvmx_helper_get_interface_num(ipd_port); + + if (interface >= 0) + return interface; + else if (ipd_port == CVMX_PIP_NUM_INPUT_PORTS) + return 10; panic("Illegal ipd_port %d passed to INTERFACE\n", ipd_port); } @@ -47,7 +49,5 @@ static inline int INTERFACE(int ipd_port) */ static inline int INDEX(int ipd_port) { - if (ipd_port < 32) - return ipd_port & 15; - return ipd_port & 3; + return cvmx_helper_get_interface_index_num(ipd_port); } -- cgit v1.2.3-59-g8ed1b From e5dd8f2cf65cb228fad881ecd35093d8409d17c6 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 7 Aug 2015 09:59:10 +0200 Subject: MIPS: BCM47xx: Use kmemdup rather than duplicating its implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch was generated using fixed coccinelle semantic patch scripts/coccinelle/api/memdup.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2014320 Signed-off-by: Andrzej Hajda Acked-by: Hauke Mehrtens Cc: Hauke Mehrtens Cc: RafaÅ‚ MiÅ‚ecki Cc: Andrzej Hajda Cc: Bartlomiej Zolnierkiewicz Cc: Marek Szyprowski Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10898/ Signed-off-by: Ralf Baechle --- arch/mips/bcm47xx/buttons.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c index 08a4abf09a33..52caa75bfe4e 100644 --- a/arch/mips/bcm47xx/buttons.c +++ b/arch/mips/bcm47xx/buttons.c @@ -396,10 +396,9 @@ static int __init bcm47xx_buttons_copy(const struct gpio_keys_button *buttons, { size_t size = nbuttons * sizeof(*buttons); - bcm47xx_button_pdata.buttons = kmalloc(size, GFP_KERNEL); + bcm47xx_button_pdata.buttons = kmemdup(buttons, size, GFP_KERNEL); if (!bcm47xx_button_pdata.buttons) return -ENOMEM; - memcpy(bcm47xx_button_pdata.buttons, buttons, size); bcm47xx_button_pdata.nbuttons = nbuttons; return 0; -- cgit v1.2.3-59-g8ed1b From cef232ec86cdadfa7f58c7db140084db0b6cc9db Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 11 Aug 2015 10:56:28 +0300 Subject: MIPS: Octeon: Fix management port MII address on Kontron S1901 Management port MII address is incorrect on Kontron S1901 resulting in broken networking. Fix by providing definitions for the in-tree DT pruning code. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10914/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-board.c | 6 ++++++ arch/mips/include/asm/octeon/cvmx-bootinfo.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index 9eb0feef4417..36e30d65ba05 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -195,6 +195,12 @@ int cvmx_helper_board_get_mii_address(int ipd_port) return 8; else return -1; + case CVMX_BOARD_TYPE_KONTRON_S1901: + if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) + return 1; + else + return -1; + } /* Some unknown board. Somebody forgot to update this function... */ diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h index c373d95b5e2c..d92cf59bdae6 100644 --- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h @@ -284,6 +284,7 @@ enum cvmx_board_types_enum { CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, CVMX_BOARD_TYPE_UBNT_E100 = 20002, CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, + CVMX_BOARD_TYPE_KONTRON_S1901 = 21901, CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, /* The remaining range is reserved for future use. */ @@ -384,6 +385,7 @@ static inline const char *cvmx_board_type_to_string(enum ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) } return "Unsupported Board"; -- cgit v1.2.3-59-g8ed1b From 107d34009ef00d1680521be2c4a1cba31f9b69a6 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:27 +0200 Subject: MIPS: inst.h: Add new MIPS R6 FPU opcodes Add opcodes for the new MIPS R6 FPU instructions. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10952/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/inst.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index 3dce80e67948..9b44d5a816fa 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -167,8 +167,13 @@ enum cop1_sdw_func { fround_op = 0x0c, ftrunc_op = 0x0d, fceil_op = 0x0e, ffloor_op = 0x0f, fmovc_op = 0x11, fmovz_op = 0x12, - fmovn_op = 0x13, frecip_op = 0x15, - frsqrt_op = 0x16, fcvts_op = 0x20, + fmovn_op = 0x13, fseleqz_op = 0x14, + frecip_op = 0x15, frsqrt_op = 0x16, + fselnez_op = 0x17, fmaddf_op = 0x18, + fmsubf_op = 0x19, frint_op = 0x1a, + fclass_op = 0x1b, fmin_op = 0x1c, + fmina_op = 0x1d, fmax_op = 0x1e, + fmaxa_op = 0x1f, fcvts_op = 0x20, fcvtd_op = 0x21, fcvte_op = 0x22, fcvtw_op = 0x24, fcvtl_op = 0x25, fcmp_op = 0x30 -- cgit v1.2.3-59-g8ed1b From f8c3c6717a7128f9601b20f890d658283d59561a Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:28 +0200 Subject: MIPS: math-emu: Add support for the CMP.condn.fmt R6 instruction Add support for emulating the new CMP.condn.fmt R6 instructions and return SIGILL for the old C.cond.fmt if R2 emulation is not enabled since it's not supported by R6. The functionality of the new CMP.condn.fmt is the following one: If the comparison specified by the condn field of the instruction is true for the operand values, the result is true; otherwise, the result is false. If no exception is taken, the result is written into FPR fd; true is all 1s and false is all 0s repeated the operand width of fmt. All other bits beyond the operand width fmt are UNPREDICTABLE. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10953/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 130 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 9 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 8a5b0eb4ddef..ef41fc895e75 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1394,6 +1394,14 @@ static const unsigned char cmptab[8] = { IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ }; +static const unsigned char negative_cmptab[8] = { + 0, /* Reserved */ + IEEE754_CLT | IEEE754_CGT | IEEE754_CEQ, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, + IEEE754_CLT | IEEE754_CGT, + /* Reserved */ +}; + /* * Additional MIPS4 instructions @@ -1838,7 +1846,7 @@ copcsr: goto copcsr; default: - if (MIPSInst_FUNC(ir) >= fcmp_op) { + if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; union ieee754sp fs, ft; @@ -2015,7 +2023,7 @@ dcopuop: goto copcsr; default: - if (MIPSInst_FUNC(ir) >= fcmp_op) { + if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; union ieee754dp fs, ft; @@ -2057,10 +2065,65 @@ dcopuop: rv.d = ieee754dp_fint(fs.bits); rfmt = d_fmt; goto copcsr; - default: - return SIGILL; + default: { + /* Emulating the new CMP.condn.fmt R6 instruction */ +#define CMPOP_MASK 0x7 +#define SIGN_BIT (0x1 << 3) +#define PREDICATE_BIT (0x1 << 4) + + int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; + int sig = MIPSInst_FUNC(ir) & SIGN_BIT; + union ieee754sp fs, ft; + + /* This is an R6 only instruction */ + if (!cpu_has_mips_r6 || + (MIPSInst_FUNC(ir) & 0x20)) + return SIGILL; + + /* fmt is w_fmt for single precision so fix it */ + rfmt = s_fmt; + /* default to false */ + rv.w = 0; + + /* CMP.condn.S */ + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + + /* positive predicates */ + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + if (ieee754sp_cmp(fs, ft, cmptab[cmpop], + sig)) + rv.w = -1; /* true, all 1s */ + if ((sig) && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + } else { + /* negative predicates */ + switch (cmpop) { + case 1: + case 2: + case 3: + if (ieee754sp_cmp(fs, ft, + negative_cmptab[cmpop], + sig)) + rv.w = -1; /* true, all 1s */ + if (sig && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + break; + default: + /* Reserved R6 ops */ + pr_err("Reserved MIPS R6 CMP.condn.S operation\n"); + return SIGILL; + } + } + break; + } } - break; } case l_fmt: @@ -2081,11 +2144,60 @@ dcopuop: rv.d = ieee754dp_flong(bits); rfmt = d_fmt; goto copcsr; - default: - return SIGILL; - } - break; + default: { + /* Emulating the new CMP.condn.fmt R6 instruction */ + int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; + int sig = MIPSInst_FUNC(ir) & SIGN_BIT; + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6 || + (MIPSInst_FUNC(ir) & 0x20)) + return SIGILL; + /* fmt is l_fmt for double precision so fix it */ + rfmt = d_fmt; + /* default to false */ + rv.l = 0; + + /* CMP.condn.D */ + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + + /* positive predicates */ + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + if (ieee754dp_cmp(fs, ft, + cmptab[cmpop], sig)) + rv.l = -1LL; /* true, all 1s */ + if (sig && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + } else { + /* negative predicates */ + switch (cmpop) { + case 1: + case 2: + case 3: + if (ieee754dp_cmp(fs, ft, + negative_cmptab[cmpop], + sig)) + rv.l = -1LL; /* true, all 1s */ + if (sig && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + break; + default: + /* Reserved R6 ops */ + pr_err("Reserved MIPS R6 CMP.condn.D operation\n"); + return SIGILL; + } + } + break; + } + } default: return SIGILL; } -- cgit v1.2.3-59-g8ed1b From 67613f02788d73541c7c9b1c851061b8c223057b Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:29 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 SELEQZ FPU instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIPS R6 introduced the following instruction: SELEQZ.fmt: FPR[fd]  FPR[ft].bit0 ? 0 : FPR[fs] Add support for emulating the single and double precision formats of the said instruction. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10954/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index ef41fc895e75..02ba536f1594 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1743,6 +1743,17 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(rv.s, MIPSInst_FS(ir)); break; + case fseleqz_op: + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(rv.s, MIPSInst_FT(ir)); + if (rv.w & 0x1) + rv.w = 0; + else + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -1940,6 +1951,18 @@ copcsr: return 0; DPFROMREG(rv.d, MIPSInst_FS(ir)); break; + + case fseleqz_op: + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(rv.d, MIPSInst_FT(ir)); + if (rv.l & 0x1) + rv.l = 0; + else + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; -- cgit v1.2.3-59-g8ed1b From 130fe357ee895421a4aefef7b1285bf52f295afe Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:30 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 SELNEZ FPU instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIPS R6 introduced the following instruction: SELNEZ.fmt: FPR[fd]  FPR[ft].bit0 ? FPR[fs] : 0 Add support for emulating the single and double precision formats of the said instruction. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10955/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 02ba536f1594..8978d52adf0e 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1754,6 +1754,17 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(rv.s, MIPSInst_FS(ir)); break; + case fselnez_op: + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(rv.s, MIPSInst_FT(ir)); + if (rv.w & 0x1) + SPFROMREG(rv.s, MIPSInst_FS(ir)); + else + rv.w = 0; + break; + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -1963,6 +1974,17 @@ copcsr: DPFROMREG(rv.d, MIPSInst_FS(ir)); break; + case fselnez_op: + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(rv.d, MIPSInst_FT(ir)); + if (rv.l & 0x1) + DPFROMREG(rv.d, MIPSInst_FS(ir)); + else + rv.l = 0; + break; + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; -- cgit v1.2.3-59-g8ed1b From e24c3bec3e8e254a3784b3e4c97bd3a76fbcc807 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:31 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction MIPS R6 introduced the following instruction: Floating Point Fused Multiply Add: MADDF.fmt To perform a fused multiply-add of FP values. MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10956/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 26 +++++ arch/mips/math-emu/dp_maddf.c | 265 ++++++++++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 5 + arch/mips/math-emu/sp_maddf.c | 255 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 553 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_maddf.c create mode 100644 arch/mips/math-emu/sp_maddf.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index 2e5f96275c38..c40816f86a7a 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o \ + dp_tint.o dp_fint.o dp_maddf.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o \ + sp_tint.o sp_fint.o sp_maddf.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 8978d52adf0e..67390ec2c2f8 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1765,6 +1765,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, rv.w = 0; break; + case fmaddf_op: { + union ieee754sp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(fd, MIPSInst_FD(ir)); + rv.s = ieee754sp_maddf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -1985,6 +1998,19 @@ copcsr: rv.l = 0; break; + case fmaddf_op: { + union ieee754dp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(fd, MIPSInst_FD(ir)); + rv.d = ieee754dp_maddf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c new file mode 100644 index 000000000000..119eda9fa1ea --- /dev/null +++ b/arch/mips/math-emu/dp_maddf.c @@ -0,0 +1,265 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MADDF.f (Fused Multiply Add) + * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + int re; + int rs; + u64 rm; + unsigned lxm; + unsigned hxm; + unsigned lym; + unsigned hym; + u64 lrm; + u64 hrm; + u64 t; + u64 at; + int s; + + COMPXDP; + COMPYDP; + + u64 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXDP; + EXPLODEYDP; + EXPLODEDP(z, zc, zs, ze, zm) + + FLUSHXDP; + FLUSHYDP; + FLUSHDP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + DPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754dp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* fall through to real computations */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 64 - (DP_FBITS + 1); + ym <<= 64 - (DP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + + /* 32 * 32 => 64 */ +#define DPXMULT(x, y) ((u64)(x) * (u64)y) + + lxm = xm; + hxm = xm >> 32; + lym = ym; + hym = ym >> 32; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + t = DPXMULT(lxm, hym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + t = DPXMULT(hxm, lym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((s64) rm < 0) { + rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | + ((rm << (DP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | + ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (DP_HIDDEN_BIT << 3)); + + /* And now the addition */ + assert(zm & DP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + rm = XDPSRS(rm, s); + re += s; + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + zm = XDPSRS(zm, s); + ze += s; + } + assert(ze == re); + assert(ze <= DP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in xm, xs and xe. + */ + zm = zm + rm; + + if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ + zm = XDPSRS1(zm); + ze++; + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize to rounding precision. + */ + while ((zm >> (DP_FBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + } + + return ieee754dp_format(zs, ze, zm); +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index a5ca108ce467..4e025f9e220c 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -75,6 +75,9 @@ int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig); union ieee754sp ieee754sp_sqrt(union ieee754sp x); +union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y); + /* * double precision (often aka double) */ @@ -99,6 +102,8 @@ int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig); union ieee754dp ieee754dp_sqrt(union ieee754dp x); +union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c new file mode 100644 index 000000000000..dd1dd83e34eb --- /dev/null +++ b/arch/mips/math-emu/sp_maddf.c @@ -0,0 +1,255 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MADDF.f (Fused Multiply Add) + * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + int re; + int rs; + unsigned rm; + unsigned short lxm; + unsigned short hxm; + unsigned short lym; + unsigned short hym; + unsigned lrm; + unsigned hrm; + unsigned t; + unsigned at; + int s; + + COMPXSP; + COMPYSP; + u32 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXSP; + EXPLODEYSP; + EXPLODESP(z, zc, zs, ze, zm) + + FLUSHXSP; + FLUSHYSP; + FLUSHSP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + SPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754sp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* fall through to real computations */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + + /* rm = xm * ym, re = xe+ye basically */ + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 32 - (SP_FBITS + 1); + ym <<= 32 - (SP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + lxm = xm & 0xffff; + hxm = xm >> 16; + lym = ym & 0xffff; + hym = ym >> 16; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + t = lxm * hym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + t = hxm * lym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | + ((rm << (SP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | + ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (SP_HIDDEN_BIT << 3)); + + /* And now the addition */ + + assert(zm & SP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + SPXSRSYn(s); + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + SPXSRSYn(s); + } + assert(ze == re); + assert(ze <= SP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in zm, zs and ze. + */ + zm = zm + rm; + + if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize in extended single precision + */ + while ((zm >> (SP_MBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + + } + return ieee754sp_format(zs, ze, zm); +} -- cgit v1.2.3-59-g8ed1b From 83d43305a1df2aa2976e3ccf012e4cf0dc29673d Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:32 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction MIPS R6 introduced the following instruction: Floating Point Fused Multiply Subtract: MSUBF.fmt To perform a fused multiply-subtract of FP values. MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10957/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 26 ++++ arch/mips/math-emu/dp_msubf.c | 269 ++++++++++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 4 + arch/mips/math-emu/sp_msubf.c | 258 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 559 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_msubf.c create mode 100644 arch/mips/math-emu/sp_msubf.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index c40816f86a7a..0037690521ee 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 67390ec2c2f8..54964b372992 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1778,6 +1778,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case fmsubf_op: { + union ieee754sp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(fd, MIPSInst_FD(ir)); + rv.s = ieee754sp_msubf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2011,6 +2024,19 @@ copcsr: break; } + case fmsubf_op: { + union ieee754dp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(fd, MIPSInst_FD(ir)); + rv.d = ieee754dp_msubf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_msubf.c b/arch/mips/math-emu/dp_msubf.c new file mode 100644 index 000000000000..12241262f856 --- /dev/null +++ b/arch/mips/math-emu/dp_msubf.c @@ -0,0 +1,269 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MSUB.f (Fused Multiply Subtract) + * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + int re; + int rs; + u64 rm; + unsigned lxm; + unsigned hxm; + unsigned lym; + unsigned hym; + u64 lrm; + u64 hrm; + u64 t; + u64 at; + int s; + + COMPXDP; + COMPYDP; + + u64 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXDP; + EXPLODEYDP; + EXPLODEDP(z, zc, zs, ze, zm) + + FLUSHXDP; + FLUSHYDP; + FLUSHDP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + DPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754dp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* fall through to real computations */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 64 - (DP_FBITS + 1); + ym <<= 64 - (DP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + + /* 32 * 32 => 64 */ +#define DPXMULT(x, y) ((u64)(x) * (u64)y) + + lxm = xm; + hxm = xm >> 32; + lym = ym; + hym = ym >> 32; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + t = DPXMULT(lxm, hym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + t = DPXMULT(hxm, lym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((s64) rm < 0) { + rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | + ((rm << (DP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | + ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (DP_HIDDEN_BIT << 3)); + + /* And now the subtraction */ + + /* flip sign of r and handle as add */ + rs ^= 1; + + assert(zm & DP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + rm = XDPSRS(rm, s); + re += s; + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + zm = XDPSRS(zm, s); + ze += s; + } + assert(ze == re); + assert(ze <= DP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in xm, xs and xe. + */ + zm = zm + rm; + + if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ + zm = XDPSRS1(zm); + ze++; + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize to rounding precision. + */ + while ((zm >> (DP_FBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + } + + return ieee754dp_format(zs, ze, zm); +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 4e025f9e220c..8c780190a059 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -77,6 +77,8 @@ union ieee754sp ieee754sp_sqrt(union ieee754sp x); union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, + union ieee754sp y); /* * double precision (often aka double) @@ -104,6 +106,8 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x); union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, + union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_msubf.c b/arch/mips/math-emu/sp_msubf.c new file mode 100644 index 000000000000..81c38b980d69 --- /dev/null +++ b/arch/mips/math-emu/sp_msubf.c @@ -0,0 +1,258 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MSUB.f (Fused Multiply Subtract) + * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + int re; + int rs; + unsigned rm; + unsigned short lxm; + unsigned short hxm; + unsigned short lym; + unsigned short hym; + unsigned lrm; + unsigned hrm; + unsigned t; + unsigned at; + int s; + + COMPXSP; + COMPYSP; + u32 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXSP; + EXPLODEYSP; + EXPLODESP(z, zc, zs, ze, zm) + + FLUSHXSP; + FLUSHYSP; + FLUSHSP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + SPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754sp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* fall through to real compuation */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + + /* rm = xm * ym, re = xe+ye basically */ + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 32 - (SP_FBITS + 1); + ym <<= 32 - (SP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + lxm = xm & 0xffff; + hxm = xm >> 16; + lym = ym & 0xffff; + hym = ym >> 16; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + t = lxm * hym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + t = hxm * lym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | + ((rm << (SP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | + ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (SP_HIDDEN_BIT << 3)); + + /* And now the subtraction */ + + /* Flip sign of r and handle as add */ + rs ^= 1; + + assert(zm & SP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + SPXSRSYn(s); + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + SPXSRSYn(s); + } + assert(ze == re); + assert(ze <= SP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in zm, zs and ze. + */ + zm = zm + rm; + + if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); /* shift preserving sticky */ + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize in extended single precision + */ + while ((zm >> (SP_MBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + + } + return ieee754sp_format(zs, ze, zm); +} -- cgit v1.2.3-59-g8ed1b From 400bd2e41393a783e0532321fdb369d2cc15ea26 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:33 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 RINT FPU instruction MIPS R6 introduced the following instruction: Floating-Point Round to Integral Scalar floating-point round to integral floating point value. RINT.fmt: FPR[fd] = round_int(FPR[fs]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10958/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 54964b372992..a348cbefe4a8 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1791,6 +1791,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case frint_op: { + union ieee754sp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754sp_tlong(fs); + rv.s = ieee754sp_flong(rv.l); + goto copcsr; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2037,6 +2049,18 @@ copcsr: break; } + case frint_op: { + union ieee754dp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754dp_tlong(fs); + rv.d = ieee754dp_flong(rv.l); + goto copcsr; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; -- cgit v1.2.3-59-g8ed1b From 38db37ba069f9d801ef56b820cfc7c247a7ffc02 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:34 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 CLASS FPU instruction MIPS R6 introduced the following instruction: Stores in fd a bit mask reflecting the floating-point class of the floating point scalar value fs. CLASS.fmt: FPR[fd] = class(FPR[fs]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10959/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +-- arch/mips/math-emu/cp1emu.c | 24 +++++++++++++++++ arch/mips/math-emu/dp_2008class.c | 55 +++++++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 2 ++ arch/mips/math-emu/sp_2008class.c | 55 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_2008class.c create mode 100644 arch/mips/math-emu/sp_2008class.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index 0037690521ee..ea8db2607d07 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index a348cbefe4a8..b65b4ea60232 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1803,6 +1803,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto copcsr; } + case fclass_op: { + union ieee754sp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754sp_2008class(fs); + rfmt = w_fmt; + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2061,6 +2073,18 @@ copcsr: goto copcsr; } + case fclass_op: { + union ieee754dp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754dp_2008class(fs); + rfmt = w_fmt; + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_2008class.c b/arch/mips/math-emu/dp_2008class.c new file mode 100644 index 000000000000..9dc39fc4835e --- /dev/null +++ b/arch/mips/math-emu/dp_2008class.c @@ -0,0 +1,55 @@ +/* + * IEEE754 floating point arithmetic + * double precision: CLASS.f + * FPR[fd] = class(FPR[fs]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +int ieee754dp_2008class(union ieee754dp x) +{ + COMPXDP; + + EXPLODEXDP; + + /* + * 10 bit mask as follows: + * + * bit0 = SNAN + * bit1 = QNAN + * bit2 = -INF + * bit3 = -NORM + * bit4 = -DNORM + * bit5 = -ZERO + * bit6 = INF + * bit7 = NORM + * bit8 = DNORM + * bit9 = ZERO + */ + + switch(xc) { + case IEEE754_CLASS_SNAN: + return 0x01; + case IEEE754_CLASS_QNAN: + return 0x02; + case IEEE754_CLASS_INF: + return 0x04 << (xs ? 0 : 4); + case IEEE754_CLASS_NORM: + return 0x08 << (xs ? 0 : 4); + case IEEE754_CLASS_DNORM: + return 0x10 << (xs ? 0 : 4); + case IEEE754_CLASS_ZERO: + return 0x20 << (xs ? 0 : 4); + default: + pr_err("Unknown class: %d\n", xc); + return 0; + } +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 8c780190a059..3b833eac48f5 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -79,6 +79,7 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp y); union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, union ieee754sp y); +int ieee754sp_2008class(union ieee754sp x); /* * double precision (often aka double) @@ -108,6 +109,7 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp y); union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, union ieee754dp y); +int ieee754dp_2008class(union ieee754dp x); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_2008class.c b/arch/mips/math-emu/sp_2008class.c new file mode 100644 index 000000000000..ff62606a1465 --- /dev/null +++ b/arch/mips/math-emu/sp_2008class.c @@ -0,0 +1,55 @@ +/* + * IEEE754 floating point arithmetic + * single precision: CLASS.f + * FPR[fd] = class(FPR[fs]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +int ieee754sp_2008class(union ieee754sp x) +{ + COMPXSP; + + EXPLODEXSP; + + /* + * 10 bit mask as follows: + * + * bit0 = SNAN + * bit1 = QNAN + * bit2 = -INF + * bit3 = -NORM + * bit4 = -DNORM + * bit5 = -ZERO + * bit6 = INF + * bit7 = NORM + * bit8 = DNORM + * bit9 = ZERO + */ + + switch(xc) { + case IEEE754_CLASS_SNAN: + return 0x01; + case IEEE754_CLASS_QNAN: + return 0x02; + case IEEE754_CLASS_INF: + return 0x04 << (xs ? 0 : 4); + case IEEE754_CLASS_NORM: + return 0x08 << (xs ? 0 : 4); + case IEEE754_CLASS_DNORM: + return 0x10 << (xs ? 0 : 4); + case IEEE754_CLASS_ZERO: + return 0x20 << (xs ? 0 : 4); + default: + pr_err("Unknown class: %d\n", xc); + return 0; + } +} -- cgit v1.2.3-59-g8ed1b From 4e9561b20e2f5c1170704a81ec7e1ac961ba5e68 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:35 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 MIN{, A} FPU instruction MIPS R6 introduced the following instruction: Scalar Floating-Point Minimum and Scalar Floating-Point argument with Minimum Absolute Value MIN.fmt writes the minimum value of the inputs fs and ft to the destination fd. MINA.fmt takes input arguments fs and ft and writes the argument with the minimum absolute value to the destination fd. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10960/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 48 ++++++++++ arch/mips/math-emu/dp_fmin.c | 213 +++++++++++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 4 + arch/mips/math-emu/sp_fmin.c | 213 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_fmin.c create mode 100644 arch/mips/math-emu/sp_fmin.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index ea8db2607d07..b9946322804e 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index b65b4ea60232..f397bdfd93fb 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1815,6 +1815,30 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case fmin_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmin(fs, ft); + break; + } + + case fmina_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmina(fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2085,6 +2109,30 @@ copcsr: break; } + case fmin_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmin(fs, ft); + break; + } + + case fmina_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmina(fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_fmin.c b/arch/mips/math-emu/dp_fmin.c new file mode 100644 index 000000000000..c1072b0dfb95 --- /dev/null +++ b/arch/mips/math-emu/dp_fmin.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MIN{,A}.f + * MIN : Scalar Floating-Point Minimum + * MINA: Scalar Floating-Point argument with Minimum Absolute Value + * + * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft]) + * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? x : y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? y : x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return x; + else if (xs < ys) + return y; + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} + +union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 3b833eac48f5..6a16357a1ddd 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -80,6 +80,8 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, union ieee754sp y); int ieee754sp_2008class(union ieee754sp x); +union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y); /* * double precision (often aka double) @@ -110,6 +112,8 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, union ieee754dp y); int ieee754dp_2008class(union ieee754dp x); +union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_fmin.c b/arch/mips/math-emu/sp_fmin.c new file mode 100644 index 000000000000..4eb1bb9e9dec --- /dev/null +++ b/arch/mips/math-emu/sp_fmin.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MIN{,A}.f + * MIN : Scalar Floating-Point Minimum + * MINA: Scalar Floating-Point argument with Minimum Absolute Value + * + * MIN.S : FPR[fd] = minNum(FPR[fs],FPR[ft]) + * MINA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? x : y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? y : x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return x; + else if (xs < ys) + return y; + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} + +union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} -- cgit v1.2.3-59-g8ed1b From a79f5f9ba5088f157482feaa6ae2bacc9da0f5db Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:36 +0200 Subject: MIPS: math-emu: Add support for the MIPS R6 MAX{, A} FPU instruction MIPS R6 introduced the following instruction: Scalar Floating-Point Maximum and Scalar Floating-Point argument with Maximum Absolute Value MAX.fmt writes the maximum value of the inputs fs and ft to the destination fd. MAXA.fmt takes input arguments fs and ft and writes the argument with the maximum absolute value to the destination fd. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10961/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 48 ++++++++++ arch/mips/math-emu/dp_fmax.c | 213 +++++++++++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 4 + arch/mips/math-emu/sp_fmax.c | 213 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_fmax.c create mode 100644 arch/mips/math-emu/sp_fmax.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index b9946322804e..a19641d3ac23 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index f397bdfd93fb..32f0e19a0d7f 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1839,6 +1839,30 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case fmax_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmax(fs, ft); + break; + } + + case fmaxa_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmaxa(fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2133,6 +2157,30 @@ copcsr: break; } + case fmax_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmax(fs, ft); + break; + } + + case fmaxa_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmaxa(fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_fmax.c b/arch/mips/math-emu/dp_fmax.c new file mode 100644 index 000000000000..fd71b8daaaf2 --- /dev/null +++ b/arch/mips/math-emu/dp_fmax.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MIN{,A}.f + * MIN : Scalar Floating-Point Minimum + * MINA: Scalar Floating-Point argument with Minimum Absolute Value + * + * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft]) + * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? y : x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? x : y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return y; + else if (xs < ys) + return x; + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} + +union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 6a16357a1ddd..df94720714c7 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -82,6 +82,8 @@ union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, int ieee754sp_2008class(union ieee754sp x); union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y); union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y); /* * double precision (often aka double) @@ -114,6 +116,8 @@ union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, int ieee754dp_2008class(union ieee754dp x); union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y); union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_fmax.c b/arch/mips/math-emu/sp_fmax.c new file mode 100644 index 000000000000..4d000844e48e --- /dev/null +++ b/arch/mips/math-emu/sp_fmax.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MAX{,A}.f + * MAX : Scalar Floating-Point Maximum + * MAXA: Scalar Floating-Point argument with Maximum Absolute Value + * + * MAX.S : FPR[fd] = maxNum(FPR[fs],FPR[ft]) + * MAXA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? y : x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? x : y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return y; + else if (xs < ys) + return x; + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} + +union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} -- cgit v1.2.3-59-g8ed1b From 65ab562cabe01d524ec6b50f37694200745c21c1 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 12 Aug 2015 10:14:35 +0100 Subject: MIPS: math-emu: Remove unused handle_dsemul function declaration handle_dsemul does not exist and it's not being used in the code at all so remove its declaration. The deliberate DS emulation exception is handled by the do_dsemulret C code. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10950/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/dsemul.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index e0b5cc27d78b..cbb36c14b155 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -33,7 +33,6 @@ struct emuframe { int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) { - extern asmlinkage void handle_dsemulret(void); struct emuframe __user *fr; int err; -- cgit v1.2.3-59-g8ed1b From fb2646ab032d12ef06225c64768691c7ecc500ec Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Tue, 18 Aug 2015 15:03:10 +0100 Subject: MIPS: Fix alignment of quiet build output for vmlinuz link The "LD vmlinuz" line in the quiet build output is misaligned with the rest of the output. Fix this. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11019/ Signed-off-by: Ralf Baechle --- arch/mips/boot/compressed/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index dc91bde10d62..d5bdee115f22 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -78,7 +78,7 @@ endif vmlinuzobjs-y += $(obj)/piggy.o -quiet_cmd_zld = LD $@ +quiet_cmd_zld = LD $@ cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ quiet_cmd_strip = STRIP $@ cmd_strip = $(STRIP) -s $@ -- cgit v1.2.3-59-g8ed1b From e0d8b2ec532852d4b5aabcec3e7611848c32237d Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 3 Sep 2015 17:47:45 +0800 Subject: MIPS: UAPI: Fix unrecognized opcode WSBH/DSBH/DSHD when using MIPS16. The nomips16 has to be added both as function attribute and assembler directive. When only function attribute is specified, the compiler will inline the function with -Os optimization. The generated assembly code cannot be correctly assembled because ISA mode switch has to be done through jump instruction. When only ".set nomips16" directive is used, the generated assembly code will use MIPS32 code for the inline assembly template and MIPS16 for the function return. The compiled binary is invalid: 00403100 <__arch_swab16>: 403100: 7c0410a0 wsbh v0,a0 403104: e820ea31 swc2 $0,-5583(at) while correct code should be: 00402650 <__arch_swab16>: 402650: 7c0410a0 wsbh v0,a0 402654: 03e00008 jr ra 402658: 3042ffff andi v0,v0,0xffff Signed-off-by: Yousong Zhou Cc: Chen Jie Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11087/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/swab.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/uapi/asm/swab.h b/arch/mips/include/uapi/asm/swab.h index 8f2d184dbe9f..c4ddc4f0d2dc 100644 --- a/arch/mips/include/uapi/asm/swab.h +++ b/arch/mips/include/uapi/asm/swab.h @@ -16,11 +16,13 @@ #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) || \ defined(_MIPS_ARCH_LOONGSON3A) -static inline __attribute_const__ __u16 __arch_swab16(__u16 x) +static inline __attribute__((nomips16)) __attribute_const__ + __u16 __arch_swab16(__u16 x) { __asm__( " .set push \n" " .set arch=mips32r2 \n" + " .set nomips16 \n" " wsbh %0, %1 \n" " .set pop \n" : "=r" (x) @@ -30,11 +32,13 @@ static inline __attribute_const__ __u16 __arch_swab16(__u16 x) } #define __arch_swab16 __arch_swab16 -static inline __attribute_const__ __u32 __arch_swab32(__u32 x) +static inline __attribute__((nomips16)) __attribute_const__ + __u32 __arch_swab32(__u32 x) { __asm__( " .set push \n" " .set arch=mips32r2 \n" + " .set nomips16 \n" " wsbh %0, %1 \n" " rotr %0, %0, 16 \n" " .set pop \n" @@ -50,11 +54,13 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x) * 64-bit kernel on r2 CPUs. */ #ifdef __mips64 -static inline __attribute_const__ __u64 __arch_swab64(__u64 x) +static inline __attribute__((nomips16)) __attribute_const__ + __u64 __arch_swab64(__u64 x) { __asm__( " .set push \n" " .set arch=mips64r2 \n" + " .set nomips16 \n" " dsbh %0, %1 \n" " dshd %0, %0 \n" " .set pop \n" -- cgit v1.2.3-59-g8ed1b