* Re: [PATCH 35/37] KVM: PPC: booke: Support perfmon interrupts
From: Alexander Graf @ 2012-02-26 11:58 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <4F481E66.8010408@freescale.com>
On 25.02.2012, at 00:33, Scott Wood wrote:
> On 02/24/2012 08:26 AM, Alexander Graf wrote:
>> When during guest context we get a performance monitor interrupt, we
>> currently bail out and oops. Let's route it to its correct handler
>> instead.
>>=20
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>> ---
>> arch/powerpc/kvm/booke.c | 4 ++++
>> 1 files changed, 4 insertions(+), 0 deletions(-)
>>=20
>> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
>> index 7adef28..423701b 100644
>> --- a/arch/powerpc/kvm/booke.c
>> +++ b/arch/powerpc/kvm/booke.c
>> @@ -677,6 +677,10 @@ int kvmppc_handle_exit(struct kvm_run *run, =
struct kvm_vcpu *vcpu,
>> r =3D RESUME_GUEST;
>> break;
>>=20
>> + case BOOKE_INTERRUPT_PERFORMANCE_MONITOR:
>> + r =3D RESUME_GUEST;
>> + break;
>> +
>> case BOOKE_INTERRUPT_HV_PRIV:
>> r =3D emulation_exit(run, vcpu);
>> break;
>=20
> Why do we need to call timer_interrupt() explicitly, but can rely on
> automatic retriggering for perfmon?
We don't rely on automatic retriggering for perfmon. There are 2 =
different places where we need to handle an incoming exit code - the =
"reinject" code path and the "big switch over all exits" code path. This =
one deals with the latter.
Alex
^ permalink raw reply
* Re: [PATCH 36/37] KVM: PPC: booke: expose guest registers on irq reinject
From: Alexander Graf @ 2012-02-26 11:59 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <4F481FE1.1080404@freescale.com>
On 25.02.2012, at 00:40, Scott Wood wrote:
> On 02/24/2012 08:26 AM, Alexander Graf wrote:
>> +static void kvmppc_fill_pt_regs(struct kvm_vcpu *vcpu, struct =
pt_regs *regs)
>> {
>> - int r =3D RESUME_HOST;
>> + int i;
>>=20
>> - /* update before a new last_exit_type is rewritten */
>> - kvmppc_update_timing_stats(vcpu);
>> + for (i =3D 0; i < 32; i++)
>> + regs->gpr[i] =3D kvmppc_get_gpr(vcpu, i);
>> + regs->nip =3D vcpu->arch.pc;
>> + regs->msr =3D vcpu->arch.shared->msr;
>> + regs->ctr =3D vcpu->arch.ctr;
>> + regs->link =3D vcpu->arch.lr;
>> + regs->xer =3D kvmppc_get_xer(vcpu);
>> + regs->ccr =3D kvmppc_get_cr(vcpu);
>> + regs->dar =3D get_guest_dear(vcpu);
>> + regs->dsisr =3D get_guest_esr(vcpu);
>> +}
>=20
> How much overhead does this add to every interrupt? Can't we keep =
this
> to the minimum that perf cares about?
I would rather not make assumptions on what perf cares about - maybe we =
want to one day implement "perf kvm" and then perf could rely on pretty =
much anything in there.
>=20
>> +
>> +static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
>> + unsigned int exit_nr)
>> +{
>> + struct pt_regs regs =3D *current->thread.regs;
>>=20
>> + kvmppc_fill_pt_regs(vcpu, ®s);
>=20
> Why are you copying out of current->thread.regs? That's old junk =
data,
> set by some previous exception and possibly overwritten since.
Because it gives us good default values for anything we don't set. Do =
you have other recommendations?
Alex
^ permalink raw reply
* Re: [PATCH] powerpc/prom: bump up maximum size of properties
From: Benjamin Herrenschmidt @ 2012-02-26 23:22 UTC (permalink / raw)
To: Nishanth Aravamudan
Cc: linuxppc-dev, Anton Blanchard, Paul Mackerras, Robert Jennings
In-Reply-To: <1330129422-2648-1-git-send-email-nacc@us.ibm.com>
On Fri, 2012-02-24 at 16:23 -0800, Nishanth Aravamudan wrote:
> On a 16TB system (using AMS/CMO), I get:
>
> WARNING: ignoring large property [/ibm,dynamic-reconfiguration-memory] ibm,dynamic-memory length 0x000000000017ffec
>
> and significantly less memory is thus shown to the partition. As far as
> I can tell, the constant used is arbitrary, but bump it up to 2MB, which
> covers the above property (approximately 1.5MB).
>
> With this patch, the kernel does see all of the system memory on the
> 16TB system.
Why not go all the way to either removing the limit, or setting it to
something much bigger ? That's just asking to break again when we get an
even bigger system.
The limit was originally set because of Apple machines carrying ROM
images in the device-tree, at a time where we were much more memory
constrained than we are now.
But even then, it never represented such a large gain and in the end,
was probably not -that- useful.
I'd say bump it to something really large like 16M or remove the limit
alltogether.
Cheers,
Ben.
> Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
> Cc: Anton Blanchard <anton@au1.ibm.com>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Robert Jennings <rcj@linux.vnet.ibm.com>
> Cc: linuxppc-dev@lists.ozlabs.org
> ---
> arch/powerpc/kernel/prom_init.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
> index eca626e..0bf0ccc 100644
> --- a/arch/powerpc/kernel/prom_init.c
> +++ b/arch/powerpc/kernel/prom_init.c
> @@ -53,7 +53,7 @@
> * ensure that we don't lose things like the interrupt-map property
> * on a PCI-PCI bridge.
> */
> -#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024)
> +#define MAX_PROPERTY_LENGTH (2UL * 1024 * 1024)
>
> /*
> * Eventually bump that one up
^ permalink raw reply
* Re: [PATCH 1/2] powerpc: Move GE GPIO and PIC drivers
From: Benjamin Herrenschmidt @ 2012-02-26 23:37 UTC (permalink / raw)
To: Martyn Welch; +Cc: Wim Van Sebroeck, linuxppc-dev, linux-kernel
In-Reply-To: <1328614121-17803-2-git-send-email-martyn.welch@ge.com>
On Tue, 2012-02-07 at 11:28 +0000, Martyn Welch wrote:
> Move the GE GPIO and PIC drivers to allow these to be used by non-86xx
> boards.
Hi, Sorry for the late review...
> Signed-off-by: Martyn Welch <martyn.welch@ge.com>
> ---
> arch/powerpc/platforms/86xx/Kconfig | 3 +
> arch/powerpc/platforms/86xx/Makefile | 7 +-
> arch/powerpc/platforms/86xx/gef_gpio.c | 171 --------------------
> arch/powerpc/platforms/86xx/gef_pic.c | 252 ------------------------------
> arch/powerpc/platforms/86xx/gef_pic.h | 11 --
> arch/powerpc/platforms/86xx/gef_ppc9a.c | 3 +-
> arch/powerpc/platforms/86xx/gef_sbc310.c | 3 +-
> arch/powerpc/platforms/86xx/gef_sbc610.c | 3 +-
> arch/powerpc/platforms/Kconfig | 7 +
> arch/powerpc/platforms/Makefile | 3 +
> arch/powerpc/platforms/ge_gpio.c | 171 ++++++++++++++++++++
> arch/powerpc/platforms/ge_pic.c | 252 ++++++++++++++++++++++++++++++
> arch/powerpc/platforms/ge_pic.h | 11 ++
So I don't like having files showing up there. In fact, I want to move
the only other one here, it's not the right place for it
(fsl_uli1575.c).
Please contemplate using arch/powerpc/sysdev instead. Maybe make a
subdir in there (geip or something like that ?)
Also, use git mv so that the file moves appear as such in the history,
this will make review easier by clearly separating the move from actual
changes to the files.
Cheers,
Ben.
> drivers/watchdog/Kconfig | 2 +-
> 14 files changed, 457 insertions(+), 442 deletions(-)
> delete mode 100644 arch/powerpc/platforms/86xx/gef_gpio.c
> delete mode 100644 arch/powerpc/platforms/86xx/gef_pic.c
> delete mode 100644 arch/powerpc/platforms/86xx/gef_pic.h
> create mode 100644 arch/powerpc/platforms/ge_gpio.c
> create mode 100644 arch/powerpc/platforms/ge_pic.c
> create mode 100644 arch/powerpc/platforms/ge_pic.h
>
> diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
> index 8d6599d..2015022 100644
> --- a/arch/powerpc/platforms/86xx/Kconfig
> +++ b/arch/powerpc/platforms/86xx/Kconfig
> @@ -39,6 +39,7 @@ config GEF_PPC9A
> select MMIO_NVRAM
> select GENERIC_GPIO
> select ARCH_REQUIRE_GPIOLIB
> + select GE_FPGA
> help
> This option enables support for the GE PPC9A.
>
> @@ -48,6 +49,7 @@ config GEF_SBC310
> select MMIO_NVRAM
> select GENERIC_GPIO
> select ARCH_REQUIRE_GPIOLIB
> + select GE_FPGA
> help
> This option enables support for the GE SBC310.
>
> @@ -58,6 +60,7 @@ config GEF_SBC610
> select GENERIC_GPIO
> select ARCH_REQUIRE_GPIOLIB
> select HAS_RAPIDIO
> + select GE_FPGA
> help
> This option enables support for the GE SBC610.
>
> diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
> index 4b0d7b1..ede815d 100644
> --- a/arch/powerpc/platforms/86xx/Makefile
> +++ b/arch/powerpc/platforms/86xx/Makefile
> @@ -7,7 +7,6 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o
> obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o
> obj-$(CONFIG_SBC8641D) += sbc8641d.o
> obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o
> -gef-gpio-$(CONFIG_GPIOLIB) += gef_gpio.o
> -obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o gef_pic.o $(gef-gpio-y)
> -obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o gef_pic.o $(gef-gpio-y)
> -obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o gef_pic.o $(gef-gpio-y)
> +obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o
> +obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o
> +obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o
> diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c
> deleted file mode 100644
> index 2a70336..0000000
> --- a/arch/powerpc/platforms/86xx/gef_gpio.c
> +++ /dev/null
> @@ -1,171 +0,0 @@
> -/*
> - * Driver for GE FPGA based GPIO
> - *
> - * Author: Martyn Welch <martyn.welch@ge.com>
> - *
> - * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
> - *
> - * This file is licensed under the terms of the GNU General Public License
> - * version 2. This program is licensed "as is" without any warranty of any
> - * kind, whether express or implied.
> - */
> -
> -/* TODO
> - *
> - * Configuration of output modes (totem-pole/open-drain)
> - * Interrupt configuration - interrupts are always generated the FPGA relies on
> - * the I/O interrupt controllers mask to stop them propergating
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/compiler.h>
> -#include <linux/init.h>
> -#include <linux/io.h>
> -#include <linux/of.h>
> -#include <linux/of_device.h>
> -#include <linux/of_platform.h>
> -#include <linux/of_gpio.h>
> -#include <linux/gpio.h>
> -#include <linux/slab.h>
> -#include <linux/module.h>
> -
> -#define GEF_GPIO_DIRECT 0x00
> -#define GEF_GPIO_IN 0x04
> -#define GEF_GPIO_OUT 0x08
> -#define GEF_GPIO_TRIG 0x0C
> -#define GEF_GPIO_POLAR_A 0x10
> -#define GEF_GPIO_POLAR_B 0x14
> -#define GEF_GPIO_INT_STAT 0x18
> -#define GEF_GPIO_OVERRUN 0x1C
> -#define GEF_GPIO_MODE 0x20
> -
> -static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
> -{
> - unsigned int data;
> -
> - data = ioread32be(reg);
> - /* value: 0=low; 1=high */
> - if (value & 0x1)
> - data = data | (0x1 << offset);
> - else
> - data = data & ~(0x1 << offset);
> -
> - iowrite32be(data, reg);
> -}
> -
> -
> -static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
> -{
> - unsigned int data;
> - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> -
> - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
> - data = data | (0x1 << offset);
> - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
> -
> - return 0;
> -}
> -
> -static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
> -{
> - unsigned int data;
> - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> -
> - /* Set direction before switching to input */
> - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
> -
> - data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
> - data = data & ~(0x1 << offset);
> - iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
> -
> - return 0;
> -}
> -
> -static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
> -{
> - unsigned int data;
> - int state = 0;
> - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> -
> - data = ioread32be(mmchip->regs + GEF_GPIO_IN);
> - state = (int)((data >> offset) & 0x1);
> -
> - return state;
> -}
> -
> -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
> -{
> - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> -
> - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
> -}
> -
> -static int __init gef_gpio_init(void)
> -{
> - struct device_node *np;
> - int retval;
> - struct of_mm_gpio_chip *gef_gpio_chip;
> -
> - for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
> -
> - pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
> -
> - /* Allocate chip structure */
> - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
> - if (!gef_gpio_chip) {
> - pr_err("%s: Unable to allocate structure\n",
> - np->full_name);
> - continue;
> - }
> -
> - /* Setup pointers to chip functions */
> - gef_gpio_chip->gc.of_gpio_n_cells = 2;
> - gef_gpio_chip->gc.ngpio = 19;
> - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
> - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
> - gef_gpio_chip->gc.get = gef_gpio_get;
> - gef_gpio_chip->gc.set = gef_gpio_set;
> -
> - /* This function adds a memory mapped GPIO chip */
> - retval = of_mm_gpiochip_add(np, gef_gpio_chip);
> - if (retval) {
> - kfree(gef_gpio_chip);
> - pr_err("%s: Unable to add GPIO\n", np->full_name);
> - }
> - }
> -
> - for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
> -
> - pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
> -
> - /* Allocate chip structure */
> - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
> - if (!gef_gpio_chip) {
> - pr_err("%s: Unable to allocate structure\n",
> - np->full_name);
> - continue;
> - }
> -
> - /* Setup pointers to chip functions */
> - gef_gpio_chip->gc.of_gpio_n_cells = 2;
> - gef_gpio_chip->gc.ngpio = 6;
> - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
> - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
> - gef_gpio_chip->gc.get = gef_gpio_get;
> - gef_gpio_chip->gc.set = gef_gpio_set;
> -
> - /* This function adds a memory mapped GPIO chip */
> - retval = of_mm_gpiochip_add(np, gef_gpio_chip);
> - if (retval) {
> - kfree(gef_gpio_chip);
> - pr_err("%s: Unable to add GPIO\n", np->full_name);
> - }
> - }
> -
> - return 0;
> -};
> -arch_initcall(gef_gpio_init);
> -
> -MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
> -MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
> -MODULE_LICENSE("GPL");
> diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
> deleted file mode 100644
> index 94594e5..0000000
> --- a/arch/powerpc/platforms/86xx/gef_pic.c
> +++ /dev/null
> @@ -1,252 +0,0 @@
> -/*
> - * Interrupt handling for GE FPGA based PIC
> - *
> - * Author: Martyn Welch <martyn.welch@ge.com>
> - *
> - * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
> - *
> - * This file is licensed under the terms of the GNU General Public License
> - * version 2. This program is licensed "as is" without any warranty of any
> - * kind, whether express or implied.
> - */
> -
> -#include <linux/stddef.h>
> -#include <linux/kernel.h>
> -#include <linux/init.h>
> -#include <linux/irq.h>
> -#include <linux/interrupt.h>
> -#include <linux/spinlock.h>
> -
> -#include <asm/byteorder.h>
> -#include <asm/io.h>
> -#include <asm/prom.h>
> -#include <asm/irq.h>
> -
> -#include "gef_pic.h"
> -
> -#define DEBUG
> -#undef DEBUG
> -
> -#ifdef DEBUG
> -#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
> -#else
> -#define DBG(fmt...) do { } while (0)
> -#endif
> -
> -#define GEF_PIC_NUM_IRQS 32
> -
> -/* Interrupt Controller Interface Registers */
> -#define GEF_PIC_INTR_STATUS 0x0000
> -
> -#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
> -#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
> -#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
> -
> -#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu))
> -#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0)
> -#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1)
> -
> -
> -static DEFINE_RAW_SPINLOCK(gef_pic_lock);
> -
> -static void __iomem *gef_pic_irq_reg_base;
> -static struct irq_host *gef_pic_irq_host;
> -static int gef_pic_cascade_irq;
> -
> -/*
> - * Interrupt Controller Handling
> - *
> - * The interrupt controller handles interrupts for most on board interrupts,
> - * apart from PCI interrupts. For example on SBC610:
> - *
> - * 17:31 RO Reserved
> - * 16 RO PCI Express Doorbell 3 Status
> - * 15 RO PCI Express Doorbell 2 Status
> - * 14 RO PCI Express Doorbell 1 Status
> - * 13 RO PCI Express Doorbell 0 Status
> - * 12 RO Real Time Clock Interrupt Status
> - * 11 RO Temperature Interrupt Status
> - * 10 RO Temperature Critical Interrupt Status
> - * 9 RO Ethernet PHY1 Interrupt Status
> - * 8 RO Ethernet PHY3 Interrupt Status
> - * 7 RO PEX8548 Interrupt Status
> - * 6 RO Reserved
> - * 5 RO Watchdog 0 Interrupt Status
> - * 4 RO Watchdog 1 Interrupt Status
> - * 3 RO AXIS Message FIFO A Interrupt Status
> - * 2 RO AXIS Message FIFO B Interrupt Status
> - * 1 RO AXIS Message FIFO C Interrupt Status
> - * 0 RO AXIS Message FIFO D Interrupt Status
> - *
> - * Interrupts can be forwarded to one of two output lines. Nothing
> - * clever is done, so if the masks are incorrectly set, a single input
> - * interrupt could generate interrupts on both output lines!
> - *
> - * The dual lines are there to allow the chained interrupts to be easily
> - * passed into two different cores. We currently do not use this functionality
> - * in this driver.
> - *
> - * Controller can also be configured to generate Machine checks (MCP), again on
> - * two lines, to be attached to two different cores. It is suggested that these
> - * should be masked out.
> - */
> -
> -void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
> -{
> - struct irq_chip *chip = irq_desc_get_chip(desc);
> - unsigned int cascade_irq;
> -
> - /*
> - * See if we actually have an interrupt, call generic handling code if
> - * we do.
> - */
> - cascade_irq = gef_pic_get_irq();
> -
> - if (cascade_irq != NO_IRQ)
> - generic_handle_irq(cascade_irq);
> -
> - chip->irq_eoi(&desc->irq_data);
> -}
> -
> -static void gef_pic_mask(struct irq_data *d)
> -{
> - unsigned long flags;
> - unsigned int hwirq = irqd_to_hwirq(d);
> - u32 mask;
> -
> - raw_spin_lock_irqsave(&gef_pic_lock, flags);
> - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> - mask &= ~(1 << hwirq);
> - out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
> - raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
> -}
> -
> -static void gef_pic_mask_ack(struct irq_data *d)
> -{
> - /* Don't think we actually have to do anything to ack an interrupt,
> - * we just need to clear down the devices interrupt and it will go away
> - */
> - gef_pic_mask(d);
> -}
> -
> -static void gef_pic_unmask(struct irq_data *d)
> -{
> - unsigned long flags;
> - unsigned int hwirq = irqd_to_hwirq(d);
> - u32 mask;
> -
> - raw_spin_lock_irqsave(&gef_pic_lock, flags);
> - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> - mask |= (1 << hwirq);
> - out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
> - raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
> -}
> -
> -static struct irq_chip gef_pic_chip = {
> - .name = "gefp",
> - .irq_mask = gef_pic_mask,
> - .irq_mask_ack = gef_pic_mask_ack,
> - .irq_unmask = gef_pic_unmask,
> -};
> -
> -
> -/* When an interrupt is being configured, this call allows some flexibilty
> - * in deciding which irq_chip structure is used
> - */
> -static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
> - irq_hw_number_t hwirq)
> -{
> - /* All interrupts are LEVEL sensitive */
> - irq_set_status_flags(virq, IRQ_LEVEL);
> - irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
> -
> - return 0;
> -}
> -
> -static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
> - const u32 *intspec, unsigned int intsize,
> - irq_hw_number_t *out_hwirq, unsigned int *out_flags)
> -{
> -
> - *out_hwirq = intspec[0];
> - if (intsize > 1)
> - *out_flags = intspec[1];
> - else
> - *out_flags = IRQ_TYPE_LEVEL_HIGH;
> -
> - return 0;
> -}
> -
> -static struct irq_host_ops gef_pic_host_ops = {
> - .map = gef_pic_host_map,
> - .xlate = gef_pic_host_xlate,
> -};
> -
> -
> -/*
> - * Initialisation of PIC, this should be called in BSP
> - */
> -void __init gef_pic_init(struct device_node *np)
> -{
> - unsigned long flags;
> -
> - /* Map the devices registers into memory */
> - gef_pic_irq_reg_base = of_iomap(np, 0);
> -
> - raw_spin_lock_irqsave(&gef_pic_lock, flags);
> -
> - /* Initialise everything as masked. */
> - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
> - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
> -
> - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
> - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
> -
> - raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
> -
> - /* Map controller */
> - gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
> - if (gef_pic_cascade_irq == NO_IRQ) {
> - printk(KERN_ERR "SBC610: failed to map cascade interrupt");
> - return;
> - }
> -
> - /* Setup an irq_host structure */
> - gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
> - GEF_PIC_NUM_IRQS,
> - &gef_pic_host_ops, NO_IRQ);
> - if (gef_pic_irq_host == NULL)
> - return;
> -
> - /* Chain with parent controller */
> - irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
> -}
> -
> -/*
> - * This is called when we receive an interrupt with apparently comes from this
> - * chip - check, returning the highest interrupt generated or return NO_IRQ
> - */
> -unsigned int gef_pic_get_irq(void)
> -{
> - u32 cause, mask, active;
> - unsigned int virq = NO_IRQ;
> - int hwirq;
> -
> - cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
> -
> - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> -
> - active = cause & mask;
> -
> - if (active) {
> - for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
> - if (active & (0x1 << hwirq))
> - break;
> - }
> - virq = irq_linear_revmap(gef_pic_irq_host,
> - (irq_hw_number_t)hwirq);
> - }
> -
> - return virq;
> -}
> -
> diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h
> deleted file mode 100644
> index 6149916..0000000
> --- a/arch/powerpc/platforms/86xx/gef_pic.h
> +++ /dev/null
> @@ -1,11 +0,0 @@
> -#ifndef __GEF_PIC_H__
> -#define __GEF_PIC_H__
> -
> -#include <linux/init.h>
> -
> -void gef_pic_cascade(unsigned int, struct irq_desc *);
> -unsigned int gef_pic_get_irq(void);
> -void gef_pic_init(struct device_node *);
> -
> -#endif /* __GEF_PIC_H__ */
> -
> diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c
> index 60ce07e..132917d 100644
> --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c
> +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c
> @@ -38,8 +38,9 @@
> #include <sysdev/fsl_pci.h>
> #include <sysdev/fsl_soc.h>
>
> +#include <platforms/ge_pic.h>
> +
> #include "mpc86xx.h"
> -#include "gef_pic.h"
>
> #undef DEBUG
>
> diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c
> index 3ecee25..3d7894d 100644
> --- a/arch/powerpc/platforms/86xx/gef_sbc310.c
> +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c
> @@ -38,8 +38,9 @@
> #include <sysdev/fsl_pci.h>
> #include <sysdev/fsl_soc.h>
>
> +#include <platforms/ge_pic.h>
> +
> #include "mpc86xx.h"
> -#include "gef_pic.h"
>
> #undef DEBUG
>
> diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c
> index 5090d60..4f6b6a4 100644
> --- a/arch/powerpc/platforms/86xx/gef_sbc610.c
> +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c
> @@ -38,8 +38,9 @@
> #include <sysdev/fsl_pci.h>
> #include <sysdev/fsl_soc.h>
>
> +#include <platforms/ge_pic.h>
> +
> #include "mpc86xx.h"
> -#include "gef_pic.h"
>
> #undef DEBUG
>
> diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
> index 0cfb46d..2578e82 100644
> --- a/arch/powerpc/platforms/Kconfig
> +++ b/arch/powerpc/platforms/Kconfig
> @@ -363,4 +363,11 @@ config XILINX_PCI
> bool "Xilinx PCI host bridge support"
> depends on PCI && XILINX_VIRTEX
>
> +config GE_FPGA
> + bool
> + default n
> + help
> + Support for common GPIO and interrupt routing functionality provided
> + on some GE Single Board Computers.
> +
> endmenu
> diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
> index 2635a22..38742cf 100644
> --- a/arch/powerpc/platforms/Makefile
> +++ b/arch/powerpc/platforms/Makefile
> @@ -3,6 +3,9 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
>
> obj-$(CONFIG_FSL_ULI1575) += fsl_uli1575.o
>
> +gef-gpio-$(CONFIG_GPIOLIB) += ge_gpio.o
> +obj-$(CONFIG_GE_FPGA) += ge_pic.o $(gef-gpio-y)
> +
> obj-$(CONFIG_PPC_PMAC) += powermac/
> obj-$(CONFIG_PPC_CHRP) += chrp/
> obj-$(CONFIG_40x) += 40x/
> diff --git a/arch/powerpc/platforms/ge_gpio.c b/arch/powerpc/platforms/ge_gpio.c
> new file mode 100644
> index 0000000..2a70336
> --- /dev/null
> +++ b/arch/powerpc/platforms/ge_gpio.c
> @@ -0,0 +1,171 @@
> +/*
> + * Driver for GE FPGA based GPIO
> + *
> + * Author: Martyn Welch <martyn.welch@ge.com>
> + *
> + * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +/* TODO
> + *
> + * Configuration of output modes (totem-pole/open-drain)
> + * Interrupt configuration - interrupts are always generated the FPGA relies on
> + * the I/O interrupt controllers mask to stop them propergating
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/compiler.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_gpio.h>
> +#include <linux/gpio.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +
> +#define GEF_GPIO_DIRECT 0x00
> +#define GEF_GPIO_IN 0x04
> +#define GEF_GPIO_OUT 0x08
> +#define GEF_GPIO_TRIG 0x0C
> +#define GEF_GPIO_POLAR_A 0x10
> +#define GEF_GPIO_POLAR_B 0x14
> +#define GEF_GPIO_INT_STAT 0x18
> +#define GEF_GPIO_OVERRUN 0x1C
> +#define GEF_GPIO_MODE 0x20
> +
> +static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
> +{
> + unsigned int data;
> +
> + data = ioread32be(reg);
> + /* value: 0=low; 1=high */
> + if (value & 0x1)
> + data = data | (0x1 << offset);
> + else
> + data = data & ~(0x1 << offset);
> +
> + iowrite32be(data, reg);
> +}
> +
> +
> +static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
> +{
> + unsigned int data;
> + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> +
> + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
> + data = data | (0x1 << offset);
> + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
> +
> + return 0;
> +}
> +
> +static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
> +{
> + unsigned int data;
> + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> +
> + /* Set direction before switching to input */
> + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
> +
> + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
> + data = data & ~(0x1 << offset);
> + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
> +
> + return 0;
> +}
> +
> +static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
> +{
> + unsigned int data;
> + int state = 0;
> + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> +
> + data = ioread32be(mmchip->regs + GEF_GPIO_IN);
> + state = (int)((data >> offset) & 0x1);
> +
> + return state;
> +}
> +
> +static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
> +{
> + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
> +
> + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
> +}
> +
> +static int __init gef_gpio_init(void)
> +{
> + struct device_node *np;
> + int retval;
> + struct of_mm_gpio_chip *gef_gpio_chip;
> +
> + for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
> +
> + pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
> +
> + /* Allocate chip structure */
> + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
> + if (!gef_gpio_chip) {
> + pr_err("%s: Unable to allocate structure\n",
> + np->full_name);
> + continue;
> + }
> +
> + /* Setup pointers to chip functions */
> + gef_gpio_chip->gc.of_gpio_n_cells = 2;
> + gef_gpio_chip->gc.ngpio = 19;
> + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
> + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
> + gef_gpio_chip->gc.get = gef_gpio_get;
> + gef_gpio_chip->gc.set = gef_gpio_set;
> +
> + /* This function adds a memory mapped GPIO chip */
> + retval = of_mm_gpiochip_add(np, gef_gpio_chip);
> + if (retval) {
> + kfree(gef_gpio_chip);
> + pr_err("%s: Unable to add GPIO\n", np->full_name);
> + }
> + }
> +
> + for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
> +
> + pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
> +
> + /* Allocate chip structure */
> + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
> + if (!gef_gpio_chip) {
> + pr_err("%s: Unable to allocate structure\n",
> + np->full_name);
> + continue;
> + }
> +
> + /* Setup pointers to chip functions */
> + gef_gpio_chip->gc.of_gpio_n_cells = 2;
> + gef_gpio_chip->gc.ngpio = 6;
> + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
> + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
> + gef_gpio_chip->gc.get = gef_gpio_get;
> + gef_gpio_chip->gc.set = gef_gpio_set;
> +
> + /* This function adds a memory mapped GPIO chip */
> + retval = of_mm_gpiochip_add(np, gef_gpio_chip);
> + if (retval) {
> + kfree(gef_gpio_chip);
> + pr_err("%s: Unable to add GPIO\n", np->full_name);
> + }
> + }
> +
> + return 0;
> +};
> +arch_initcall(gef_gpio_init);
> +
> +MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
> +MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
> +MODULE_LICENSE("GPL");
> diff --git a/arch/powerpc/platforms/ge_pic.c b/arch/powerpc/platforms/ge_pic.c
> new file mode 100644
> index 0000000..a1ccef2
> --- /dev/null
> +++ b/arch/powerpc/platforms/ge_pic.c
> @@ -0,0 +1,252 @@
> +/*
> + * Interrupt handling for GE FPGA based PIC
> + *
> + * Author: Martyn Welch <martyn.welch@ge.com>
> + *
> + * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/stddef.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/spinlock.h>
> +
> +#include <asm/byteorder.h>
> +#include <asm/io.h>
> +#include <asm/prom.h>
> +#include <asm/irq.h>
> +
> +#include <platforms/ge_pic.h>
> +
> +#define DEBUG
> +#undef DEBUG
> +
> +#ifdef DEBUG
> +#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
> +#else
> +#define DBG(fmt...) do { } while (0)
> +#endif
> +
> +#define GEF_PIC_NUM_IRQS 32
> +
> +/* Interrupt Controller Interface Registers */
> +#define GEF_PIC_INTR_STATUS 0x0000
> +
> +#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
> +#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
> +#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
> +
> +#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu))
> +#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0)
> +#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1)
> +
> +
> +static DEFINE_RAW_SPINLOCK(gef_pic_lock);
> +
> +static void __iomem *gef_pic_irq_reg_base;
> +static struct irq_host *gef_pic_irq_host;
> +static int gef_pic_cascade_irq;
> +
> +/*
> + * Interrupt Controller Handling
> + *
> + * The interrupt controller handles interrupts for most on board interrupts,
> + * apart from PCI interrupts. For example on SBC610:
> + *
> + * 17:31 RO Reserved
> + * 16 RO PCI Express Doorbell 3 Status
> + * 15 RO PCI Express Doorbell 2 Status
> + * 14 RO PCI Express Doorbell 1 Status
> + * 13 RO PCI Express Doorbell 0 Status
> + * 12 RO Real Time Clock Interrupt Status
> + * 11 RO Temperature Interrupt Status
> + * 10 RO Temperature Critical Interrupt Status
> + * 9 RO Ethernet PHY1 Interrupt Status
> + * 8 RO Ethernet PHY3 Interrupt Status
> + * 7 RO PEX8548 Interrupt Status
> + * 6 RO Reserved
> + * 5 RO Watchdog 0 Interrupt Status
> + * 4 RO Watchdog 1 Interrupt Status
> + * 3 RO AXIS Message FIFO A Interrupt Status
> + * 2 RO AXIS Message FIFO B Interrupt Status
> + * 1 RO AXIS Message FIFO C Interrupt Status
> + * 0 RO AXIS Message FIFO D Interrupt Status
> + *
> + * Interrupts can be forwarded to one of two output lines. Nothing
> + * clever is done, so if the masks are incorrectly set, a single input
> + * interrupt could generate interrupts on both output lines!
> + *
> + * The dual lines are there to allow the chained interrupts to be easily
> + * passed into two different cores. We currently do not use this functionality
> + * in this driver.
> + *
> + * Controller can also be configured to generate Machine checks (MCP), again on
> + * two lines, to be attached to two different cores. It is suggested that these
> + * should be masked out.
> + */
> +
> +void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
> +{
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> + unsigned int cascade_irq;
> +
> + /*
> + * See if we actually have an interrupt, call generic handling code if
> + * we do.
> + */
> + cascade_irq = gef_pic_get_irq();
> +
> + if (cascade_irq != NO_IRQ)
> + generic_handle_irq(cascade_irq);
> +
> + chip->irq_eoi(&desc->irq_data);
> +}
> +
> +static void gef_pic_mask(struct irq_data *d)
> +{
> + unsigned long flags;
> + unsigned int hwirq = irqd_to_hwirq(d);
> + u32 mask;
> +
> + raw_spin_lock_irqsave(&gef_pic_lock, flags);
> + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> + mask &= ~(1 << hwirq);
> + out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
> + raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
> +}
> +
> +static void gef_pic_mask_ack(struct irq_data *d)
> +{
> + /* Don't think we actually have to do anything to ack an interrupt,
> + * we just need to clear down the devices interrupt and it will go away
> + */
> + gef_pic_mask(d);
> +}
> +
> +static void gef_pic_unmask(struct irq_data *d)
> +{
> + unsigned long flags;
> + unsigned int hwirq = irqd_to_hwirq(d);
> + u32 mask;
> +
> + raw_spin_lock_irqsave(&gef_pic_lock, flags);
> + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> + mask |= (1 << hwirq);
> + out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
> + raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
> +}
> +
> +static struct irq_chip gef_pic_chip = {
> + .name = "gefp",
> + .irq_mask = gef_pic_mask,
> + .irq_mask_ack = gef_pic_mask_ack,
> + .irq_unmask = gef_pic_unmask,
> +};
> +
> +
> +/* When an interrupt is being configured, this call allows some flexibilty
> + * in deciding which irq_chip structure is used
> + */
> +static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
> + irq_hw_number_t hwirq)
> +{
> + /* All interrupts are LEVEL sensitive */
> + irq_set_status_flags(virq, IRQ_LEVEL);
> + irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
> +
> + return 0;
> +}
> +
> +static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
> + const u32 *intspec, unsigned int intsize,
> + irq_hw_number_t *out_hwirq, unsigned int *out_flags)
> +{
> +
> + *out_hwirq = intspec[0];
> + if (intsize > 1)
> + *out_flags = intspec[1];
> + else
> + *out_flags = IRQ_TYPE_LEVEL_HIGH;
> +
> + return 0;
> +}
> +
> +static struct irq_host_ops gef_pic_host_ops = {
> + .map = gef_pic_host_map,
> + .xlate = gef_pic_host_xlate,
> +};
> +
> +
> +/*
> + * Initialisation of PIC, this should be called in BSP
> + */
> +void __init gef_pic_init(struct device_node *np)
> +{
> + unsigned long flags;
> +
> + /* Map the devices registers into memory */
> + gef_pic_irq_reg_base = of_iomap(np, 0);
> +
> + raw_spin_lock_irqsave(&gef_pic_lock, flags);
> +
> + /* Initialise everything as masked. */
> + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
> + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
> +
> + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
> + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
> +
> + raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
> +
> + /* Map controller */
> + gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
> + if (gef_pic_cascade_irq == NO_IRQ) {
> + printk(KERN_ERR "SBC610: failed to map cascade interrupt");
> + return;
> + }
> +
> + /* Setup an irq_host structure */
> + gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
> + GEF_PIC_NUM_IRQS,
> + &gef_pic_host_ops, NO_IRQ);
> + if (gef_pic_irq_host == NULL)
> + return;
> +
> + /* Chain with parent controller */
> + irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
> +}
> +
> +/*
> + * This is called when we receive an interrupt with apparently comes from this
> + * chip - check, returning the highest interrupt generated or return NO_IRQ
> + */
> +unsigned int gef_pic_get_irq(void)
> +{
> + u32 cause, mask, active;
> + unsigned int virq = NO_IRQ;
> + int hwirq;
> +
> + cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
> +
> + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
> +
> + active = cause & mask;
> +
> + if (active) {
> + for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
> + if (active & (0x1 << hwirq))
> + break;
> + }
> + virq = irq_linear_revmap(gef_pic_irq_host,
> + (irq_hw_number_t)hwirq);
> + }
> +
> + return virq;
> +}
> +
> diff --git a/arch/powerpc/platforms/ge_pic.h b/arch/powerpc/platforms/ge_pic.h
> new file mode 100644
> index 0000000..6149916
> --- /dev/null
> +++ b/arch/powerpc/platforms/ge_pic.h
> @@ -0,0 +1,11 @@
> +#ifndef __GEF_PIC_H__
> +#define __GEF_PIC_H__
> +
> +#include <linux/init.h>
> +
> +void gef_pic_cascade(unsigned int, struct irq_desc *);
> +unsigned int gef_pic_get_irq(void);
> +void gef_pic_init(struct device_node *);
> +
> +#endif /* __GEF_PIC_H__ */
> +
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 877b107..2955c3f 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -1039,7 +1039,7 @@ config LANTIQ_WDT
>
> config GEF_WDT
> tristate "GE Watchdog Timer"
> - depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A
> + depends on GE_FPGA
> ---help---
> Watchdog timer found in a number of GE single board computers.
>
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: Board support for GE IMP3A
From: Benjamin Herrenschmidt @ 2012-02-26 23:42 UTC (permalink / raw)
To: Martyn Welch; +Cc: Wim Van Sebroeck, linuxppc-dev, linux-kernel
In-Reply-To: <1328614121-17803-3-git-send-email-martyn.welch@ge.com>
On Tue, 2012-02-07 at 11:28 +0000, Martyn Welch wrote:
> +
> + if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {
> + mpic = mpic_alloc(NULL, 0,
> + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
> + MPIC_SINGLE_DEST_CPU,
> + 0, 256, " OpenPIC ");
> + } else {
> + mpic = mpic_alloc(NULL, 0,
> + MPIC_WANTS_RESET |
> + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
> + MPIC_SINGLE_DEST_CPU,
> + 0, 256, " OpenPIC ");
> + }
> +
Can you rebase this on top of powerpc-next ? There have been some mpic
changes from Kyle Moffett that clash with this (mostly some of the flags
are gone, the remaining ones you should just put in the device-tree).
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH] powerpc: icswx: fix race condition where threads do not get their ACOP register updated in time.
From: Benjamin Herrenschmidt @ 2012-02-26 23:47 UTC (permalink / raw)
To: Jimi Xenidis; +Cc: linuxppc-dev, Anton Blanchard
In-Reply-To: <1329948466-325-1-git-send-email-jimix@pobox.com>
>
> + /*
> + * We could be here because another thread has enabled acop
> + * but the ACOP register has yet to be updated.
> + *
> + * This should have been taken care of by the IPI to sync all
> + * the threads (see smp_call_function(sync_cop, mm, 1)), but
> + * that could take forever if there are a significant amount
> + * of threads.
> + *
> + * Given the number of threads on some of these systems,
> + * perhaps this is the best way to sync ACOP rather than whack
> + * every thread with an IPI.
> + */
This is actually pretty standard stuff... If it was me I would make it
all lazy and avoid the IPI completely but it doesn't necessarily hurt
that much. In any case the "recovery" is indeed needed and you should
probably also remove the pr_debug, it's really just spam.
> + if (acop_copro_type_bit(ct) && current->active_mm->context.acop) {
Shouldn't that be "&" ? In fact, gcc would even warn so either make
it acop_check_copro(acop, ct) or do a (x & y) != 0
Cheers,
Ben.
> + pr_debug("%s[%d]: Spurrious ACOP Fault, CT: %d, bit: 0x%llx "
> + "SPR: 0x%lx, mm->acop: 0x%lx\n",
> + current->comm, current->pid,
> + ct, acop_copro_type_bit(ct), mfspr(SPRN_ACOP),
> + current->active_mm->context.acop);
> +
> + sync_cop(current->active_mm);
> + return 0;
> + }
> +
> + /* check for alternate policy */
> if (!acop_use_cop(ct))
> return 0;
>
> /* at this point the CT is unknown to the system */
> - pr_warn("%s[%d]: Coprocessor %d is unavailable",
> + pr_warn("%s[%d]: Coprocessor %d is unavailable\n",
> current->comm, current->pid, ct);
>
> /* get inst if we don't already have it */
> diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
> index 42176bd..6dedc08 100644
> --- a/arch/powerpc/mm/icswx.h
> +++ b/arch/powerpc/mm/icswx.h
> @@ -59,4 +59,10 @@ extern void free_cop_pid(int free_pid);
>
> extern int acop_handle_fault(struct pt_regs *regs, unsigned long address,
> unsigned long error_code);
> +
> +static inline u64 acop_copro_type_bit(unsigned int type)
> +{
> + return 1ULL << (63 - type);
> +}
> +
> #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */
^ permalink raw reply
* Re: [PATCH/RFC] rapidio: temporarily exclude FSL_RIO from 64 bit builds
From: Paul Gortmaker @ 2012-02-27 1:26 UTC (permalink / raw)
To: benh; +Cc: Gang.Liu, linux-next, linuxppc-dev
In-Reply-To: <1329865853-17277-1-git-send-email-paul.gortmaker@windriver.com>
Hi Ben,
Given a week has passed with the absence of any feedback
with respect to SRIO on 64 bit, are you OK with applying the
below patch[1] pretty much as-is?
Thanks,
Paul.
[1] http://patchwork.ozlabs.org/patch/142383/
---
On Tue, Feb 21, 2012 at 6:10 PM, Paul Gortmaker
<paul.gortmaker@windriver.com> wrote:
> The following are seen while using the corenet64_smp_defconfig:
>
> arch/powerpc/sysdev/fsl_rmu.c:315: error: cast from pointer to integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:320: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:320: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:320: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:330: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:332: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:339: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:340: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:341: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:348: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:348: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:348: error: cast to pointer from integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:659: error: cast from pointer to integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:659: error: format '%8.8x' expects type 'un=
signed int', but argument 5 has type 'size_t'
> arch/powerpc/sysdev/fsl_rmu.c:985: error: cast from pointer to integer of=
different size
> arch/powerpc/sysdev/fsl_rmu.c:997: error: cast to pointer from integer of=
different size
>
> A quick inspection of the code leaves one with the impression
> that it was not explicitly written with 64 bit support in mind,
> so just block that as a possible config selection for now.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
>
> ---
>
> [This is seen in linux-next -- not sure if this is the right way to go
> =A0but at least it will give the issue some visibility to the right ppl.]
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 75f061e..5ad8013 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -773,7 +773,7 @@ config RAPIDIO
>
> =A0config FSL_RIO
> =A0 =A0 =A0 =A0bool "Freescale Embedded SRIO Controller support"
> - =A0 =A0 =A0 depends on RAPIDIO && HAS_RAPIDIO
> + =A0 =A0 =A0 depends on RAPIDIO && HAS_RAPIDIO && (BROKEN || !PPC64)
> =A0 =A0 =A0 =A0default "n"
> =A0 =A0 =A0 =A0---help---
> =A0 =A0 =A0 =A0 =A0Include support for RapidIO controller on Freescale em=
bedded
> --
> 1.7.9.1
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH/RFC] rapidio: temporarily exclude FSL_RIO from 64 bit builds
From: Benjamin Herrenschmidt @ 2012-02-27 1:49 UTC (permalink / raw)
To: Paul Gortmaker; +Cc: Gang.Liu, linux-next, linuxppc-dev
In-Reply-To: <CAP=VYLroaEKncpy7VBobJdXijnDS5UdTV7qPG2A--SicnGvFSg@mail.gmail.com>
On Sun, 2012-02-26 at 20:26 -0500, Paul Gortmaker wrote:
> Hi Ben,
>
> Given a week has passed with the absence of any feedback
> with respect to SRIO on 64 bit, are you OK with applying the
> below patch[1] pretty much as-is?
It can't hurt, I'll put it in. That's normally Kumar's side of things
but then with him leaving FSL things are a bit in flux right now.
Cheers,
Ben.
> Thanks,
> Paul.
>
> [1] http://patchwork.ozlabs.org/patch/142383/
>
> ---
>
> On Tue, Feb 21, 2012 at 6:10 PM, Paul Gortmaker
> <paul.gortmaker@windriver.com> wrote:
> > The following are seen while using the corenet64_smp_defconfig:
> >
> > arch/powerpc/sysdev/fsl_rmu.c:315: error: cast from pointer to integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:320: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:320: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:320: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:330: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:332: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:339: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:340: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:341: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:348: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:348: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:348: error: cast to pointer from integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:659: error: cast from pointer to integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:659: error: format '%8.8x' expects type 'unsigned int', but argument 5 has type 'size_t'
> > arch/powerpc/sysdev/fsl_rmu.c:985: error: cast from pointer to integer of different size
> > arch/powerpc/sysdev/fsl_rmu.c:997: error: cast to pointer from integer of different size
> >
> > A quick inspection of the code leaves one with the impression
> > that it was not explicitly written with 64 bit support in mind,
> > so just block that as a possible config selection for now.
> >
> > Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> >
> > ---
> >
> > [This is seen in linux-next -- not sure if this is the right way to go
> > but at least it will give the issue some visibility to the right ppl.]
> >
> > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> > index 75f061e..5ad8013 100644
> > --- a/arch/powerpc/Kconfig
> > +++ b/arch/powerpc/Kconfig
> > @@ -773,7 +773,7 @@ config RAPIDIO
> >
> > config FSL_RIO
> > bool "Freescale Embedded SRIO Controller support"
> > - depends on RAPIDIO && HAS_RAPIDIO
> > + depends on RAPIDIO && HAS_RAPIDIO && (BROKEN || !PPC64)
> > default "n"
> > ---help---
> > Include support for RapidIO controller on Freescale embedded
> > --
> > 1.7.9.1
> >
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* linux-next: build failure after merge of the final tree
From: Stephen Rothwell @ 2012-02-27 6:37 UTC (permalink / raw)
To: Jesse Barnes; +Cc: Bjorn Helgaas, linux-next, ppc-dev, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1565 bytes --]
Hi all,
After merging the final tree, today's linux-next build (powerpc
ppc44x_defconfig) failed like this:
arch/powerpc/kernel/pci-common.c: In function 'pcibios_setup_phb_resources':
arch/powerpc/kernel/pci-common.c:1520:4: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast]
Caused by commit 6c5705fec63d ("powerpc/PCI: get rid of device resource
fixups") from the pci tree. In this build, resource_size_t is 64 bits
while pointers are only 32.
I applied the following fix patch.
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Mon, 27 Feb 2012 17:33:48 +1100
Subject: [PATCH] powerpc/PCI: fix up for mismatch between resource_size_t and
pointer size
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/kernel/pci-common.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 910b9de..808ecbb 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1517,7 +1517,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
(unsigned long long)res->end,
(unsigned long)res->flags);
pci_add_resource_offset(resources, res,
- (resource_size_t) hose->io_base_virt - _IO_BASE);
+ (resource_size_t)(unsigned long)hose->io_base_virt - _IO_BASE);
/* Hookup PHB Memory resources */
for (i = 0; i < 3; ++i) {
--
1.7.9.1
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply related
* Re: [PATCH/RFC] rapidio: temporarily exclude FSL_RIO from 64 bit builds
From: Liu Gang @ 2012-02-27 6:48 UTC (permalink / raw)
To: Paul Gortmaker; +Cc: Alexandre.Bounine, linux-next, linuxppc-dev
In-Reply-To: <CAP=VYLroaEKncpy7VBobJdXijnDS5UdTV7qPG2A--SicnGvFSg@mail.gmail.com>
On Sun, 2012-02-26 at 20:26 -0500, Paul Gortmaker wrote:
> Hi Ben,
>
> Given a week has passed with the absence of any feedback
> with respect to SRIO on 64 bit, are you OK with applying the
> below patch[1] pretty much as-is?
Hi, Paul, Ben,
Sorry for the late reply because of my other urgent issues. I also found
these errors of 64bit building last week. I'll provide patch for this
issue as soon as possible.
Thanks.
Best Regards,
Liu Gang
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree
From: Benjamin Herrenschmidt @ 2012-02-27 9:19 UTC (permalink / raw)
To: Stephen Rothwell
Cc: Bjorn Helgaas, linux-next, ppc-dev, linux-kernel, Jesse Barnes
In-Reply-To: <20120227173747.853e7fbe3ce3afab8939720b@canb.auug.org.au>
On Mon, 2012-02-27 at 17:37 +1100, Stephen Rothwell wrote:
> pci_add_resource_offset(resources, res,
> - (resource_size_t) hose->io_base_virt - _IO_BASE);
> + (resource_size_t)(unsigned long)hose->io_base_virt - _IO_BASE);
We have to be careful here as we do want sign extension to happen (yeah
it's odd, but it's the way we do IOs on ppc32 :-) Maybe I should change
it one day).
So we probably want to do:
(resource_size_t)(long long)(hose->io_base_virt - _IO_BASE)
Basically, IO resources are relative to _IO_BASE which on ppc32 is
basically the virtual address where we map the first PHB IO space.
Subsequent PHB mappings can end up below _IO_BASE, leading to negative
resource values for IO BARs on those busses. It all works fine because
even an unsigned addition will do the right thing as long as the value
is fully sign extended.
Cheers,
Ben.
^ permalink raw reply
* [PATCH 1/2] powerpc/e500: make load_up_spe a normal fuction
From: Olivia Yin @ 2012-02-27 10:59 UTC (permalink / raw)
To: kvm-ppc, kvm, linuxppc-dev; +Cc: Liu Yu, Olivia Yin
So that we can call it in kernel.
Signed-off-by: Liu Yu <yu.liu@freescale.com>
---
arch/powerpc/kernel/head_fsl_booke.S | 23 ++++++-----------------
1 files changed, 6 insertions(+), 17 deletions(-)
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index d5d78c4..c96e025 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -539,8 +539,10 @@ interrupt_base:
/* SPE Unavailable */
START_EXCEPTION(SPEUnavailable)
NORMAL_EXCEPTION_PROLOG
- bne load_up_spe
- addi r3,r1,STACK_FRAME_OVERHEAD
+ beq 1f
+ bl load_up_spe
+ b fast_exception_return
+1: addi r3,r1,STACK_FRAME_OVERHEAD
EXC_XFER_EE_LITE(0x2010, KernelSPE)
#else
EXCEPTION(0x2020, SPEUnavailable, unknown_exception, EXC_XFER_EE)
@@ -743,7 +745,7 @@ tlb_write_entry:
/* Note that the SPE support is closely modeled after the AltiVec
* support. Changes to one are likely to be applicable to the
* other! */
-load_up_spe:
+_GLOBAL(load_up_spe)
/*
* Disable SPE for the task which had SPE previously,
* and save its SPE registers in its thread_struct.
@@ -791,20 +793,7 @@ load_up_spe:
subi r4,r5,THREAD
stw r4,last_task_used_spe@l(r3)
#endif /* !CONFIG_SMP */
- /* restore registers and return */
-2: REST_4GPRS(3, r11)
- lwz r10,_CCR(r11)
- REST_GPR(1, r11)
- mtcr r10
- lwz r10,_LINK(r11)
- mtlr r10
- REST_GPR(10, r11)
- mtspr SPRN_SRR1,r9
- mtspr SPRN_SRR0,r12
- REST_GPR(9, r11)
- REST_GPR(12, r11)
- lwz r11,GPR11(r11)
- rfi
+ blr
/*
* SPE unavailable trap from kernel - print a message, but let
--
1.6.4
^ permalink raw reply related
* [PATCH 2/2] KVM: booke: Improve SPE switch
From: Olivia Yin @ 2012-02-27 11:00 UTC (permalink / raw)
To: kvm-ppc, kvm, linuxppc-dev; +Cc: Liu Yu, Olivia Yin
Like book3s did for fp switch,
instead of switch SPE between host and guest,
the patch switch SPE state between qemu and guest.
In this way, we can simulate a host loadup SPE when load guest SPE state,
and let host to decide when to giveup SPE state.
Therefor it cooperates better with host SPE usage,
and so that has some performance benifit in UP host(lazy SPE).
Moreover, since the patch save guest SPE state into linux thread field,
it creates the condition to emulate guest SPE instructions in host,
so that we can avoid injecting SPE exception to guest.
The patch also turns all asm code into C code,
and add SPE stat counts.
Signed-off-by: Liu Yu <yu.liu@freescale.com>
---
arch/powerpc/include/asm/kvm_host.h | 11 +++++-
arch/powerpc/kernel/asm-offsets.c | 7 ----
arch/powerpc/kvm/booke.c | 63 +++++++++++++++++++++++++++++++----
arch/powerpc/kvm/booke.h | 8 +----
arch/powerpc/kvm/booke_interrupts.S | 37 --------------------
arch/powerpc/kvm/e500.c | 5 ---
arch/powerpc/kvm/timing.c | 5 +++
arch/powerpc/kvm/timing.h | 11 ++++++
8 files changed, 83 insertions(+), 64 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 1843d5d..6186d08 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -117,6 +117,11 @@ struct kvm_vcpu_stat {
u32 st;
u32 st_slow;
#endif
+#ifdef CONFIG_SPE
+ u32 spe_unavail;
+ u32 spe_fp_data;
+ u32 spe_fp_round;
+#endif
};
enum kvm_exit_types {
@@ -147,6 +152,11 @@ enum kvm_exit_types {
FP_UNAVAIL,
DEBUG_EXITS,
TIMEINGUEST,
+#ifdef CONFIG_SPE
+ SPE_UNAVAIL,
+ SPE_FP_DATA,
+ SPE_FP_ROUND,
+#endif
__NUMBER_OF_KVM_EXIT_TYPES
};
@@ -330,7 +340,6 @@ struct kvm_vcpu_arch {
#ifdef CONFIG_SPE
ulong evr[32];
ulong spefscr;
- ulong host_spefscr;
u64 acc;
#endif
#ifdef CONFIG_ALTIVEC
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8e0db0b..ff68f71 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -604,13 +604,6 @@ int main(void)
DEFINE(TLBCAM_MAS7, offsetof(struct tlbcam, MAS7));
#endif
-#if defined(CONFIG_KVM) && defined(CONFIG_SPE)
- DEFINE(VCPU_EVR, offsetof(struct kvm_vcpu, arch.evr[0]));
- DEFINE(VCPU_ACC, offsetof(struct kvm_vcpu, arch.acc));
- DEFINE(VCPU_SPEFSCR, offsetof(struct kvm_vcpu, arch.spefscr));
- DEFINE(VCPU_HOST_SPEFSCR, offsetof(struct kvm_vcpu, arch.host_spefscr));
-#endif
-
#ifdef CONFIG_KVM_EXIT_TIMING
DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu,
arch.timing_exit.tv32.tbu));
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index ee9e1ee..f20010b 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -55,6 +55,11 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "dec", VCPU_STAT(dec_exits) },
{ "ext_intr", VCPU_STAT(ext_intr_exits) },
{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
+#ifdef CONFIG_SPE
+ { "spe_unavail", VCPU_STAT(spe_unavail) },
+ { "spe_fp_data", VCPU_STAT(spe_fp_data) },
+ { "spe_fp_round", VCPU_STAT(spe_fp_round) },
+#endif
{ NULL }
};
@@ -80,11 +85,11 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
}
#ifdef CONFIG_SPE
-void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu)
+static void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu)
{
preempt_disable();
- enable_kernel_spe();
- kvmppc_save_guest_spe(vcpu);
+ if (current->thread.regs->msr & MSR_SPE)
+ giveup_spe(current);
vcpu->arch.shadow_msr &= ~MSR_SPE;
preempt_enable();
}
@@ -92,8 +97,10 @@ void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu)
static void kvmppc_vcpu_enable_spe(struct kvm_vcpu *vcpu)
{
preempt_disable();
- enable_kernel_spe();
- kvmppc_load_guest_spe(vcpu);
+ if (!(current->thread.regs->msr & MSR_SPE)) {
+ load_up_spe(NULL);
+ current->thread.regs->msr |= MSR_SPE;
+ }
vcpu->arch.shadow_msr |= MSR_SPE;
preempt_enable();
}
@@ -104,7 +111,7 @@ static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu)
if (!(vcpu->arch.shadow_msr & MSR_SPE))
kvmppc_vcpu_enable_spe(vcpu);
} else if (vcpu->arch.shadow_msr & MSR_SPE) {
- kvmppc_vcpu_disable_spe(vcpu);
+ vcpu->arch.shadow_msr &= ~MSR_SPE;
}
}
#else
@@ -124,7 +131,8 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
vcpu->arch.shared->msr = new_msr;
kvmppc_mmu_msr_notify(vcpu, old_msr);
- kvmppc_vcpu_sync_spe(vcpu);
+ if ((old_msr ^ new_msr) & MSR_SPE)
+ kvmppc_vcpu_sync_spe(vcpu);
}
static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
@@ -338,6 +346,11 @@ void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
int ret;
+#ifdef CONFIG_SPE
+ ulong evr[32];
+ ulong spefscr;
+ u64 acc;
+#endif
if (!vcpu->arch.sane) {
kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
@@ -355,7 +368,40 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
}
kvm_guest_enter();
+#ifdef CONFIG_SPE
+ /* Save userspace SPE state in stack */
+ enable_kernel_spe();
+ memcpy(evr, current->thread.evr, sizeof(current->thread.evr));
+ acc = current->thread.acc;
+
+ /* Restore guest SPE state to thread */
+ memcpy(current->thread.evr, vcpu->arch.evr, sizeof(vcpu->arch.evr));
+ current->thread.acc = vcpu->arch.acc;
+
+ /* Switch SPEFSCR and load guest SPE state if needed */
+ spefscr = mfspr(SPRN_SPEFSCR);
+ kvmppc_vcpu_sync_spe(vcpu);
+ mtspr(SPRN_SPEFSCR, vcpu->arch.spefscr);
+#endif
+
ret = __kvmppc_vcpu_run(kvm_run, vcpu);
+
+#ifdef CONFIG_SPE
+ /* Switch SPEFSCR and save guest SPE state if needed */
+ vcpu->arch.spefscr = mfspr(SPRN_SPEFSCR);
+ kvmppc_vcpu_disable_spe(vcpu);
+ mtspr(SPRN_SPEFSCR, spefscr);
+
+ /* Save guest SPE state from thread */
+ memcpy(vcpu->arch.evr, current->thread.evr, sizeof(vcpu->arch.evr));
+ vcpu->arch.acc = current->thread.acc;
+
+ /* Restore userspace SPE state from stack */
+ memcpy(current->thread.evr, evr, sizeof(current->thread.evr));
+ current->thread.spefscr = spefscr;
+ current->thread.acc = acc;
+#endif
+
kvm_guest_exit();
out:
@@ -457,17 +503,20 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
else
kvmppc_booke_queue_irqprio(vcpu,
BOOKE_IRQPRIO_SPE_UNAVAIL);
+ kvmppc_account_exit(vcpu, SPE_UNAVAIL);
r = RESUME_GUEST;
break;
}
case BOOKE_INTERRUPT_SPE_FP_DATA:
kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_DATA);
+ kvmppc_account_exit(vcpu, SPE_FP_DATA);
r = RESUME_GUEST;
break;
case BOOKE_INTERRUPT_SPE_FP_ROUND:
kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND);
+ kvmppc_account_exit(vcpu, SPE_FP_ROUND);
r = RESUME_GUEST;
break;
#else
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index 2fe2027..c02b8f9 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/kvm_host.h>
+#include <asm/system.h>
#include <asm/kvm_ppc.h>
#include "timing.h"
@@ -64,11 +65,4 @@ int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt);
int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs);
-/* low-level asm code to transfer guest state */
-void kvmppc_load_guest_spe(struct kvm_vcpu *vcpu);
-void kvmppc_save_guest_spe(struct kvm_vcpu *vcpu);
-
-/* high-level function, manages flags, host state */
-void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu);
-
#endif /* __KVM_BOOKE_H__ */
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index 10d8ef6..c44367d 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -245,15 +245,6 @@ _GLOBAL(kvmppc_resume_host)
heavyweight_exit:
/* Not returning to guest. */
-
-#ifdef CONFIG_SPE
- /* save guest SPEFSCR and load host SPEFSCR */
- mfspr r9, SPRN_SPEFSCR
- stw r9, VCPU_SPEFSCR(r4)
- lwz r9, VCPU_HOST_SPEFSCR(r4)
- mtspr SPRN_SPEFSCR, r9
-#endif
-
/* We already saved guest volatile register state; now save the
* non-volatiles. */
stw r15, VCPU_GPR(r15)(r4)
@@ -355,14 +346,6 @@ _GLOBAL(__kvmppc_vcpu_run)
lwz r30, VCPU_GPR(r30)(r4)
lwz r31, VCPU_GPR(r31)(r4)
-#ifdef CONFIG_SPE
- /* save host SPEFSCR and load guest SPEFSCR */
- mfspr r3, SPRN_SPEFSCR
- stw r3, VCPU_HOST_SPEFSCR(r4)
- lwz r3, VCPU_SPEFSCR(r4)
- mtspr SPRN_SPEFSCR, r3
-#endif
-
lightweight_exit:
stw r2, HOST_R2(r1)
@@ -460,23 +443,3 @@ lightweight_exit:
lwz r4, VCPU_GPR(r4)(r4)
rfi
-#ifdef CONFIG_SPE
-_GLOBAL(kvmppc_save_guest_spe)
- cmpi 0,r3,0
- beqlr-
- SAVE_32EVRS(0, r4, r3, VCPU_EVR)
- evxor evr6, evr6, evr6
- evmwumiaa evr6, evr6, evr6
- li r4,VCPU_ACC
- evstddx evr6, r4, r3 /* save acc */
- blr
-
-_GLOBAL(kvmppc_load_guest_spe)
- cmpi 0,r3,0
- beqlr-
- li r4,VCPU_ACC
- evlddx evr6,r4,r3
- evmra evr6,evr6 /* load acc */
- REST_32EVRS(0, r4, r3, VCPU_EVR)
- blr
-#endif
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index ddcd896..74da9c8 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -42,11 +42,6 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
{
kvmppc_e500_tlb_put(vcpu);
-
-#ifdef CONFIG_SPE
- if (vcpu->arch.shadow_msr & MSR_SPE)
- kvmppc_vcpu_disable_spe(vcpu);
-#endif
}
int kvmppc_core_check_processor_compat(void)
diff --git a/arch/powerpc/kvm/timing.c b/arch/powerpc/kvm/timing.c
index 07b6110..c9ce332 100644
--- a/arch/powerpc/kvm/timing.c
+++ b/arch/powerpc/kvm/timing.c
@@ -135,6 +135,11 @@ static const char *kvm_exit_names[__NUMBER_OF_KVM_EXIT_TYPES] = {
[USR_PR_INST] = "USR_PR_INST",
[FP_UNAVAIL] = "FP_UNAVAIL",
[DEBUG_EXITS] = "DEBUG",
+#ifdef CONFIG_SPE
+ [SPE_UNAVAIL] = "SPE_UNAVAIL",
+ [SPE_FP_DATA] = "SPE_FP_DATA",
+ [SPE_FP_ROUND] = "SPE_FP_ROUND",
+#endif
[TIMEINGUEST] = "TIMEINGUEST"
};
diff --git a/arch/powerpc/kvm/timing.h b/arch/powerpc/kvm/timing.h
index 8167d42..712ab3a 100644
--- a/arch/powerpc/kvm/timing.h
+++ b/arch/powerpc/kvm/timing.h
@@ -93,6 +93,17 @@ static inline void kvmppc_account_exit_stat(struct kvm_vcpu *vcpu, int type)
case SIGNAL_EXITS:
vcpu->stat.signal_exits++;
break;
+#ifdef CONFIG_SPE
+ case SPE_UNAVAIL:
+ vcpu->stat.spe_unavail++;
+ break;
+ case SPE_FP_DATA:
+ vcpu->stat.spe_fp_data++;
+ break;
+ case SPE_FP_ROUND:
+ vcpu->stat.spe_fp_round++;
+ break;
+#endif
}
}
--
1.6.4
^ permalink raw reply related
* [PATCH] mpc836x: fix failed phy detection for ucc ethernet on MDS
From: Paul Gortmaker @ 2012-02-27 12:25 UTC (permalink / raw)
To: afleming, benh; +Cc: netdev, linuxppc-dev, Paul Gortmaker
The mpc836x_mds platform has been broken since the commit
6fe3264945ee63292cdfb27b6e95bc52c603bb09
"netdev/phy: Use mdiobus_read() so that proper locks are taken"
which caused the fsl_pq_mdio TBI autoprobe to oops. The oops
was "fixed" in commit 28d8ea2d568534026ccda3e8936f5ea1e04a86a1
"fsl_pq_mdio: Clean up tbi address configuration"
by simply removing the the autoscan code, and making tbi nodes
mandatory. Some of the newer reference platforms were updated
to have tbi nodes in 220669495bf8b68130a8218607147c7b74c28d2b
"powerpc: Add TBI PHY node to first MDIO bus"
but the older mpc836x didn't get one and hence was just failing
with -EBUSY as follows:
fsl-pq_mdio: probe of e0102120.mdio failed with error -16
...
net eth0: Could not attach to PHY
eth0: Cannot initialize PHY, aborting.
Add a TBI node and use the 1st free address for it.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
[Andy: There may be other boards that could be having this problem
git grep -l enet.*ucc arch/powerpc/boot/dts/|xargs grep -L tbi
shows four possible candidates -- but I've only got the 8360MDS. ]
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 45cfa1c5..1de33ce 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -405,6 +405,10 @@
reg = <0x1>;
device_type = "ethernet-phy";
};
+ tbi-phy@2 {
+ device_type = "tbi-phy";
+ reg = <0x2>;
+ };
};
qeic: interrupt-controller@80 {
--
1.7.9.1
^ permalink raw reply related
* [PATCH net-next] ucc_geth: separate out rx/tx ring alloc and free operations
From: Paul Gortmaker @ 2012-02-27 12:36 UTC (permalink / raw)
To: leoli; +Cc: netdev, linuxppc-dev, Paul Gortmaker
Factor out the the existing allocation and free operations
so that they can be used individually.
This is to improve code readability, and also to prepare for
possible future changes like better error recovery and more
dynamic configuration (e.g on-the-fly resizing of the rings).
This change represents a straight up relocation of the existing
code into separate routines without changing any of the contained
code itself. Local variables are relocated as necessary.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
[boot tested net-next on mpc8360 once I fixed mpc836x_mds.dts]
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index ec09054..4e3cd2f 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -1856,11 +1856,93 @@ static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *uge
return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in hardware */
}
-static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
+static void ucc_geth_free_rx(struct ucc_geth_private *ugeth)
+{
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_info *uf_info;
+ u16 i, j;
+ u8 __iomem *bd;
+
+
+ ug_info = ugeth->ug_info;
+ uf_info = &ug_info->uf_info;
+
+ for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
+ if (ugeth->p_rx_bd_ring[i]) {
+ /* Return existing data buffers in ring */
+ bd = ugeth->p_rx_bd_ring[i];
+ for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
+ if (ugeth->rx_skbuff[i][j]) {
+ dma_unmap_single(ugeth->dev,
+ in_be32(&((struct qe_bd __iomem *)bd)->buf),
+ ugeth->ug_info->
+ uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(
+ ugeth->rx_skbuff[i][j]);
+ ugeth->rx_skbuff[i][j] = NULL;
+ }
+ bd += sizeof(struct qe_bd);
+ }
+
+ kfree(ugeth->rx_skbuff[i]);
+
+ if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_SYSTEM)
+ kfree((void *)ugeth->rx_bd_ring_offset[i]);
+ else if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_MURAM)
+ qe_muram_free(ugeth->rx_bd_ring_offset[i]);
+ ugeth->p_rx_bd_ring[i] = NULL;
+ }
+ }
+
+}
+
+static void ucc_geth_free_tx(struct ucc_geth_private *ugeth)
{
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_info *uf_info;
u16 i, j;
u8 __iomem *bd;
+ ug_info = ugeth->ug_info;
+ uf_info = &ug_info->uf_info;
+
+ for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
+ bd = ugeth->p_tx_bd_ring[i];
+ if (!bd)
+ continue;
+ for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
+ if (ugeth->tx_skbuff[i][j]) {
+ dma_unmap_single(ugeth->dev,
+ in_be32(&((struct qe_bd __iomem *)bd)->buf),
+ (in_be32((u32 __iomem *)bd) &
+ BD_LENGTH_MASK),
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(ugeth->tx_skbuff[i][j]);
+ ugeth->tx_skbuff[i][j] = NULL;
+ }
+ }
+
+ kfree(ugeth->tx_skbuff[i]);
+
+ if (ugeth->p_tx_bd_ring[i]) {
+ if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_SYSTEM)
+ kfree((void *)ugeth->tx_bd_ring_offset[i]);
+ else if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_MURAM)
+ qe_muram_free(ugeth->tx_bd_ring_offset[i]);
+ ugeth->p_tx_bd_ring[i] = NULL;
+ }
+ }
+
+}
+
+static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
+{
if (!ugeth)
return;
@@ -1927,64 +2009,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
kfree(ugeth->p_init_enet_param_shadow);
ugeth->p_init_enet_param_shadow = NULL;
}
- for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
- bd = ugeth->p_tx_bd_ring[i];
- if (!bd)
- continue;
- for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
- if (ugeth->tx_skbuff[i][j]) {
- dma_unmap_single(ugeth->dev,
- in_be32(&((struct qe_bd __iomem *)bd)->buf),
- (in_be32((u32 __iomem *)bd) &
- BD_LENGTH_MASK),
- DMA_TO_DEVICE);
- dev_kfree_skb_any(ugeth->tx_skbuff[i][j]);
- ugeth->tx_skbuff[i][j] = NULL;
- }
- }
-
- kfree(ugeth->tx_skbuff[i]);
-
- if (ugeth->p_tx_bd_ring[i]) {
- if (ugeth->ug_info->uf_info.bd_mem_part ==
- MEM_PART_SYSTEM)
- kfree((void *)ugeth->tx_bd_ring_offset[i]);
- else if (ugeth->ug_info->uf_info.bd_mem_part ==
- MEM_PART_MURAM)
- qe_muram_free(ugeth->tx_bd_ring_offset[i]);
- ugeth->p_tx_bd_ring[i] = NULL;
- }
- }
- for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
- if (ugeth->p_rx_bd_ring[i]) {
- /* Return existing data buffers in ring */
- bd = ugeth->p_rx_bd_ring[i];
- for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
- if (ugeth->rx_skbuff[i][j]) {
- dma_unmap_single(ugeth->dev,
- in_be32(&((struct qe_bd __iomem *)bd)->buf),
- ugeth->ug_info->
- uf_info.max_rx_buf_length +
- UCC_GETH_RX_DATA_BUF_ALIGNMENT,
- DMA_FROM_DEVICE);
- dev_kfree_skb_any(
- ugeth->rx_skbuff[i][j]);
- ugeth->rx_skbuff[i][j] = NULL;
- }
- bd += sizeof(struct qe_bd);
- }
-
- kfree(ugeth->rx_skbuff[i]);
-
- if (ugeth->ug_info->uf_info.bd_mem_part ==
- MEM_PART_SYSTEM)
- kfree((void *)ugeth->rx_bd_ring_offset[i]);
- else if (ugeth->ug_info->uf_info.bd_mem_part ==
- MEM_PART_MURAM)
- qe_muram_free(ugeth->rx_bd_ring_offset[i]);
- ugeth->p_rx_bd_ring[i] = NULL;
- }
- }
+ ucc_geth_free_tx(ugeth);
+ ucc_geth_free_rx(ugeth);
while (!list_empty(&ugeth->group_hash_q))
put_enet_addr_container(ENET_ADDR_CONT_ENTRY
(dequeue(&ugeth->group_hash_q)));
@@ -2210,6 +2236,171 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
return 0;
}
+static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)
+{
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_info *uf_info;
+ int length;
+ u16 i, j;
+ u8 __iomem *bd;
+
+ ug_info = ugeth->ug_info;
+ uf_info = &ug_info->uf_info;
+
+ /* Allocate Tx bds */
+ for (j = 0; j < ug_info->numQueuesTx; j++) {
+ /* Allocate in multiple of
+ UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT,
+ according to spec */
+ length = ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd))
+ / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+ * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+ if ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)) %
+ UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+ length += UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+ if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
+ u32 align = 4;
+ if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
+ align = UCC_GETH_TX_BD_RING_ALIGNMENT;
+ ugeth->tx_bd_ring_offset[j] =
+ (u32) kmalloc((u32) (length + align), GFP_KERNEL);
+
+ if (ugeth->tx_bd_ring_offset[j] != 0)
+ ugeth->p_tx_bd_ring[j] =
+ (u8 __iomem *)((ugeth->tx_bd_ring_offset[j] +
+ align) & ~(align - 1));
+ } else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
+ ugeth->tx_bd_ring_offset[j] =
+ qe_muram_alloc(length,
+ UCC_GETH_TX_BD_RING_ALIGNMENT);
+ if (!IS_ERR_VALUE(ugeth->tx_bd_ring_offset[j]))
+ ugeth->p_tx_bd_ring[j] =
+ (u8 __iomem *) qe_muram_addr(ugeth->
+ tx_bd_ring_offset[j]);
+ }
+ if (!ugeth->p_tx_bd_ring[j]) {
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate memory for Tx bd rings.",
+ __func__);
+ return -ENOMEM;
+ }
+ /* Zero unused end of bd ring, according to spec */
+ memset_io((void __iomem *)(ugeth->p_tx_bd_ring[j] +
+ ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)), 0,
+ length - ug_info->bdRingLenTx[j] * sizeof(struct qe_bd));
+ }
+
+ /* Init Tx bds */
+ for (j = 0; j < ug_info->numQueuesTx; j++) {
+ /* Setup the skbuff rings */
+ ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenTx[j],
+ GFP_KERNEL);
+
+ if (ugeth->tx_skbuff[j] == NULL) {
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Could not allocate tx_skbuff",
+ __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ugeth->ug_info->bdRingLenTx[j]; i++)
+ ugeth->tx_skbuff[j][i] = NULL;
+
+ ugeth->skb_curtx[j] = ugeth->skb_dirtytx[j] = 0;
+ bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j];
+ for (i = 0; i < ug_info->bdRingLenTx[j]; i++) {
+ /* clear bd buffer */
+ out_be32(&((struct qe_bd __iomem *)bd)->buf, 0);
+ /* set bd status and length */
+ out_be32((u32 __iomem *)bd, 0);
+ bd += sizeof(struct qe_bd);
+ }
+ bd -= sizeof(struct qe_bd);
+ /* set bd status and length */
+ out_be32((u32 __iomem *)bd, T_W); /* for last BD set Wrap bit */
+ }
+
+ return 0;
+}
+
+static int ucc_geth_alloc_rx(struct ucc_geth_private *ugeth)
+{
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_info *uf_info;
+ int length;
+ u16 i, j;
+ u8 __iomem *bd;
+
+ ug_info = ugeth->ug_info;
+ uf_info = &ug_info->uf_info;
+
+ /* Allocate Rx bds */
+ for (j = 0; j < ug_info->numQueuesRx; j++) {
+ length = ug_info->bdRingLenRx[j] * sizeof(struct qe_bd);
+ if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
+ u32 align = 4;
+ if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
+ align = UCC_GETH_RX_BD_RING_ALIGNMENT;
+ ugeth->rx_bd_ring_offset[j] =
+ (u32) kmalloc((u32) (length + align), GFP_KERNEL);
+ if (ugeth->rx_bd_ring_offset[j] != 0)
+ ugeth->p_rx_bd_ring[j] =
+ (u8 __iomem *)((ugeth->rx_bd_ring_offset[j] +
+ align) & ~(align - 1));
+ } else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
+ ugeth->rx_bd_ring_offset[j] =
+ qe_muram_alloc(length,
+ UCC_GETH_RX_BD_RING_ALIGNMENT);
+ if (!IS_ERR_VALUE(ugeth->rx_bd_ring_offset[j]))
+ ugeth->p_rx_bd_ring[j] =
+ (u8 __iomem *) qe_muram_addr(ugeth->
+ rx_bd_ring_offset[j]);
+ }
+ if (!ugeth->p_rx_bd_ring[j]) {
+ if (netif_msg_ifup(ugeth))
+ ugeth_err
+ ("%s: Can not allocate memory for Rx bd rings.",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+
+ /* Init Rx bds */
+ for (j = 0; j < ug_info->numQueuesRx; j++) {
+ /* Setup the skbuff rings */
+ ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenRx[j],
+ GFP_KERNEL);
+
+ if (ugeth->rx_skbuff[j] == NULL) {
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Could not allocate rx_skbuff",
+ __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ugeth->ug_info->bdRingLenRx[j]; i++)
+ ugeth->rx_skbuff[j][i] = NULL;
+
+ ugeth->skb_currx[j] = 0;
+ bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j];
+ for (i = 0; i < ug_info->bdRingLenRx[j]; i++) {
+ /* set bd status and length */
+ out_be32((u32 __iomem *)bd, R_I);
+ /* clear bd buffer */
+ out_be32(&((struct qe_bd __iomem *)bd)->buf, 0);
+ bd += sizeof(struct qe_bd);
+ }
+ bd -= sizeof(struct qe_bd);
+ /* set bd status and length */
+ out_be32((u32 __iomem *)bd, R_W); /* for last BD set Wrap bit */
+ }
+
+ return 0;
+}
+
static int ucc_geth_startup(struct ucc_geth_private *ugeth)
{
struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
@@ -2222,11 +2413,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
int ret_val = -EINVAL;
u32 remoder = UCC_GETH_REMODER_INIT;
u32 init_enet_pram_offset, cecr_subblock, command;
- u32 ifstat, i, j, size, l2qt, l3qt, length;
+ u32 ifstat, i, j, size, l2qt, l3qt;
u16 temoder = UCC_GETH_TEMODER_INIT;
u16 test;
u8 function_code = 0;
- u8 __iomem *bd;
u8 __iomem *endOfRing;
u8 numThreadsRxNumerical, numThreadsTxNumerical;
@@ -2366,142 +2556,13 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE),
0, &uf_regs->upsmr, &ug_regs->uescr);
- /* Allocate Tx bds */
- for (j = 0; j < ug_info->numQueuesTx; j++) {
- /* Allocate in multiple of
- UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT,
- according to spec */
- length = ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd))
- / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
- * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
- if ((ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)) %
- UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
- length += UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
- if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
- u32 align = 4;
- if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
- align = UCC_GETH_TX_BD_RING_ALIGNMENT;
- ugeth->tx_bd_ring_offset[j] =
- (u32) kmalloc((u32) (length + align), GFP_KERNEL);
-
- if (ugeth->tx_bd_ring_offset[j] != 0)
- ugeth->p_tx_bd_ring[j] =
- (u8 __iomem *)((ugeth->tx_bd_ring_offset[j] +
- align) & ~(align - 1));
- } else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
- ugeth->tx_bd_ring_offset[j] =
- qe_muram_alloc(length,
- UCC_GETH_TX_BD_RING_ALIGNMENT);
- if (!IS_ERR_VALUE(ugeth->tx_bd_ring_offset[j]))
- ugeth->p_tx_bd_ring[j] =
- (u8 __iomem *) qe_muram_addr(ugeth->
- tx_bd_ring_offset[j]);
- }
- if (!ugeth->p_tx_bd_ring[j]) {
- if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate memory for Tx bd rings.",
- __func__);
- return -ENOMEM;
- }
- /* Zero unused end of bd ring, according to spec */
- memset_io((void __iomem *)(ugeth->p_tx_bd_ring[j] +
- ug_info->bdRingLenTx[j] * sizeof(struct qe_bd)), 0,
- length - ug_info->bdRingLenTx[j] * sizeof(struct qe_bd));
- }
-
- /* Allocate Rx bds */
- for (j = 0; j < ug_info->numQueuesRx; j++) {
- length = ug_info->bdRingLenRx[j] * sizeof(struct qe_bd);
- if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
- u32 align = 4;
- if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
- align = UCC_GETH_RX_BD_RING_ALIGNMENT;
- ugeth->rx_bd_ring_offset[j] =
- (u32) kmalloc((u32) (length + align), GFP_KERNEL);
- if (ugeth->rx_bd_ring_offset[j] != 0)
- ugeth->p_rx_bd_ring[j] =
- (u8 __iomem *)((ugeth->rx_bd_ring_offset[j] +
- align) & ~(align - 1));
- } else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
- ugeth->rx_bd_ring_offset[j] =
- qe_muram_alloc(length,
- UCC_GETH_RX_BD_RING_ALIGNMENT);
- if (!IS_ERR_VALUE(ugeth->rx_bd_ring_offset[j]))
- ugeth->p_rx_bd_ring[j] =
- (u8 __iomem *) qe_muram_addr(ugeth->
- rx_bd_ring_offset[j]);
- }
- if (!ugeth->p_rx_bd_ring[j]) {
- if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate memory for Rx bd rings.",
- __func__);
- return -ENOMEM;
- }
- }
-
- /* Init Tx bds */
- for (j = 0; j < ug_info->numQueuesTx; j++) {
- /* Setup the skbuff rings */
- ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenTx[j],
- GFP_KERNEL);
-
- if (ugeth->tx_skbuff[j] == NULL) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Could not allocate tx_skbuff",
- __func__);
- return -ENOMEM;
- }
-
- for (i = 0; i < ugeth->ug_info->bdRingLenTx[j]; i++)
- ugeth->tx_skbuff[j][i] = NULL;
-
- ugeth->skb_curtx[j] = ugeth->skb_dirtytx[j] = 0;
- bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j];
- for (i = 0; i < ug_info->bdRingLenTx[j]; i++) {
- /* clear bd buffer */
- out_be32(&((struct qe_bd __iomem *)bd)->buf, 0);
- /* set bd status and length */
- out_be32((u32 __iomem *)bd, 0);
- bd += sizeof(struct qe_bd);
- }
- bd -= sizeof(struct qe_bd);
- /* set bd status and length */
- out_be32((u32 __iomem *)bd, T_W); /* for last BD set Wrap bit */
- }
-
- /* Init Rx bds */
- for (j = 0; j < ug_info->numQueuesRx; j++) {
- /* Setup the skbuff rings */
- ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenRx[j],
- GFP_KERNEL);
-
- if (ugeth->rx_skbuff[j] == NULL) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Could not allocate rx_skbuff",
- __func__);
- return -ENOMEM;
- }
-
- for (i = 0; i < ugeth->ug_info->bdRingLenRx[j]; i++)
- ugeth->rx_skbuff[j][i] = NULL;
+ ret_val = ucc_geth_alloc_tx(ugeth);
+ if (ret_val != 0)
+ return ret_val;
- ugeth->skb_currx[j] = 0;
- bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j];
- for (i = 0; i < ug_info->bdRingLenRx[j]; i++) {
- /* set bd status and length */
- out_be32((u32 __iomem *)bd, R_I);
- /* clear bd buffer */
- out_be32(&((struct qe_bd __iomem *)bd)->buf, 0);
- bd += sizeof(struct qe_bd);
- }
- bd -= sizeof(struct qe_bd);
- /* set bd status and length */
- out_be32((u32 __iomem *)bd, R_W); /* for last BD set Wrap bit */
- }
+ ret_val = ucc_geth_alloc_rx(ugeth);
+ if (ret_val != 0)
+ return ret_val;
/*
* Global PRAM
--
1.7.9.1
^ permalink raw reply related
* [PATCH] of/mdio: fix fixed link bus name
From: Baruch Siach @ 2012-02-27 12:48 UTC (permalink / raw)
To: Grant Likely, Rob Herring
Cc: netdev, devicetree-discuss, linuxppc-dev, Baruch Siach
Since 9e6c643b (phy/fixed: use an unique MDIO bus name) the name of the fixed
PHY bus is "fixed-0". Teach of_phy_connect_fixed_link() the new name.
Tested on a P1020RDB PowerPC system.
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---
drivers/of/of_mdio.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 980c079..483c0ad 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -182,7 +182,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
if (!phy_id || sz < sizeof(*phy_id))
return NULL;
- sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
+ sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
phy = phy_connect(dev, bus_id, hndlr, 0, iface);
return IS_ERR(phy) ? NULL : phy;
--
1.7.9
^ permalink raw reply related
* Re: [PATCH 1/2] powerpc: Move GE GPIO and PIC drivers
From: Martyn Welch @ 2012-02-27 13:57 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Wim Van Sebroeck, linuxppc-dev, linux-kernel
In-Reply-To: <1330299464.20389.58.camel@pasglop>
On 26/02/12 23:37, Benjamin Herrenschmidt wrote:
> On Tue, 2012-02-07 at 11:28 +0000, Martyn Welch wrote:
>> Move the GE GPIO and PIC drivers to allow these to be used by non-86xx
>> boards.
>
> Hi, Sorry for the late review...
>
No problem, thanks for the review!
>> Signed-off-by: Martyn Welch <martyn.welch@ge.com>
>> ---
>> arch/powerpc/platforms/86xx/Kconfig | 3 +
>> arch/powerpc/platforms/86xx/Makefile | 7 +-
>> arch/powerpc/platforms/86xx/gef_gpio.c | 171 --------------------
>> arch/powerpc/platforms/86xx/gef_pic.c | 252 ------------------------------
>> arch/powerpc/platforms/86xx/gef_pic.h | 11 --
>> arch/powerpc/platforms/86xx/gef_ppc9a.c | 3 +-
>> arch/powerpc/platforms/86xx/gef_sbc310.c | 3 +-
>> arch/powerpc/platforms/86xx/gef_sbc610.c | 3 +-
>> arch/powerpc/platforms/Kconfig | 7 +
>> arch/powerpc/platforms/Makefile | 3 +
>> arch/powerpc/platforms/ge_gpio.c | 171 ++++++++++++++++++++
>> arch/powerpc/platforms/ge_pic.c | 252 ++++++++++++++++++++++++++++++
>> arch/powerpc/platforms/ge_pic.h | 11 ++
>
> So I don't like having files showing up there. In fact, I want to move
> the only other one here, it's not the right place for it
> (fsl_uli1575.c).
>
This patch (or one like it) has been around for a while now. Kumar wanted me
to put them here rather than sysdev[1], but I'm easy either way.
> Please contemplate using arch/powerpc/sysdev instead. Maybe make a
> subdir in there (geip or something like that ?)
>
I'd rather avoid "geip" (we seem to have a habit of renaming divisions), would
"ge" be acceptable?
> Also, use git mv so that the file moves appear as such in the history,
> this will make review easier by clearly separating the move from actual
> changes to the files.
>
Hmm, thought I'd done that. Will try again.
Martyn
[1] http://old.nabble.com/GE-GPIO-and-PIC-support.-td27212938.html
--
Martyn Welch (Lead Software Engineer) | Registered in England and Wales
GE Intelligent Platforms | (3828642) at 100 Barbirolli Square
T +44(0)1327322748 | Manchester, M2 3AB
E martyn.welch@ge.com | VAT:GB 927559189
^ permalink raw reply
* Re: [PATCH] of/mdio: fix fixed link bus name
From: Florian Fainelli @ 2012-02-27 14:46 UTC (permalink / raw)
To: Baruch Siach; +Cc: netdev, devicetree-discuss, linuxppc-dev, Rob Herring
In-Reply-To: <8ebe6a3f11343c392a7353581d5f648980206e8e.1330346765.git.baruch@tkos.co.il>
Le 02/27/12 13:48, Baruch Siach a écrit :
> Since 9e6c643b (phy/fixed: use an unique MDIO bus name) the name of the fixed
> PHY bus is "fixed-0". Teach of_phy_connect_fixed_link() the new name.
>
> Tested on a P1020RDB PowerPC system.
>
> Signed-off-by: Baruch Siach<baruch@tkos.co.il>
Acked-by: Florian Fainelli <florian@openwrt.org>
> ---
> drivers/of/of_mdio.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
> index 980c079..483c0ad 100644
> --- a/drivers/of/of_mdio.c
> +++ b/drivers/of/of_mdio.c
> @@ -182,7 +182,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
> if (!phy_id || sz< sizeof(*phy_id))
> return NULL;
>
> - sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
> + sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
>
> phy = phy_connect(dev, bus_id, hndlr, 0, iface);
> return IS_ERR(phy) ? NULL : phy;
^ permalink raw reply
* Re: [PATCH 1/2] powerpc/e500: make load_up_spe a normal fuction
From: Tabi Timur-B04825 @ 2012-02-27 15:50 UTC (permalink / raw)
To: Yin Olivia-R63875
Cc: linuxppc-dev@lists.ozlabs.org, kvm@vger.kernel.org,
kvm-ppc@vger.kernel.org
In-Reply-To: <1330340388-30296-1-git-send-email-hong-hua.yin@freescale.com>
On Mon, Feb 27, 2012 at 4:59 AM, Olivia Yin <hong-hua.yin@freescale.com> wr=
ote:
> So that we can call it in kernel.
And why would we want that?
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* Re: [PATCH] of/mdio: fix fixed link bus name
From: Rob Herring @ 2012-02-27 15:59 UTC (permalink / raw)
To: Baruch Siach; +Cc: netdev, devicetree-discuss, linuxppc-dev
In-Reply-To: <8ebe6a3f11343c392a7353581d5f648980206e8e.1330346765.git.baruch@tkos.co.il>
On 02/27/2012 06:48 AM, Baruch Siach wrote:
> Since 9e6c643b (phy/fixed: use an unique MDIO bus name) the name of the fixed
> PHY bus is "fixed-0". Teach of_phy_connect_fixed_link() the new name.
>
Applied for 3.3.
Rob
> Tested on a P1020RDB PowerPC system.
>
> Signed-off-by: Baruch Siach <baruch@tkos.co.il>
> ---
> drivers/of/of_mdio.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
> index 980c079..483c0ad 100644
> --- a/drivers/of/of_mdio.c
> +++ b/drivers/of/of_mdio.c
> @@ -182,7 +182,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
> if (!phy_id || sz < sizeof(*phy_id))
> return NULL;
>
> - sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
> + sprintf(bus_id, PHY_ID_FMT, "fixed-0", be32_to_cpu(phy_id[0]));
>
> phy = phy_connect(dev, bus_id, hndlr, 0, iface);
> return IS_ERR(phy) ? NULL : phy;
^ permalink raw reply
* RE: [PATCH 24/37] KVM: PPC: booke: rework rescheduling checks
From: Bhushan Bharat-R65777 @ 2012-02-27 16:34 UTC (permalink / raw)
To: Alexander Graf, kvm-ppc@vger.kernel.org
Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org,
kvm@vger.kernel.org
In-Reply-To: <1330093591-19523-25-git-send-email-agraf@suse.de>
> -----Original Message-----
> From: kvm-owner@vger.kernel.org [mailto:kvm-owner@vger.kernel.org] On Beh=
alf Of
> Alexander Graf
> Sent: Friday, February 24, 2012 7:56 PM
> To: kvm-ppc@vger.kernel.org
> Cc: kvm@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; Wood Scott-B07421
> Subject: [PATCH 24/37] KVM: PPC: booke: rework rescheduling checks
>=20
> Instead of checking whether we should reschedule only when we exited due =
to an
> interrupt, let's always check before entering the guest back again. This =
gets
> the target more in line with the other archs.
>=20
> Also while at it, generalize the whole thing so that eventually we could =
have a
> single kvmppc_prepare_to_enter function for all ppc targets that does sig=
nal and
> reschedule checking for us.
>=20
> Signed-off-by: Alexander Graf <agraf@suse.de>
> ---
> arch/powerpc/include/asm/kvm_ppc.h | 2 +-
> arch/powerpc/kvm/book3s.c | 4 ++-
> arch/powerpc/kvm/booke.c | 70 ++++++++++++++++++++++++------=
-----
> 3 files changed, 52 insertions(+), 24 deletions(-)
>=20
> diff --git a/arch/powerpc/include/asm/kvm_ppc.h
> b/arch/powerpc/include/asm/kvm_ppc.h
> index e709975..7f0a3da 100644
> --- a/arch/powerpc/include/asm/kvm_ppc.h
> +++ b/arch/powerpc/include/asm/kvm_ppc.h
> @@ -95,7 +95,7 @@ extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *=
vcpu,
> extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu); exter=
n void
> kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu);
>=20
> -extern void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu);
> +extern int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu);
> extern int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu); extern void
> kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags); extern vo=
id
> kvmppc_core_queue_dec(struct kvm_vcpu *vcpu); diff --git
> a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 7d54f4e..c8=
ead7b
> 100644
> --- a/arch/powerpc/kvm/book3s.c
> +++ b/arch/powerpc/kvm/book3s.c
> @@ -258,7 +258,7 @@ static bool clear_irqprio(struct kvm_vcpu *vcpu, unsi=
gned
> int priority)
> return true;
> }
>=20
> -void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
> +int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
> {
> unsigned long *pending =3D &vcpu->arch.pending_exceptions;
> unsigned long old_pending =3D vcpu->arch.pending_exceptions; @@ -283,6
> +283,8 @@ void kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
>=20
> /* Tell the guest about our interrupt status */
> kvmppc_update_int_pending(vcpu, *pending, old_pending);
> +
> + return 0;
> }
>=20
> pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn) diff --git
> a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 9979be1..3fce=
c2c
> 100644
> --- a/arch/powerpc/kvm/booke.c
> +++ b/arch/powerpc/kvm/booke.c
> @@ -439,8 +439,9 @@ static void kvmppc_core_check_exceptions(struct kvm_v=
cpu
> *vcpu) }
>=20
> /* Check pending exceptions and deliver one, if possible. */ -void
> kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
> +int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
> {
> + int r =3D 0;
> WARN_ON_ONCE(!irqs_disabled());
>=20
> kvmppc_core_check_exceptions(vcpu);
> @@ -451,8 +452,44 @@ void kvmppc_core_prepare_to_enter(struct kvm_vcpu *v=
cpu)
> local_irq_disable();
>=20
> kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
> - kvmppc_core_check_exceptions(vcpu);
> + r =3D 1;
> };
> +
> + return r;
> +}
> +
> +/*
> + * Common checks before entering the guest world. Call with interrupts
> + * disabled.
> + *
> + * returns !0 if a signal is pending and check_signal is true */
> +static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu, bool
> +check_signal) {
> + int r =3D 0;
> +
> + WARN_ON_ONCE(!irqs_disabled());
> + while (true) {
> + if (need_resched()) {
> + local_irq_enable();
> + cond_resched();
> + local_irq_disable();
> + continue;
> + }
> +
> + if (kvmppc_core_prepare_to_enter(vcpu)) {
kvmppc_prepare_to_enter() is called even on heavyweight_exit. Should not th=
is be called only on lightweight_exit?
Thanks
-Bharat
> + /* interrupts got enabled in between, so we
> + are back at square 1 */
> + continue;
> + }
> +
> + if (check_signal && signal_pending(current))
> + r =3D 1;
> +
> + break;
> + }
> +
> + return r;
> }
>=20
> int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) @@ -=
470,10
> +507,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *v=
cpu)
> }
>=20
> local_irq_disable();
> -
> - kvmppc_core_prepare_to_enter(vcpu);
> -
> - if (signal_pending(current)) {
> + if (kvmppc_prepare_to_enter(vcpu, true)) {
> kvm_run->exit_reason =3D KVM_EXIT_INTR;
> ret =3D -EINTR;
> goto out;
> @@ -598,25 +632,21 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu,
>=20
> switch (exit_nr) {
> case BOOKE_INTERRUPT_MACHINE_CHECK:
> - kvm_resched(vcpu);
> r =3D RESUME_GUEST;
> break;
>=20
> case BOOKE_INTERRUPT_EXTERNAL:
> kvmppc_account_exit(vcpu, EXT_INTR_EXITS);
> - kvm_resched(vcpu);
> r =3D RESUME_GUEST;
> break;
>=20
> case BOOKE_INTERRUPT_DECREMENTER:
> kvmppc_account_exit(vcpu, DEC_EXITS);
> - kvm_resched(vcpu);
> r =3D RESUME_GUEST;
> break;
>=20
> case BOOKE_INTERRUPT_DOORBELL:
> kvmppc_account_exit(vcpu, DBELL_EXITS);
> - kvm_resched(vcpu);
> r =3D RESUME_GUEST;
> break;
>=20
> @@ -865,19 +895,15 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu,
> BUG();
> }
>=20
> + /*
> + * To avoid clobbering exit_reason, only check for signals if we
> + * aren't already exiting to userspace for some other reason.
> + */
> local_irq_disable();
> -
> - kvmppc_core_prepare_to_enter(vcpu);
> -
> - if (!(r & RESUME_HOST)) {
> - /* To avoid clobbering exit_reason, only check for signals if
> - * we aren't already exiting to userspace for some other
> - * reason. */
> - if (signal_pending(current)) {
> - run->exit_reason =3D KVM_EXIT_INTR;
> - r =3D (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
> - kvmppc_account_exit(vcpu, SIGNAL_EXITS);
> - }
> + if (kvmppc_prepare_to_enter(vcpu, !(r & RESUME_HOST))) {
> + run->exit_reason =3D KVM_EXIT_INTR;
> + r =3D (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
> + kvmppc_account_exit(vcpu, SIGNAL_EXITS);
> }
>=20
> return r;
> --
> 1.6.0.2
>=20
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in the bod=
y of a
> message to majordomo@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 24/37] KVM: PPC: booke: rework rescheduling checks
From: Alexander Graf @ 2012-02-27 17:33 UTC (permalink / raw)
To: Bhushan Bharat-R65777
Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org,
kvm@vger.kernel.org, kvm-ppc@vger.kernel.org
In-Reply-To: <6A3DF150A5B70D4F9B66A25E3F7C888D141083@039-SN2MPN1-023.039d.mgd.msft.net>
On 02/27/2012 05:34 PM, Bhushan Bharat-R65777 wrote:
>
>> +}
>> +
>> +/*
>> + * Common checks before entering the guest world. Call with interrupts
>> + * disabled.
>> + *
>> + * returns !0 if a signal is pending and check_signal is true */
>> +static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu, bool
>> +check_signal) {
>> + int r = 0;
>> +
>> + WARN_ON_ONCE(!irqs_disabled());
>> + while (true) {
>> + if (need_resched()) {
>> + local_irq_enable();
>> + cond_resched();
>> + local_irq_disable();
>> + continue;
>> + }
>> +
>> + if (kvmppc_core_prepare_to_enter(vcpu)) {
> kvmppc_prepare_to_enter() is called even on heavyweight_exit. Should not this be called only on lightweight_exit?
Yeah, we don't need to call it when exiting anyways. That's a functional
change though, which this patch is trying not to introduce. So we should
rather do that as a patch on top.
Alex
^ permalink raw reply
* Re: [PATCH] powerpc: icswx: fix race condition where threads do not get their ACOP register updated in time.
From: Jimi Xenidis @ 2012-02-27 17:56 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Anton Blanchard
In-Reply-To: <1330300068.20389.63.camel@pasglop>
On Feb 26, 2012, at 5:47 PM, Benjamin Herrenschmidt wrote:
>=20
>>=20
>> + /*
>> + * We could be here because another thread has enabled acop
>> + * but the ACOP register has yet to be updated.
>> + *
>> + * This should have been taken care of by the IPI to sync all
>> + * the threads (see smp_call_function(sync_cop, mm, 1)), but
>> + * that could take forever if there are a significant amount
>> + * of threads.
>> + *
>> + * Given the number of threads on some of these systems,
>> + * perhaps this is the best way to sync ACOP rather than whack
>> + * every thread with an IPI.
>> + */
>=20
> This is actually pretty standard stuff... If it was me I would make it
> all lazy and avoid the IPI completely but it doesn't necessarily hurt
> that much.
I'm happy to get rid of the IPI completely if Anton (or someone else) =
agrees to test on his end.
If not, do you want me to reduce the comment?
> In any case the "recovery" is indeed needed and you should
> probably also remove the pr_debug, it's really just spam.
ack
>=20
>> + if (acop_copro_type_bit(ct) && current->active_mm->context.acop) =
{
>=20
> Shouldn't that be "&" ? In fact, gcc would even warn so either make
> it acop_check_copro(acop, ct) or do a (x & y) !=3D 0
Ach!! nice catch!
-jx
>=20
> Cheers,
> Ben.
>=20
>> + pr_debug("%s[%d]: Spurrious ACOP Fault, CT: %d, bit: =
0x%llx "
>> + "SPR: 0x%lx, mm->acop: 0x%lx\n",
>> + current->comm, current->pid,
>> + ct, acop_copro_type_bit(ct), mfspr(SPRN_ACOP),
>> + current->active_mm->context.acop);
>> +
>> + sync_cop(current->active_mm);
>> + return 0;
>> + }
>> +
>> + /* check for alternate policy */
>> if (!acop_use_cop(ct))
>> return 0;
>>=20
>> /* at this point the CT is unknown to the system */
>> - pr_warn("%s[%d]: Coprocessor %d is unavailable",
>> + pr_warn("%s[%d]: Coprocessor %d is unavailable\n",
>> current->comm, current->pid, ct);
>>=20
>> /* get inst if we don't already have it */
>> diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
>> index 42176bd..6dedc08 100644
>> --- a/arch/powerpc/mm/icswx.h
>> +++ b/arch/powerpc/mm/icswx.h
>> @@ -59,4 +59,10 @@ extern void free_cop_pid(int free_pid);
>>=20
>> extern int acop_handle_fault(struct pt_regs *regs, unsigned long =
address,
>> unsigned long error_code);
>> +
>> +static inline u64 acop_copro_type_bit(unsigned int type)
>> +{
>> + return 1ULL << (63 - type);
>> +}
>> +
>> #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */
>=20
>=20
^ permalink raw reply
* Re: [PATCH 24/37] KVM: PPC: booke: rework rescheduling checks
From: Alexander Graf @ 2012-02-27 18:23 UTC (permalink / raw)
To: Bhushan Bharat-R65777
Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org,
kvm@vger.kernel.org, kvm-ppc@vger.kernel.org
In-Reply-To: <4F4BBE55.6020204@suse.de>
On 02/27/2012 06:33 PM, Alexander Graf wrote:
> On 02/27/2012 05:34 PM, Bhushan Bharat-R65777 wrote:
>>
>>> +}
>>> +
>>> +/*
>>> + * Common checks before entering the guest world. Call with
>>> interrupts
>>> + * disabled.
>>> + *
>>> + * returns !0 if a signal is pending and check_signal is true */
>>> +static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu, bool
>>> +check_signal) {
>>> + int r = 0;
>>> +
>>> + WARN_ON_ONCE(!irqs_disabled());
>>> + while (true) {
>>> + if (need_resched()) {
>>> + local_irq_enable();
>>> + cond_resched();
>>> + local_irq_disable();
>>> + continue;
>>> + }
>>> +
>>> + if (kvmppc_core_prepare_to_enter(vcpu)) {
>> kvmppc_prepare_to_enter() is called even on heavyweight_exit. Should
>> not this be called only on lightweight_exit?
>
> Yeah, we don't need to call it when exiting anyways. That's a
> functional change though, which this patch is trying not to introduce.
> So we should rather do that as a patch on top.
So how about this (warning! broken whitespace)?
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 7a16b56..616aa2d 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -464,7 +464,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
*
* returns !0 if a signal is pending and check_signal is true
*/
-static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu, bool
check_signal)
+static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
{
int r = 0;
@@ -483,7 +483,7 @@ static int kvmppc_prepare_to_enter(struct kvm_vcpu
*vcpu, bool check_signal)
continue;
}
- if (check_signal && signal_pending(current))
+ if (signal_pending(current))
r = 1;
break;
@@ -507,7 +507,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct
kvm_vcpu *vcpu)
}
local_irq_disable();
- if (kvmppc_prepare_to_enter(vcpu, true)) {
+ if (kvmppc_prepare_to_enter(vcpu)) {
kvm_run->exit_reason = KVM_EXIT_INTR;
ret = -EINTR;
goto out;
@@ -941,13 +941,16 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
kvm_vcpu *vcpu,
* To avoid clobbering exit_reason, only check for signals if we
* aren't already exiting to userspace for some other reason.
*/
- local_irq_disable();
- if (kvmppc_prepare_to_enter(vcpu, !(r & RESUME_HOST))) {
- run->exit_reason = KVM_EXIT_INTR;
- r = (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
- kvmppc_account_exit(vcpu, SIGNAL_EXITS);
+ if (!(r & RESUME_HOST)) {
+ local_irq_disable();
+ if (kvmppc_prepare_to_enter(vcpu)) {
+ run->exit_reason = KVM_EXIT_INTR;
+ r = (-EINTR << 2) | RESUME_HOST | (r &
RESUME_FLAG_NV);
+ kvmppc_account_exit(vcpu, SIGNAL_EXITS);
+ }
}
+out:
return r;
}
^ permalink raw reply related
* RE: [PATCH 24/37] KVM: PPC: booke: rework rescheduling checks
From: Bhushan Bharat-R65777 @ 2012-02-27 18:29 UTC (permalink / raw)
To: Alexander Graf
Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org,
kvm@vger.kernel.org, kvm-ppc@vger.kernel.org
In-Reply-To: <4F4BCA1F.5040905@suse.de>
> -----Original Message-----
> From: Alexander Graf [mailto:agraf@suse.de]
> Sent: Monday, February 27, 2012 11:53 PM
> To: Bhushan Bharat-R65777
> Cc: kvm-ppc@vger.kernel.org; kvm@vger.kernel.org; linuxppc-dev@lists.ozla=
bs.org;
> Wood Scott-B07421
> Subject: Re: [PATCH 24/37] KVM: PPC: booke: rework rescheduling checks
>=20
> On 02/27/2012 06:33 PM, Alexander Graf wrote:
> > On 02/27/2012 05:34 PM, Bhushan Bharat-R65777 wrote:
> >>
> >>> +}
> >>> +
> >>> +/*
> >>> + * Common checks before entering the guest world. Call with
> >>> interrupts
> >>> + * disabled.
> >>> + *
> >>> + * returns !0 if a signal is pending and check_signal is true */
> >>> +static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu, bool
> >>> +check_signal) {
> >>> + int r =3D 0;
> >>> +
> >>> + WARN_ON_ONCE(!irqs_disabled());
> >>> + while (true) {
> >>> + if (need_resched()) {
> >>> + local_irq_enable();
> >>> + cond_resched();
> >>> + local_irq_disable();
> >>> + continue;
> >>> + }
> >>> +
> >>> + if (kvmppc_core_prepare_to_enter(vcpu)) {
> >> kvmppc_prepare_to_enter() is called even on heavyweight_exit. Should
> >> not this be called only on lightweight_exit?
> >
> > Yeah, we don't need to call it when exiting anyways. That's a
> > functional change though, which this patch is trying not to introduce.
> > So we should rather do that as a patch on top.
>=20
> So how about this (warning! broken whitespace)?
>=20
>=20
> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index
> 7a16b56..616aa2d 100644
> --- a/arch/powerpc/kvm/booke.c
> +++ b/arch/powerpc/kvm/booke.c
> @@ -464,7 +464,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcp=
u)
> *
> * returns !0 if a signal is pending and check_signal is true
> */
> -static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu, bool
> check_signal)
> +static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
> {
> int r =3D 0;
>=20
> @@ -483,7 +483,7 @@ static int kvmppc_prepare_to_enter(struct kvm_vcpu *v=
cpu,
> bool check_signal)
> continue;
> }
>=20
> - if (check_signal && signal_pending(current))
> + if (signal_pending(current))
> r =3D 1;
>=20
> break;
> @@ -507,7 +507,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct k=
vm_vcpu
> *vcpu)
> }
>=20
> local_irq_disable();
> - if (kvmppc_prepare_to_enter(vcpu, true)) {
> + if (kvmppc_prepare_to_enter(vcpu)) {
> kvm_run->exit_reason =3D KVM_EXIT_INTR;
> ret =3D -EINTR;
> goto out;
> @@ -941,13 +941,16 @@ int kvmppc_handle_exit(struct kvm_run *run, struct
> kvm_vcpu *vcpu,
> * To avoid clobbering exit_reason, only check for signals if we
> * aren't already exiting to userspace for some other reason.
> */
> - local_irq_disable();
> - if (kvmppc_prepare_to_enter(vcpu, !(r & RESUME_HOST))) {
> - run->exit_reason =3D KVM_EXIT_INTR;
> - r =3D (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
> - kvmppc_account_exit(vcpu, SIGNAL_EXITS);
> + if (!(r & RESUME_HOST)) {
> + local_irq_disable();
> + if (kvmppc_prepare_to_enter(vcpu)) {
> + run->exit_reason =3D KVM_EXIT_INTR;
> + r =3D (-EINTR << 2) | RESUME_HOST | (r &
> RESUME_FLAG_NV);
> + kvmppc_account_exit(vcpu, SIGNAL_EXITS);
> + }
> }
>=20
> +out:
Why?
Otherwise looks ok to me.
Thanks
-Bharat
> return r;
> }
>=20
>=20
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox