Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d227e87e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* '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.
parents f66d45e9 364ca8a8
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -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
+33 −21
Original line number Original line Diff line number Diff line
@@ -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,
	 * Replay any accumulated deferred IPIs. If "Instant Replay"
	 * we may have accumulated deferred IPIs.  This is subtle.
	 * is in use, there should never be any.
	 * 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) {
#ifndef CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY
		struct smtc_ipi *pipi;
	smtc_ipi_replay();
		extern void self_ipi(struct smtc_ipi *);
#endif /* CONFIG_MIPS_MT_SMTC_INSTANT_REPLAY */

		if ((pipi = smtc_ipi_dq(&IPIQ[smp_processor_id()])) != NULL) {
			self_ipi(pipi);
			smtc_cpu_stats[smp_processor_id()].selfipis++;
		}
	}
}
}


void smtc_soft_dump(void)
void smtc_soft_dump(void)
+9 −3
Original line number Original line Diff line number Diff line
/*
/*
 *  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;
		if (desc->chip->mask_ack)
			desc->chip->mask_ack(source_irq);
		else {
			desc->chip->mask(source_irq);
			desc->chip->ack(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);
}
}
+52 −62
Original line number Original line Diff line number Diff line
@@ -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);
+22 −0
Original line number Original line Diff line number Diff line
@@ -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)