Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: [MIPS] Vr41xx: Fix after GENERIC_HARDIRQS_NO__DO_IRQ change [MIPS] SMTC: Instant IPI replay.hifive-unleashed-5.1
commit
d227e87e6c
|
@ -1568,6 +1568,20 @@ config MIPS_MT_FPAFF
|
||||||
depends on MIPS_MT
|
depends on MIPS_MT
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config MIPS_MT_SMTC_INSTANT_REPLAY
|
||||||
|
bool "Low-latency Dispatch of Deferred SMTC IPIs"
|
||||||
|
depends on MIPS_MT_SMTC
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
SMTC pseudo-interrupts between TCs are deferred and queued
|
||||||
|
if the target TC is interrupt-inhibited (IXMT). In the first
|
||||||
|
SMTC prototypes, these queued IPIs were serviced on return
|
||||||
|
to user mode, or on entry into the kernel idle loop. The
|
||||||
|
INSTANT_REPLAY option dispatches them as part of local_irq_restore()
|
||||||
|
processing, which adds runtime overhead (hence the option to turn
|
||||||
|
it off), but ensures that IPIs are handled promptly even under
|
||||||
|
heavy I/O interrupt load.
|
||||||
|
|
||||||
config MIPS_VPE_LOADER_TOM
|
config MIPS_VPE_LOADER_TOM
|
||||||
bool "Load VPE program into memory hidden from linux"
|
bool "Load VPE program into memory hidden from linux"
|
||||||
depends on MIPS_VPE_LOADER
|
depends on MIPS_VPE_LOADER
|
||||||
|
|
|
@ -1017,6 +1017,33 @@ void setup_cross_vpe_interrupts(void)
|
||||||
* SMTC-specific hacks invoked from elsewhere in the kernel.
|
* SMTC-specific hacks invoked from elsewhere in the kernel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void smtc_ipi_replay(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* To the extent that we've ever turned interrupts off,
|
||||||
|
* we may have accumulated deferred IPIs. This is subtle.
|
||||||
|
* If we use the smtc_ipi_qdepth() macro, we'll get an
|
||||||
|
* exact number - but we'll also disable interrupts
|
||||||
|
* and create a window of failure where a new IPI gets
|
||||||
|
* queued after we test the depth but before we re-enable
|
||||||
|
* interrupts. So long as IXMT never gets set, however,
|
||||||
|
* we should be OK: If we pick up something and dispatch
|
||||||
|
* it here, that's great. If we see nothing, but concurrent
|
||||||
|
* with this operation, another TC sends us an IPI, IXMT
|
||||||
|
* is clear, and we'll handle it as a real pseudo-interrupt
|
||||||
|
* and not a pseudo-pseudo interrupt.
|
||||||
|
*/
|
||||||
|
if (IPIQ[smp_processor_id()].depth > 0) {
|
||||||
|
struct smtc_ipi *pipi;
|
||||||
|
extern void self_ipi(struct smtc_ipi *);
|
||||||
|
|
||||||
|
while ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()]))) {
|
||||||
|
self_ipi(pipi);
|
||||||
|
smtc_cpu_stats[smp_processor_id()].selfipis++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void smtc_idle_loop_hook(void)
|
void smtc_idle_loop_hook(void)
|
||||||
{
|
{
|
||||||
#ifdef SMTC_IDLE_HOOK_DEBUG
|
#ifdef SMTC_IDLE_HOOK_DEBUG
|
||||||
|
@ -1113,29 +1140,14 @@ void smtc_idle_loop_hook(void)
|
||||||
if (pdb_msg != &id_ho_db_msg[0])
|
if (pdb_msg != &id_ho_db_msg[0])
|
||||||
printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
|
printk("CPU%d: %s", smp_processor_id(), id_ho_db_msg);
|
||||||
#endif /* SMTC_IDLE_HOOK_DEBUG */
|
#endif /* SMTC_IDLE_HOOK_DEBUG */
|
||||||
/*
|
|
||||||
* To the extent that we've ever turned interrupts off,
|
|
||||||
* we may have accumulated deferred IPIs. This is subtle.
|
|
||||||
* If we use the smtc_ipi_qdepth() macro, we'll get an
|
|
||||||
* exact number - but we'll also disable interrupts
|
|
||||||
* and create a window of failure where a new IPI gets
|
|
||||||
* queued after we test the depth but before we re-enable
|
|
||||||
* interrupts. So long as IXMT never gets set, however,
|
|
||||||
* we should be OK: If we pick up something and dispatch
|
|
||||||
* it here, that's great. If we see nothing, but concurrent
|
|
||||||
* with this operation, another TC sends us an IPI, IXMT
|
|
||||||
* is clear, and we'll handle it as a real pseudo-interrupt
|
|
||||||
* and not a pseudo-pseudo interrupt.
|
|
||||||
*/
|
|
||||||
if (IPIQ[smp_processor_id()].depth > 0) {
|
|
||||||
struct smtc_ipi *pipi;
|
|
||||||
extern void self_ipi(struct smtc_ipi *);
|
|
||||||
|
|
||||||
if ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()])) != NULL) {
|
/*
|
||||||
self_ipi(pipi);
|
* Replay any accumulated deferred IPIs. If "Instant Replay"
|
||||||
smtc_cpu_stats[smp_processor_id()].selfipis++;
|
* is in use, there should never be any.
|
||||||
}
|
*/
|
||||||
}
|
#ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
|
||||||
|
smtc_ipi_replay();
|
||||||
|
#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
|
||||||
}
|
}
|
||||||
|
|
||||||
void smtc_soft_dump(void)
|
void smtc_soft_dump(void)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Interrupt handing routines for NEC VR4100 series.
|
* Interrupt handing routines for NEC VR4100 series.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
* Copyright (C) 2005-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -73,13 +73,19 @@ static void irq_dispatch(unsigned int irq)
|
||||||
if (cascade->get_irq != NULL) {
|
if (cascade->get_irq != NULL) {
|
||||||
unsigned int source_irq = irq;
|
unsigned int source_irq = irq;
|
||||||
desc = irq_desc + source_irq;
|
desc = irq_desc + source_irq;
|
||||||
desc->chip->ack(source_irq);
|
if (desc->chip->mask_ack)
|
||||||
|
desc->chip->mask_ack(source_irq);
|
||||||
|
else {
|
||||||
|
desc->chip->mask(source_irq);
|
||||||
|
desc->chip->ack(source_irq);
|
||||||
|
}
|
||||||
irq = cascade->get_irq(irq);
|
irq = cascade->get_irq(irq);
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
atomic_inc(&irq_err_count);
|
atomic_inc(&irq_err_count);
|
||||||
else
|
else
|
||||||
irq_dispatch(irq);
|
irq_dispatch(irq);
|
||||||
desc->chip->end(source_irq);
|
if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
|
||||||
|
desc->chip->unmask(source_irq);
|
||||||
} else
|
} else
|
||||||
do_IRQ(irq);
|
do_IRQ(irq);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002 MontaVista Software Inc.
|
* Copyright (C) 2002 MontaVista Software Inc.
|
||||||
* Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
|
* Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
|
||||||
* Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
* Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -125,30 +125,17 @@ static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int startup_giuint_low_irq(unsigned int irq)
|
static void ack_giuint_low(unsigned int irq)
|
||||||
{
|
{
|
||||||
unsigned int pin;
|
giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
|
||||||
|
|
||||||
pin = GPIO_PIN_OF_IRQ(irq);
|
|
||||||
giu_write(GIUINTSTATL, 1 << pin);
|
|
||||||
giu_set(GIUINTENL, 1 << pin);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown_giuint_low_irq(unsigned int irq)
|
static void mask_giuint_low(unsigned int irq)
|
||||||
{
|
{
|
||||||
giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
|
giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_giuint_low_irq(unsigned int irq)
|
static void mask_ack_giuint_low(unsigned int irq)
|
||||||
{
|
|
||||||
giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define disable_giuint_low_irq shutdown_giuint_low_irq
|
|
||||||
|
|
||||||
static void ack_giuint_low_irq(unsigned int irq)
|
|
||||||
{
|
{
|
||||||
unsigned int pin;
|
unsigned int pin;
|
||||||
|
|
||||||
|
@ -157,46 +144,30 @@ static void ack_giuint_low_irq(unsigned int irq)
|
||||||
giu_write(GIUINTSTATL, 1 << pin);
|
giu_write(GIUINTSTATL, 1 << pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_giuint_low_irq(unsigned int irq)
|
static void unmask_giuint_low(unsigned int irq)
|
||||||
{
|
{
|
||||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
|
||||||
giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hw_interrupt_type giuint_low_irq_type = {
|
static struct irq_chip giuint_low_irq_chip = {
|
||||||
.typename = "GIUINTL",
|
.name = "GIUINTL",
|
||||||
.startup = startup_giuint_low_irq,
|
.ack = ack_giuint_low,
|
||||||
.shutdown = shutdown_giuint_low_irq,
|
.mask = mask_giuint_low,
|
||||||
.enable = enable_giuint_low_irq,
|
.mask_ack = mask_ack_giuint_low,
|
||||||
.disable = disable_giuint_low_irq,
|
.unmask = unmask_giuint_low,
|
||||||
.ack = ack_giuint_low_irq,
|
|
||||||
.end = end_giuint_low_irq,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int startup_giuint_high_irq(unsigned int irq)
|
static void ack_giuint_high(unsigned int irq)
|
||||||
{
|
{
|
||||||
unsigned int pin;
|
giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
|
||||||
|
|
||||||
pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
|
|
||||||
giu_write(GIUINTSTATH, 1 << pin);
|
|
||||||
giu_set(GIUINTENH, 1 << pin);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown_giuint_high_irq(unsigned int irq)
|
static void mask_giuint_high(unsigned int irq)
|
||||||
{
|
{
|
||||||
giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
|
giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_giuint_high_irq(unsigned int irq)
|
static void mask_ack_giuint_high(unsigned int irq)
|
||||||
{
|
|
||||||
giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define disable_giuint_high_irq shutdown_giuint_high_irq
|
|
||||||
|
|
||||||
static void ack_giuint_high_irq(unsigned int irq)
|
|
||||||
{
|
{
|
||||||
unsigned int pin;
|
unsigned int pin;
|
||||||
|
|
||||||
|
@ -205,20 +176,17 @@ static void ack_giuint_high_irq(unsigned int irq)
|
||||||
giu_write(GIUINTSTATH, 1 << pin);
|
giu_write(GIUINTSTATH, 1 << pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_giuint_high_irq(unsigned int irq)
|
static void unmask_giuint_high(unsigned int irq)
|
||||||
{
|
{
|
||||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
|
||||||
giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hw_interrupt_type giuint_high_irq_type = {
|
static struct irq_chip giuint_high_irq_chip = {
|
||||||
.typename = "GIUINTH",
|
.name = "GIUINTH",
|
||||||
.startup = startup_giuint_high_irq,
|
.ack = ack_giuint_high,
|
||||||
.shutdown = shutdown_giuint_high_irq,
|
.mask = mask_giuint_high,
|
||||||
.enable = enable_giuint_high_irq,
|
.mask_ack = mask_ack_giuint_high,
|
||||||
.disable = disable_giuint_high_irq,
|
.unmask = unmask_giuint_high,
|
||||||
.ack = ack_giuint_high_irq,
|
|
||||||
.end = end_giuint_high_irq,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int giu_get_irq(unsigned int irq)
|
static int giu_get_irq(unsigned int irq)
|
||||||
|
@ -282,9 +250,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
set_irq_chip_and_handler(GIU_IRQ(pin),
|
||||||
|
&giuint_low_irq_chip,
|
||||||
|
handle_edge_irq);
|
||||||
} else {
|
} else {
|
||||||
giu_clear(GIUINTTYPL, mask);
|
giu_clear(GIUINTTYPL, mask);
|
||||||
giu_clear(GIUINTHTSELL, mask);
|
giu_clear(GIUINTHTSELL, mask);
|
||||||
|
set_irq_chip_and_handler(GIU_IRQ(pin),
|
||||||
|
&giuint_low_irq_chip,
|
||||||
|
handle_level_irq);
|
||||||
}
|
}
|
||||||
giu_write(GIUINTSTATL, mask);
|
giu_write(GIUINTSTATL, mask);
|
||||||
} else if (pin < GIUINT_HIGH_MAX) {
|
} else if (pin < GIUINT_HIGH_MAX) {
|
||||||
|
@ -311,9 +285,15 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
set_irq_chip_and_handler(GIU_IRQ(pin),
|
||||||
|
&giuint_high_irq_chip,
|
||||||
|
handle_edge_irq);
|
||||||
} else {
|
} else {
|
||||||
giu_clear(GIUINTTYPH, mask);
|
giu_clear(GIUINTTYPH, mask);
|
||||||
giu_clear(GIUINTHTSELH, mask);
|
giu_clear(GIUINTHTSELH, mask);
|
||||||
|
set_irq_chip_and_handler(GIU_IRQ(pin),
|
||||||
|
&giuint_high_irq_chip,
|
||||||
|
handle_level_irq);
|
||||||
}
|
}
|
||||||
giu_write(GIUINTSTATH, mask);
|
giu_write(GIUINTSTATH, mask);
|
||||||
}
|
}
|
||||||
|
@ -617,10 +597,11 @@ static const struct file_operations gpio_fops = {
|
||||||
static int __devinit giu_probe(struct platform_device *dev)
|
static int __devinit giu_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
unsigned long start, size, flags = 0;
|
unsigned long start, size, flags = 0;
|
||||||
unsigned int nr_pins = 0;
|
unsigned int nr_pins = 0, trigger, i, pin;
|
||||||
struct resource *res1, *res2 = NULL;
|
struct resource *res1, *res2 = NULL;
|
||||||
void *base;
|
void *base;
|
||||||
int retval, i;
|
struct irq_chip *chip;
|
||||||
|
int retval;
|
||||||
|
|
||||||
switch (current_cpu_data.cputype) {
|
switch (current_cpu_data.cputype) {
|
||||||
case CPU_VR4111:
|
case CPU_VR4111:
|
||||||
|
@ -688,11 +669,20 @@ static int __devinit giu_probe(struct platform_device *dev)
|
||||||
giu_write(GIUINTENL, 0);
|
giu_write(GIUINTENL, 0);
|
||||||
giu_write(GIUINTENH, 0);
|
giu_write(GIUINTENH, 0);
|
||||||
|
|
||||||
|
trigger = giu_read(GIUINTTYPH) << 16;
|
||||||
|
trigger |= giu_read(GIUINTTYPL);
|
||||||
for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
|
for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
|
||||||
if (i < GIU_IRQ(GIUINT_HIGH_OFFSET))
|
pin = GPIO_PIN_OF_IRQ(i);
|
||||||
irq_desc[i].chip = &giuint_low_irq_type;
|
if (pin < GIUINT_HIGH_OFFSET)
|
||||||
|
chip = &giuint_low_irq_chip;
|
||||||
else
|
else
|
||||||
irq_desc[i].chip = &giuint_high_irq_type;
|
chip = &giuint_high_irq_chip;
|
||||||
|
|
||||||
|
if (trigger & (1 << pin))
|
||||||
|
set_irq_chip_and_handler(i, chip, handle_edge_irq);
|
||||||
|
else
|
||||||
|
set_irq_chip_and_handler(i, chip, handle_level_irq);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cascade_irq(GIUINT_IRQ, giu_get_irq);
|
return cascade_irq(GIUINT_IRQ, giu_get_irq);
|
||||||
|
|
|
@ -15,6 +15,27 @@
|
||||||
|
|
||||||
#include <asm/hazards.h>
|
#include <asm/hazards.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY does prompt replay of deferred IPIs,
|
||||||
|
* at the cost of branch and call overhead on each local_irq_restore()
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
|
||||||
|
|
||||||
|
extern void smtc_ipi_replay(void);
|
||||||
|
|
||||||
|
#define irq_restore_epilog(flags) \
|
||||||
|
do { \
|
||||||
|
if (!(flags & 0x0400)) \
|
||||||
|
smtc_ipi_replay(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define irq_restore_epilog(ignore) do { } while (0)
|
||||||
|
|
||||||
|
#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */
|
||||||
|
|
||||||
__asm__ (
|
__asm__ (
|
||||||
" .macro raw_local_irq_enable \n"
|
" .macro raw_local_irq_enable \n"
|
||||||
" .set push \n"
|
" .set push \n"
|
||||||
|
@ -193,6 +214,7 @@ do { \
|
||||||
: "=r" (__tmp1) \
|
: "=r" (__tmp1) \
|
||||||
: "0" (flags) \
|
: "0" (flags) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
|
irq_restore_epilog(flags); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
static inline int raw_irqs_disabled_flags(unsigned long flags)
|
static inline int raw_irqs_disabled_flags(unsigned long flags)
|
||||||
|
|
Loading…
Reference in New Issue