From daed1285c33582d93447a0ad971bbc1dd15d1940 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 12 Sep 2013 12:01:53 +0100 Subject: MIPS: DECstation HRT initialization rearrangement Not all I/O ASIC versions have the free-running counter implemented, an early revision used in the 5000/1xx models aka 3MIN and 4MIN did not have it. Therefore we cannot unconditionally use it as a clock source. Fortunately if not implemented its register slot has a fixed value so it is enough if we check for the value at the end of the calibration period being the same as at the beginning. This also means we need to look for another high-precision clock source on the systems affected. The 5000/1xx can have an R4000SC processor installed where the CP0 Count register can be used as a clock source. Unfortunately all the R4k DECstations suffer from the missed timer interrupt on CP0 Count reads erratum, so we cannot use the CP0 timer as a clock source and a clock event both at a time. However we never need an R4k clock event device because all DECstations have a DS1287A RTC chip whose periodic interrupt can be used as a clock source. This gives us the following four configuration possibilities for I/O ASIC DECstations: 1. No I/O ASIC counter and no CP0 timer, e.g. R3k 5000/1xx (3MIN). 2. No I/O ASIC counter but the CP0 timer, i.e. R4k 5000/150 (4MIN). 3. The I/O ASIC counter but no CP0 timer, e.g. R3k 5000/240 (3MAX+). 4. The I/O ASIC counter and the CP0 timer, e.g. R4k 5000/260 (4MAX+). For #1 and #2 this change stops the I/O ASIC free-running counter from being installed as a clock source of a 0Hz frequency. For #2 it also arranges for the CP0 timer to be used as a clock source rather than a clock event device, because having an accurate wall clock is more important than a high-precision interval timer. For #3 there is no change. For #4 the change makes the I/O ASIC free-running counter installed as a clock source so that the CP0 timer can be used as a clock event device. Unfortunately the use of the CP0 timer as a clock event device relies on a succesful completion of c0_compare_interrupt. That never happens, because while waiting for a CP0 Compare interrupt to happen the function spins in a loop reading the CP0 Count register. This makes the CP0 Count erratum trigger reliably causing the interrupt waited for to be lost in all cases. As a result #4 resorts to using the CP0 timer as a clock source as well, just as #2. However we want to keep this separate arrangement in case (hope) c0_compare_interrupt is eventually rewritten such that it avoids the erratum. Signed-off-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5825/ Signed-off-by: Ralf Baechle --- arch/mips/dec/time.c | 22 +++++++++++++++++++--- arch/mips/include/asm/dec/ioasic.h | 2 +- arch/mips/kernel/csrc-ioasic.c | 8 +++++++- 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index 56ebc7f2bede..1914e56f0d96 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -125,12 +125,16 @@ int rtc_mips_set_mmss(unsigned long nowtime) void __init plat_time_init(void) { + int ioasic_clock = 0; u32 start, end; int i = HZ / 8; /* Set up the rate of periodic DS1287 interrupts. */ ds1287_set_base_clock(HZ); + /* On some I/O ASIC systems we have the I/O ASIC's counter. */ + if (IOASIC) + ioasic_clock = dec_ioasic_clocksource_init() == 0; if (cpu_has_counter) { ds1287_timer_state(); while (!ds1287_timer_state()) @@ -147,9 +151,21 @@ void __init plat_time_init(void) mips_hpt_frequency = (end - start) * 8; printk(KERN_INFO "MIPS counter frequency %dHz\n", mips_hpt_frequency); - } else if (IOASIC) - /* For pre-R4k systems we use the I/O ASIC's counter. */ - dec_ioasic_clocksource_init(); + + /* + * All R4k DECstations suffer from the CP0 Count erratum, + * so we can't use the timer as a clock source, and a clock + * event both at a time. An accurate wall clock is more + * important than a high-precision interval timer so only + * use the timer as a clock source, and not a clock event + * if there's no I/O ASIC counter available to serve as a + * clock source. + */ + if (!ioasic_clock) { + init_r4k_clocksource(); + mips_hpt_frequency = 0; + } + } ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]); } diff --git a/arch/mips/include/asm/dec/ioasic.h b/arch/mips/include/asm/dec/ioasic.h index 98badd6bf22d..be4d62a5a10e 100644 --- a/arch/mips/include/asm/dec/ioasic.h +++ b/arch/mips/include/asm/dec/ioasic.h @@ -33,6 +33,6 @@ static inline u32 ioasic_read(unsigned int reg) extern void init_ioasic_irqs(int base); -extern void dec_ioasic_clocksource_init(void); +extern int dec_ioasic_clocksource_init(void); #endif /* __ASM_DEC_IOASIC_H */ diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c index 87e88feb4a25..6cbbf6e106b9 100644 --- a/arch/mips/kernel/csrc-ioasic.c +++ b/arch/mips/kernel/csrc-ioasic.c @@ -37,7 +37,7 @@ static struct clocksource clocksource_dec = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -void __init dec_ioasic_clocksource_init(void) +int __init dec_ioasic_clocksource_init(void) { unsigned int freq; u32 start, end; @@ -56,8 +56,14 @@ void __init dec_ioasic_clocksource_init(void) end = dec_ioasic_hpt_read(&clocksource_dec); freq = (end - start) * 8; + + /* An early revision of the I/O ASIC didn't have the counter. */ + if (!freq) + return -ENXIO; + printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); clocksource_dec.rating = 200 + freq / 10000000; clocksource_register_hz(&clocksource_dec, freq); + return 0; } -- cgit v1.2.3 From 5359b938c088423a28c41499f183cd10824c1816 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 12 Sep 2013 12:14:31 +0100 Subject: MIPS: DECstation I/O ASIC DMA interrupt handling fix This change complements commit d0da7c002f7b2a93582187a9e3f73891a01d8ee4 and brings clear_ioasic_irq back, renaming it to clear_ioasic_dma_irq at the same time, to make I/O ASIC DMA interrupts functional. Unlike ordinary I/O ASIC interrupts DMA interrupts need to be deasserted by software by writing 0 to the respective bit in I/O ASIC's System Interrupt Register (SIR), similarly to how CP0.Cause.IP0 and CP0.Cause.IP1 bits are handled in the CPU (the difference is SIR DMA interrupt bits are R/W0C so there's no need for an RMW cycle). Otherwise the handler is reentered over and over again. The only current user is the DEC LANCE Ethernet driver and its extremely uncommon DMA memory error handler that does not care when exactly the interrupt is cleared. Anticipating the use of DMA interrupts by the Zilog SCC driver this change however exports clear_ioasic_dma_irq for device drivers to choose the right application-specific sequence to clear the request explicitly rather than calling it implicitly in the .irq_eoi handler of `struct irq_chip'. Previously these interrupts were cleared in the .end handler of the said structure, before it was removed. Signed-off-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5826/ Signed-off-by: Ralf Baechle --- arch/mips/dec/ioasic-irq.c | 8 ++++++++ arch/mips/include/asm/dec/ioasic.h | 2 ++ drivers/net/ethernet/amd/declance.c | 1 + 3 files changed, 11 insertions(+) (limited to 'arch') diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c index 824e08c73798..4b3e3a4375a6 100644 --- a/arch/mips/dec/ioasic-irq.c +++ b/arch/mips/dec/ioasic-irq.c @@ -51,6 +51,14 @@ static struct irq_chip ioasic_irq_type = { .irq_unmask = unmask_ioasic_irq, }; +void clear_ioasic_dma_irq(unsigned int irq) +{ + u32 sir; + + sir = ~(1 << (irq - ioasic_irq_base)); + ioasic_write(IO_REG_SIR, sir); +} + static struct irq_chip ioasic_dma_irq_type = { .name = "IO-ASIC-DMA", .irq_ack = ack_ioasic_irq, diff --git a/arch/mips/include/asm/dec/ioasic.h b/arch/mips/include/asm/dec/ioasic.h index be4d62a5a10e..a6e505a0e44b 100644 --- a/arch/mips/include/asm/dec/ioasic.h +++ b/arch/mips/include/asm/dec/ioasic.h @@ -31,6 +31,8 @@ static inline u32 ioasic_read(unsigned int reg) return ioasic_base[reg / 4]; } +extern void clear_ioasic_dma_irq(unsigned int irq); + extern void init_ioasic_irqs(int base); extern int dec_ioasic_clocksource_init(void); diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c index 3d86ffeb4e15..94edc9c6fbbf 100644 --- a/drivers/net/ethernet/amd/declance.c +++ b/drivers/net/ethernet/amd/declance.c @@ -725,6 +725,7 @@ static irqreturn_t lance_dma_merr_int(int irq, void *dev_id) { struct net_device *dev = dev_id; + clear_ioasic_dma_irq(irq); printk(KERN_ERR "%s: DMA error\n", dev->name); return IRQ_HANDLED; } -- cgit v1.2.3 From 670bac3a8c201fc1f5f92ac6b4a8b42dc8172937 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Wed, 11 Sep 2013 14:17:47 -0500 Subject: MIPS: Fix SMP core calculations when using MT support. The TCBIND register is only available if the core has MT support. It should not be read otherwise. Secondly, the number of TCs (siblings) are calculated differently depending on if the kernel is configured as SMVP or SMTC. Signed-off-by: Leonid Yegoshin Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5822/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp-cmp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/mips/kernel/smp-cmp.c b/arch/mips/kernel/smp-cmp.c index c2e5d74739b4..5969f1e9b62a 100644 --- a/arch/mips/kernel/smp-cmp.c +++ b/arch/mips/kernel/smp-cmp.c @@ -99,7 +99,9 @@ static void cmp_init_secondary(void) c->core = (read_c0_ebase() >> 1) & 0x1ff; #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) - c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE; + if (cpu_has_mipsmt) + c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & + TCBIND_CURVPE; #endif #ifdef CONFIG_MIPS_MT_SMTC c->tc_id = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; @@ -177,9 +179,16 @@ void __init cmp_smp_setup(void) } if (cpu_has_mipsmt) { - unsigned int nvpe, mvpconf0 = read_c0_mvpconf0(); + unsigned int nvpe = 1; +#ifdef CONFIG_MIPS_MT_SMP + unsigned int mvpconf0 = read_c0_mvpconf0(); + + nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; +#elif defined(CONFIG_MIPS_MT_SMTC) + unsigned int mvpconf0 = read_c0_mvpconf0(); nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; +#endif smp_num_siblings = nvpe; } pr_info("Detected %i available secondary CPU(s)\n", ncpu); -- cgit v1.2.3 From 1b4676330aa6782bd73ec24cb4896467475f29f5 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 11 Sep 2013 13:17:52 +0100 Subject: MIPS: kernel: vpe: Make vpe_attrs an array of pointers. Commit 567b21e973ccf5b0d13776e408d7c67099749eb8 "mips: convert vpe_class to use dev_groups" broke the build on MIPS since vpe_attrs should be an array of 'struct device_attribute' pointers. Fixes the following build problem: arch/mips/kernel/vpe.c:1372:2: error: missing braces around initializer [-Werror=missing-braces] arch/mips/kernel/vpe.c:1372:2: error: (near initialization for 'vpe_attrs[0]') [-Werror=missing-braces] Cc: Ralf Baechle Cc: John Crispin Cc: Greg Kroah-Hartman Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5819/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/vpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index faf84c5f2629..59b2b3cd7885 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -1368,7 +1368,7 @@ out_einval: } static DEVICE_ATTR_RW(ntcs); -static struct attribute vpe_attrs[] = { +static struct attribute *vpe_attrs[] = { &dev_attr_kill.attr, &dev_attr_ntcs.attr, NULL, -- cgit v1.2.3