aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 08:37:40 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 08:37:40 -0700
commitec31b2124158f60c515ed84bd5e40db1a883c7b6 (patch)
tree05de4bebce63cf1eaf25d24c9de4b59e5aa7e100 /arch/powerpc/platforms
parentca72cddfcb6afd75a808da4f027325fa63a1b856 (diff)
parenteabd90944b3a00766e84da3d117ea0f3e0a3b1a3 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: [POWERPC] Fix crashkernel= handling when no crashkernel= specified [POWERPC] Make emergency stack safe for current_thread_info() use [POWERPC] spufs: add .gitignore for spu_save_dump.h & spu_restore_dump.h [POWERPC] spufs: trace spu_acquire_saved events [POWERPC] spufs: fix marker name for find_victim [POWERPC] spufs: add marker for destroy_spu_context [POWERPC] spufs: add sputrace marker parameter names [POWERPC] spufs: add context switch notification log [POWERPC] mpc5200: defconfigs for CM5200, Lite5200B, Motion-PRO and TQM5200 [POWERPC] mpc5200: Switch mpc5200 dts files to dts-v1 format [POWERPC] mpc5200: Fix FEC error handling on FIFO errors [POWERPC] mpc5200: add Phytec pcm030 board support [POWERPC] mpc5200: add gpiolib support for mpc5200 [POWERPC] mpc5200: add interrupt type function [POWERPC] mpc5200: Fix unterminated of_device_id table
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/52xx/Kconfig6
-rw-r--r--arch/powerpc/platforms/52xx/Makefile2
-rw-r--r--arch/powerpc/platforms/52xx/mpc5200_simple.c1
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_gpio.c465
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c38
-rw-r--r--arch/powerpc/platforms/cell/spufs/.gitignore2
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c166
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h33
-rw-r--r--arch/powerpc/platforms/cell/spufs/sputrace.c36
12 files changed, 738 insertions, 21 deletions
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig
index cf945d55c27..acd2fc8cf49 100644
--- a/arch/powerpc/platforms/52xx/Kconfig
+++ b/arch/powerpc/platforms/52xx/Kconfig
@@ -44,3 +44,9 @@ config PPC_MPC5200_BUGFIX
It is safe to say 'Y' here
+config PPC_MPC5200_GPIO
+ bool "MPC5200 GPIO support"
+ depends on PPC_MPC52xx
+ select HAVE_GPIO_LIB
+ help
+ Enable gpiolib support for mpc5200 based boards
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
index fe1b81bb522..daf0e1568d6 100644
--- a/arch/powerpc/platforms/52xx/Makefile
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -14,3 +14,5 @@ obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o
ifeq ($(CONFIG_PPC_LITE5200),y)
obj-$(CONFIG_PM) += lite5200_sleep.o lite5200_pm.o
endif
+
+obj-$(CONFIG_PPC_MPC5200_GPIO) += mpc52xx_gpio.o \ No newline at end of file
diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c
index c48b82bc2aa..a3bda0b9f1f 100644
--- a/arch/powerpc/platforms/52xx/mpc5200_simple.c
+++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c
@@ -51,6 +51,7 @@ static void __init mpc5200_simple_setup_arch(void)
/* list of the supported boards */
static char *board[] __initdata = {
"promess,motionpro",
+ "phytec,pcm030",
"schindler,cm5200",
"tqc,tqm5200",
NULL
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpio.c b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
new file mode 100644
index 00000000000..48da5dfe485
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpio.c
@@ -0,0 +1,465 @@
+/*
+ * MPC52xx gpio driver
+ *
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+
+#include <asm/gpio.h>
+#include <asm/mpc52xx.h>
+#include <sysdev/fsl_soc.h>
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+struct mpc52xx_gpiochip {
+ struct of_mm_gpio_chip mmchip;
+ unsigned int shadow_dvo;
+ unsigned int shadow_gpioe;
+ unsigned int shadow_ddr;
+};
+
+/*
+ * GPIO LIB API implementation for wakeup GPIOs.
+ *
+ * There's a maximum of 8 wakeup GPIOs. Which of these are available
+ * for use depends on your board setup.
+ *
+ * 0 -> GPIO_WKUP_7
+ * 1 -> GPIO_WKUP_6
+ * 2 -> PSC6_1
+ * 3 -> PSC6_0
+ * 4 -> ETH_17
+ * 5 -> PSC3_9
+ * 6 -> PSC2_4
+ * 7 -> PSC1_4
+ *
+ */
+static int mpc52xx_wkup_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
+ unsigned int ret;
+
+ ret = (in_8(&regs->wkup_ival) >> (7 - gpio)) & 1;
+
+ pr_debug("%s: gpio: %d ret: %d\n", __func__, gpio, ret);
+
+ return ret;
+}
+
+static inline void
+__mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+ struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpio_wkup __iomem *regs = mm_gc->regs;
+
+ if (val)
+ chip->shadow_dvo |= 1 << (7 - gpio);
+ else
+ chip->shadow_dvo &= ~(1 << (7 - gpio));
+
+ out_8(&regs->wkup_dvo, chip->shadow_dvo);
+}
+
+static void
+mpc52xx_wkup_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ __mpc52xx_wkup_gpio_set(gc, gpio, val);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+}
+
+static int mpc52xx_wkup_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+ struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpio_wkup *regs = mm_gc->regs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ /* set the direction */
+ chip->shadow_ddr &= ~(1 << (7 - gpio));
+ out_8(&regs->wkup_ddr, chip->shadow_ddr);
+
+ /* and enable the pin */
+ chip->shadow_gpioe |= 1 << (7 - gpio);
+ out_8(&regs->wkup_gpioe, chip->shadow_gpioe);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return 0;
+}
+
+static int
+mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpio_wkup *regs = mm_gc->regs;
+ struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+ struct mpc52xx_gpiochip, mmchip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ __mpc52xx_wkup_gpio_set(gc, gpio, val);
+
+ /* Then set direction */
+ chip->shadow_ddr |= 1 << (7 - gpio);
+ out_8(&regs->wkup_ddr, chip->shadow_ddr);
+
+ /* Finally enable the pin */
+ chip->shadow_gpioe |= 1 << (7 - gpio);
+ out_8(&regs->wkup_gpioe, chip->shadow_gpioe);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+
+ return 0;
+}
+
+static int __devinit mpc52xx_wkup_gpiochip_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct mpc52xx_gpiochip *chip;
+ struct mpc52xx_gpio_wkup *regs;
+ struct of_gpio_chip *ofchip;
+ int ret;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ ofchip = &chip->mmchip.of_gc;
+
+ ofchip->gpio_cells = 2;
+ ofchip->gc.ngpio = 8;
+ ofchip->gc.direction_input = mpc52xx_wkup_gpio_dir_in;
+ ofchip->gc.direction_output = mpc52xx_wkup_gpio_dir_out;
+ ofchip->gc.get = mpc52xx_wkup_gpio_get;
+ ofchip->gc.set = mpc52xx_wkup_gpio_set;
+
+ ret = of_mm_gpiochip_add(ofdev->node, &chip->mmchip);
+ if (ret)
+ return ret;
+
+ regs = chip->mmchip.regs;
+ chip->shadow_gpioe = in_8(&regs->wkup_gpioe);
+ chip->shadow_ddr = in_8(&regs->wkup_ddr);
+ chip->shadow_dvo = in_8(&regs->wkup_dvo);
+
+ return 0;
+}
+
+static int mpc52xx_gpiochip_remove(struct of_device *ofdev)
+{
+ return -EBUSY;
+}
+
+static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = {
+ {
+ .compatible = "fsl,mpc5200-gpio-wkup",
+ },
+ {}
+};
+
+static struct of_platform_driver mpc52xx_wkup_gpiochip_driver = {
+ .name = "gpio_wkup",
+ .match_table = mpc52xx_wkup_gpiochip_match,
+ .probe = mpc52xx_wkup_gpiochip_probe,
+ .remove = mpc52xx_gpiochip_remove,
+};
+
+/*
+ * GPIO LIB API implementation for simple GPIOs
+ *
+ * There's a maximum of 32 simple GPIOs. Which of these are available
+ * for use depends on your board setup.
+ * The numbering reflects the bit numbering in the port registers:
+ *
+ * 0..1 > reserved
+ * 2..3 > IRDA
+ * 4..7 > ETHR
+ * 8..11 > reserved
+ * 12..15 > USB
+ * 16..17 > reserved
+ * 18..23 > PSC3
+ * 24..27 > PSC2
+ * 28..31 > PSC1
+ */
+static int mpc52xx_simple_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
+ unsigned int ret;
+
+ ret = (in_be32(&regs->simple_ival) >> (31 - gpio)) & 1;
+
+ return ret;
+}
+
+static inline void
+__mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+ struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpio __iomem *regs = mm_gc->regs;
+
+ if (val)
+ chip->shadow_dvo |= 1 << (31 - gpio);
+ else
+ chip->shadow_dvo &= ~(1 << (31 - gpio));
+ out_be32(&regs->simple_dvo, chip->shadow_dvo);
+}
+
+static void
+mpc52xx_simple_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ __mpc52xx_simple_gpio_set(gc, gpio, val);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+}
+
+static int mpc52xx_simple_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+ struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpio *regs = mm_gc->regs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ /* set the direction */
+ chip->shadow_ddr &= ~(1 << (31 - gpio));
+ out_be32(&regs->simple_ddr, chip->shadow_ddr);
+
+ /* and enable the pin */
+ chip->shadow_gpioe |= 1 << (31 - gpio);
+ out_be32(&regs->simple_gpioe, chip->shadow_gpioe);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return 0;
+}
+
+static int
+mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpiochip *chip = container_of(mm_gc,
+ struct mpc52xx_gpiochip, mmchip);
+ struct mpc52xx_gpio *regs = mm_gc->regs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ /* First set initial value */
+ __mpc52xx_simple_gpio_set(gc, gpio, val);
+
+ /* Then set direction */
+ chip->shadow_ddr |= 1 << (31 - gpio);
+ out_be32(&regs->simple_ddr, chip->shadow_ddr);
+
+ /* Finally enable the pin */
+ chip->shadow_gpioe |= 1 << (31 - gpio);
+ out_be32(&regs->simple_gpioe, chip->shadow_gpioe);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+
+ return 0;
+}
+
+static int __devinit mpc52xx_simple_gpiochip_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct mpc52xx_gpiochip *chip;
+ struct of_gpio_chip *ofchip;
+ struct mpc52xx_gpio *regs;
+ int ret;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ ofchip = &chip->mmchip.of_gc;
+
+ ofchip->gpio_cells = 2;
+ ofchip->gc.ngpio = 32;
+ ofchip->gc.direction_input = mpc52xx_simple_gpio_dir_in;
+ ofchip->gc.direction_output = mpc52xx_simple_gpio_dir_out;
+ ofchip->gc.get = mpc52xx_simple_gpio_get;
+ ofchip->gc.set = mpc52xx_simple_gpio_set;
+
+ ret = of_mm_gpiochip_add(ofdev->node, &chip->mmchip);
+ if (ret)
+ return ret;
+
+ regs = chip->mmchip.regs;
+ chip->shadow_gpioe = in_be32(&regs->simple_gpioe);
+ chip->shadow_ddr = in_be32(&regs->simple_ddr);
+ chip->shadow_dvo = in_be32(&regs->simple_dvo);
+
+ return 0;
+}
+
+static const struct of_device_id mpc52xx_simple_gpiochip_match[] = {
+ {
+ .compatible = "fsl,mpc5200-gpio",
+ },
+ {}
+};
+
+static struct of_platform_driver mpc52xx_simple_gpiochip_driver = {
+ .name = "gpio",
+ .match_table = mpc52xx_simple_gpiochip_match,
+ .probe = mpc52xx_simple_gpiochip_probe,
+ .remove = mpc52xx_gpiochip_remove,
+};
+
+/*
+ * GPIO LIB API implementation for gpt GPIOs.
+ *
+ * Each gpt only has a single GPIO.
+ */
+static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpt __iomem *regs = mm_gc->regs;
+ unsigned int ret;
+
+ return (in_be32(&regs->status) & (1 << (31 - 23))) ? 1 : 0;
+
+ return ret;
+}
+
+static void
+mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpt __iomem *regs = mm_gc->regs;
+
+ if (val)
+ out_be32(&regs->mode, 0x34);
+ else
+ out_be32(&regs->mode, 0x24);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+}
+
+static int mpc52xx_gpt_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc52xx_gpt *regs = mm_gc->regs;
+
+ out_be32(&regs->mode, 0x04);
+
+ return 0;
+}
+
+static int
+mpc52xx_gpt_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ mpc52xx_gpt_gpio_set(gc, gpio, val);
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+
+ return 0;
+}
+
+static int __devinit mpc52xx_gpt_gpiochip_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct of_mm_gpio_chip *mmchip;
+ struct of_gpio_chip *chip;
+
+ mmchip = kzalloc(sizeof(*mmchip), GFP_KERNEL);
+ if (!mmchip)
+ return -ENOMEM;
+
+ chip = &mmchip->of_gc;
+
+ chip->gpio_cells = 2;
+ chip->gc.ngpio = 1;
+ chip->gc.direction_input = mpc52xx_gpt_gpio_dir_in;
+ chip->gc.direction_output = mpc52xx_gpt_gpio_dir_out;
+ chip->gc.get = mpc52xx_gpt_gpio_get;
+ chip->gc.set = mpc52xx_gpt_gpio_set;
+
+ return of_mm_gpiochip_add(ofdev->node, mmchip);
+}
+
+static const struct of_device_id mpc52xx_gpt_gpiochip_match[] = {
+ {
+ .compatible = "fsl,mpc5200-gpt-gpio",
+ },
+ {}
+};
+
+static struct of_platform_driver mpc52xx_gpt_gpiochip_driver = {
+ .name = "gpio_gpt",
+ .match_table = mpc52xx_gpt_gpiochip_match,
+ .probe = mpc52xx_gpt_gpiochip_probe,
+ .remove = mpc52xx_gpiochip_remove,
+};
+
+static int __init mpc52xx_gpio_init(void)
+{
+ if (of_register_platform_driver(&mpc52xx_wkup_gpiochip_driver))
+ printk(KERN_ERR "Unable to register wakeup GPIO driver\n");
+
+ if (of_register_platform_driver(&mpc52xx_simple_gpiochip_driver))
+ printk(KERN_ERR "Unable to register simple GPIO driver\n");
+
+ if (of_register_platform_driver(&mpc52xx_gpt_gpiochip_driver))
+ printk(KERN_ERR "Unable to register gpt GPIO driver\n");
+
+ return 0;
+}
+
+
+/* Make sure we get initialised before anyone else tries to use us */
+subsys_initcall(mpc52xx_gpio_init);
+
+/* No exit call at the moment as we cannot unregister of gpio chips */
+
+MODULE_DESCRIPTION("Freescale MPC52xx gpio driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index d0dead8b9a9..8479394e9ab 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -18,6 +18,7 @@
#undef DEBUG
+#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <asm/io.h>
@@ -109,11 +110,48 @@ static void mpc52xx_extirq_ack(unsigned int virq)
io_be_setbit(&intr->ctrl, 27-l2irq);
}
+static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
+{
+ u32 ctrl_reg, type;
+ int irq;
+ int l2irq;
+
+ irq = irq_map[virq].hwirq;
+ l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
+
+ pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type);
+
+ switch (flow_type) {
+ case IRQF_TRIGGER_HIGH:
+ type = 0;
+ break;
+ case IRQF_TRIGGER_RISING:
+ type = 1;
+ break;
+ case IRQF_TRIGGER_FALLING:
+ type = 2;
+ break;
+ case IRQF_TRIGGER_LOW:
+ type = 3;
+ break;
+ default:
+ type = 0;
+ }
+
+ ctrl_reg = in_be32(&intr->ctrl);
+ ctrl_reg &= ~(0x3 << (22 - (l2irq * 2)));
+ ctrl_reg |= (type << (22 - (l2irq * 2)));
+ out_be32(&intr->ctrl, ctrl_reg);
+
+ return 0;
+}
+
static struct irq_chip mpc52xx_extirq_irqchip = {
.typename = " MPC52xx IRQ[0-3] ",
.mask = mpc52xx_extirq_mask,
.unmask = mpc52xx_extirq_unmask,
.ack = mpc52xx_extirq_ack,
+ .set_type = mpc52xx_extirq_set_type,
};
/*
diff --git a/arch/powerpc/platforms/cell/spufs/.gitignore b/arch/powerpc/platforms/cell/spufs/.gitignore
new file mode 100644
index 00000000000..a09ee8d84d6
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/.gitignore
@@ -0,0 +1,2 @@
+spu_save_dump.h
+spu_restore_dump.h
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 0ad83aeb70b..177735f7931 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -78,6 +78,7 @@ void destroy_spu_context(struct kref *kref)
{
struct spu_context *ctx;
ctx = container_of(kref, struct spu_context, kref);
+ spu_context_nospu_trace(destroy_spu_context__enter, ctx);
mutex_lock(&ctx->state_mutex);
spu_deactivate(ctx);
mutex_unlock(&ctx->state_mutex);
@@ -88,6 +89,7 @@ void destroy_spu_context(struct kref *kref)
kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
BUG_ON(!list_empty(&ctx->rq));
atomic_dec(&nr_spu_contexts);
+ kfree(ctx->switch_log);
kfree(ctx);
}
@@ -150,6 +152,8 @@ int spu_acquire_saved(struct spu_context *ctx)
{
int ret;
+ spu_context_nospu_trace(spu_acquire_saved__enter, ctx);
+
ret = spu_acquire(ctx);
if (ret)
return ret;
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 08f44d1971a..80911a37340 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -2386,6 +2386,171 @@ static const struct file_operations spufs_stat_fops = {
.release = single_release,
};
+static inline int spufs_switch_log_used(struct spu_context *ctx)
+{
+ return (ctx->switch_log->head - ctx->switch_log->tail) %
+ SWITCH_LOG_BUFSIZE;
+}
+
+static inline int spufs_switch_log_avail(struct spu_context *ctx)
+{
+ return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx);
+}
+
+static int spufs_switch_log_open(struct inode *inode, struct file *file)
+{
+ struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
+
+ /*
+ * We (ab-)use the mapping_lock here because it serves the similar
+ * purpose for synchronizing open/close elsewhere. Maybe it should
+ * be renamed eventually.
+ */
+ mutex_lock(&ctx->mapping_lock);
+ if (ctx->switch_log) {
+ spin_lock(&ctx->switch_log->lock);
+ ctx->switch_log->head = 0;
+ ctx->switch_log->tail = 0;
+ spin_unlock(&ctx->switch_log->lock);
+ } else {
+ /*
+ * We allocate the switch log data structures on first open.
+ * They will never be free because we assume a context will
+ * be traced until it goes away.
+ */
+ ctx->switch_log = kzalloc(sizeof(struct switch_log) +
+ SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry),
+ GFP_KERNEL);
+ if (!ctx->switch_log)
+ goto out;
+ spin_lock_init(&ctx->switch_log->lock);
+ init_waitqueue_head(&ctx->switch_log->wait);
+ }
+ mutex_unlock(&ctx->mapping_lock);
+
+ return 0;
+ out:
+ mutex_unlock(&ctx->mapping_lock);
+ return -ENOMEM;
+}
+
+static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n)
+{
+ struct switch_log_entry *p;
+
+ p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE;
+
+ return snprintf(tbuf, n, "%u.%09u %d %u %u %llu\n",
+ (unsigned int) p->tstamp.tv_sec,
+ (unsigned int) p->tstamp.tv_nsec,
+ p->spu_id,
+ (unsigned int) p->type,
+ (unsigned int) p->val,
+ (unsigned long long) p->timebase);
+}
+
+static ssize_t spufs_switch_log_read(struct file *file, char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
+ int error = 0, cnt = 0;
+
+ if (!buf || len < 0)
+ return -EINVAL;
+
+ while (cnt < len) {
+ char tbuf[128];
+ int width;
+
+ if (file->f_flags & O_NONBLOCK) {
+ if (spufs_switch_log_used(ctx) <= 0)
+ return cnt ? cnt : -EAGAIN;
+ } else {
+ /* Wait for data in buffer */
+ error = wait_event_interruptible(ctx->switch_log->wait,
+ spufs_switch_log_used(ctx) > 0);
+ if (error)
+ break;
+ }
+
+ spin_lock(&ctx->switch_log->lock);
+ if (ctx->switch_log->head == ctx->switch_log->tail) {
+ /* multiple readers race? */
+ spin_unlock(&ctx->switch_log->lock);
+ continue;
+ }
+
+ width = switch_log_sprint(ctx, tbuf, sizeof(tbuf));
+ if (width < len) {
+ ctx->switch_log->tail =
+ (ctx->switch_log->tail + 1) %
+ SWITCH_LOG_BUFSIZE;
+ }
+
+ spin_unlock(&ctx->switch_log->lock);
+
+ /*
+ * If the record is greater than space available return
+ * partial buffer (so far)
+ */
+ if (width >= len)
+ break;
+
+ error = copy_to_user(buf + cnt, tbuf, width);
+ if (error)
+ break;
+ cnt += width;
+ }
+
+ return cnt == 0 ? error : cnt;
+}
+
+static unsigned int spufs_switch_log_poll(struct file *file, poll_table *wait)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct spu_context *ctx = SPUFS_I(inode)->i_ctx;
+ unsigned int mask = 0;
+
+ poll_wait(file, &ctx->switch_log->wait, wait);
+
+ if (spufs_switch_log_used(ctx) > 0)
+ mask |= POLLIN;
+
+ return mask;
+}
+
+static const struct file_operations spufs_switch_log_fops = {
+ .owner = THIS_MODULE,
+ .open = spufs_switch_log_open,
+ .read = spufs_switch_log_read,
+ .poll = spufs_switch_log_poll,
+};
+
+void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx,
+ u32 type, u32 val)
+{
+ if (!ctx->switch_log)
+ return;
+
+ spin_lock(&ctx->switch_log->lock);
+ if (spufs_switch_log_avail(ctx) > 1) {
+ struct switch_log_entry *p;
+
+ p = ctx->switch_log->log + ctx->switch_log->head;
+ ktime_get_ts(&p->tstamp);
+ p->timebase = get_tb();
+ p->spu_id = spu ? spu->number : -1;
+ p->type = type;
+ p->val = val;
+
+ ctx->switch_log->head =
+ (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE;
+ }
+ spin_unlock(&ctx->switch_log->lock);
+
+ wake_up(&ctx->switch_log->wait);
+}
struct tree_descr spufs_dir_contents[] = {
{ "capabilities", &spufs_caps_fops, 0444, },
@@ -2422,6 +2587,7 @@ struct tree_descr spufs_dir_contents[] = {
{ "proxydma_info", &spufs_proxydma_info_fops, 0444, },
{ "tid", &spufs_tid_fops, 0444, },
{ "stat", &spufs_stat_fops, 0444, },
+ { "switch_log", &spufs_switch_log_fops, 0444 },
{},
};
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 96bf7c2b86f..a9c35b7b719 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -405,6 +405,8 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
ret = spu_run_fini(ctx, npc, &status);
spu_yield(ctx);
+ spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, status);
+
if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
(((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100))
ctx->stats.libassist++;
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 45dcd269350..7298e7db2c8 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -240,6 +240,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
spu->mfc_callback = spufs_mfc_callback;
mb();
spu_unmap_mappings(ctx);
+ spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0);
spu_restore(&ctx->csa, spu);
spu->timestamp = jiffies;
spu_cpu_affinity_set(spu, raw_smp_processor_id());
@@ -419,6 +420,7 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
spu_switch_notify(spu, NULL);
spu_unmap_mappings(ctx);
spu_save(&ctx->csa, spu);
+ spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0);
spu->timestamp = jiffies;
ctx->state = SPU_STATE_SAVED;
spu->ibox_callback = NULL;
@@ -591,7 +593,7 @@ static struct spu *find_victim(struct spu_context *ctx)
struct spu *spu;
int node, n;
- spu_context_nospu_trace(spu_find_vitim__enter, ctx);
+ spu_context_nospu_trace(spu_find_victim__enter, ctx);
/*
* Look for a possible preemption candidate on the local node first.
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index cdc515182f8..7312745b754 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -47,6 +47,30 @@ enum {
SPU_SCHED_SPU_RUN, /* context is within spu_run */
};
+enum {
+ SWITCH_LOG_BUFSIZE = 4096,
+};
+
+enum {
+ SWITCH_LOG_START,
+ SWITCH_LOG_STOP,
+ SWITCH_LOG_EXIT,
+};
+
+struct switch_log {
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ unsigned long head;
+ unsigned long tail;
+ struct switch_log_entry {
+ struct timespec tstamp;
+ s32 spu_id;
+ u32 type;
+ u32 val;
+ u64 timebase;
+ } log[];
+};
+
struct spu_context {
struct spu *spu; /* pointer to a physical SPU */
struct spu_state csa; /* SPU context save area. */
@@ -116,6 +140,9 @@ struct spu_context {
unsigned long long libassist;
} stats;
+ /* context switch log */
+ struct switch_log *switch_log;
+
struct list_head aff_list;
int aff_head;
int aff_offset;
@@ -256,6 +283,8 @@ int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx);
void spu_yield(struct spu_context *ctx);
void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
+void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx,
+ u32 type, u32 val);
void spu_set_timeslice(struct spu_context *ctx);
void spu_update_sched_info(struct spu_context *ctx);
void __spu_update_sched_info(struct spu_context *ctx);
@@ -330,8 +359,8 @@ extern void spuctx_switch_state(struct spu_context *ctx,
enum spu_utilization_state new_state);
#define spu_context_trace(name, ctx, spu) \
- trace_mark(name, "%p %p", ctx, spu);
+ trace_mark(name, "ctx %p spu %p", ctx, spu);
#define spu_context_nospu_trace(name, ctx) \
- trace_mark(name, "%p", ctx);
+ trace_mark(name, "ctx %p", ctx);
#endif
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c
index aea5286f124..53202422ba7 100644
--- a/arch/powerpc/platforms/cell/spufs/sputrace.c
+++ b/arch/powerpc/platforms/cell/spufs/sputrace.c
@@ -171,24 +171,24 @@ static void spu_context_nospu_event(void *probe_private, void *call_data,
}
struct spu_probe spu_probes[] = {
- { "spu_bind_context__enter", "%p %p", spu_context_event },
- { "spu_unbind_context__enter", "%p %p", spu_context_event },
- { "spu_get_idle__enter", "%p", spu_context_nospu_event },
- { "spu_get_idle__found", "%p %p", spu_context_event },
- { "spu_get_idle__not_found", "%p", spu_context_nospu_event },
- { "spu_find_victim__enter", "%p", spu_context_nospu_event },
- { "spusched_tick__preempt", "%p %p", spu_context_event },
- { "spusched_tick__newslice", "%p", spu_context_nospu_event },
- { "spu_yield__enter", "%p", spu_context_nospu_event },
- { "spu_deactivate__enter", "%p", spu_context_nospu_event },
- { "__spu_deactivate__unload", "%p %p", spu_context_event },
- { "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event },
- { "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event },
- { "spufs_ps_nopfn__wake", "%p %p", spu_context_event },
- { "spufs_ps_nopfn__insert", "%p %p", spu_context_event },
- { "spu_acquire_saved__enter", "%p", spu_context_nospu_event },
- { "destroy_spu_context__enter", "%p", spu_context_nospu_event },
- { "spufs_stop_callback__enter", "%p %p", spu_context_event },
+ { "spu_bind_context__enter", "ctx %p spu %p", spu_context_event },
+ { "spu_unbind_context__enter", "ctx %p spu %p", spu_context_event },
+ { "spu_get_idle__enter", "ctx %p", spu_context_nospu_event },
+ { "spu_get_idle__found", "ctx %p spu %p", spu_context_event },
+ { "spu_get_idle__not_found", "ctx %p", spu_context_nospu_event },
+ { "spu_find_victim__enter", "ctx %p", spu_context_nospu_event },
+ { "spusched_tick__preempt", "ctx %p spu %p", spu_context_event },
+ { "spusched_tick__newslice", "ctx %p", spu_context_nospu_event },
+ { "spu_yield__enter", "ctx %p", spu_context_nospu_event },
+ { "spu_deactivate__enter", "ctx %p", spu_context_nospu_event },
+ { "__spu_deactivate__unload", "ctx %p spu %p", spu_context_event },
+ { "spufs_ps_nopfn__enter", "ctx %p", spu_context_nospu_event },
+ { "spufs_ps_nopfn__sleep", "ctx %p", spu_context_nospu_event },
+ { "spufs_ps_nopfn__wake", "ctx %p spu %p", spu_context_event },
+ { "spufs_ps_nopfn__insert", "ctx %p spu %p", spu_context_event },
+ { "spu_acquire_saved__enter", "ctx %p", spu_context_nospu_event },
+ { "destroy_spu_context__enter", "ctx %p", spu_context_nospu_event },
+ { "spufs_stop_callback__enter", "ctx %p spu %p", spu_context_event },
};
static int __init sputrace_init(void)