* RE: Loading Linux from already running code..
From: Sumesh Kaana @ 2011-09-27 6:51 UTC (permalink / raw)
To: p.ittershagen, cmunoz; +Cc: linuxppc-dev
In-Reply-To: <CAC157GAaqdNVQf9hycEVft3cgpbVWxOwncBSNwfVFBGQugZjpQ@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1953 bytes --]
Hi Philipp and Carlos,
Thanks for the reply.
When simpleImage.elf is loaded by a debugger, the debugger reads the elf image header and places various sections of image into right place in the RAM. But when I do it from already_running_code, I should manually unpack the elf and place the sections in the memory, then jump to the start address, Am I right?
Also,
Is it possible to load a simpleImage.bin file and jump to the start address using a function pointer, Hence I can avoid unpack_elf_image()...? - Will this work?
Thanks,
Sumesh.
> Date: Mon, 26 Sep 2011 20:13:24 +0200
> Subject: Re: Loading Linux from already running code..
> From: p.ittershagen@googlemail.com
> To: cmunoz@sablenetworks.com
> CC: linuxppc-dev@lists.ozlabs.org; sumeshkkn@hotmail.com
>
> On Mon, Sep 26, 2011 at 7:26 PM, Carlos Munoz <cmunoz@sablenetworks.com> wrote:
> > You could build a tarball containing the root files system, dtb, Linux,
> > plus a header indicating where the different pieces need to be loaded.
> > Then your initial code loads the different parts at the right memory
> > locations, sets up the Linux arguments, and jumps to Linux.
>
> That is exactly what the firmware-independent simpleImage.initrd.*
> targets already do. The resulting elf file include the dtb and initrd
> as well as a prompt-like boot arg cli.
> I think it will be possible to just place the simpleImage.initrd.*
> into you memory and let the existing code jump to the start adress of
> the elf image. I managed to start a ppc core using JTAG and the
> simpleImage.initrd elf files and I think the procedure is very much
> the same but instead of the JTAG debugger setting the PC to the start
> address, your startup code has to do it.
>
>
> Philipp
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
[-- Attachment #2: Type: text/html, Size: 2370 bytes --]
^ permalink raw reply
* [PATCH] powerpc/82xx: updates for mgcoge
From: Holger Brunck @ 2011-09-27 7:44 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Holger Brunck
Add:
- Setup dts node for USB
- pin description and setup for SMC1 (serial interface)
Update and cleanup mgcoge_defconfig:
- enable: TIPC, UBIFS, USB_GADGET driver, SQUASHFS, HIGHRES timers
POSIX_MQUEUE, EMBEDDED
- disable: EXT3, PPC_PMAC
Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
Acked-by: Heiko Schocher <hs@denx.de>
cc: Kumar Gala <galak@kernel.crashing.org>
---
arch/powerpc/boot/dts/mgcoge.dts | 9 +++++++++
arch/powerpc/configs/mgcoge_defconfig | 27 ++++++++++++++++-----------
arch/powerpc/platforms/82xx/km82xx.c | 4 ++++
3 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/boot/dts/mgcoge.dts b/arch/powerpc/boot/dts/mgcoge.dts
index 1360d2f..ededaf5 100644
--- a/arch/powerpc/boot/dts/mgcoge.dts
+++ b/arch/powerpc/boot/dts/mgcoge.dts
@@ -213,6 +213,15 @@
linux,network-index = <2>;
fsl,cpm-command = <0x16200300>;
};
+
+ usb@11b60 {
+ compatible = "fsl,mpc8272-cpm-usb";
+ mode = "peripheral";
+ reg = <0x11b60 0x40 0x8b00 0x100>;
+ interrupts = <11 8>;
+ interrupt-parent = <&PIC>;
+ usb-clock = <5>;
+ };
};
cpm2_pio_c: gpio-controller@10d40 {
diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig
index 6cb588a..0d36b0e 100644
--- a/arch/powerpc/configs/mgcoge_defconfig
+++ b/arch/powerpc/configs/mgcoge_defconfig
@@ -1,15 +1,22 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
CONFIG_SPARSE_IRQ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
+# CONFIG_RD_GZIP is not set
CONFIG_KALLSYMS_ALL=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_EMBEDDED=y
CONFIG_SLAB=y
# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_PPC_PMAC is not set
CONFIG_PPC_82xx=y
CONFIG_MGCOGE=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_BINFMT_MISC=y
# CONFIG_SECCOMP is not set
CONFIG_NET=y
@@ -24,11 +31,10 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
+CONFIG_TIPC=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
@@ -42,7 +48,6 @@ CONFIG_MTD_PHYSMAP_OF=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
CONFIG_FIXED_PHY=y
CONFIG_NET_ETHERNET=y
@@ -50,6 +55,7 @@ CONFIG_FS_ENET=y
CONFIG_FS_ENET_MDIO_FCC=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -57,24 +63,24 @@ CONFIG_SERIAL_CPM=y
CONFIG_SERIAL_CPM_CONSOLE=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
-# CONFIG_I2C_POWERMAC is not set
CONFIG_I2C_CPM=y
# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_FSL_USB2=y
+CONFIG_USB_G_SERIAL=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=y
CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-# CONFIG_EXT3_FS_XATTR is not set
CONFIG_AUTOFS4_FS=y
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
CONFIG_CRAMFS=y
+CONFIG_SQUASHFS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_PARTITION_ADVANCED=y
-# CONFIG_MAC_PARTITION is not set
CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
@@ -82,7 +88,6 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_DEBUG_INFO=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c
index 428c5e0..3661bcd 100644
--- a/arch/powerpc/platforms/82xx/km82xx.c
+++ b/arch/powerpc/platforms/82xx/km82xx.c
@@ -49,6 +49,9 @@ struct cpm_pin {
};
static __initdata struct cpm_pin km82xx_pins[] = {
+ /* SMC1 */
+ {2, 4, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {2, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
/* SMC2 */
{0, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
@@ -137,6 +140,7 @@ static void __init init_ioports(void)
}
cpm2_smc_clk_setup(CPM_CLK_SMC2, CPM_BRG8);
+ cpm2_smc_clk_setup(CPM_CLK_SMC1, CPM_BRG7);
cpm2_clk_setup(CPM_CLK_SCC1, CPM_CLK11, CPM_CLK_RX);
cpm2_clk_setup(CPM_CLK_SCC1, CPM_CLK11, CPM_CLK_TX);
cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_RTX);
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] powerpc: Fix deadlock in icswx code
From: Anton Blanchard @ 2011-09-27 10:04 UTC (permalink / raw)
To: Jimi Xenidis; +Cc: paulus, linuxppc-dev
In-Reply-To: <743CC253-C7B7-473E-84A2-B9A2A956D4D3@pobox.com>
Hi Jimi,
> It would really help me a lot if you could review and maybe merge
> this with my earlier patch that splits this file.
> <http://patchwork.ozlabs.org/patch/109103/> All it does is split.. I
> promise. You don't have to take the other stuff.. yet :)
Sorry it took so long to get to this. Looking at it now.
Anton
^ permalink raw reply
* Re: [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing
From: Anton Blanchard @ 2011-09-27 10:05 UTC (permalink / raw)
To: Jimi Xenidis; +Cc: linuxppc-dev
In-Reply-To: <1316793594-22407-1-git-send-email-jimix@pobox.com>
Hi Jimi,
> Some processors, like embedded, that already have a PID register that
> is managed by the system. This patch separates the ACOP and PID
> processing into separate files so that the ACOP code can be shared.
>
> Signed-off-by: Jimi Xenidis <jimix@pobox.com>
Looks good.
Acked-by: Anton Blanchard <anton@samba.org>
Anton
> ---
> Re: galak@kernel.crashing.org
> Fix typo in arch/powerpc/mm/Makefile
>
> Re: anton@samba.org
> merge in: powerpc: Fix deadlock in icswx code
> ---
> arch/powerpc/mm/Makefile | 2 +
> arch/powerpc/mm/icswx.c | 162
> ++++++++++++++++++++++++++ arch/powerpc/mm/icswx.h |
> 34 ++++++ arch/powerpc/mm/icswx_pid.c | 87 ++++++++++++++
> arch/powerpc/mm/mmu_context_hash64.c | 195
> --------------------------------
> arch/powerpc/platforms/Kconfig.cputype | 10 ++- 6 files changed,
> 294 insertions(+), 196 deletions(-) create mode 100644
> arch/powerpc/mm/icswx.c create mode 100644 arch/powerpc/mm/icswx.h
> create mode 100644 arch/powerpc/mm/icswx_pid.c
>
> diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
> index bdca46e..fb7976f 100644
> --- a/arch/powerpc/mm/Makefile
> +++ b/arch/powerpc/mm/Makefile
> @@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o
> obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \
> tlb_hash$(CONFIG_WORD_SIZE).o \
> mmu_context_hash$(CONFIG_WORD_SIZE).o
> +obj-$(CONFIG_PPC_ICSWX) += icswx.o
> +obj-$(CONFIG_PPC_ICSWX_PID) += icswx_pid.o
> obj-$(CONFIG_40x) += 40x_mmu.o
> obj-$(CONFIG_44x) += 44x_mmu.o
> obj-$(CONFIG_PPC_FSL_BOOK3E) += fsl_booke_mmu.o
> diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
> new file mode 100644
> index 0000000..2f1dd29
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx.c
> @@ -0,0 +1,162 @@
> +/*
> + * ICSWX and ACOP Management
> + *
> + * Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/spinlock.h>
> +#include <linux/module.h>
> +#include "icswx.h"
> +
> +
> +/*
> + * The processor and its L2 cache cause the icswx instruction to
> + * generate a COP_REQ transaction on PowerBus. The transaction has no
> + * address, and the processor does not perform an MMU access to
> + * authenticate the transaction. The command portion of the PowerBus
> + * COP_REQ transaction includes the LPAR_ID (LPID) and the
> coprocessor
> + * Process ID (PID), which the coprocessor compares to the authorized
> + * LPID and PID held in the coprocessor, to determine if the process
> + * is authorized to generate the transaction. The data of the
> COP_REQ
> + * transaction is cache block or less, typically 64 or 128 bytes in
> + * size, and is placed in cacheable memory on a 128-byte boundary
> + * _always_.
> + *
> + * The task to use a coprocessor should use use_cop() mark the use of
> + * the coprocessor type (CT) and context swithing. On a server
> + * processor the PID register is used only for coprocessor management
> + * and so a coprocessor PID is allocated before executing icswx
> + * instruction. Drop_cop() is used to free the resources created by
> + * use_cop().
> + *
> + * Example:
> + * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> + * Each HFI have multiple windows. Each HFI window serves as a
> + * network device sending to and receiving from HFI network.
> + * HFI immediate send function uses icswx instruction. The immediate
> + * send function allows small (single cache-line) packets be sent
> + * without using the regular HFI send FIFO and doorbell, which are
> + * much slower than immediate send.
> + *
> + * For each task intending to use HFI immediate send, the HFI driver
> + * calls use_cop() to obtain a coprocessor PID for the task.
> + * The HFI driver then allocate a free HFI window and save the
> + * coprocessor PID to the HFI window to allow the task to use the
> + * HFI window.
> + *
> + * The HFI driver repeatedly creates immediate send packets and
> + * issues icswx instruction to send data through the HFI window.
> + * The HFI compares the coprocessor PID in the CPU PID register
> + * to the PID held in the HFI window to determine if the transaction
> + * is allowed.
> + *
> + * When the task to release the HFI window, the HFI driver calls
> + * drop_cop() to release the coprocessor PID.
> + */
> +
> +void switch_cop(struct mm_struct *next)
> +{
> +#ifdef CONFIG_ICSWX_PID
> + mtspr(SPRN_PID, next->context.cop_pid);
> +#endif
> + mtspr(SPRN_ACOP, next->context.acop);
> +}
> +
> +/**
> + * Start using a coprocessor.
> + * @acop: mask of coprocessor to be used.
> + * @mm: The mm the coprocessor to associate with. Most likely
> current mm.
> + *
> + * Return a positive PID if successful. Negative errno otherwise.
> + * The returned PID will be fed to the coprocessor to determine if an
> + * icswx transaction is authenticated.
> + */
> +int use_cop(unsigned long acop, struct mm_struct *mm)
> +{
> + int ret;
> +
> + if (!cpu_has_feature(CPU_FTR_ICSWX))
> + return -ENODEV;
> +
> + if (!mm || !acop)
> + return -EINVAL;
> +
> + /* The page_table_lock ensures mm_users won't change under
> us */
> + spin_lock(&mm->page_table_lock);
> + spin_lock(mm->context.cop_lockp);
> +
> + ret = get_cop_pid(mm);
> + if (ret < 0)
> + goto out;
> +
> + /* update acop */
> + mm->context.acop |= acop;
> +
> + sync_cop(mm);
> +
> + /*
> + * If this is a threaded process then there might be other
> threads
> + * running. We need to send an IPI to force them to pick up
> any
> + * change in PID and ACOP.
> + */
> + if (atomic_read(&mm->mm_users) > 1)
> + smp_call_function(sync_cop, mm, 1);
> +
> +out:
> + spin_unlock(mm->context.cop_lockp);
> + spin_unlock(&mm->page_table_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(use_cop);
> +
> +/**
> + * Stop using a coprocessor.
> + * @acop: mask of coprocessor to be stopped.
> + * @mm: The mm the coprocessor associated with.
> + */
> +void drop_cop(unsigned long acop, struct mm_struct *mm)
> +{
> + int free_pid;
> +
> + if (!cpu_has_feature(CPU_FTR_ICSWX))
> + return;
> +
> + if (WARN_ON_ONCE(!mm))
> + return;
> +
> + /* The page_table_lock ensures mm_users won't change under
> us */
> + spin_lock(&mm->page_table_lock);
> + spin_lock(mm->context.cop_lockp);
> +
> + mm->context.acop &= ~acop;
> +
> + free_pid = disable_cop_pid(mm);
> + sync_cop(mm);
> +
> + /*
> + * If this is a threaded process then there might be other
> threads
> + * running. We need to send an IPI to force them to pick up
> any
> + * change in PID and ACOP.
> + */
> + if (atomic_read(&mm->mm_users) > 1)
> + smp_call_function(sync_cop, mm, 1);
> +
> + if (free_pid != COP_PID_NONE)
> + free_cop_pid(free_pid);
> +
> + spin_unlock(mm->context.cop_lockp);
> + spin_unlock(&mm->page_table_lock);
> +}
> +EXPORT_SYMBOL_GPL(drop_cop);
> diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
> new file mode 100644
> index 0000000..5121ddd
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx.h
> @@ -0,0 +1,34 @@
> +/*
> + * ICSWX and ACOP Management
> + *
> + * Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <asm/mmu_context.h>
> +
> +/* also used to denote that PIDs are not used */
> +#define COP_PID_NONE 0
> +
> +static inline void sync_cop(void *arg)
> +{
> + struct mm_struct *mm = arg;
> +
> + if (mm == current->active_mm)
> + switch_cop(current->active_mm);
> +}
> +
> +#ifdef CONFIG_PPC_ICSWX_PID
> +extern int get_cop_pid(struct mm_struct *mm);
> +extern int disable_cop_pid(struct mm_struct *mm);
> +extern void free_cop_pid(int free_pid);
> +#else
> +#define get_cop_pid(m) (COP_PID_NONE)
> +#define disable_cop_pid(m) (COP_PID_NONE)
> +#define free_cop_pid(p)
> +#endif
> diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c
> new file mode 100644
> index 0000000..91e30eb
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx_pid.c
> @@ -0,0 +1,87 @@
> +/*
> + * ICSWX and ACOP/PID Management
> + *
> + * Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/spinlock.h>
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include "icswx.h"
> +
> +#define COP_PID_MIN (COP_PID_NONE + 1)
> +#define COP_PID_MAX (0xFFFF)
> +
> +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> +static DEFINE_IDA(cop_ida);
> +
> +static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> + spinlock_t *lock)
> +{
> + int index;
> + int err;
> +
> +again:
> + if (!ida_pre_get(ida, GFP_KERNEL))
> + return -ENOMEM;
> +
> + spin_lock(lock);
> + err = ida_get_new_above(ida, min_id, &index);
> + spin_unlock(lock);
> +
> + if (err == -EAGAIN)
> + goto again;
> + else if (err)
> + return err;
> +
> + if (index > max_id) {
> + spin_lock(lock);
> + ida_remove(ida, index);
> + spin_unlock(lock);
> + return -ENOMEM;
> + }
> +
> + return index;
> +}
> +
> +int get_cop_pid(struct mm_struct *mm)
> +{
> + int pid;
> +
> + if (mm->context.cop_pid == COP_PID_NONE) {
> + pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> + &mmu_context_acop_lock);
> + if (pid >= 0)
> + mm->context.cop_pid = pid;
> + }
> + return mm->context.cop_pid;
> +}
> +
> +int disable_cop_pid(struct mm_struct *mm)
> +{
> + int free_pid = COP_PID_NONE;
> +
> + if ((!mm->context.acop) && (mm->context.cop_pid !=
> COP_PID_NONE)) {
> + free_pid = mm->context.cop_pid;
> + mm->context.cop_pid = COP_PID_NONE;
> + }
> + return free_pid;
> +}
> +
> +void free_cop_pid(int free_pid)
> +{
> + spin_lock(&mmu_context_acop_lock);
> + ida_remove(&cop_ida, free_pid);
> + spin_unlock(&mmu_context_acop_lock);
> +}
> diff --git a/arch/powerpc/mm/mmu_context_hash64.c
> b/arch/powerpc/mm/mmu_context_hash64.c index 3bafc3d..a75832c 100644
> --- a/arch/powerpc/mm/mmu_context_hash64.c
> +++ b/arch/powerpc/mm/mmu_context_hash64.c
> @@ -24,201 +24,6 @@
>
> #include <asm/mmu_context.h>
>
> -#ifdef CONFIG_PPC_ICSWX
> -/*
> - * The processor and its L2 cache cause the icswx instruction to
> - * generate a COP_REQ transaction on PowerBus. The transaction has
> - * no address, and the processor does not perform an MMU access
> - * to authenticate the transaction. The command portion of the
> - * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
> - * the coprocessor Process ID (PID), which the coprocessor compares
> - * to the authorized LPID and PID held in the coprocessor, to
> determine
> - * if the process is authorized to generate the transaction.
> - * The data of the COP_REQ transaction is 128-byte or less and is
> - * placed in cacheable memory on a 128-byte cache line boundary.
> - *
> - * The task to use a coprocessor should use use_cop() to allocate
> - * a coprocessor PID before executing icswx instruction. use_cop()
> - * also enables the coprocessor context switching. Drop_cop() is
> - * used to free the coprocessor PID.
> - *
> - * Example:
> - * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> - * Each HFI have multiple windows. Each HFI window serves as a
> - * network device sending to and receiving from HFI network.
> - * HFI immediate send function uses icswx instruction. The immediate
> - * send function allows small (single cache-line) packets be sent
> - * without using the regular HFI send FIFO and doorbell, which are
> - * much slower than immediate send.
> - *
> - * For each task intending to use HFI immediate send, the HFI driver
> - * calls use_cop() to obtain a coprocessor PID for the task.
> - * The HFI driver then allocate a free HFI window and save the
> - * coprocessor PID to the HFI window to allow the task to use the
> - * HFI window.
> - *
> - * The HFI driver repeatedly creates immediate send packets and
> - * issues icswx instruction to send data through the HFI window.
> - * The HFI compares the coprocessor PID in the CPU PID register
> - * to the PID held in the HFI window to determine if the transaction
> - * is allowed.
> - *
> - * When the task to release the HFI window, the HFI driver calls
> - * drop_cop() to release the coprocessor PID.
> - */
> -
> -#define COP_PID_NONE 0
> -#define COP_PID_MIN (COP_PID_NONE + 1)
> -#define COP_PID_MAX (0xFFFF)
> -
> -static DEFINE_SPINLOCK(mmu_context_acop_lock);
> -static DEFINE_IDA(cop_ida);
> -
> -void switch_cop(struct mm_struct *next)
> -{
> - mtspr(SPRN_PID, next->context.cop_pid);
> - mtspr(SPRN_ACOP, next->context.acop);
> -}
> -
> -static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> - spinlock_t *lock)
> -{
> - int index;
> - int err;
> -
> -again:
> - if (!ida_pre_get(ida, GFP_KERNEL))
> - return -ENOMEM;
> -
> - spin_lock(lock);
> - err = ida_get_new_above(ida, min_id, &index);
> - spin_unlock(lock);
> -
> - if (err == -EAGAIN)
> - goto again;
> - else if (err)
> - return err;
> -
> - if (index > max_id) {
> - spin_lock(lock);
> - ida_remove(ida, index);
> - spin_unlock(lock);
> - return -ENOMEM;
> - }
> -
> - return index;
> -}
> -
> -static void sync_cop(void *arg)
> -{
> - struct mm_struct *mm = arg;
> -
> - if (mm == current->active_mm)
> - switch_cop(current->active_mm);
> -}
> -
> -/**
> - * Start using a coprocessor.
> - * @acop: mask of coprocessor to be used.
> - * @mm: The mm the coprocessor to associate with. Most likely
> current mm.
> - *
> - * Return a positive PID if successful. Negative errno otherwise.
> - * The returned PID will be fed to the coprocessor to determine if an
> - * icswx transaction is authenticated.
> - */
> -int use_cop(unsigned long acop, struct mm_struct *mm)
> -{
> - int ret;
> -
> - if (!cpu_has_feature(CPU_FTR_ICSWX))
> - return -ENODEV;
> -
> - if (!mm || !acop)
> - return -EINVAL;
> -
> - /* We need to make sure mm_users doesn't change */
> - down_read(&mm->mmap_sem);
> - spin_lock(mm->context.cop_lockp);
> -
> - if (mm->context.cop_pid == COP_PID_NONE) {
> - ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> - &mmu_context_acop_lock);
> - if (ret < 0)
> - goto out;
> -
> - mm->context.cop_pid = ret;
> - }
> - mm->context.acop |= acop;
> -
> - sync_cop(mm);
> -
> - /*
> - * If this is a threaded process then there might be other
> threads
> - * running. We need to send an IPI to force them to pick up
> any
> - * change in PID and ACOP.
> - */
> - if (atomic_read(&mm->mm_users) > 1)
> - smp_call_function(sync_cop, mm, 1);
> -
> - ret = mm->context.cop_pid;
> -
> -out:
> - spin_unlock(mm->context.cop_lockp);
> - up_read(&mm->mmap_sem);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL_GPL(use_cop);
> -
> -/**
> - * Stop using a coprocessor.
> - * @acop: mask of coprocessor to be stopped.
> - * @mm: The mm the coprocessor associated with.
> - */
> -void drop_cop(unsigned long acop, struct mm_struct *mm)
> -{
> - int free_pid = COP_PID_NONE;
> -
> - if (!cpu_has_feature(CPU_FTR_ICSWX))
> - return;
> -
> - if (WARN_ON_ONCE(!mm))
> - return;
> -
> - /* We need to make sure mm_users doesn't change */
> - down_read(&mm->mmap_sem);
> - spin_lock(mm->context.cop_lockp);
> -
> - mm->context.acop &= ~acop;
> -
> - if ((!mm->context.acop) && (mm->context.cop_pid !=
> COP_PID_NONE)) {
> - free_pid = mm->context.cop_pid;
> - mm->context.cop_pid = COP_PID_NONE;
> - }
> -
> - sync_cop(mm);
> -
> - /*
> - * If this is a threaded process then there might be other
> threads
> - * running. We need to send an IPI to force them to pick up
> any
> - * change in PID and ACOP.
> - */
> - if (atomic_read(&mm->mm_users) > 1)
> - smp_call_function(sync_cop, mm, 1);
> -
> - if (free_pid != COP_PID_NONE) {
> - spin_lock(&mmu_context_acop_lock);
> - ida_remove(&cop_ida, free_pid);
> - spin_unlock(&mmu_context_acop_lock);
> - }
> -
> - spin_unlock(mm->context.cop_lockp);
> - up_read(&mm->mmap_sem);
> -}
> -EXPORT_SYMBOL_GPL(drop_cop);
> -
> -#endif /* CONFIG_PPC_ICSWX */
> -
> static DEFINE_SPINLOCK(mmu_context_lock);
> static DEFINE_IDA(mmu_context_ida);
>
> diff --git a/arch/powerpc/platforms/Kconfig.cputype
> b/arch/powerpc/platforms/Kconfig.cputype index e06e395..3cd22e5 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -234,7 +234,7 @@ config VSX
>
> config PPC_ICSWX
> bool "Support for PowerPC icswx coprocessor instruction"
> - depends on POWER4
> + depends on POWER4 || PPC_A2
> default n
> ---help---
>
> @@ -250,6 +250,14 @@ config PPC_ICSWX
>
> If in doubt, say N here.
>
> +config PPC_ICSWX_PID
> + bool "icswx requires direct PID management"
> + depends on PPC_ICSWX && POWER4
> + default y
> + ---help---
> + PID register in server is used explicitly for ICSWX. In
> + embedded systems PID managment is done by the system.
> +
> config SPE
> bool "SPE Support"
> depends on E200 || (E500 && !PPC_E500MC)
^ permalink raw reply
* [RFC] CONFIG_RELOCATABLE : __va() & __pa() definitions
From: Suzuki Poulose @ 2011-09-27 12:24 UTC (permalink / raw)
To: linux ppc dev; +Cc: Mahesh Jagannath Salgaonkar, Paul Mackerras
Hi,
I am working on enabling CONFIG_RELOCATABLE for PPC44x Embedded PowerPC
boards as a foundation to enable CONFIG_CRASH_DUMP. After a discussion
on the linux-ppcdev we decided that we will follow the 'processing
relocation entries' approach for running the kernel from a different
address.
On PPC44x we pin the kernel text/data sections using 256M sized TLB
entries. Since the embedded boards have limited amount of RAM, we cannot
enforce the kernel load address to be aligned to 256M. This prevents us
from mapping the 'loaded physical address' of the kernel to 'KERNELBASE'
(virtual address of the kernel start). So we are forced to generate
relocation entries and process them before we start using the virtual
address(s) at the kernel boot time.
Please note that the KERNELBASE doesn't have to be 256M aligned.
I have adopted the following method for finding the relocation offset.
1) Find the physical address of _start (start of kernel text)
2) Calculate the relocation offset as :
reloc_offset = (Phy_Addr(_stext) % 256M) - (KERNELBASE % 256M)
And then map ALIGN_DOWN(KERNELBASE,256M) to ALIGN_DOWN(Phys_Addr(_stext),256M).
| Phys. Addr | Virt. Addr |
PageBoundary (256M) |-------------------------------|
| | |
| | |
| | |
(Phys. Start)%256M-> |_______________|_ _ _ _ _ _ _ _|<- Act. Kernel
| | ^ | Virtual Address
| | | |
| | | |
| | reloc_offset |
| | | |
| | | |
| |_______v_______|<-(KERNELBASE)%
| | | 256M
| | |
| | |
| | |
| | |
PageBoundary (256M) |---------------|---------------|
| | |
| | |
So the conversion of the addresses from virtual to physical and vice versa,
needs to take care of the actual kernel virtual address taking into account
of the relocation offset.
Currently __va() & __pa() has been defined as follows :
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) - PHYSICAL_START + KERNELBASE))
#define __pa(x) ((unsigned long)(x) + PHYSICAL_START - KERNELBASE)
Where:
* PHYSICAL_START (defined to variable, kernstart_addr) which holds
the physical address where the kernel is loaded. This variable is
initialized at the boot time.
* KERNELBASE is the (compiled) kernel virtual start address.
These definitions would hold only if the load address is Page aligned,
which is not feasible onf PPC44x(as mentioned in the beginning).
So we need new definitions for them in CONFIG_RELOCATABLE case.
Here are the solutions that I could think of :
1) Update kernstart_addr(PHSYICAL_START) to match the Physical address of
KERNELBASE.
i.e, kernstart_addr = Phys.Addr(_stext) + Reloc Offset
This may not sound good, however, the kernstart_addr is only used for the
__va()/__pa() calculation. So we are OK to use that.
2) Redefine __va() & __pa()
i.e,
#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_44x)
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) - PHYSICAL_START + (KERNELBASE + RELOC_OFFSET)))
#define __pa(x) ((unsigned long)(x) + PHYSICAL_START - (KERNELBASE + RELOC_OFFSET))
#endif
where, RELOC_OFFSET could be
a) Either stored in a variable, say relocation_offset (like kernstart_addr)
at boot time.
OR
b) #define RELOC_OFFSET ((PHYSICAL_START & PPC_PIN_SIZE_OFFSET_MASK) - \
(KERNELBASE & PPC_PIN_SIZE_OFFSET_MASK))
I am more tempted to adopt 2(a). Could you please let me know your
suggestions / thoughts / comments.
OR
Do should we support CONFIG_RELOCATABLE & CONFIG_KERNEL_START in the same time ?
Thanks
Suzuki
^ permalink raw reply
* [RFC] CONFIG_RELOCATABLE - __va() , __pa() definitions
From: Suzuki Poulose @ 2011-09-27 13:34 UTC (permalink / raw)
To: linux-ppc dev
Cc: Michal Simek, tmarri, David Laight, Paul Mackerras,
Mahesh Jagannath Salgaonkar, Scott Wood, John Williams
[Resending - Missed a few key people on the Cc list + Some more comments]
Hi,
I am working on enabling CONFIG_RELOCATABLE for PPC44x Embedded PowerPC
boards as a foundation to enable CONFIG_CRASH_DUMP. After a discussion
on the linux-ppcdev , we decided that we will follow the 'processing
relocation entries' approach for running the kernel from a different
address.
http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-June/090986.html
On PPC44x we pin the kernel text/data sections using 256M sized TLB
entries. Since the embedded boards have limited amount of RAM, we cannot
enforce the kernel load address to be aligned to 256M. This prevents us
from mapping the 'loaded physical address' of the kernel to 'KERNELBASE'
(virtual address of the kernel start). So we are forced to generate
relocation entries and process them before we start using the virtual
address(s) at the kernel boot time.
Please note that the KERNELBASE doesn't have to be 256M aligned.
I have adopted the following method for finding the relocation offset.
1) Find the physical address of _start (start of kernel text)
2) Calculate the relocation offset as :
reloc_offset = (Phy_Addr(_stext) % 256M) - (KERNELBASE % 256M)
And then map ALIGN_DOWN(KERNELBASE,256M) to
ALIGN_DOWN(Phys_Addr(_stext),256M).
| Phys. Addr | Virt. Addr |
PageBoundary(256M) |-------------------------------|
| | |
| | |
| | |
(Phys. Start)%256M-> |_______________|_ _ _ _ _ _ _ _|<- Act.Kernel
| | ^ | Virtual Address
| | | |
| | | |
| | reloc_offset |
| | | |
| | | |
| |_______v_______|<-(KERNELBASE)%
| | | 256M
| | |
| | |
| | |
| | |
PageBoundary(256M) |---------------|---------------|
| | |
| | |
So the conversion of the addresses from virtual to physical and vice
versa, needs to take care of the actual kernel virtual address taking
into account of the relocation offset.
Currently __va() & __pa() has been defined as follows :
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) -
PHYSICAL_START + KERNELBASE)) #define __pa(x) ((unsigned long)(x) +
PHYSICAL_START - KERNELBASE)
Where:
* PHYSICAL_START (defined to variable, kernstart_addr) which holds
the physical address where the kernel is loaded. This variable is
initialized at the boot time.
* KERNELBASE is the (compiled) kernel virtual start address.
These definitions would hold only if the load address is Page aligned,
which is not feasible onf PPC44x(as mentioned in the beginning).
So we need new definitions for them in CONFIG_RELOCATABLE case.
Here are the solutions that I could think of :
1) Update kernstart_addr(PHSYICAL_START) to match the Physical address
of KERNELBASE.
i.e, kernstart_addr = Phys.Addr(_stext) + Reloc Offset
This may not sound good, however, the kernstart_addr is only used for
the __va()/__pa() calculation. So we are OK to use that.
2) Redefine __va() & __pa()
i.e,
#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_44x)
#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) -
PHYSICAL_START + (KERNELBASE + RELOC_OFFSET))) #define __pa(x)
((unsigned long)(x) + PHYSICAL_START - (KERNELBASE + RELOC_OFFSET))
#endif
where, RELOC_OFFSET could be
a) Either stored in a variable, say relocation_offset (like
kernstart_addr) at boot time.
OR
b) #define RELOC_OFFSET ((PHYSICAL_START & PPC_PIN_SIZE_OFFSET_MASK)
- \ (KERNELBASE & PPC_PIN_SIZE_OFFSET_MASK))
3) Enforce CONFIG_KERNEL_START (i.e, KERNELBASE) to be PPC_PIN_SIZE(256M
on PPC44x) aligned.
I am more tempted to adopt 2(a). Could you please let me know your
suggestions / thoughts / comments.
Thanks
Suzuki
^ permalink raw reply
* Handling multiple GPIO controllers in 8xxx GPIO driver
From: Felix Radensky @ 2011-09-27 13:59 UTC (permalink / raw)
To: linuxppc-dev@ozlabs.org, jacmet@sunsite.dk, grant.likely
Hi,
Looks like 8xxx GPIO driver cannot properly handle interrupts
when multiple GPIO controllers exist in the system.
On Freescale P1022 there are 3 GPIO controllers. All 3 use
the same interrupt line, internal interrupt 31. If all controllers
are defined in device tree set_irq_chained_handler() is invoked
3 times with same hardware irq number. The result is interrupt
storm, mpc8xxx_gpio_irq_cascade() is invoked indefinitely.
What would be the best way to fix the problem ?
Thanks.
Felix Radensky.
^ permalink raw reply
* Re: Handling multiple GPIO controllers in 8xxx GPIO driver
From: Grant Likely @ 2011-09-27 18:29 UTC (permalink / raw)
To: Felix Radensky; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <4E81D6C0.3010201@embedded-sol.com>
On Tue, Sep 27, 2011 at 04:59:28PM +0300, Felix Radensky wrote:
> Hi,
>
> Looks like 8xxx GPIO driver cannot properly handle interrupts
> when multiple GPIO controllers exist in the system.
>
> On Freescale P1022 there are 3 GPIO controllers. All 3 use
> the same interrupt line, internal interrupt 31. If all controllers
> are defined in device tree set_irq_chained_handler() is invoked
> 3 times with same hardware irq number. The result is interrupt
> storm, mpc8xxx_gpio_irq_cascade() is invoked indefinitely.
>
> What would be the best way to fix the problem ?
The solution is to make the gpio driver register as a regular
interrupt handler, and not as a chained handler.
g.
^ permalink raw reply
* Re: Handling multiple GPIO controllers in 8xxx GPIO driver
From: Felix Radensky @ 2011-09-27 22:07 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <20110927182912.GA3994@ponder.secretlab.ca>
Hi Grant,
On 09/27/2011 09:29 PM, Grant Likely wrote:
> On Tue, Sep 27, 2011 at 04:59:28PM +0300, Felix Radensky wrote:
>> Hi,
>>
>> Looks like 8xxx GPIO driver cannot properly handle interrupts
>> when multiple GPIO controllers exist in the system.
>>
>> On Freescale P1022 there are 3 GPIO controllers. All 3 use
>> the same interrupt line, internal interrupt 31. If all controllers
>> are defined in device tree set_irq_chained_handler() is invoked
>> 3 times with same hardware irq number. The result is interrupt
>> storm, mpc8xxx_gpio_irq_cascade() is invoked indefinitely.
>>
>> What would be the best way to fix the problem ?
> The solution is to make the gpio driver register as a regular
> interrupt handler, and not as a chained handler.
>
> g.
>
You mean interrupt handler per GPIO pin ?
Felix.
^ permalink raw reply
* linux-next: build failure after merge of the akpm tree
From: Stephen Rothwell @ 2011-09-28 9:22 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-kernel, linux-next, Paul Mackerras, Joe Perches,
linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 1729 bytes --]
Hi Andrew,
After merging the akpm tree, today's linux-next build (powerpc
ppc64_defconfig) failed like this:
In file included from arch/powerpc/boot/stdio.c:12:0:
arch/powerpc/boot/stdio.h:10:17: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:10:20: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:10:8: warning: return type defaults to 'int'
arch/powerpc/boot/stdio.h:10:8: warning: function declaration isn't a prototype
arch/powerpc/boot/stdio.h: In function '__printf':
arch/powerpc/boot/stdio.h:14:17: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:14:20: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:14:23: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'int'
arch/powerpc/boot/stdio.h:16:12: error: storage class specified for parameter 'vsprintf'
And went down hill from there (it produced hundreds of errors).
Caused by commit a52af697aaeb ("treewide: use __printf not __attribute__
((format(printf,...)))"). Maybe because some of these files are part of
the boot wrappers and are built (effectively) independently of the kernel
itself. Notice that arch/powerpc/boot/stdio.h does not include any
kernel headers ...
I have reverted that commit (and the follup ones b31d03e43e56
"treewide-use-__printf-not-__attribute__formatprintf-checkpatch-fixes"
and f43c361e2bd9 "kernel.h/checkpatch: mark strict_strto<foo> and
simple_strto<foo> as obsolete") for today.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: Handling multiple GPIO controllers in 8xxx GPIO driver
From: Tabi Timur-B04825 @ 2011-09-28 20:52 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev@ozlabs.org, Felix Radensky
In-Reply-To: <20110927182912.GA3994@ponder.secretlab.ca>
On Tue, Sep 27, 2011 at 1:29 PM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> The solution is to make the gpio driver register as a regular
> interrupt handler, and not as a chained handler.
I was wondering about that.
What exactly is a chained handler? How is it different from a regular hand=
ler?
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* [PATCH REPOST] perf event, POWER 6: L1 cache read and write access event code fix]
From: Carl E. Love @ 2011-09-28 21:23 UTC (permalink / raw)
To: pmac, bherren, linuxppc-dev
Ben, Paul:
I posted this patch to lkml but did not copy the linuxppc-dev@ozlabs.org
mailing list.
Carl Love
---------------------------------------------------------------------
The current L1 cache read event code 0x80082 only counts for thread 0. The
event code 0x280030 should be used to count events on thread 0 and 1. The
patch fixes the event code for the L1 cache read.
The current L1 cache write event code 0x80086 only counts for thread 0. The
event code 0x180032 should be used to count events on thread 0 and 1. The
patch fixes the event code for the L1 cache write.
FYI, the documentation lists three event codes for the L1 cache read event
and three event codes for the L1 cache write event. The event description
for the event codes is as follows:
L1 cache read requests 0x80082 LSU 0 only
L1 cache read requests 0x8008A LSU 1 only
L1 cache read requests 0x80030 LSU 1 or LSU 0, counter 2 only.
L1 cache store requests 0x80086 LSU 0 only
L1 cache store requests 0x8008E LSU 1 only
L1 cache store requests 0x80032 LSU 0 or LSU 1, counter 1 only.
There can only be one request from either LSU 0 or 1 active at a time.
Signed-off-by: Carl Love <cel@us.ibm.com>
---
arch/powerpc/kernel/power6-pmu.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c
index 03b95e2..0bbc901 100644
--- a/arch/powerpc/kernel/power6-pmu.c
+++ b/arch/powerpc/kernel/power6-pmu.c
@@ -487,8 +487,8 @@ static int power6_generic_events[] = {
*/
static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
[C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
- [C(OP_READ)] = { 0x80082, 0x80080 },
- [C(OP_WRITE)] = { 0x80086, 0x80088 },
+ [C(OP_READ)] = { 0x280030, 0x80080 },
+ [C(OP_WRITE)] = { 0x180032, 0x80088 },
[C(OP_PREFETCH)] = { 0x810a4, 0 },
},
[C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
^ permalink raw reply related
* Re: linux-next: build failure after merge of the akpm tree
From: Andrew Morton @ 2011-09-28 22:03 UTC (permalink / raw)
To: Stephen Rothwell
Cc: linux-kernel, linux-next, Paul Mackerras, Joe Perches,
Andrew Morton, linuxppc-dev
In-Reply-To: <20110928192220.6d85ae23a2f2ef316139a310@canb.auug.org.au>
On Wed, 28 Sep 2011 19:22:20 +1000
Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> After merging the akpm tree, today's linux-next build (powerpc
> ppc64_defconfig) failed like this:
>
> In file included from arch/powerpc/boot/stdio.c:12:0:
> arch/powerpc/boot/stdio.h:10:17: error: expected declaration specifiers or '...' before numeric constant
> arch/powerpc/boot/stdio.h:10:20: error: expected declaration specifiers or '...' before numeric constant
> arch/powerpc/boot/stdio.h:10:8: warning: return type defaults to 'int'
> arch/powerpc/boot/stdio.h:10:8: warning: function declaration isn't a prototype
> arch/powerpc/boot/stdio.h: In function '__printf':
> arch/powerpc/boot/stdio.h:14:17: error: expected declaration specifiers or '...' before numeric constant
> arch/powerpc/boot/stdio.h:14:20: error: expected declaration specifiers or '...' before numeric constant
> arch/powerpc/boot/stdio.h:14:23: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'int'
> arch/powerpc/boot/stdio.h:16:12: error: storage class specified for parameter 'vsprintf'
>
> And went down hill from there (it produced hundreds of errors).
I could only find two non-kernel files which were modified by that
patch so afaict we just need to revert those two bits. I'll test the
below..
From: Andrew Morton <akpm@google.com>
Subject: treewide-use-__printf-not-__attribute__formatprintf-fix
After merging the akpm tree, today's linux-next build (powerpc
ppc64_defconfig) failed like this:
In file included from arch/powerpc/boot/stdio.c:12:0:
arch/powerpc/boot/stdio.h:10:17: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:10:20: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:10:8: warning: return type defaults to 'int'
arch/powerpc/boot/stdio.h:10:8: warning: function declaration isn't a prototype
arch/powerpc/boot/stdio.h: In function '__printf':
arch/powerpc/boot/stdio.h:14:17: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:14:20: error: expected declaration specifiers or '...' before numeric constant
arch/powerpc/boot/stdio.h:14:23: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'int'
arch/powerpc/boot/stdio.h:16:12: error: storage class specified for parameter 'vsprintf'
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Joe Perches <joe@perches.com>
Signed-off-by: Andrew Morton <akpm@google.com>
---
arch/powerpc/boot/ps3.c | 3 ++-
arch/powerpc/boot/stdio.h | 5 +++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff -puN arch/alpha/boot/misc.c~treewide-use-__printf-not-__attribute__formatprintf-fix arch/alpha/boot/misc.c
diff -puN arch/alpha/include/asm/console.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/alpha/include/asm/console.h
diff -puN arch/frv/include/asm/system.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/frv/include/asm/system.h
diff -puN arch/ia64/include/asm/mca.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/ia64/include/asm/mca.h
diff -puN arch/m68k/include/asm/natfeat.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/m68k/include/asm/natfeat.h
diff -puN arch/mn10300/include/asm/gdb-stub.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/mn10300/include/asm/gdb-stub.h
diff -puN arch/powerpc/boot/ps3.c~treewide-use-__printf-not-__attribute__formatprintf-fix arch/powerpc/boot/ps3.c
--- a/arch/powerpc/boot/ps3.c~treewide-use-__printf-not-__attribute__formatprintf-fix
+++ a/arch/powerpc/boot/ps3.c
@@ -36,7 +36,8 @@ extern int lv1_get_repository_node_value
#ifdef DEBUG
#define DBG(fmt...) printf(fmt)
#else
-static inline __printf(1, 2) int DBG(const char *fmt, ...) {return 0;}
+static inline int __attribute__ ((format (printf, 1, 2))) DBG(
+ const char *fmt, ...) {return 0;}
#endif
BSS_STACK(4096);
diff -puN arch/powerpc/boot/stdio.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/powerpc/boot/stdio.h
--- a/arch/powerpc/boot/stdio.h~treewide-use-__printf-not-__attribute__formatprintf-fix
+++ a/arch/powerpc/boot/stdio.h
@@ -7,11 +7,12 @@
#define EINVAL 22 /* Invalid argument */
#define ENOSPC 28 /* No space left on device */
-extern __printf(1, 2) int printf(const char *fmt, ...);
+extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
#define fprintf(fmt, args...) printf(args)
-extern __printf(2, 3) int sprintf(char *buf, const char *fmt, ...);
+extern int sprintf(char *buf, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
extern int vsprintf(char *buf, const char *fmt, va_list args);
diff -puN arch/powerpc/include/asm/udbg.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/powerpc/include/asm/udbg.h
diff -puN arch/s390/include/asm/debug.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/s390/include/asm/debug.h
diff -puN arch/um/include/shared/user.h~treewide-use-__printf-not-__attribute__formatprintf-fix arch/um/include/shared/user.h
diff -puN drivers/isdn/hisax/callc.c~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/isdn/hisax/callc.c
diff -puN drivers/isdn/hisax/hisax.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/isdn/hisax/hisax.h
diff -puN drivers/isdn/hisax/isdnl1.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/isdn/hisax/isdnl1.h
diff -puN drivers/isdn/hisax/isdnl3.c~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/isdn/hisax/isdnl3.c
diff -puN drivers/isdn/hisax/st5481_d.c~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/isdn/hisax/st5481_d.c
diff -puN drivers/net/ethernet/mellanox/mlx4/mlx4_en.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
diff -puN drivers/net/wireless/ath/ath.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/net/wireless/ath/ath.h
diff -puN drivers/net/wireless/ath/ath5k/debug.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/net/wireless/ath/ath5k/debug.h
diff -puN drivers/net/wireless/ath/ath6kl/debug.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/net/wireless/ath/ath6kl/debug.h
diff -puN drivers/net/wireless/b43/b43.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/net/wireless/b43/b43.h
diff -puN drivers/net/wireless/b43legacy/b43legacy.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/net/wireless/b43legacy/b43legacy.h
diff -puN drivers/staging/iio/trigger.h~treewide-use-__printf-not-__attribute__formatprintf-fix drivers/staging/iio/trigger.h
diff -puN fs/ecryptfs/ecryptfs_kernel.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/ecryptfs/ecryptfs_kernel.h
diff -puN fs/ext2/ext2.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/ext2/ext2.h
diff -puN fs/ext4/ext4.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/ext4/ext4.h
diff -puN fs/fat/fat.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/fat/fat.h
diff -puN fs/gfs2/glock.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/gfs2/glock.h
diff -puN fs/hpfs/hpfs_fn.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/hpfs/hpfs_fn.h
diff -puN fs/nilfs2/nilfs.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/nilfs2/nilfs.h
diff -puN fs/ntfs/debug.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/ntfs/debug.h
diff -puN fs/ocfs2/super.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/ocfs2/super.h
diff -puN fs/partitions/ldm.c~treewide-use-__printf-not-__attribute__formatprintf-fix fs/partitions/ldm.c
diff -puN fs/udf/udfdecl.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/udf/udfdecl.h
diff -puN fs/ufs/ufs.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/ufs/ufs.h
diff -puN fs/xfs/xfs_message.h~treewide-use-__printf-not-__attribute__formatprintf-fix fs/xfs/xfs_message.h
diff -puN include/asm-generic/bug.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/asm-generic/bug.h
diff -puN include/drm/drmP.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/drm/drmP.h
diff -puN include/linux/audit.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/audit.h
diff -puN include/linux/blktrace_api.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/blktrace_api.h
diff -puN include/linux/device.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/device.h
diff -puN include/linux/dynamic_debug.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/dynamic_debug.h
diff -puN include/linux/ext3_fs.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/ext3_fs.h
diff -puN include/linux/fs.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/fs.h
diff -puN include/linux/fscache-cache.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/fscache-cache.h
diff -puN include/linux/gameport.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/gameport.h
diff -puN include/linux/kallsyms.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/kallsyms.h
diff -puN include/linux/kdb.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/kdb.h
diff -puN include/linux/kernel.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/kernel.h
diff -puN include/linux/kexec.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/kexec.h
diff -puN include/linux/kmod.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/kmod.h
diff -puN include/linux/kobject.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/kobject.h
diff -puN include/linux/kthread.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/kthread.h
diff -puN include/linux/libata.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/libata.h
diff -puN include/linux/mmiotrace.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/mmiotrace.h
diff -puN include/linux/netdevice.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/netdevice.h
diff -puN include/linux/printk.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/printk.h
diff -puN include/linux/quotaops.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/quotaops.h
diff -puN include/linux/seq_file.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/seq_file.h
diff -puN include/linux/trace_seq.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/linux/trace_seq.h
diff -puN include/net/bluetooth/bluetooth.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/net/bluetooth/bluetooth.h
diff -puN include/net/netfilter/nf_log.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/net/netfilter/nf_log.h
diff -puN include/net/sock.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/net/sock.h
diff -puN include/sound/core.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/sound/core.h
diff -puN include/sound/info.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/sound/info.h
diff -puN include/sound/seq_kernel.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/sound/seq_kernel.h
diff -puN include/xen/hvc-console.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/xen/hvc-console.h
diff -puN include/xen/xenbus.h~treewide-use-__printf-not-__attribute__formatprintf-fix include/xen/xenbus.h
diff -puN net/nfc/nfc.h~treewide-use-__printf-not-__attribute__formatprintf-fix net/nfc/nfc.h
diff -puN net/rds/rds.h~treewide-use-__printf-not-__attribute__formatprintf-fix net/rds/rds.h
diff -puN net/sunrpc/svc.c~treewide-use-__printf-not-__attribute__formatprintf-fix net/sunrpc/svc.c
diff -puN sound/firewire/cmp.c~treewide-use-__printf-not-__attribute__formatprintf-fix sound/firewire/cmp.c
_
^ permalink raw reply
* Re: [RFC] CONFIG_RELOCATABLE : __va() & __pa() definitions
From: Benjamin Herrenschmidt @ 2011-09-28 23:03 UTC (permalink / raw)
To: Suzuki Poulose; +Cc: Mahesh Jagannath Salgaonkar, Paul Mackerras, linux ppc dev
In-Reply-To: <20110927175433.0c300384@suzukikp.in.ibm.com>
On Tue, 2011-09-27 at 17:54 +0530, Suzuki Poulose wrote:
> Hi,
>
> I am working on enabling CONFIG_RELOCATABLE for PPC44x Embedded PowerPC
> boards as a foundation to enable CONFIG_CRASH_DUMP. After a discussion
> on the linux-ppcdev we decided that we will follow the 'processing
> relocation entries' approach for running the kernel from a different
> address.
I think the best approach is to not touch KERNELBASE and PAGE_OFFSET,
and just process relocations, that way __va() and __pa() are unoutched
and plenty of other stuff won't break.
Ben.
>
> On PPC44x we pin the kernel text/data sections using 256M sized TLB
> entries. Since the embedded boards have limited amount of RAM, we cannot
> enforce the kernel load address to be aligned to 256M. This prevents us
> from mapping the 'loaded physical address' of the kernel to 'KERNELBASE'
> (virtual address of the kernel start). So we are forced to generate
> relocation entries and process them before we start using the virtual
> address(s) at the kernel boot time.
>
> Please note that the KERNELBASE doesn't have to be 256M aligned.
>
>
> I have adopted the following method for finding the relocation offset.
>
> 1) Find the physical address of _start (start of kernel text)
> 2) Calculate the relocation offset as :
>
> reloc_offset = (Phy_Addr(_stext) % 256M) - (KERNELBASE % 256M)
>
> And then map ALIGN_DOWN(KERNELBASE,256M) to ALIGN_DOWN(Phys_Addr(_stext),256M).
>
>
>
>
>
> | Phys. Addr | Virt. Addr |
> PageBoundary (256M) |-------------------------------|
> | | |
> | | |
> | | |
> (Phys. Start)%256M-> |_______________|_ _ _ _ _ _ _ _|<- Act. Kernel
> | | ^ | Virtual Address
> | | | |
> | | | |
> | | reloc_offset |
> | | | |
> | | | |
> | |_______v_______|<-(KERNELBASE)%
> | | | 256M
> | | |
> | | |
> | | |
> | | |
> PageBoundary (256M) |---------------|---------------|
> | | |
> | | |
>
>
> So the conversion of the addresses from virtual to physical and vice versa,
> needs to take care of the actual kernel virtual address taking into account
> of the relocation offset.
>
> Currently __va() & __pa() has been defined as follows :
>
> #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) - PHYSICAL_START + KERNELBASE))
> #define __pa(x) ((unsigned long)(x) + PHYSICAL_START - KERNELBASE)
>
> Where:
>
> * PHYSICAL_START (defined to variable, kernstart_addr) which holds
> the physical address where the kernel is loaded. This variable is
> initialized at the boot time.
>
> * KERNELBASE is the (compiled) kernel virtual start address.
>
> These definitions would hold only if the load address is Page aligned,
> which is not feasible onf PPC44x(as mentioned in the beginning).
>
> So we need new definitions for them in CONFIG_RELOCATABLE case.
>
> Here are the solutions that I could think of :
>
> 1) Update kernstart_addr(PHSYICAL_START) to match the Physical address of
> KERNELBASE.
>
> i.e, kernstart_addr = Phys.Addr(_stext) + Reloc Offset
>
> This may not sound good, however, the kernstart_addr is only used for the
> __va()/__pa() calculation. So we are OK to use that.
>
> 2) Redefine __va() & __pa()
> i.e,
>
> #if defined(CONFIG_RELOCATABLE) && defined(CONFIG_44x)
> #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) - PHYSICAL_START + (KERNELBASE + RELOC_OFFSET)))
> #define __pa(x) ((unsigned long)(x) + PHYSICAL_START - (KERNELBASE + RELOC_OFFSET))
> #endif
>
> where, RELOC_OFFSET could be
>
> a) Either stored in a variable, say relocation_offset (like kernstart_addr)
> at boot time.
>
> OR
>
> b) #define RELOC_OFFSET ((PHYSICAL_START & PPC_PIN_SIZE_OFFSET_MASK) - \
> (KERNELBASE & PPC_PIN_SIZE_OFFSET_MASK))
>
>
> I am more tempted to adopt 2(a). Could you please let me know your
> suggestions / thoughts / comments.
>
> OR
>
> Do should we support CONFIG_RELOCATABLE & CONFIG_KERNEL_START in the same time ?
>
>
> Thanks
> Suzuki
>
>
>
>
>
>
>
>
>
>
^ permalink raw reply
* [PATCH 3/4] p4080ds-dts: Add two rapidio ports and message units support
From: Liu Gang @ 2011-09-29 2:29 UTC (permalink / raw)
To: linuxppc-dev
Cc: Jin Qing, r58472, r61911, linux-kernel, Liu Gang, akpm, B11780
In-Reply-To: <1317263341-19010-1-git-send-email-Gang.Liu@freescale.com>
Add two message units and number of ports according to the p4080 reference manual.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Liu Gang <Gang.Liu@freescale.com>
---
arch/powerpc/boot/dts/p4080ds.dts | 4 +-
arch/powerpc/boot/dts/p4080si.dtsi | 37 +++++++++++++++++++++++++++--------
2 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
index eb11098..94a0cd4 100644
--- a/arch/powerpc/boot/dts/p4080ds.dts
+++ b/arch/powerpc/boot/dts/p4080ds.dts
@@ -101,9 +101,9 @@
};
};
- rapidio0: rapidio@ffe0c0000 {
+ rapidio: rapidio@ffe0c0000 {
reg = <0xf 0xfe0c0000 0 0x20000>;
- ranges = <0 0 0xc 0x20000000 0 0x01000000>;
+ ranges = <0 0 0xc 0x20000000 0 0x20000000>;
};
localbus@ffe124000 {
diff --git a/arch/powerpc/boot/dts/p4080si.dtsi b/arch/powerpc/boot/dts/p4080si.dtsi
index b71051f..816a629 100644
--- a/arch/powerpc/boot/dts/p4080si.dtsi
+++ b/arch/powerpc/boot/dts/p4080si.dtsi
@@ -69,8 +69,9 @@
rtic_c = &rtic_c;
rtic_d = &rtic_d;
sec_mon = &sec_mon;
+ rmu = &rmu;
- rio0 = &rapidio0;
+ rio = &rapidio;
};
cpus {
@@ -555,20 +556,38 @@
interrupt-parent = <&mpic>;
interrupts = <93 2 0 0>;
};
+
+ rmu: rmu@d3000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,rmu";
+ reg = <0xd3000 0x200>;
+
+ message-unit@0 {
+ reg = <0x0 0x100>;
+ interrupts = <
+ 60 2 0 0 /* msg1_tx_irq */
+ 61 2 0 0>;/* msg1_rx_irq */
+ };
+ message-unit@1 {
+ reg = <0x100 0x100>;
+ interrupts = <
+ 62 2 0 0 /* msg2_tx_irq */
+ 63 2 0 0>;/* msg2_rx_irq */
+ };
+ };
};
- rapidio0: rapidio@ffe0c0000 {
+ rapidio: rapidio@ffe0c0000 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "fsl,rapidio-delta";
interrupts = <
- 16 2 1 11 /* err_irq */
- 56 2 0 0 /* bell_outb_irq */
- 57 2 0 0 /* bell_inb_irq */
- 60 2 0 0 /* msg1_tx_irq */
- 61 2 0 0 /* msg1_rx_irq */
- 62 2 0 0 /* msg2_tx_irq */
- 63 2 0 0>; /* msg2_rx_irq */
+ 16 2 1 11 /* err_irq */
+ 56 2 0 0 /* bell_outb_irq */
+ 57 2 0 0>;/* bell_inb_irq */
+ fsl,rio-num-ports = <2>;
+ rmu-handle = <&rmu>;
};
localbus@ffe124000 {
--
1.7.3.1
^ permalink raw reply related
* [PATCH 2/4] fsl-rio: Add two ports and rapidio message units support
From: Liu Gang @ 2011-09-29 2:28 UTC (permalink / raw)
To: linuxppc-dev
Cc: Jin Qing, r58472, r61911, linux-kernel, Liu Gang, akpm, B11780
In-Reply-To: <1317263341-19010-1-git-send-email-Gang.Liu@freescale.com>
Usually, freescale rapidio endpoint can support one 1X or two 4X LP-Serial link interfaces,
and rapidio message transactions can be implemented by two message units. This patch adds the
support of two rapidio ports and initializes message unit 0 and message unit 1. And these ports
and message units can work simultaneously.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Liu Gang <Gang.Liu@freescale.com>
---
arch/powerpc/sysdev/fsl_rio.c | 336 +++++++++++++++++++++----------
arch/powerpc/sysdev/fsl_rio.h | 73 +++++++-
arch/powerpc/sysdev/fsl_rmu.c | 434 ++++++++++++++++++++---------------------
3 files changed, 502 insertions(+), 341 deletions(-)
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 9484484..c7f8080 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -45,7 +45,6 @@
#define RIO_PORT1_IECSR 0x10130
#define RIO_PORT2_IECSR 0x101B0
-#define RIO_ATMU_REGS_OFFSET 0x10c00
#define RIO_GCCSR 0x13c
#define RIO_ESCSR 0x158
#define ESCSR_CLEAR 0x07120204
@@ -74,6 +73,11 @@
: "b" (addr), "i" (-EFAULT), "0" (err))
void __iomem *rio_regs_win;
+void __iomem *rmu_regs_win;
+resource_size_t rio_law_start;
+
+struct fsl_rio_dbell *dbell;
+struct fsl_rio_pw *pw;
#ifdef CONFIG_E500
int fsl_rio_mcheck_exception(struct pt_regs *regs)
@@ -120,7 +124,7 @@ static int fsl_local_config_read(struct rio_mport *mport,
{
struct rio_priv *priv = mport->priv;
pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index,
- offset);
+ offset);
*data = in_be32(priv->regs_win + offset);
return 0;
@@ -173,7 +177,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
pr_debug
("fsl_rio_config_read:"
" index %d destid %d hopcount %d offset %8.8x len %d\n",
- index, destid, hopcount, offset, len);
+ index, destid, hopcount, offset, len);
/* 16MB maintenance window possible */
/* allow only aligned access to maintenance registers */
@@ -230,8 +234,8 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
u8 *data;
pr_debug
("fsl_rio_config_write:"
- "index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
- index, destid, hopcount, offset, len, val);
+ " index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
+ index, destid, hopcount, offset, len, val);
/* 16MB maintenance windows possible */
/* allow only aligned access to maintenance registers */
@@ -260,7 +264,7 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
return 0;
}
-void fsl_rio_port_error_handler(struct rio_mport *port, int offset)
+void fsl_rio_port_error_handler(int offset)
{
/*XXX: Error recovery is not implemented, we just clear errors */
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
@@ -331,12 +335,17 @@ int fsl_rio_setup(struct platform_device *dev)
struct rio_mport *port;
struct rio_priv *priv;
int rc = 0;
- const u32 *dt_range, *cell;
- struct resource regs;
- int rlen;
+ const u32 *dt_range, *cell, *ports_num;
+ u32 active_ports = 0;
+ struct resource regs, rmu_regs;
+ struct device_node *np, *rmu_node;
+ int rlen, len;
u32 ccsr;
u64 law_start, law_size;
int paw, aw, sw;
+ int i;
+ static int tmp;
+ struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL};
if (!dev->dev.of_node) {
dev_err(&dev->dev, "Device OF-Node is NULL");
@@ -360,6 +369,14 @@ int fsl_rio_setup(struct platform_device *dev)
return -EFAULT;
}
+ ports_num = of_get_property(dev->dev.of_node,
+ "fsl,rio-num-ports", &len);
+ if (!ports_num || len < sizeof(*ports_num)) {
+ dev_err(&dev->dev, "Can't get %s property 'rio-num-ports'\n",
+ dev->dev.of_node->full_name);
+ return -EFAULT;
+ }
+
/* Get node address wide */
cell = of_get_property(dev->dev.of_node, "#address-cells", NULL);
if (cell)
@@ -378,8 +395,17 @@ int fsl_rio_setup(struct platform_device *dev)
law_start = of_read_number(dt_range + aw, paw);
law_size = of_read_number(dt_range + aw + paw, sw);
+ rio_law_start = law_start;
+
dev_info(&dev->dev, "LAW start 0x%016llx, size 0x%016llx.\n",
law_start, law_size);
+ rio_regs_win = ioremap(regs.start, resource_size(®s));
+
+ if (!rio_regs_win) {
+ printk(KERN_ERR "Unable to map rio register window\n");
+ rc = -ENOMEM;
+ goto err_rio_regs;
+ }
ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL);
if (!ops) {
@@ -390,130 +416,224 @@ int fsl_rio_setup(struct platform_device *dev)
ops->lcwrite = fsl_local_config_write;
ops->cread = fsl_rio_config_read;
ops->cwrite = fsl_rio_config_write;
+ ops->dsend = fsl_rio_doorbell_send;
ops->pwenable = fsl_rio_pw_enable;
-
- port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
- if (!port) {
+ ops->open_outb_mbox = fsl_open_outb_mbox;
+ ops->open_inb_mbox = fsl_open_inb_mbox;
+ ops->close_outb_mbox = fsl_close_outb_mbox;
+ ops->close_inb_mbox = fsl_close_inb_mbox;
+ ops->add_outb_message = fsl_add_outb_message;
+ ops->add_inb_buffer = fsl_add_inb_buffer;
+ ops->get_inb_message = fsl_get_inb_message;
+
+ dbell = kzalloc(sizeof(struct fsl_rio_dbell), GFP_KERNEL);
+ if (!(dbell)) {
+ printk(KERN_ERR "Can't alloc memory for 'fsl_rio_dbell'\n");
rc = -ENOMEM;
- goto err_port;
+ goto err_dbell;
}
- port->index = 0;
-
- priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL);
- if (!priv) {
- printk(KERN_ERR "Can't alloc memory for 'priv'\n");
+ dbell->dev = &dev->dev;
+
+ dbell->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2);
+ dev_info(&dev->dev, "bellirq: %d\n", dbell->bellirq);
+ dbell->dbell_regs = (struct rio_dbell_regs *)(rio_regs_win +
+ RIO_S_DBELL_REGS_OFFSET);
+ dbell->dbell_atmu_regs = (struct rio_atmu_regs *)(rio_regs_win +
+ RIO_ATMU_REGS_DBELL_OFFSET);
+ /* Configure outbound doorbell window */
+ out_be32(&dbell->dbell_atmu_regs->rowbar,
+ (law_start + RIO_MAINT_WIN_SIZE) >> 12);
+ /* 4k window size */
+ out_be32(&dbell->dbell_atmu_regs->rowar, DOORBELL_ROWAR_EN |
+ DOORBELL_ROWAR_NREAD | DOORBELL_ROWAR_RES |
+ DOORBELL_ROWAR_SIZE);
+ fsl_rio_doorbell_init(dbell);
+
+ pw = kzalloc(sizeof(struct fsl_rio_pw), GFP_KERNEL);
+ if (!(pw)) {
+ printk(KERN_ERR "Can't alloc memory for 'fsl_rio_pw'\n");
+ rc = -ENOMEM;
+ goto err_pw;
+ }
+ pw->dev = &dev->dev;
+ pw->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0);
+ dev_info(&dev->dev, "pwirq: %d\n", pw->pwirq);
+ pw->pw_regs = (struct rio_pw_regs *)(rio_regs_win +
+ RIO_S_PW_REGS_OFFSET);
+ fsl_rio_port_write_init(pw);
+
+ rmu_node = of_parse_phandle(dev->dev.of_node, "rmu-handle", 0);
+ if (!rmu_node)
+ goto err_rmu;
+
+ rc = of_address_to_resource(rmu_node, 0, &rmu_regs);
+ if (rc) {
+ dev_err(&dev->dev, "Can't get %s property 'reg'\n",
+ rmu_node->full_name);
+ goto err_rmu;
+ }
+ rmu_regs_win = ioremap(rmu_regs.start, resource_size(&rmu_regs));
+ if (!rmu_regs_win) {
+ printk(KERN_ERR "Unable to map rmu register window\n");
rc = -ENOMEM;
- goto err_priv;
+ goto err_rmu;
}
- INIT_LIST_HEAD(&port->dbells);
- port->iores.start = law_start;
- port->iores.end = law_start + law_size - 1;
- port->iores.flags = IORESOURCE_MEM;
- port->iores.name = "rio_io_win";
-
- if (request_resource(&iomem_resource, &port->iores) < 0) {
- dev_err(&dev->dev, "RIO: Error requesting master port region"
- " 0x%016llx-0x%016llx\n",
- (u64)port->iores.start, (u64)port->iores.end);
- rc = -ENOMEM;
- goto err_res;
+ for_each_child_of_node(rmu_node, np) {
+ rmu_np[tmp] = np;
+ tmp++;
}
- priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0);
- dev_info(&dev->dev, "pwirq: %d\n", priv->pwirq);
- strcpy(port->name, "RIO0 mport");
-
- priv->dev = &dev->dev;
-
- port->ops = ops;
- port->priv = priv;
- port->phys_efptr = 0x100;
-
- priv->regs_win = ioremap(regs.start, resource_size(®s));
- rio_regs_win = priv->regs_win;
-
- /* Probe the master port phy type */
- ccsr = in_be32(priv->regs_win + RIO_CCSR);
- port->phy_type = (ccsr & 1) ? RIO_PHY_SERIAL : RIO_PHY_PARALLEL;
- dev_info(&dev->dev, "RapidIO PHY type: %s\n",
- (port->phy_type == RIO_PHY_PARALLEL) ? "parallel" :
- ((port->phy_type == RIO_PHY_SERIAL) ? "serial" :
- "unknown"));
- /* Checking the port training status */
- if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) {
- dev_err(&dev->dev, "Port is not ready. "
- "Try to restart connection...\n");
- switch (port->phy_type) {
- case RIO_PHY_SERIAL:
- /* Disable ports */
- out_be32(priv->regs_win + RIO_CCSR, 0);
- /* Set 1x lane */
- setbits32(priv->regs_win + RIO_CCSR, 0x02000000);
- /* Enable ports */
- setbits32(priv->regs_win + RIO_CCSR, 0x00600000);
- break;
- case RIO_PHY_PARALLEL:
- /* Disable ports */
- out_be32(priv->regs_win + RIO_CCSR, 0x22000000);
- /* Enable ports */
- out_be32(priv->regs_win + RIO_CCSR, 0x44000000);
- break;
+ for (i = 0; i < *ports_num; i++) {
+ port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
+ if (!port)
+ continue;
+
+ port->index = i;
+
+ priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL);
+ if (!priv) {
+ printk(KERN_ERR "Can't alloc memory for 'priv'\n");
+ kfree(port);
+ continue;
+ }
+
+ INIT_LIST_HEAD(&port->dbells);
+ port->iores.start = law_start + i *
+ (law_size >> (ilog2(*ports_num)));
+ port->iores.end = port->iores.start +
+ (law_size >> (ilog2(*ports_num)))
+ - 1;
+ port->iores.flags = IORESOURCE_MEM;
+ port->iores.name = "rio_io_win";
+
+ if (request_resource(&iomem_resource, &port->iores) < 0) {
+ dev_err(&dev->dev, "RIO: Error requesting master port region"
+ " 0x%016llx-0x%016llx\n",
+ (u64)port->iores.start, (u64)port->iores.end);
+ kfree(priv);
+ kfree(port);
+ continue;
}
- msleep(100);
- if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) {
- dev_err(&dev->dev, "Port restart failed.\n");
- rc = -ENOLINK;
- goto err;
+ sprintf(port->name, "RIO mport %d", i);
+
+ priv->dev = &dev->dev;
+
+ port->ops = ops;
+ port->priv = priv;
+ port->phys_efptr = 0x100;
+
+ priv->regs_win = rio_regs_win;
+
+ /* Probe the master port phy type */
+ ccsr = in_be32(priv->regs_win + RIO_CCSR + i*0x20);
+ port->phy_type = (ccsr & 1) ? RIO_PHY_SERIAL : RIO_PHY_PARALLEL;
+ dev_info(&dev->dev, "RapidIO PHY type: %s\n",
+ (port->phy_type == RIO_PHY_PARALLEL) ?
+ "parallel" :
+ ((port->phy_type == RIO_PHY_SERIAL) ? "serial" :
+ "unknown"));
+ /* Checking the port training status */
+ if (in_be32((priv->regs_win + RIO_ESCSR + i*0x20)) & 1) {
+ dev_err(&dev->dev, "Port %d is not ready. "
+ "Try to restart connection...\n", i);
+ switch (port->phy_type) {
+ case RIO_PHY_SERIAL:
+ /* Disable ports */
+ out_be32(priv->regs_win
+ + RIO_CCSR + i*0x20, 0);
+ /* Set 1x lane */
+ setbits32(priv->regs_win
+ + RIO_CCSR + i*0x20, 0x02000000);
+ /* Enable ports */
+ setbits32(priv->regs_win
+ + RIO_CCSR + i*0x20, 0x00600000);
+ break;
+ case RIO_PHY_PARALLEL:
+ /* Disable ports */
+ out_be32(priv->regs_win
+ + RIO_CCSR + i*0x20, 0x22000000);
+ /* Enable ports */
+ out_be32(priv->regs_win
+ + RIO_CCSR + i*0x20, 0x44000000);
+ break;
+ }
+ msleep(100);
+ if (in_be32((priv->regs_win
+ + RIO_ESCSR + i*0x20)) & 1) {
+ dev_err(&dev->dev,
+ "Port %d restart failed.\n", i);
+ release_resource(&port->iores);
+ kfree(priv);
+ kfree(port);
+ continue;
+ }
+ dev_info(&dev->dev, "Port %d restart success!\n", i);
}
- dev_info(&dev->dev, "Port restart success!\n");
- }
- fsl_rio_info(&dev->dev, ccsr);
+ fsl_rio_info(&dev->dev, ccsr);
- port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR))
+ port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR))
& RIO_PEF_CTLS) >> 4;
- dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
- port->sys_size ? 65536 : 256);
+ dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
+ port->sys_size ? 65536 : 256);
+
+ if (rio_register_mport(port)) {
+ release_resource(&port->iores);
+ kfree(priv);
+ kfree(port);
+ continue;
+ }
+ if (port->host_deviceid >= 0)
+ out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST |
+ RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED);
+ else
+ out_be32(priv->regs_win + RIO_GCCSR,
+ RIO_PORT_GEN_MASTER);
- if (rio_register_mport(port))
- goto err;
+ priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win
+ + ((i == 0) ? RIO_ATMU_REGS_PORT1_OFFSET :
+ RIO_ATMU_REGS_PORT2_OFFSET));
- if (port->host_deviceid >= 0)
- out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST |
- RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED);
- else
- out_be32(priv->regs_win + RIO_GCCSR, 0x00000000);
+ priv->maint_atmu_regs = priv->atmu_regs + 1;
- priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win
- + RIO_ATMU_REGS_OFFSET);
- priv->maint_atmu_regs = priv->atmu_regs + 1;
+ /* Set to receive any dist ID for serial RapidIO controller. */
+ if (port->phy_type == RIO_PHY_SERIAL)
+ out_be32((priv->regs_win
+ + RIO_ISR_AACR + i*0x80), RIO_ISR_AACR_AA);
- /* Set to receive any dist ID for serial RapidIO controller. */
- if (port->phy_type == RIO_PHY_SERIAL)
- out_be32((priv->regs_win + RIO_ISR_AACR), RIO_ISR_AACR_AA);
+ /* Configure maintenance transaction window */
+ out_be32(&priv->maint_atmu_regs->rowbar,
+ port->iores.start >> 12);
+ out_be32(&priv->maint_atmu_regs->rowar,
+ 0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1));
- /* Configure maintenance transaction window */
- out_be32(&priv->maint_atmu_regs->rowbar, law_start >> 12);
- out_be32(&priv->maint_atmu_regs->rowar,
- 0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1));
+ priv->maint_win = ioremap(port->iores.start,
+ RIO_MAINT_WIN_SIZE);
- priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE);
+ fsl_rio_setup_rmu(port, rmu_np[i]);
- fsl_rio_setup_rmu(port, dev->dev.of_node);
+ dbell->mport[i] = port;
- fsl_rio_port_write_init(port);
+ active_ports++;
+ }
+
+ if (!active_ports) {
+ rc = -ENOLINK;
+ goto err;
+ }
return 0;
err:
- iounmap(priv->regs_win);
- release_resource(&port->iores);
-err_res:
- kfree(priv);
-err_priv:
- kfree(port);
-err_port:
+ iounmap(rmu_regs_win);
+err_rmu:
+ kfree(pw);
+err_pw:
+ kfree(dbell);
+err_dbell:
kfree(ops);
err_ops:
+ iounmap(rio_regs_win);
+err_rio_regs:
return rc;
}
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h
index f888a1e..b9e7d1f 100644
--- a/arch/powerpc/sysdev/fsl_rio.h
+++ b/arch/powerpc/sysdev/fsl_rio.h
@@ -36,6 +36,24 @@
#define RIO_MAINT_WIN_SIZE 0x400000
#define RIO_LTLEDCSR 0x0608
+#define DOORBELL_ROWAR_EN 0x80000000
+#define DOORBELL_ROWAR_TFLOWLV 0x08000000 /* highest priority level */
+#define DOORBELL_ROWAR_PCI 0x02000000 /* PCI window */
+#define DOORBELL_ROWAR_NREAD 0x00040000 /* NREAD */
+#define DOORBELL_ROWAR_MAINTRD 0x00070000 /* maintenance read */
+#define DOORBELL_ROWAR_RES 0x00002000 /* wrtpy: reserverd */
+#define DOORBELL_ROWAR_MAINTWD 0x00007000
+#define DOORBELL_ROWAR_SIZE 0x0000000b /* window size is 4k */
+
+#define RIO_ATMU_REGS_PORT1_OFFSET 0x10c00
+#define RIO_ATMU_REGS_PORT2_OFFSET 0x10e00
+#define RIO_S_DBELL_REGS_OFFSET 0x13400
+#define RIO_S_PW_REGS_OFFSET 0x134e0
+#define RIO_ATMU_REGS_DBELL_OFFSET 0x10C40
+
+#define MAX_MSG_UNIT_NUM 2
+#define MAX_PORT_NUM 4
+
struct rio_atmu_regs {
u32 rowtar;
u32 rowtear;
@@ -45,6 +63,11 @@ struct rio_atmu_regs {
u32 pad3[3];
};
+struct rio_dbell_ring {
+ void *virt;
+ dma_addr_t phys;
+};
+
struct rio_port_write_msg {
void *virt;
dma_addr_t phys;
@@ -53,26 +76,62 @@ struct rio_port_write_msg {
u32 discard_count;
};
-struct rio_priv {
+struct fsl_rio_dbell {
+ struct rio_mport *mport[MAX_PORT_NUM];
struct device *dev;
- void __iomem *regs_win;
- struct rio_atmu_regs __iomem *atmu_regs;
- struct rio_atmu_regs __iomem *maint_atmu_regs;
- void __iomem *maint_win;
+ struct rio_dbell_regs __iomem *dbell_regs;
+ struct rio_atmu_regs __iomem *dbell_atmu_regs;
+ void __iomem *dbell_win;
+ struct rio_dbell_ring dbell_ring;
+ int bellirq;
+};
+
+struct fsl_rio_pw {
+ struct device *dev;
+ struct rio_pw_regs __iomem *pw_regs;
struct rio_port_write_msg port_write_msg;
int pwirq;
struct work_struct pw_work;
struct kfifo pw_fifo;
spinlock_t pw_fifo_lock;
+};
+
+struct rio_priv {
+ struct device *dev;
+ void __iomem *regs_win;
+ struct rio_atmu_regs __iomem *atmu_regs;
+ struct rio_atmu_regs __iomem *maint_atmu_regs;
+ void __iomem *maint_win;
void *rmm_handle; /* RapidIO message manager(unit) Handle */
};
extern void __iomem *rio_regs_win;
+extern void __iomem *rmu_regs_win;
+
+extern resource_size_t rio_law_start;
+
+extern struct fsl_rio_dbell *dbell;
+extern struct fsl_rio_pw *pw;
extern int fsl_rio_setup_rmu(struct rio_mport *mport,
struct device_node *node);
-extern int fsl_rio_port_write_init(struct rio_mport *mport);
+extern int fsl_rio_port_write_init(struct fsl_rio_pw *pw);
extern int fsl_rio_pw_enable(struct rio_mport *mport, int enable);
-extern void fsl_rio_port_error_handler(struct rio_mport *port, int offset);
+extern void fsl_rio_port_error_handler(int offset);
+extern int fsl_rio_doorbell_init(struct fsl_rio_dbell *dbell);
+
+extern int fsl_rio_doorbell_send(struct rio_mport *mport,
+ int index, u16 destid, u16 data);
+extern int fsl_add_outb_message(struct rio_mport *mport,
+ struct rio_dev *rdev,
+ int mbox, void *buffer, size_t len);
+extern int fsl_open_outb_mbox(struct rio_mport *mport,
+ void *dev_id, int mbox, int entries);
+extern void fsl_close_outb_mbox(struct rio_mport *mport, int mbox);
+extern int fsl_open_inb_mbox(struct rio_mport *mport,
+ void *dev_id, int mbox, int entries);
+extern void fsl_close_inb_mbox(struct rio_mport *mport, int mbox);
+extern int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf);
+extern void *fsl_get_inb_message(struct rio_mport *mport, int mbox);
#endif
diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c
index 0a3e6cf..4686db3 100644
--- a/arch/powerpc/sysdev/fsl_rmu.c
+++ b/arch/powerpc/sysdev/fsl_rmu.c
@@ -36,8 +36,8 @@
(((struct rio_priv *)(mport->priv))->rmm_handle)
/* RapidIO definition irq, which read from OF-tree */
-#define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq)
-#define IRQ_RIO_BELL(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->bellirq)
+#define IRQ_RIO_PW(m) (((struct fsl_rio_pw *)(m))->pwirq)
+#define IRQ_RIO_BELL(m) (((struct fsl_rio_dbell *)(m))->bellirq)
#define IRQ_RIO_TX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->txirq)
#define IRQ_RIO_RX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->rxirq)
@@ -113,61 +113,53 @@
#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET))
struct rio_msg_regs {
- u32 omr; /* 0xD_3000 - Outbound message 0 mode register */
- u32 osr; /* 0xD_3004 - Outbound message 0 status register */
+ u32 omr;
+ u32 osr;
u32 pad1;
- u32 odqdpar; /* 0xD_300C - Outbound message 0 descriptor queue
- dequeue pointer address register */
+ u32 odqdpar;
u32 pad2;
- u32 osar; /* 0xD_3014 - Outbound message 0 source address
- register */
- u32 odpr; /* 0xD_3018 - Outbound message 0 destination port
- register */
- u32 odatr; /* 0xD_301C - Outbound message 0 destination attributes
- Register*/
- u32 odcr; /* 0xD_3020 - Outbound message 0 double-word count
- register */
+ u32 osar;
+ u32 odpr;
+ u32 odatr;
+ u32 odcr;
u32 pad3;
- u32 odqepar; /* 0xD_3028 - Outbound message 0 descriptor queue
- enqueue pointer address register */
+ u32 odqepar;
u32 pad4[13];
- u32 imr; /* 0xD_3060 - Inbound message 0 mode register */
- u32 isr; /* 0xD_3064 - Inbound message 0 status register */
+ u32 imr;
+ u32 isr;
u32 pad5;
- u32 ifqdpar; /* 0xD_306C - Inbound message 0 frame queue dequeue
- pointer address register*/
+ u32 ifqdpar;
u32 pad6;
- u32 ifqepar; /* 0xD_3074 - Inbound message 0 frame queue enqueue
- pointer address register */
- u32 pad7[226];
- u32 odmr; /* 0xD_3400 - Outbound doorbell mode register */
- u32 odsr; /* 0xD_3404 - Outbound doorbell status register */
+ u32 ifqepar;
+ u32 pad7;
+};
+
+struct rio_dbell_regs {
+ u32 odmr;
+ u32 odsr;
u32 res0[4];
- u32 oddpr; /* 0xD_3418 - Outbound doorbell destination port
- register */
- u32 oddatr; /* 0xD_341c - Outbound doorbell destination attributes
- register */
+ u32 oddpr;
+ u32 oddatr;
u32 res1[3];
- u32 odretcr; /* 0xD_342C - Outbound doorbell retry error threshold
- configuration register */
+ u32 odretcr;
u32 res2[12];
- u32 dmr; /* 0xD_3460 - Inbound doorbell mode register */
- u32 dsr; /* 0xD_3464 - Inbound doorbell status register */
+ u32 dmr;
+ u32 dsr;
u32 pad8;
- u32 dqdpar; /* 0xD_346C - Inbound doorbell queue dequeue Pointer
- address register */
+ u32 dqdpar;
u32 pad9;
- u32 dqepar; /* 0xD_3474 - Inbound doorbell Queue enqueue pointer
- address register */
+ u32 dqepar;
u32 pad10[26];
- u32 pwmr; /* 0xD_34E0 - Inbound port-write mode register */
- u32 pwsr; /* 0xD_34E4 - Inbound port-write status register */
- u32 epwqbar; /* 0xD_34E8 - Extended Port-Write Queue Base Address
- register */
- u32 pwqbar; /* 0xD_34EC - Inbound port-write queue base address
- register */
};
+struct rio_pw_regs {
+ u32 pwmr;
+ u32 pwsr;
+ u32 epwqbar;
+ u32 pwqbar;
+};
+
+
struct rio_tx_desc {
u32 res1;
u32 saddr;
@@ -179,11 +171,6 @@ struct rio_tx_desc {
u32 res4;
};
-struct rio_dbell_ring {
- void *virt;
- dma_addr_t phys;
-};
-
struct rio_msg_tx_ring {
void *virt;
dma_addr_t phys;
@@ -204,13 +191,9 @@ struct rio_msg_rx_ring {
};
struct fsl_rmu {
- struct rio_atmu_regs __iomem *dbell_atmu_regs;
- void __iomem *dbell_win;
struct rio_msg_regs __iomem *msg_regs;
- struct rio_dbell_ring dbell_ring;
struct rio_msg_tx_ring msg_tx_ring;
struct rio_msg_rx_ring msg_rx_ring;
- int bellirq;
int txirq;
int rxirq;
};
@@ -247,9 +230,11 @@ fsl_rio_tx_handler(int irq, void *dev_instance)
if (osr & RIO_MSG_OSR_EOMI) {
u32 dqp = in_be32(&rmu->msg_regs->odqdpar);
int slot = (dqp - rmu->msg_tx_ring.phys) >> 5;
- port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id, -1,
- slot);
-
+ if (port->outb_msg[0].mcback != NULL) {
+ port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id,
+ -1,
+ slot);
+ }
/* Ack the end-of-message interrupt */
out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_EOMI);
}
@@ -284,12 +269,14 @@ fsl_rio_rx_handler(int irq, void *dev_instance)
/* XXX Need to check/dispatch until queue empty */
if (isr & RIO_MSG_ISR_DIQI) {
/*
- * We implement *only* mailbox 0, but can receive messages
- * for any mailbox/letter to that mailbox destination. So,
- * make the callback with an unknown/invalid mailbox number
- * argument.
- */
- port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id, -1, -1);
+ * Can receive messages for any mailbox/letter to that
+ * mailbox destination. So, make the callback with an
+ * unknown/invalid mailbox number argument.
+ */
+ if (port->inb_msg[0].mcback != NULL)
+ port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id,
+ -1,
+ -1);
/* Ack the queueing interrupt */
out_be32(&rmu->msg_regs->isr, RIO_MSG_ISR_DIQI);
@@ -311,27 +298,27 @@ static irqreturn_t
fsl_rio_dbell_handler(int irq, void *dev_instance)
{
int dsr;
- struct rio_mport *port = (struct rio_mport *)dev_instance;
- struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
+ struct fsl_rio_dbell *fsl_dbell = (struct fsl_rio_dbell *)dev_instance;
+ int i;
- dsr = in_be32(&rmu->msg_regs->dsr);
+ dsr = in_be32(&fsl_dbell->dbell_regs->dsr);
if (dsr & DOORBELL_DSR_TE) {
pr_info("RIO: doorbell reception error\n");
- out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_TE);
+ out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_TE);
goto out;
}
if (dsr & DOORBELL_DSR_QFI) {
pr_info("RIO: doorbell queue full\n");
- out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_QFI);
+ out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_QFI);
}
/* XXX Need to check/dispatch until queue empty */
if (dsr & DOORBELL_DSR_DIQI) {
u32 dmsg =
- (u32) rmu->dbell_ring.virt +
- (in_be32(&rmu->msg_regs->dqdpar) & 0xfff);
+ (u32) fsl_dbell->dbell_ring.virt +
+ (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff);
struct rio_dbell *dbell;
int found = 0;
@@ -340,35 +327,45 @@ fsl_rio_dbell_handler(int irq, void *dev_instance)
" sid %2.2x tid %2.2x info %4.4x\n",
DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
- list_for_each_entry(dbell, &port->dbells, node) {
- if ((dbell->res->start <= DBELL_INF(dmsg)) &&
- (dbell->res->end >= DBELL_INF(dmsg))) {
- found = 1;
- break;
+ for (i = 0; i < MAX_PORT_NUM; i++) {
+ if (fsl_dbell->mport[i]) {
+ list_for_each_entry(dbell,
+ &fsl_dbell->mport[i]->dbells, node) {
+ if ((dbell->res->start
+ <= DBELL_INF(dmsg))
+ && (dbell->res->end
+ >= DBELL_INF(dmsg))) {
+ found = 1;
+ break;
+ }
+ }
+ if (found && dbell->dinb) {
+ dbell->dinb(fsl_dbell->mport[i],
+ dbell->dev_id, DBELL_SID(dmsg),
+ DBELL_TID(dmsg),
+ DBELL_INF(dmsg));
+ break;
+ }
}
}
- if (found) {
- dbell->dinb(port, dbell->dev_id,
- DBELL_SID(dmsg),
- DBELL_TID(dmsg), DBELL_INF(dmsg));
- } else {
+
+ if (!found) {
pr_debug
("RIO: spurious doorbell,"
" sid %2.2x tid %2.2x info %4.4x\n",
DBELL_SID(dmsg), DBELL_TID(dmsg),
DBELL_INF(dmsg));
}
- setbits32(&rmu->msg_regs->dmr, DOORBELL_DMR_DI);
- out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_DIQI);
+ setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI);
+ out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI);
}
out:
return IRQ_HANDLED;
}
-void msg_unit_error_handler(struct rio_mport *port)
+void msg_unit_error_handler(void)
{
- struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
/*XXX: Error recovery is not implemented, we just clear errors */
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
@@ -378,10 +375,10 @@ void msg_unit_error_handler(struct rio_mport *port)
out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR);
out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR);
- out_be32(&rmu->msg_regs->odsr, ODSR_CLEAR);
- out_be32(&rmu->msg_regs->dsr, IDSR_CLEAR);
+ out_be32(&dbell->dbell_regs->odsr, ODSR_CLEAR);
+ out_be32(&dbell->dbell_regs->dsr, IDSR_CLEAR);
- out_be32(&rmu->msg_regs->pwsr, IPWSR_CLEAR);
+ out_be32(&pw->pw_regs->pwsr, IPWSR_CLEAR);
}
/**
@@ -396,18 +393,15 @@ static irqreturn_t
fsl_rio_port_write_handler(int irq, void *dev_instance)
{
u32 ipwmr, ipwsr;
- struct rio_mport *port = (struct rio_mport *)dev_instance;
- struct rio_priv *priv = port->priv;
- struct fsl_rmu *rmu;
+ struct fsl_rio_pw *pw = (struct fsl_rio_pw *)dev_instance;
u32 epwisr, tmp;
- rmu = GET_RMM_HANDLE(port);
- epwisr = in_be32(priv->regs_win + RIO_EPWISR);
+ epwisr = in_be32(rio_regs_win + RIO_EPWISR);
if (!(epwisr & RIO_EPWISR_PW))
goto pw_done;
- ipwmr = in_be32(&rmu->msg_regs->pwmr);
- ipwsr = in_be32(&rmu->msg_regs->pwsr);
+ ipwmr = in_be32(&pw->pw_regs->pwmr);
+ ipwsr = in_be32(&pw->pw_regs->pwsr);
#ifdef DEBUG_PW
pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
@@ -428,60 +422,60 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
/* Save PW message (if there is room in FIFO),
* otherwise discard it.
*/
- if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) {
- priv->port_write_msg.msg_count++;
- kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt,
+ if (kfifo_avail(&pw->pw_fifo) >= RIO_PW_MSG_SIZE) {
+ pw->port_write_msg.msg_count++;
+ kfifo_in(&pw->pw_fifo, pw->port_write_msg.virt,
RIO_PW_MSG_SIZE);
} else {
- priv->port_write_msg.discard_count++;
+ pw->port_write_msg.discard_count++;
pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
- priv->port_write_msg.discard_count);
+ pw->port_write_msg.discard_count);
}
/* Clear interrupt and issue Clear Queue command. This allows
* another port-write to be received.
*/
- out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_QFI);
- out_be32(&rmu->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+ out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_QFI);
+ out_be32(&pw->pw_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
- schedule_work(&priv->pw_work);
+ schedule_work(&pw->pw_work);
}
if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
- priv->port_write_msg.err_count++;
+ pw->port_write_msg.err_count++;
pr_debug("RIO: Port-Write Transaction Err (%d)\n",
- priv->port_write_msg.err_count);
+ pw->port_write_msg.err_count);
/* Clear Transaction Error: port-write controller should be
* disabled when clearing this error
*/
- out_be32(&rmu->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
- out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_TE);
- out_be32(&rmu->msg_regs->pwmr, ipwmr);
+ out_be32(&pw->pw_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
+ out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_TE);
+ out_be32(&pw->pw_regs->pwmr, ipwmr);
}
if (ipwsr & RIO_IPWSR_PWD) {
- priv->port_write_msg.discard_count++;
+ pw->port_write_msg.discard_count++;
pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
- priv->port_write_msg.discard_count);
- out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_PWD);
+ pw->port_write_msg.discard_count);
+ out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_PWD);
}
pw_done:
if (epwisr & RIO_EPWISR_PINT1) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
- fsl_rio_port_error_handler(port, 0);
+ fsl_rio_port_error_handler(0);
}
if (epwisr & RIO_EPWISR_PINT2) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
- fsl_rio_port_error_handler(port, 1);
+ fsl_rio_port_error_handler(1);
}
if (epwisr & RIO_EPWISR_MU) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ tmp = in_be32(rio_regs_win + RIO_LTLEDCSR);
pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
- msg_unit_error_handler(port);
+ msg_unit_error_handler();
}
return IRQ_HANDLED;
@@ -489,18 +483,18 @@ pw_done:
static void fsl_pw_dpc(struct work_struct *work)
{
- struct rio_priv *priv = container_of(work, struct rio_priv, pw_work);
+ struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work);
unsigned long flags;
u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
/*
* Process port-write messages
*/
- spin_lock_irqsave(&priv->pw_fifo_lock, flags);
- while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
+ spin_lock_irqsave(&pw->pw_fifo_lock, flags);
+ while (kfifo_out(&pw->pw_fifo, (unsigned char *)msg_buffer,
RIO_PW_MSG_SIZE)) {
/* Process one message */
- spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+ spin_unlock_irqrestore(&pw->pw_fifo_lock, flags);
#ifdef DEBUG_PW
{
u32 i;
@@ -517,31 +511,28 @@ static void fsl_pw_dpc(struct work_struct *work)
#endif
/* Pass the port-write message to RIO core for processing */
rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
- spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+ spin_lock_irqsave(&pw->pw_fifo_lock, flags);
}
- spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+ spin_unlock_irqrestore(&pw->pw_fifo_lock, flags);
}
/**
* fsl_rio_pw_enable - enable/disable port-write interface init
* @mport: Master port implementing the port write unit
- * @enable: 1=enable; 0=disable port-write message handling
+ * @enable: 1=enable; 0=disable port-write message handling
*/
int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
{
- struct fsl_rmu *rmu;
u32 rval;
- rmu = GET_RMM_HANDLE(mport);
-
- rval = in_be32(&rmu->msg_regs->pwmr);
+ rval = in_be32(&pw->pw_regs->pwmr);
if (enable)
rval |= RIO_IPWMR_PWE;
else
rval &= ~RIO_IPWMR_PWE;
- out_be32(&rmu->msg_regs->pwmr, rval);
+ out_be32(&pw->pw_regs->pwmr, rval);
return 0;
}
@@ -555,51 +546,47 @@ int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
* or %-ENOMEM on failure.
*/
-int fsl_rio_port_write_init(struct rio_mport *mport)
+int fsl_rio_port_write_init(struct fsl_rio_pw *pw)
{
- struct rio_priv *priv = mport->priv;
- struct fsl_rmu *rmu;
int rc = 0;
- rmu = GET_RMM_HANDLE(mport);
-
/* Following configurations require a disabled port write controller */
- out_be32(&rmu->msg_regs->pwmr,
- in_be32(&rmu->msg_regs->pwmr) & ~RIO_IPWMR_PWE);
+ out_be32(&pw->pw_regs->pwmr,
+ in_be32(&pw->pw_regs->pwmr) & ~RIO_IPWMR_PWE);
/* Initialize port write */
- priv->port_write_msg.virt = dma_alloc_coherent(priv->dev,
+ pw->port_write_msg.virt = dma_alloc_coherent(pw->dev,
RIO_PW_MSG_SIZE,
- &priv->port_write_msg.phys, GFP_KERNEL);
- if (!priv->port_write_msg.virt) {
+ &pw->port_write_msg.phys, GFP_KERNEL);
+ if (!pw->port_write_msg.virt) {
pr_err("RIO: unable allocate port write queue\n");
return -ENOMEM;
}
- priv->port_write_msg.err_count = 0;
- priv->port_write_msg.discard_count = 0;
+ pw->port_write_msg.err_count = 0;
+ pw->port_write_msg.discard_count = 0;
/* Point dequeue/enqueue pointers at first entry */
- out_be32(&rmu->msg_regs->epwqbar, 0);
- out_be32(&rmu->msg_regs->pwqbar, (u32) priv->port_write_msg.phys);
+ out_be32(&pw->pw_regs->epwqbar, 0);
+ out_be32(&pw->pw_regs->pwqbar, (u32) pw->port_write_msg.phys);
pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
- in_be32(&rmu->msg_regs->epwqbar),
- in_be32(&rmu->msg_regs->pwqbar));
+ in_be32(&pw->pw_regs->epwqbar),
+ in_be32(&pw->pw_regs->pwqbar));
/* Clear interrupt status IPWSR */
- out_be32(&rmu->msg_regs->pwsr,
+ out_be32(&pw->pw_regs->pwsr,
(RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
/* Configure port write contoller for snooping enable all reporting,
clear queue full */
- out_be32(&rmu->msg_regs->pwmr,
+ out_be32(&pw->pw_regs->pwmr,
RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
/* Hook up port-write handler */
- rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler,
- IRQF_SHARED, "port-write", (void *)mport);
+ rc = request_irq(IRQ_RIO_PW(pw), fsl_rio_port_write_handler,
+ IRQF_SHARED, "port-write", (void *)pw);
if (rc < 0) {
pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
goto err_out;
@@ -607,26 +594,26 @@ int fsl_rio_port_write_init(struct rio_mport *mport)
/* Enable Error Interrupt */
out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
- INIT_WORK(&priv->pw_work, fsl_pw_dpc);
- spin_lock_init(&priv->pw_fifo_lock);
- if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
+ INIT_WORK(&pw->pw_work, fsl_pw_dpc);
+ spin_lock_init(&pw->pw_fifo_lock);
+ if (kfifo_alloc(&pw->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
pr_err("FIFO allocation failed\n");
rc = -ENOMEM;
goto err_out_irq;
}
pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
- in_be32(&rmu->msg_regs->pwmr),
- in_be32(&rmu->msg_regs->pwsr));
+ in_be32(&pw->pw_regs->pwmr),
+ in_be32(&pw->pw_regs->pwsr));
return rc;
err_out_irq:
- free_irq(IRQ_RIO_PW(mport), (void *)mport);
+ free_irq(IRQ_RIO_PW(pw), (void *)pw);
err_out:
- dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE,
- priv->port_write_msg.virt,
- priv->port_write_msg.phys);
+ dma_free_coherent(pw->dev, RIO_PW_MSG_SIZE,
+ pw->port_write_msg.virt,
+ pw->port_write_msg.phys);
return rc;
}
@@ -640,27 +627,25 @@ err_out:
* Sends a MPC85xx doorbell message. Returns %0 on success or
* %-EINVAL on failure.
*/
-static int fsl_rio_doorbell_send(struct rio_mport *mport,
+int fsl_rio_doorbell_send(struct rio_mport *mport,
int index, u16 destid, u16 data)
{
- struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
-
pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
index, destid, data);
switch (mport->phy_type) {
case RIO_PHY_PARALLEL:
- out_be32(&rmu->dbell_atmu_regs->rowtar, destid << 22);
- out_be16(rmu->dbell_win, data);
+ out_be32(&dbell->dbell_atmu_regs->rowtar, destid << 22);
+ out_be16(dbell->dbell_win, data);
break;
case RIO_PHY_SERIAL:
/* In the serial version silicons, such as MPC8548, MPC8641,
* below operations is must be.
*/
- out_be32(&rmu->msg_regs->odmr, 0x00000000);
- out_be32(&rmu->msg_regs->odretcr, 0x00000004);
- out_be32(&rmu->msg_regs->oddpr, destid << 16);
- out_be32(&rmu->msg_regs->oddatr, data);
- out_be32(&rmu->msg_regs->odmr, 0x00000001);
+ out_be32(&dbell->dbell_regs->odmr, 0x00000000);
+ out_be32(&dbell->dbell_regs->odretcr, 0x00000004);
+ out_be32(&dbell->dbell_regs->oddpr, destid << 16);
+ out_be32(&dbell->dbell_regs->oddatr, (index << 20) | data);
+ out_be32(&dbell->dbell_regs->odmr, 0x00000001);
break;
}
@@ -678,7 +663,7 @@ static int fsl_rio_doorbell_send(struct rio_mport *mport,
* Adds the @buffer message to the MPC85xx outbound message queue. Returns
* %0 on success or %-EINVAL on failure.
*/
-static int
+int
fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
void *buffer, size_t len)
{
@@ -690,7 +675,6 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
"%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len);
-
if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
ret = -EINVAL;
goto out;
@@ -716,7 +700,7 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
desc->dport = (rdev->destid << 16) | (mbox & 0x3);
/* Enable EOMI interrupt and priority */
- desc->dattr = 0x28000000;
+ desc->dattr = 0x28000000 | ((mport->index) << 20);
break;
}
@@ -750,7 +734,7 @@ out:
* and enables the outbound message unit. Returns %0 on success and
* %-EINVAL or %-ENOMEM on failure.
*/
-static int
+int
fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
{
int i, j, rc = 0;
@@ -855,7 +839,7 @@ out_dma:
* Disables the outbound message unit, free all buffers, and
* frees the outbound message interrupt.
*/
-static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
+void fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
{
struct rio_priv *priv = mport->priv;
struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
@@ -883,7 +867,7 @@ static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
* and enables the inbound message unit. Returns %0 on success
* and %-EINVAL or %-ENOMEM on failure.
*/
-static int
+int
fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
{
int i, rc = 0;
@@ -956,7 +940,7 @@ out:
* Disables the inbound message unit, free all buffers, and
* frees the inbound message interrupt.
*/
-static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
+void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
{
struct rio_priv *priv = mport->priv;
struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
@@ -966,7 +950,7 @@ static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
/* Free ring */
dma_free_coherent(priv->dev, rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
- rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
+ rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
/* Free interrupt */
free_irq(IRQ_RIO_RX(mport), (void *)mport);
@@ -981,7 +965,7 @@ static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
* Adds the @buf buffer to the MPC85xx inbound message queue. Returns
* %0 on success or %-EINVAL on failure.
*/
-static int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
+int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
{
int rc = 0;
struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
@@ -1013,7 +997,7 @@ out:
* Gets the next available inbound message from the inbound message queue.
* A pointer to the message is returned on success or NULL on failure.
*/
-static void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
+void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
{
struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
u32 phys_buf, virt_buf;
@@ -1058,16 +1042,14 @@ out2:
* ring. Called from fsl_rio_setup(). Returns %0 on success
* or %-ENOMEM on failure.
*/
-static int fsl_rio_doorbell_init(struct rio_mport *mport)
+int fsl_rio_doorbell_init(struct fsl_rio_dbell *dbell)
{
- struct rio_priv *priv = mport->priv;
- struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
int rc = 0;
/* Map outbound doorbell window immediately after maintenance window */
- rmu->dbell_win = ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
+ dbell->dbell_win = ioremap(rio_law_start + RIO_MAINT_WIN_SIZE,
RIO_DBELL_WIN_SIZE);
- if (!rmu->dbell_win) {
+ if (!dbell->dbell_win) {
printk(KERN_ERR
"RIO: unable to map outbound doorbell window\n");
rc = -ENOMEM;
@@ -1075,36 +1057,36 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
}
/* Initialize inbound doorbells */
- rmu->dbell_ring.virt = dma_alloc_coherent(priv->dev, 512 *
- DOORBELL_MESSAGE_SIZE, &rmu->dbell_ring.phys, GFP_KERNEL);
- if (!rmu->dbell_ring.virt) {
+ dbell->dbell_ring.virt = dma_alloc_coherent(dbell->dev, 512 *
+ DOORBELL_MESSAGE_SIZE, &dbell->dbell_ring.phys, GFP_KERNEL);
+ if (!dbell->dbell_ring.virt) {
printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
rc = -ENOMEM;
- iounmap(rmu->dbell_win);
+ iounmap(dbell->dbell_win);
goto out;
}
/* Point dequeue/enqueue pointers at first entry in ring */
- out_be32(&rmu->msg_regs->dqdpar, (u32) rmu->dbell_ring.phys);
- out_be32(&rmu->msg_regs->dqepar, (u32) rmu->dbell_ring.phys);
+ out_be32(&dbell->dbell_regs->dqdpar, (u32) dbell->dbell_ring.phys);
+ out_be32(&dbell->dbell_regs->dqepar, (u32) dbell->dbell_ring.phys);
/* Clear interrupt status */
- out_be32(&rmu->msg_regs->dsr, 0x00000091);
+ out_be32(&dbell->dbell_regs->dsr, 0x00000091);
/* Hook up doorbell handler */
- rc = request_irq(IRQ_RIO_BELL(mport), fsl_rio_dbell_handler, 0,
- "dbell_rx", (void *)mport);
+ rc = request_irq(IRQ_RIO_BELL(dbell), fsl_rio_dbell_handler, 0,
+ "dbell_rx", (void *)dbell);
if (rc < 0) {
- iounmap(rmu->dbell_win);
- dma_free_coherent(priv->dev, 512 * DOORBELL_MESSAGE_SIZE,
- rmu->dbell_ring.virt, rmu->dbell_ring.phys);
+ iounmap(dbell->dbell_win);
+ dma_free_coherent(dbell->dev, 512 * DOORBELL_MESSAGE_SIZE,
+ dbell->dbell_ring.virt, dbell->dbell_ring.phys);
printk(KERN_ERR
"MPC85xx RIO: unable to request inbound doorbell irq");
goto out;
}
/* Configure doorbells for snooping, 512 entries, and enable */
- out_be32(&rmu->msg_regs->dmr, 0x00108161);
+ out_be32(&dbell->dbell_regs->dmr, 0x00108161);
out:
return rc;
@@ -1114,50 +1096,50 @@ int fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node)
{
struct rio_priv *priv;
struct fsl_rmu *rmu;
- struct rio_ops *ops;
+ u64 msg_start, msg_size;
+ const u32 *msg_addr;
+ int mlen;
+ int aw, sw;
- if (!mport || !mport->priv || !node)
- return -1;
+ if (!mport || !mport->priv)
+ return -EFAULT;
+
+ priv = mport->priv;
+
+ if (!node) {
+ dev_warn(priv->dev, "Can't get %s property 'fsl,rmu'\n",
+ priv->dev->of_node->full_name);
+ return -EFAULT;
+ }
rmu = kzalloc(sizeof(struct fsl_rmu), GFP_KERNEL);
if (!rmu)
return -ENOMEM;
- priv = mport->priv;
+ aw = of_n_addr_cells(node);
+ sw = of_n_size_cells(node);
+ msg_addr = of_get_property(node, "reg", &mlen);
+ msg_start = of_read_number(msg_addr, aw);
+ msg_size = of_read_number(msg_addr + aw, sw);
+ if (!msg_addr) {
+ pr_err("%s: unable to find 'reg' property of message-unit\n",
+ node->full_name);
+ return -ENOMEM;
+ }
+
+ rmu->msg_regs = (struct rio_msg_regs *)
+ (rmu_regs_win + (u32)msg_start);
+
+ rmu->txirq = irq_of_parse_and_map(node, 0);
+ rmu->rxirq = irq_of_parse_and_map(node, 1);
+ printk(KERN_INFO "%s: txirq: %d, rxirq %d\n",
+ node->full_name, rmu->txirq, rmu->rxirq);
+
priv->rmm_handle = rmu;
- rmu->dbell_atmu_regs = priv->atmu_regs + 2;
- rmu->msg_regs = (struct rio_msg_regs *)(priv->regs_win +
- ((mport->phy_type == RIO_PHY_SERIAL) ?
- RIO_S_MSG_REGS_OFFSET : RIO_P_MSG_REGS_OFFSET));
-
- rmu->bellirq = irq_of_parse_and_map(node, 2);
- rmu->txirq = irq_of_parse_and_map(node, 3);
- rmu->rxirq = irq_of_parse_and_map(node, 4);
- dev_info(priv->dev, "bellirq: %d, txirq: %d, rxirq %d\n",
- rmu->bellirq, rmu->txirq, rmu->rxirq);
-
- ops = mport->ops;
-
- ops->dsend = fsl_rio_doorbell_send;
- ops->open_outb_mbox = fsl_open_outb_mbox;
- ops->open_inb_mbox = fsl_open_inb_mbox;
- ops->close_outb_mbox = fsl_close_outb_mbox;
- ops->close_inb_mbox = fsl_close_inb_mbox;
- ops->add_outb_message = fsl_add_outb_message;
- ops->add_inb_buffer = fsl_add_inb_buffer;
- ops->get_inb_message = fsl_get_inb_message;
rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
- /* Configure outbound doorbell window */
- out_be32(&rmu->dbell_atmu_regs->rowbar,
- (mport->iores.start + RIO_MAINT_WIN_SIZE) >> 12);
- /* 4k window size */
- out_be32(&rmu->dbell_atmu_regs->rowar, 0x8004200b);
-
- fsl_rio_doorbell_init(mport);
-
return 0;
}
--
1.7.3.1
^ permalink raw reply related
* [PATCH 1/4] fsl-rio: Split rio driver into two parts, RapidIO endpoint and RapidIO message unit
From: Liu Gang @ 2011-09-29 2:28 UTC (permalink / raw)
To: linuxppc-dev
Cc: r58472, r61911, linux-kernel, Lian Minghuan-B31939, Liu Gang,
akpm, B11780
The Freescale PowerPC RapidIO controller consists of a RapidIO endpoint and a RapidIO
message unit(RMU). Or use RapidIO message manager(RMan) to replace the RMU in DPAA
architecture. Therefore, we should split the code into two function modules according
to the hardware architecture.
Add new struct for RMU module, and new initialization function to set up RMU module. This policy
is very conducive to adding new module like RMan, or adding multi-ports or message units support.
Signed-off-by: Lian Minghuan-B31939 <Minghuan.Lian@freescale.com>
Signed-off-by: Liu Gang <Gang.Liu@freescale.com>
---
arch/powerpc/sysdev/Makefile | 2 +-
arch/powerpc/sysdev/fsl_rio.c | 1152 +---------------------------------------
arch/powerpc/sysdev/fsl_rio.h | 78 +++
arch/powerpc/sysdev/fsl_rmu.c | 1163 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 1267 insertions(+), 1128 deletions(-)
create mode 100644 arch/powerpc/sysdev/fsl_rio.h
create mode 100644 arch/powerpc/sysdev/fsl_rmu.c
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index cf736ca..d6be400 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -21,7 +21,7 @@ obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o
obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
-obj-$(CONFIG_FSL_RIO) += fsl_rio.o
+obj-$(CONFIG_FSL_RIO) += fsl_rio.o fsl_rmu.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 22ffccd..9484484 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -10,7 +10,7 @@
* - Added Port-Write message handling
* - Added Machine Check exception handling
*
- * Copyright (C) 2007, 2008, 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc.
* Zhang Wei <wei.zhang@freescale.com>
*
* Copyright 2005 MontaVista Software, Inc.
@@ -28,240 +28,34 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include <linux/rio.h>
-#include <linux/rio_drv.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/kfifo.h>
-#include <asm/io.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
#include <asm/machdep.h>
-#include <asm/uaccess.h>
-#undef DEBUG_PW /* Port-Write debugging */
+#include "fsl_rio.h"
-/* RapidIO definition irq, which read from OF-tree */
-#define IRQ_RIO_BELL(m) (((struct rio_priv *)(m->priv))->bellirq)
-#define IRQ_RIO_TX(m) (((struct rio_priv *)(m->priv))->txirq)
-#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq)
-#define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq)
-
-#define IPWSR_CLEAR 0x98
-#define OMSR_CLEAR 0x1cb3
-#define IMSR_CLEAR 0x491
-#define IDSR_CLEAR 0x91
-#define ODSR_CLEAR 0x1c00
-#define LTLEECSR_ENABLE_ALL 0xFFC000FC
-#define ESCSR_CLEAR 0x07120204
-#define IECSR_CLEAR 0x80000000
+#undef DEBUG_PW /* Port-Write debugging */
#define RIO_PORT1_EDCSR 0x0640
#define RIO_PORT2_EDCSR 0x0680
#define RIO_PORT1_IECSR 0x10130
#define RIO_PORT2_IECSR 0x101B0
-#define RIO_IM0SR 0x13064
-#define RIO_IM1SR 0x13164
-#define RIO_OM0SR 0x13004
-#define RIO_OM1SR 0x13104
#define RIO_ATMU_REGS_OFFSET 0x10c00
-#define RIO_P_MSG_REGS_OFFSET 0x11000
-#define RIO_S_MSG_REGS_OFFSET 0x13000
#define RIO_GCCSR 0x13c
#define RIO_ESCSR 0x158
+#define ESCSR_CLEAR 0x07120204
#define RIO_PORT2_ESCSR 0x178
#define RIO_CCSR 0x15c
-#define RIO_LTLEDCSR 0x0608
#define RIO_LTLEDCSR_IER 0x80000000
#define RIO_LTLEDCSR_PRT 0x01000000
-#define RIO_LTLEECSR 0x060c
-#define RIO_EPWISR 0x10010
+#define IECSR_CLEAR 0x80000000
#define RIO_ISR_AACR 0x10120
#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */
-#define RIO_MAINT_WIN_SIZE 0x400000
-#define RIO_DBELL_WIN_SIZE 0x1000
-
-#define RIO_MSG_OMR_MUI 0x00000002
-#define RIO_MSG_OSR_TE 0x00000080
-#define RIO_MSG_OSR_QOI 0x00000020
-#define RIO_MSG_OSR_QFI 0x00000010
-#define RIO_MSG_OSR_MUB 0x00000004
-#define RIO_MSG_OSR_EOMI 0x00000002
-#define RIO_MSG_OSR_QEI 0x00000001
-
-#define RIO_MSG_IMR_MI 0x00000002
-#define RIO_MSG_ISR_TE 0x00000080
-#define RIO_MSG_ISR_QFI 0x00000010
-#define RIO_MSG_ISR_DIQI 0x00000001
-
-#define RIO_IPWMR_SEN 0x00100000
-#define RIO_IPWMR_QFIE 0x00000100
-#define RIO_IPWMR_EIE 0x00000020
-#define RIO_IPWMR_CQ 0x00000002
-#define RIO_IPWMR_PWE 0x00000001
-
-#define RIO_IPWSR_QF 0x00100000
-#define RIO_IPWSR_TE 0x00000080
-#define RIO_IPWSR_QFI 0x00000010
-#define RIO_IPWSR_PWD 0x00000008
-#define RIO_IPWSR_PWB 0x00000004
-
-/* EPWISR Error match value */
-#define RIO_EPWISR_PINT1 0x80000000
-#define RIO_EPWISR_PINT2 0x40000000
-#define RIO_EPWISR_MU 0x00000002
-#define RIO_EPWISR_PW 0x00000001
-
-#define RIO_MSG_DESC_SIZE 32
-#define RIO_MSG_BUFFER_SIZE 4096
-#define RIO_MIN_TX_RING_SIZE 2
-#define RIO_MAX_TX_RING_SIZE 2048
-#define RIO_MIN_RX_RING_SIZE 2
-#define RIO_MAX_RX_RING_SIZE 2048
-
-#define DOORBELL_DMR_DI 0x00000002
-#define DOORBELL_DSR_TE 0x00000080
-#define DOORBELL_DSR_QFI 0x00000010
-#define DOORBELL_DSR_DIQI 0x00000001
-#define DOORBELL_TID_OFFSET 0x02
-#define DOORBELL_SID_OFFSET 0x04
-#define DOORBELL_INFO_OFFSET 0x06
-
-#define DOORBELL_MESSAGE_SIZE 0x08
-#define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET))
-#define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET))
-#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET))
-
-struct rio_atmu_regs {
- u32 rowtar;
- u32 rowtear;
- u32 rowbar;
- u32 pad2;
- u32 rowar;
- u32 pad3[3];
-};
-
-struct rio_msg_regs {
- u32 omr; /* 0xD_3000 - Outbound message 0 mode register */
- u32 osr; /* 0xD_3004 - Outbound message 0 status register */
- u32 pad1;
- u32 odqdpar; /* 0xD_300C - Outbound message 0 descriptor queue
- dequeue pointer address register */
- u32 pad2;
- u32 osar; /* 0xD_3014 - Outbound message 0 source address
- register */
- u32 odpr; /* 0xD_3018 - Outbound message 0 destination port
- register */
- u32 odatr; /* 0xD_301C - Outbound message 0 destination attributes
- Register*/
- u32 odcr; /* 0xD_3020 - Outbound message 0 double-word count
- register */
- u32 pad3;
- u32 odqepar; /* 0xD_3028 - Outbound message 0 descriptor queue
- enqueue pointer address register */
- u32 pad4[13];
- u32 imr; /* 0xD_3060 - Inbound message 0 mode register */
- u32 isr; /* 0xD_3064 - Inbound message 0 status register */
- u32 pad5;
- u32 ifqdpar; /* 0xD_306C - Inbound message 0 frame queue dequeue
- pointer address register*/
- u32 pad6;
- u32 ifqepar; /* 0xD_3074 - Inbound message 0 frame queue enqueue
- pointer address register */
- u32 pad7[226];
- u32 odmr; /* 0xD_3400 - Outbound doorbell mode register */
- u32 odsr; /* 0xD_3404 - Outbound doorbell status register */
- u32 res0[4];
- u32 oddpr; /* 0xD_3418 - Outbound doorbell destination port
- register */
- u32 oddatr; /* 0xD_341c - Outbound doorbell destination attributes
- register */
- u32 res1[3];
- u32 odretcr; /* 0xD_342C - Outbound doorbell retry error threshold
- configuration register */
- u32 res2[12];
- u32 dmr; /* 0xD_3460 - Inbound doorbell mode register */
- u32 dsr; /* 0xD_3464 - Inbound doorbell status register */
- u32 pad8;
- u32 dqdpar; /* 0xD_346C - Inbound doorbell queue dequeue Pointer
- address register */
- u32 pad9;
- u32 dqepar; /* 0xD_3474 - Inbound doorbell Queue enqueue pointer
- address register */
- u32 pad10[26];
- u32 pwmr; /* 0xD_34E0 - Inbound port-write mode register */
- u32 pwsr; /* 0xD_34E4 - Inbound port-write status register */
- u32 epwqbar; /* 0xD_34E8 - Extended Port-Write Queue Base Address
- register */
- u32 pwqbar; /* 0xD_34EC - Inbound port-write queue base address
- register */
-};
-
-struct rio_tx_desc {
- u32 res1;
- u32 saddr;
- u32 dport;
- u32 dattr;
- u32 res2;
- u32 res3;
- u32 dwcnt;
- u32 res4;
-};
-
-struct rio_dbell_ring {
- void *virt;
- dma_addr_t phys;
-};
-
-struct rio_msg_tx_ring {
- void *virt;
- dma_addr_t phys;
- void *virt_buffer[RIO_MAX_TX_RING_SIZE];
- dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
- int tx_slot;
- int size;
- void *dev_id;
-};
-
-struct rio_msg_rx_ring {
- void *virt;
- dma_addr_t phys;
- void *virt_buffer[RIO_MAX_RX_RING_SIZE];
- int rx_slot;
- int size;
- void *dev_id;
-};
-
-struct rio_port_write_msg {
- void *virt;
- dma_addr_t phys;
- u32 msg_count;
- u32 err_count;
- u32 discard_count;
-};
-
-struct rio_priv {
- struct device *dev;
- void __iomem *regs_win;
- struct rio_atmu_regs __iomem *atmu_regs;
- struct rio_atmu_regs __iomem *maint_atmu_regs;
- struct rio_atmu_regs __iomem *dbell_atmu_regs;
- void __iomem *dbell_win;
- void __iomem *maint_win;
- struct rio_msg_regs __iomem *msg_regs;
- struct rio_dbell_ring dbell_ring;
- struct rio_msg_tx_ring msg_tx_ring;
- struct rio_msg_rx_ring msg_rx_ring;
- struct rio_port_write_msg port_write_msg;
- int bellirq;
- int txirq;
- int rxirq;
- int pwirq;
- struct work_struct pw_work;
- struct kfifo pw_fifo;
- spinlock_t pw_fifo_lock;
-};
#define __fsl_read_rio_config(x, addr, err, op) \
__asm__ __volatile__( \
@@ -279,7 +73,7 @@ struct rio_priv {
: "=r" (err), "=r" (x) \
: "b" (addr), "i" (-EFAULT), "0" (err))
-static void __iomem *rio_regs_win;
+void __iomem *rio_regs_win;
#ifdef CONFIG_E500
int fsl_rio_mcheck_exception(struct pt_regs *regs)
@@ -311,42 +105,6 @@ EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception);
#endif
/**
- * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
- * @mport: RapidIO master port info
- * @index: ID of RapidIO interface
- * @destid: Destination ID of target device
- * @data: 16-bit info field of RapidIO doorbell message
- *
- * Sends a MPC85xx doorbell message. Returns %0 on success or
- * %-EINVAL on failure.
- */
-static int fsl_rio_doorbell_send(struct rio_mport *mport,
- int index, u16 destid, u16 data)
-{
- struct rio_priv *priv = mport->priv;
- pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
- index, destid, data);
- switch (mport->phy_type) {
- case RIO_PHY_PARALLEL:
- out_be32(&priv->dbell_atmu_regs->rowtar, destid << 22);
- out_be16(priv->dbell_win, data);
- break;
- case RIO_PHY_SERIAL:
- /* In the serial version silicons, such as MPC8548, MPC8641,
- * below operations is must be.
- */
- out_be32(&priv->msg_regs->odmr, 0x00000000);
- out_be32(&priv->msg_regs->odretcr, 0x00000004);
- out_be32(&priv->msg_regs->oddpr, destid << 16);
- out_be32(&priv->msg_regs->oddatr, data);
- out_be32(&priv->msg_regs->odmr, 0x00000001);
- break;
- }
-
- return 0;
-}
-
-/**
* fsl_local_config_read - Generate a MPC85xx local config space read
* @mport: RapidIO master port info
* @index: ID of RapdiIO interface
@@ -362,7 +120,7 @@ static int fsl_local_config_read(struct rio_mport *mport,
{
struct rio_priv *priv = mport->priv;
pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index,
- offset);
+ offset);
*data = in_be32(priv->regs_win + offset);
return 0;
@@ -384,8 +142,8 @@ static int fsl_local_config_write(struct rio_mport *mport,
{
struct rio_priv *priv = mport->priv;
pr_debug
- ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n",
- index, offset, data);
+ ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n",
+ index, offset, data);
out_be32(priv->regs_win + offset, data);
return 0;
@@ -413,7 +171,8 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
u32 rval, err = 0;
pr_debug
- ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
+ ("fsl_rio_config_read:"
+ " index %d destid %d hopcount %d offset %8.8x len %d\n",
index, destid, hopcount, offset, len);
/* 16MB maintenance window possible */
@@ -423,7 +182,7 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
out_be32(&priv->maint_atmu_regs->rowtar,
(destid << 22) | (hopcount << 12) | (offset >> 12));
- out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10));
+ out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10));
data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));
switch (len) {
@@ -470,7 +229,8 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
struct rio_priv *priv = mport->priv;
u8 *data;
pr_debug
- ("fsl_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
+ ("fsl_rio_config_write:"
+ "index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
index, destid, hopcount, offset, len, val);
/* 16MB maintenance windows possible */
@@ -480,7 +240,7 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
out_be32(&priv->maint_atmu_regs->rowtar,
(destid << 22) | (hopcount << 12) | (offset >> 12));
- out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10));
+ out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10));
data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));
switch (len) {
@@ -500,590 +260,7 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
return 0;
}
-/**
- * fsl_add_outb_message - Add message to the MPC85xx outbound message queue
- * @mport: Master port with outbound message queue
- * @rdev: Target of outbound message
- * @mbox: Outbound mailbox
- * @buffer: Message to add to outbound queue
- * @len: Length of message
- *
- * Adds the @buffer message to the MPC85xx outbound message queue. Returns
- * %0 on success or %-EINVAL on failure.
- */
-static int
-fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
- void *buffer, size_t len)
-{
- struct rio_priv *priv = mport->priv;
- u32 omr;
- struct rio_tx_desc *desc = (struct rio_tx_desc *)priv->msg_tx_ring.virt
- + priv->msg_tx_ring.tx_slot;
- int ret = 0;
-
- pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
- "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len);
-
- if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
- ret = -EINVAL;
- goto out;
- }
-
- /* Copy and clear rest of buffer */
- memcpy(priv->msg_tx_ring.virt_buffer[priv->msg_tx_ring.tx_slot], buffer,
- len);
- if (len < (RIO_MAX_MSG_SIZE - 4))
- memset(priv->msg_tx_ring.virt_buffer[priv->msg_tx_ring.tx_slot]
- + len, 0, RIO_MAX_MSG_SIZE - len);
-
- switch (mport->phy_type) {
- case RIO_PHY_PARALLEL:
- /* Set mbox field for message */
- desc->dport = mbox & 0x3;
-
- /* Enable EOMI interrupt, set priority, and set destid */
- desc->dattr = 0x28000000 | (rdev->destid << 2);
- break;
- case RIO_PHY_SERIAL:
- /* Set mbox field for message, and set destid */
- desc->dport = (rdev->destid << 16) | (mbox & 0x3);
-
- /* Enable EOMI interrupt and priority */
- desc->dattr = 0x28000000;
- break;
- }
-
- /* Set transfer size aligned to next power of 2 (in double words) */
- desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
-
- /* Set snooping and source buffer address */
- desc->saddr = 0x00000004
- | priv->msg_tx_ring.phys_buffer[priv->msg_tx_ring.tx_slot];
-
- /* Increment enqueue pointer */
- omr = in_be32(&priv->msg_regs->omr);
- out_be32(&priv->msg_regs->omr, omr | RIO_MSG_OMR_MUI);
-
- /* Go to next descriptor */
- if (++priv->msg_tx_ring.tx_slot == priv->msg_tx_ring.size)
- priv->msg_tx_ring.tx_slot = 0;
-
- out:
- return ret;
-}
-
-/**
- * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
- * @irq: Linux interrupt number
- * @dev_instance: Pointer to interrupt-specific data
- *
- * Handles outbound message interrupts. Executes a register outbound
- * mailbox event handler and acks the interrupt occurrence.
- */
-static irqreturn_t
-fsl_rio_tx_handler(int irq, void *dev_instance)
-{
- int osr;
- struct rio_mport *port = (struct rio_mport *)dev_instance;
- struct rio_priv *priv = port->priv;
-
- osr = in_be32(&priv->msg_regs->osr);
-
- if (osr & RIO_MSG_OSR_TE) {
- pr_info("RIO: outbound message transmission error\n");
- out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_TE);
- goto out;
- }
-
- if (osr & RIO_MSG_OSR_QOI) {
- pr_info("RIO: outbound message queue overflow\n");
- out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_QOI);
- goto out;
- }
-
- if (osr & RIO_MSG_OSR_EOMI) {
- u32 dqp = in_be32(&priv->msg_regs->odqdpar);
- int slot = (dqp - priv->msg_tx_ring.phys) >> 5;
- port->outb_msg[0].mcback(port, priv->msg_tx_ring.dev_id, -1,
- slot);
-
- /* Ack the end-of-message interrupt */
- out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_EOMI);
- }
-
- out:
- return IRQ_HANDLED;
-}
-
-/**
- * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox
- * @mport: Master port implementing the outbound message unit
- * @dev_id: Device specific pointer to pass on event
- * @mbox: Mailbox to open
- * @entries: Number of entries in the outbound mailbox ring
- *
- * Initializes buffer ring, request the outbound message interrupt,
- * and enables the outbound message unit. Returns %0 on success and
- * %-EINVAL or %-ENOMEM on failure.
- */
-static int
-fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
-{
- int i, j, rc = 0;
- struct rio_priv *priv = mport->priv;
-
- if ((entries < RIO_MIN_TX_RING_SIZE) ||
- (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
- rc = -EINVAL;
- goto out;
- }
-
- /* Initialize shadow copy ring */
- priv->msg_tx_ring.dev_id = dev_id;
- priv->msg_tx_ring.size = entries;
-
- for (i = 0; i < priv->msg_tx_ring.size; i++) {
- priv->msg_tx_ring.virt_buffer[i] =
- dma_alloc_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
- &priv->msg_tx_ring.phys_buffer[i], GFP_KERNEL);
- if (!priv->msg_tx_ring.virt_buffer[i]) {
- rc = -ENOMEM;
- for (j = 0; j < priv->msg_tx_ring.size; j++)
- if (priv->msg_tx_ring.virt_buffer[j])
- dma_free_coherent(priv->dev,
- RIO_MSG_BUFFER_SIZE,
- priv->msg_tx_ring.
- virt_buffer[j],
- priv->msg_tx_ring.
- phys_buffer[j]);
- goto out;
- }
- }
-
- /* Initialize outbound message descriptor ring */
- priv->msg_tx_ring.virt = dma_alloc_coherent(priv->dev,
- priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
- &priv->msg_tx_ring.phys, GFP_KERNEL);
- if (!priv->msg_tx_ring.virt) {
- rc = -ENOMEM;
- goto out_dma;
- }
- memset(priv->msg_tx_ring.virt, 0,
- priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE);
- priv->msg_tx_ring.tx_slot = 0;
-
- /* Point dequeue/enqueue pointers at first entry in ring */
- out_be32(&priv->msg_regs->odqdpar, priv->msg_tx_ring.phys);
- out_be32(&priv->msg_regs->odqepar, priv->msg_tx_ring.phys);
-
- /* Configure for snooping */
- out_be32(&priv->msg_regs->osar, 0x00000004);
-
- /* Clear interrupt status */
- out_be32(&priv->msg_regs->osr, 0x000000b3);
-
- /* Hook up outbound message handler */
- rc = request_irq(IRQ_RIO_TX(mport), fsl_rio_tx_handler, 0,
- "msg_tx", (void *)mport);
- if (rc < 0)
- goto out_irq;
-
- /*
- * Configure outbound message unit
- * Snooping
- * Interrupts (all enabled, except QEIE)
- * Chaining mode
- * Disable
- */
- out_be32(&priv->msg_regs->omr, 0x00100220);
-
- /* Set number of entries */
- out_be32(&priv->msg_regs->omr,
- in_be32(&priv->msg_regs->omr) |
- ((get_bitmask_order(entries) - 2) << 12));
-
- /* Now enable the unit */
- out_be32(&priv->msg_regs->omr, in_be32(&priv->msg_regs->omr) | 0x1);
-
- out:
- return rc;
-
- out_irq:
- dma_free_coherent(priv->dev,
- priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
- priv->msg_tx_ring.virt, priv->msg_tx_ring.phys);
-
- out_dma:
- for (i = 0; i < priv->msg_tx_ring.size; i++)
- dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
- priv->msg_tx_ring.virt_buffer[i],
- priv->msg_tx_ring.phys_buffer[i]);
-
- return rc;
-}
-
-/**
- * fsl_close_outb_mbox - Shut down MPC85xx outbound mailbox
- * @mport: Master port implementing the outbound message unit
- * @mbox: Mailbox to close
- *
- * Disables the outbound message unit, free all buffers, and
- * frees the outbound message interrupt.
- */
-static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
-{
- struct rio_priv *priv = mport->priv;
- /* Disable inbound message unit */
- out_be32(&priv->msg_regs->omr, 0);
-
- /* Free ring */
- dma_free_coherent(priv->dev,
- priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
- priv->msg_tx_ring.virt, priv->msg_tx_ring.phys);
-
- /* Free interrupt */
- free_irq(IRQ_RIO_TX(mport), (void *)mport);
-}
-
-/**
- * fsl_rio_rx_handler - MPC85xx inbound message interrupt handler
- * @irq: Linux interrupt number
- * @dev_instance: Pointer to interrupt-specific data
- *
- * Handles inbound message interrupts. Executes a registered inbound
- * mailbox event handler and acks the interrupt occurrence.
- */
-static irqreturn_t
-fsl_rio_rx_handler(int irq, void *dev_instance)
-{
- int isr;
- struct rio_mport *port = (struct rio_mport *)dev_instance;
- struct rio_priv *priv = port->priv;
-
- isr = in_be32(&priv->msg_regs->isr);
-
- if (isr & RIO_MSG_ISR_TE) {
- pr_info("RIO: inbound message reception error\n");
- out_be32((void *)&priv->msg_regs->isr, RIO_MSG_ISR_TE);
- goto out;
- }
-
- /* XXX Need to check/dispatch until queue empty */
- if (isr & RIO_MSG_ISR_DIQI) {
- /*
- * We implement *only* mailbox 0, but can receive messages
- * for any mailbox/letter to that mailbox destination. So,
- * make the callback with an unknown/invalid mailbox number
- * argument.
- */
- port->inb_msg[0].mcback(port, priv->msg_rx_ring.dev_id, -1, -1);
-
- /* Ack the queueing interrupt */
- out_be32(&priv->msg_regs->isr, RIO_MSG_ISR_DIQI);
- }
-
- out:
- return IRQ_HANDLED;
-}
-
-/**
- * fsl_open_inb_mbox - Initialize MPC85xx inbound mailbox
- * @mport: Master port implementing the inbound message unit
- * @dev_id: Device specific pointer to pass on event
- * @mbox: Mailbox to open
- * @entries: Number of entries in the inbound mailbox ring
- *
- * Initializes buffer ring, request the inbound message interrupt,
- * and enables the inbound message unit. Returns %0 on success
- * and %-EINVAL or %-ENOMEM on failure.
- */
-static int
-fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
-{
- int i, rc = 0;
- struct rio_priv *priv = mport->priv;
-
- if ((entries < RIO_MIN_RX_RING_SIZE) ||
- (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
- rc = -EINVAL;
- goto out;
- }
-
- /* Initialize client buffer ring */
- priv->msg_rx_ring.dev_id = dev_id;
- priv->msg_rx_ring.size = entries;
- priv->msg_rx_ring.rx_slot = 0;
- for (i = 0; i < priv->msg_rx_ring.size; i++)
- priv->msg_rx_ring.virt_buffer[i] = NULL;
-
- /* Initialize inbound message ring */
- priv->msg_rx_ring.virt = dma_alloc_coherent(priv->dev,
- priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
- &priv->msg_rx_ring.phys, GFP_KERNEL);
- if (!priv->msg_rx_ring.virt) {
- rc = -ENOMEM;
- goto out;
- }
-
- /* Point dequeue/enqueue pointers at first entry in ring */
- out_be32(&priv->msg_regs->ifqdpar, (u32) priv->msg_rx_ring.phys);
- out_be32(&priv->msg_regs->ifqepar, (u32) priv->msg_rx_ring.phys);
-
- /* Clear interrupt status */
- out_be32(&priv->msg_regs->isr, 0x00000091);
-
- /* Hook up inbound message handler */
- rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
- "msg_rx", (void *)mport);
- if (rc < 0) {
- dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
- priv->msg_tx_ring.virt_buffer[i],
- priv->msg_tx_ring.phys_buffer[i]);
- goto out;
- }
-
- /*
- * Configure inbound message unit:
- * Snooping
- * 4KB max message size
- * Unmask all interrupt sources
- * Disable
- */
- out_be32(&priv->msg_regs->imr, 0x001b0060);
-
- /* Set number of queue entries */
- setbits32(&priv->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12);
-
- /* Now enable the unit */
- setbits32(&priv->msg_regs->imr, 0x1);
-
- out:
- return rc;
-}
-
-/**
- * fsl_close_inb_mbox - Shut down MPC85xx inbound mailbox
- * @mport: Master port implementing the inbound message unit
- * @mbox: Mailbox to close
- *
- * Disables the inbound message unit, free all buffers, and
- * frees the inbound message interrupt.
- */
-static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
-{
- struct rio_priv *priv = mport->priv;
- /* Disable inbound message unit */
- out_be32(&priv->msg_regs->imr, 0);
-
- /* Free ring */
- dma_free_coherent(priv->dev, priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
- priv->msg_rx_ring.virt, priv->msg_rx_ring.phys);
-
- /* Free interrupt */
- free_irq(IRQ_RIO_RX(mport), (void *)mport);
-}
-
-/**
- * fsl_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
- * @mport: Master port implementing the inbound message unit
- * @mbox: Inbound mailbox number
- * @buf: Buffer to add to inbound queue
- *
- * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
- * %0 on success or %-EINVAL on failure.
- */
-static int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
-{
- int rc = 0;
- struct rio_priv *priv = mport->priv;
-
- pr_debug("RIO: fsl_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
- priv->msg_rx_ring.rx_slot);
-
- if (priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot]) {
- printk(KERN_ERR
- "RIO: error adding inbound buffer %d, buffer exists\n",
- priv->msg_rx_ring.rx_slot);
- rc = -EINVAL;
- goto out;
- }
-
- priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot] = buf;
- if (++priv->msg_rx_ring.rx_slot == priv->msg_rx_ring.size)
- priv->msg_rx_ring.rx_slot = 0;
-
- out:
- return rc;
-}
-
-/**
- * fsl_get_inb_message - Fetch inbound message from the MPC85xx message unit
- * @mport: Master port implementing the inbound message unit
- * @mbox: Inbound mailbox number
- *
- * Gets the next available inbound message from the inbound message queue.
- * A pointer to the message is returned on success or NULL on failure.
- */
-static void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
-{
- struct rio_priv *priv = mport->priv;
- u32 phys_buf, virt_buf;
- void *buf = NULL;
- int buf_idx;
-
- phys_buf = in_be32(&priv->msg_regs->ifqdpar);
-
- /* If no more messages, then bail out */
- if (phys_buf == in_be32(&priv->msg_regs->ifqepar))
- goto out2;
-
- virt_buf = (u32) priv->msg_rx_ring.virt + (phys_buf
- - priv->msg_rx_ring.phys);
- buf_idx = (phys_buf - priv->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
- buf = priv->msg_rx_ring.virt_buffer[buf_idx];
-
- if (!buf) {
- printk(KERN_ERR
- "RIO: inbound message copy failed, no buffers\n");
- goto out1;
- }
-
- /* Copy max message size, caller is expected to allocate that big */
- memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
-
- /* Clear the available buffer */
- priv->msg_rx_ring.virt_buffer[buf_idx] = NULL;
-
- out1:
- setbits32(&priv->msg_regs->imr, RIO_MSG_IMR_MI);
-
- out2:
- return buf;
-}
-
-/**
- * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler
- * @irq: Linux interrupt number
- * @dev_instance: Pointer to interrupt-specific data
- *
- * Handles doorbell interrupts. Parses a list of registered
- * doorbell event handlers and executes a matching event handler.
- */
-static irqreturn_t
-fsl_rio_dbell_handler(int irq, void *dev_instance)
-{
- int dsr;
- struct rio_mport *port = (struct rio_mport *)dev_instance;
- struct rio_priv *priv = port->priv;
-
- dsr = in_be32(&priv->msg_regs->dsr);
-
- if (dsr & DOORBELL_DSR_TE) {
- pr_info("RIO: doorbell reception error\n");
- out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_TE);
- goto out;
- }
-
- if (dsr & DOORBELL_DSR_QFI) {
- pr_info("RIO: doorbell queue full\n");
- out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_QFI);
- }
-
- /* XXX Need to check/dispatch until queue empty */
- if (dsr & DOORBELL_DSR_DIQI) {
- u32 dmsg =
- (u32) priv->dbell_ring.virt +
- (in_be32(&priv->msg_regs->dqdpar) & 0xfff);
- struct rio_dbell *dbell;
- int found = 0;
-
- pr_debug
- ("RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n",
- DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
-
- list_for_each_entry(dbell, &port->dbells, node) {
- if ((dbell->res->start <= DBELL_INF(dmsg)) &&
- (dbell->res->end >= DBELL_INF(dmsg))) {
- found = 1;
- break;
- }
- }
- if (found) {
- dbell->dinb(port, dbell->dev_id, DBELL_SID(dmsg), DBELL_TID(dmsg),
- DBELL_INF(dmsg));
- } else {
- pr_debug
- ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",
- DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
- }
- setbits32(&priv->msg_regs->dmr, DOORBELL_DMR_DI);
- out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_DIQI);
- }
-
- out:
- return IRQ_HANDLED;
-}
-
-/**
- * fsl_rio_doorbell_init - MPC85xx doorbell interface init
- * @mport: Master port implementing the inbound doorbell unit
- *
- * Initializes doorbell unit hardware and inbound DMA buffer
- * ring. Called from fsl_rio_setup(). Returns %0 on success
- * or %-ENOMEM on failure.
- */
-static int fsl_rio_doorbell_init(struct rio_mport *mport)
-{
- struct rio_priv *priv = mport->priv;
- int rc = 0;
-
- /* Map outbound doorbell window immediately after maintenance window */
- priv->dbell_win = ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
- RIO_DBELL_WIN_SIZE);
- if (!priv->dbell_win) {
- printk(KERN_ERR
- "RIO: unable to map outbound doorbell window\n");
- rc = -ENOMEM;
- goto out;
- }
-
- /* Initialize inbound doorbells */
- priv->dbell_ring.virt = dma_alloc_coherent(priv->dev, 512 *
- DOORBELL_MESSAGE_SIZE, &priv->dbell_ring.phys, GFP_KERNEL);
- if (!priv->dbell_ring.virt) {
- printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
- rc = -ENOMEM;
- iounmap(priv->dbell_win);
- goto out;
- }
-
- /* Point dequeue/enqueue pointers at first entry in ring */
- out_be32(&priv->msg_regs->dqdpar, (u32) priv->dbell_ring.phys);
- out_be32(&priv->msg_regs->dqepar, (u32) priv->dbell_ring.phys);
-
- /* Clear interrupt status */
- out_be32(&priv->msg_regs->dsr, 0x00000091);
-
- /* Hook up doorbell handler */
- rc = request_irq(IRQ_RIO_BELL(mport), fsl_rio_dbell_handler, 0,
- "dbell_rx", (void *)mport);
- if (rc < 0) {
- iounmap(priv->dbell_win);
- dma_free_coherent(priv->dev, 512 * DOORBELL_MESSAGE_SIZE,
- priv->dbell_ring.virt, priv->dbell_ring.phys);
- printk(KERN_ERR
- "MPC85xx RIO: unable to request inbound doorbell irq");
- goto out;
- }
-
- /* Configure doorbells for snooping, 512 entries, and enable */
- out_be32(&priv->msg_regs->dmr, 0x00108161);
-
- out:
- return rc;
-}
-
-static void port_error_handler(struct rio_mport *port, int offset)
+void fsl_rio_port_error_handler(struct rio_mport *port, int offset)
{
/*XXX: Error recovery is not implemented, we just clear errors */
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
@@ -1098,263 +275,6 @@ static void port_error_handler(struct rio_mport *port, int offset)
out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
}
}
-
-static void msg_unit_error_handler(struct rio_mport *port)
-{
- struct rio_priv *priv = port->priv;
-
- /*XXX: Error recovery is not implemented, we just clear errors */
- out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
-
- out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR);
- out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR);
- out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR);
- out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR);
-
- out_be32(&priv->msg_regs->odsr, ODSR_CLEAR);
- out_be32(&priv->msg_regs->dsr, IDSR_CLEAR);
-
- out_be32(&priv->msg_regs->pwsr, IPWSR_CLEAR);
-}
-
-/**
- * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
- * @irq: Linux interrupt number
- * @dev_instance: Pointer to interrupt-specific data
- *
- * Handles port write interrupts. Parses a list of registered
- * port write event handlers and executes a matching event handler.
- */
-static irqreturn_t
-fsl_rio_port_write_handler(int irq, void *dev_instance)
-{
- u32 ipwmr, ipwsr;
- struct rio_mport *port = (struct rio_mport *)dev_instance;
- struct rio_priv *priv = port->priv;
- u32 epwisr, tmp;
-
- epwisr = in_be32(priv->regs_win + RIO_EPWISR);
- if (!(epwisr & RIO_EPWISR_PW))
- goto pw_done;
-
- ipwmr = in_be32(&priv->msg_regs->pwmr);
- ipwsr = in_be32(&priv->msg_regs->pwsr);
-
-#ifdef DEBUG_PW
- pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
- if (ipwsr & RIO_IPWSR_QF)
- pr_debug(" QF");
- if (ipwsr & RIO_IPWSR_TE)
- pr_debug(" TE");
- if (ipwsr & RIO_IPWSR_QFI)
- pr_debug(" QFI");
- if (ipwsr & RIO_IPWSR_PWD)
- pr_debug(" PWD");
- if (ipwsr & RIO_IPWSR_PWB)
- pr_debug(" PWB");
- pr_debug(" )\n");
-#endif
- /* Schedule deferred processing if PW was received */
- if (ipwsr & RIO_IPWSR_QFI) {
- /* Save PW message (if there is room in FIFO),
- * otherwise discard it.
- */
- if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) {
- priv->port_write_msg.msg_count++;
- kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt,
- RIO_PW_MSG_SIZE);
- } else {
- priv->port_write_msg.discard_count++;
- pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
- priv->port_write_msg.discard_count);
- }
- /* Clear interrupt and issue Clear Queue command. This allows
- * another port-write to be received.
- */
- out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_QFI);
- out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
-
- schedule_work(&priv->pw_work);
- }
-
- if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
- priv->port_write_msg.err_count++;
- pr_debug("RIO: Port-Write Transaction Err (%d)\n",
- priv->port_write_msg.err_count);
- /* Clear Transaction Error: port-write controller should be
- * disabled when clearing this error
- */
- out_be32(&priv->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
- out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_TE);
- out_be32(&priv->msg_regs->pwmr, ipwmr);
- }
-
- if (ipwsr & RIO_IPWSR_PWD) {
- priv->port_write_msg.discard_count++;
- pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
- priv->port_write_msg.discard_count);
- out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_PWD);
- }
-
-pw_done:
- if (epwisr & RIO_EPWISR_PINT1) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
- pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
- port_error_handler(port, 0);
- }
-
- if (epwisr & RIO_EPWISR_PINT2) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
- pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
- port_error_handler(port, 1);
- }
-
- if (epwisr & RIO_EPWISR_MU) {
- tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
- pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
- msg_unit_error_handler(port);
- }
-
- return IRQ_HANDLED;
-}
-
-static void fsl_pw_dpc(struct work_struct *work)
-{
- struct rio_priv *priv = container_of(work, struct rio_priv, pw_work);
- unsigned long flags;
- u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
-
- /*
- * Process port-write messages
- */
- spin_lock_irqsave(&priv->pw_fifo_lock, flags);
- while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
- RIO_PW_MSG_SIZE)) {
- /* Process one message */
- spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
-#ifdef DEBUG_PW
- {
- u32 i;
- pr_debug("%s : Port-Write Message:", __func__);
- for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
- if ((i%4) == 0)
- pr_debug("\n0x%02x: 0x%08x", i*4,
- msg_buffer[i]);
- else
- pr_debug(" 0x%08x", msg_buffer[i]);
- }
- pr_debug("\n");
- }
-#endif
- /* Pass the port-write message to RIO core for processing */
- rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
- spin_lock_irqsave(&priv->pw_fifo_lock, flags);
- }
- spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
-}
-
-/**
- * fsl_rio_pw_enable - enable/disable port-write interface init
- * @mport: Master port implementing the port write unit
- * @enable: 1=enable; 0=disable port-write message handling
- */
-static int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
-{
- struct rio_priv *priv = mport->priv;
- u32 rval;
-
- rval = in_be32(&priv->msg_regs->pwmr);
-
- if (enable)
- rval |= RIO_IPWMR_PWE;
- else
- rval &= ~RIO_IPWMR_PWE;
-
- out_be32(&priv->msg_regs->pwmr, rval);
-
- return 0;
-}
-
-/**
- * fsl_rio_port_write_init - MPC85xx port write interface init
- * @mport: Master port implementing the port write unit
- *
- * Initializes port write unit hardware and DMA buffer
- * ring. Called from fsl_rio_setup(). Returns %0 on success
- * or %-ENOMEM on failure.
- */
-static int fsl_rio_port_write_init(struct rio_mport *mport)
-{
- struct rio_priv *priv = mport->priv;
- int rc = 0;
-
- /* Following configurations require a disabled port write controller */
- out_be32(&priv->msg_regs->pwmr,
- in_be32(&priv->msg_regs->pwmr) & ~RIO_IPWMR_PWE);
-
- /* Initialize port write */
- priv->port_write_msg.virt = dma_alloc_coherent(priv->dev,
- RIO_PW_MSG_SIZE,
- &priv->port_write_msg.phys, GFP_KERNEL);
- if (!priv->port_write_msg.virt) {
- pr_err("RIO: unable allocate port write queue\n");
- return -ENOMEM;
- }
-
- priv->port_write_msg.err_count = 0;
- priv->port_write_msg.discard_count = 0;
-
- /* Point dequeue/enqueue pointers at first entry */
- out_be32(&priv->msg_regs->epwqbar, 0);
- out_be32(&priv->msg_regs->pwqbar, (u32) priv->port_write_msg.phys);
-
- pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
- in_be32(&priv->msg_regs->epwqbar),
- in_be32(&priv->msg_regs->pwqbar));
-
- /* Clear interrupt status IPWSR */
- out_be32(&priv->msg_regs->pwsr,
- (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
-
- /* Configure port write contoller for snooping enable all reporting,
- clear queue full */
- out_be32(&priv->msg_regs->pwmr,
- RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
-
-
- /* Hook up port-write handler */
- rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler,
- IRQF_SHARED, "port-write", (void *)mport);
- if (rc < 0) {
- pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
- goto err_out;
- }
- /* Enable Error Interrupt */
- out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
-
- INIT_WORK(&priv->pw_work, fsl_pw_dpc);
- spin_lock_init(&priv->pw_fifo_lock);
- if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
- pr_err("FIFO allocation failed\n");
- rc = -ENOMEM;
- goto err_out_irq;
- }
-
- pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
- in_be32(&priv->msg_regs->pwmr),
- in_be32(&priv->msg_regs->pwsr));
-
- return rc;
-
-err_out_irq:
- free_irq(IRQ_RIO_PW(mport), (void *)mport);
-err_out:
- dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE,
- priv->port_write_msg.virt,
- priv->port_write_msg.phys);
- return rc;
-}
-
static inline void fsl_rio_info(struct device *dev, u32 ccsr)
{
const char *str;
@@ -1429,7 +349,8 @@ int fsl_rio_setup(struct platform_device *dev)
dev->dev.of_node->full_name);
return -EFAULT;
}
- dev_info(&dev->dev, "Of-device full name %s\n", dev->dev.of_node->full_name);
+ dev_info(&dev->dev, "Of-device full name %s\n",
+ dev->dev.of_node->full_name);
dev_info(&dev->dev, "Regs: %pR\n", ®s);
dt_range = of_get_property(dev->dev.of_node, "ranges", &rlen);
@@ -1469,15 +390,7 @@ int fsl_rio_setup(struct platform_device *dev)
ops->lcwrite = fsl_local_config_write;
ops->cread = fsl_rio_config_read;
ops->cwrite = fsl_rio_config_write;
- ops->dsend = fsl_rio_doorbell_send;
ops->pwenable = fsl_rio_pw_enable;
- ops->open_outb_mbox = fsl_open_outb_mbox;
- ops->open_inb_mbox = fsl_open_inb_mbox;
- ops->close_outb_mbox = fsl_close_outb_mbox;
- ops->close_inb_mbox = fsl_close_inb_mbox;
- ops->add_outb_message = fsl_add_outb_message;
- ops->add_inb_buffer = fsl_add_inb_buffer;
- ops->get_inb_message = fsl_get_inb_message;
port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
if (!port) {
@@ -1507,16 +420,8 @@ int fsl_rio_setup(struct platform_device *dev)
goto err_res;
}
- priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0);
- priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2);
- priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3);
- priv->rxirq = irq_of_parse_and_map(dev->dev.of_node, 4);
- dev_info(&dev->dev, "pwirq: %d, bellirq: %d, txirq: %d, rxirq %d\n",
- priv->pwirq, priv->bellirq, priv->txirq, priv->rxirq);
-
- rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
- rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
- rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
+ priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0);
+ dev_info(&dev->dev, "pwirq: %d\n", priv->pwirq);
strcpy(port->name, "RIO0 mport");
priv->dev = &dev->dev;
@@ -1538,7 +443,7 @@ int fsl_rio_setup(struct platform_device *dev)
/* Checking the port training status */
if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) {
dev_err(&dev->dev, "Port is not ready. "
- "Try to restart connection...\n");
+ "Try to restart connection...\n");
switch (port->phy_type) {
case RIO_PHY_SERIAL:
/* Disable ports */
@@ -1582,10 +487,6 @@ int fsl_rio_setup(struct platform_device *dev)
priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win
+ RIO_ATMU_REGS_OFFSET);
priv->maint_atmu_regs = priv->atmu_regs + 1;
- priv->dbell_atmu_regs = priv->atmu_regs + 2;
- priv->msg_regs = (struct rio_msg_regs *)(priv->regs_win +
- ((port->phy_type == RIO_PHY_SERIAL) ?
- RIO_S_MSG_REGS_OFFSET : RIO_P_MSG_REGS_OFFSET));
/* Set to receive any dist ID for serial RapidIO controller. */
if (port->phy_type == RIO_PHY_SERIAL)
@@ -1598,11 +499,8 @@ int fsl_rio_setup(struct platform_device *dev)
priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE);
- /* Configure outbound doorbell window */
- out_be32(&priv->dbell_atmu_regs->rowbar,
- (law_start + RIO_MAINT_WIN_SIZE) >> 12);
- out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b); /* 4k */
- fsl_rio_doorbell_init(port);
+ fsl_rio_setup_rmu(port, dev->dev.of_node);
+
fsl_rio_port_write_init(port);
return 0;
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h
new file mode 100644
index 0000000..f888a1e
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rio.h
@@ -0,0 +1,78 @@
+/*
+ * Freescale MPC85xx/MPC86xx RapidIO support
+ *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - fixed maintenance access routines, check for aligned access
+ *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write message handling
+ * - Added Machine Check exception handling
+ *
+ * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc.
+ * Zhang Wei <wei.zhang@freescale.com>
+ * Lian Minghuan-B31939 <Minghuan.Lian@freescale.com>
+ * Liu Gang <Gang.Liu@freescale.com>
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __FSL_RIO_H
+#define __FSL_RIO_H
+
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/kfifo.h>
+
+#define RIO_REGS_WIN(mport) (((struct rio_priv *)(mport->priv))->regs_win)
+
+#define RIO_MAINT_WIN_SIZE 0x400000
+#define RIO_LTLEDCSR 0x0608
+
+struct rio_atmu_regs {
+ u32 rowtar;
+ u32 rowtear;
+ u32 rowbar;
+ u32 pad2;
+ u32 rowar;
+ u32 pad3[3];
+};
+
+struct rio_port_write_msg {
+ void *virt;
+ dma_addr_t phys;
+ u32 msg_count;
+ u32 err_count;
+ u32 discard_count;
+};
+
+struct rio_priv {
+ struct device *dev;
+ void __iomem *regs_win;
+ struct rio_atmu_regs __iomem *atmu_regs;
+ struct rio_atmu_regs __iomem *maint_atmu_regs;
+ void __iomem *maint_win;
+ struct rio_port_write_msg port_write_msg;
+ int pwirq;
+ struct work_struct pw_work;
+ struct kfifo pw_fifo;
+ spinlock_t pw_fifo_lock;
+ void *rmm_handle; /* RapidIO message manager(unit) Handle */
+};
+
+extern void __iomem *rio_regs_win;
+
+extern int fsl_rio_setup_rmu(struct rio_mport *mport,
+ struct device_node *node);
+extern int fsl_rio_port_write_init(struct rio_mport *mport);
+extern int fsl_rio_pw_enable(struct rio_mport *mport, int enable);
+extern void fsl_rio_port_error_handler(struct rio_mport *port, int offset);
+
+#endif
diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c
new file mode 100644
index 0000000..0a3e6cf
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rmu.c
@@ -0,0 +1,1163 @@
+/*
+ * Freescale MPC85xx/MPC86xx RapidIO RMU support
+ *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - fixed maintenance access routines, check for aligned access
+ *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write message handling
+ * - Added Machine Check exception handling
+ *
+ * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc.
+ * Zhang Wei <wei.zhang@freescale.com>
+ * Lian Minghuan-B31939 <Minghuan.Lian@freescale.com>
+ * Liu Gang <Gang.Liu@freescale.com>
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#include "fsl_rio.h"
+
+#define GET_RMM_HANDLE(mport) \
+ (((struct rio_priv *)(mport->priv))->rmm_handle)
+
+/* RapidIO definition irq, which read from OF-tree */
+#define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq)
+#define IRQ_RIO_BELL(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->bellirq)
+#define IRQ_RIO_TX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->txirq)
+#define IRQ_RIO_RX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->rxirq)
+
+#define RIO_MIN_TX_RING_SIZE 2
+#define RIO_MAX_TX_RING_SIZE 2048
+#define RIO_MIN_RX_RING_SIZE 2
+#define RIO_MAX_RX_RING_SIZE 2048
+
+#define RIO_IPWMR_SEN 0x00100000
+#define RIO_IPWMR_QFIE 0x00000100
+#define RIO_IPWMR_EIE 0x00000020
+#define RIO_IPWMR_CQ 0x00000002
+#define RIO_IPWMR_PWE 0x00000001
+
+#define RIO_IPWSR_QF 0x00100000
+#define RIO_IPWSR_TE 0x00000080
+#define RIO_IPWSR_QFI 0x00000010
+#define RIO_IPWSR_PWD 0x00000008
+#define RIO_IPWSR_PWB 0x00000004
+
+#define RIO_EPWISR 0x10010
+/* EPWISR Error match value */
+#define RIO_EPWISR_PINT1 0x80000000
+#define RIO_EPWISR_PINT2 0x40000000
+#define RIO_EPWISR_MU 0x00000002
+#define RIO_EPWISR_PW 0x00000001
+
+#define IPWSR_CLEAR 0x98
+#define OMSR_CLEAR 0x1cb3
+#define IMSR_CLEAR 0x491
+#define IDSR_CLEAR 0x91
+#define ODSR_CLEAR 0x1c00
+#define LTLEECSR_ENABLE_ALL 0xFFC000FC
+#define RIO_LTLEECSR 0x060c
+
+#define RIO_IM0SR 0x13064
+#define RIO_IM1SR 0x13164
+#define RIO_OM0SR 0x13004
+#define RIO_OM1SR 0x13104
+
+#define RIO_P_MSG_REGS_OFFSET 0x11000
+#define RIO_S_MSG_REGS_OFFSET 0x13000
+
+#define RIO_DBELL_WIN_SIZE 0x1000
+
+#define RIO_MSG_OMR_MUI 0x00000002
+#define RIO_MSG_OSR_TE 0x00000080
+#define RIO_MSG_OSR_QOI 0x00000020
+#define RIO_MSG_OSR_QFI 0x00000010
+#define RIO_MSG_OSR_MUB 0x00000004
+#define RIO_MSG_OSR_EOMI 0x00000002
+#define RIO_MSG_OSR_QEI 0x00000001
+
+#define RIO_MSG_IMR_MI 0x00000002
+#define RIO_MSG_ISR_TE 0x00000080
+#define RIO_MSG_ISR_QFI 0x00000010
+#define RIO_MSG_ISR_DIQI 0x00000001
+
+#define RIO_MSG_DESC_SIZE 32
+#define RIO_MSG_BUFFER_SIZE 4096
+
+#define DOORBELL_DMR_DI 0x00000002
+#define DOORBELL_DSR_TE 0x00000080
+#define DOORBELL_DSR_QFI 0x00000010
+#define DOORBELL_DSR_DIQI 0x00000001
+#define DOORBELL_TID_OFFSET 0x02
+#define DOORBELL_SID_OFFSET 0x04
+#define DOORBELL_INFO_OFFSET 0x06
+
+#define DOORBELL_MESSAGE_SIZE 0x08
+#define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET))
+#define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET))
+#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET))
+
+struct rio_msg_regs {
+ u32 omr; /* 0xD_3000 - Outbound message 0 mode register */
+ u32 osr; /* 0xD_3004 - Outbound message 0 status register */
+ u32 pad1;
+ u32 odqdpar; /* 0xD_300C - Outbound message 0 descriptor queue
+ dequeue pointer address register */
+ u32 pad2;
+ u32 osar; /* 0xD_3014 - Outbound message 0 source address
+ register */
+ u32 odpr; /* 0xD_3018 - Outbound message 0 destination port
+ register */
+ u32 odatr; /* 0xD_301C - Outbound message 0 destination attributes
+ Register*/
+ u32 odcr; /* 0xD_3020 - Outbound message 0 double-word count
+ register */
+ u32 pad3;
+ u32 odqepar; /* 0xD_3028 - Outbound message 0 descriptor queue
+ enqueue pointer address register */
+ u32 pad4[13];
+ u32 imr; /* 0xD_3060 - Inbound message 0 mode register */
+ u32 isr; /* 0xD_3064 - Inbound message 0 status register */
+ u32 pad5;
+ u32 ifqdpar; /* 0xD_306C - Inbound message 0 frame queue dequeue
+ pointer address register*/
+ u32 pad6;
+ u32 ifqepar; /* 0xD_3074 - Inbound message 0 frame queue enqueue
+ pointer address register */
+ u32 pad7[226];
+ u32 odmr; /* 0xD_3400 - Outbound doorbell mode register */
+ u32 odsr; /* 0xD_3404 - Outbound doorbell status register */
+ u32 res0[4];
+ u32 oddpr; /* 0xD_3418 - Outbound doorbell destination port
+ register */
+ u32 oddatr; /* 0xD_341c - Outbound doorbell destination attributes
+ register */
+ u32 res1[3];
+ u32 odretcr; /* 0xD_342C - Outbound doorbell retry error threshold
+ configuration register */
+ u32 res2[12];
+ u32 dmr; /* 0xD_3460 - Inbound doorbell mode register */
+ u32 dsr; /* 0xD_3464 - Inbound doorbell status register */
+ u32 pad8;
+ u32 dqdpar; /* 0xD_346C - Inbound doorbell queue dequeue Pointer
+ address register */
+ u32 pad9;
+ u32 dqepar; /* 0xD_3474 - Inbound doorbell Queue enqueue pointer
+ address register */
+ u32 pad10[26];
+ u32 pwmr; /* 0xD_34E0 - Inbound port-write mode register */
+ u32 pwsr; /* 0xD_34E4 - Inbound port-write status register */
+ u32 epwqbar; /* 0xD_34E8 - Extended Port-Write Queue Base Address
+ register */
+ u32 pwqbar; /* 0xD_34EC - Inbound port-write queue base address
+ register */
+};
+
+struct rio_tx_desc {
+ u32 res1;
+ u32 saddr;
+ u32 dport;
+ u32 dattr;
+ u32 res2;
+ u32 res3;
+ u32 dwcnt;
+ u32 res4;
+};
+
+struct rio_dbell_ring {
+ void *virt;
+ dma_addr_t phys;
+};
+
+struct rio_msg_tx_ring {
+ void *virt;
+ dma_addr_t phys;
+ void *virt_buffer[RIO_MAX_TX_RING_SIZE];
+ dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
+ int tx_slot;
+ int size;
+ void *dev_id;
+};
+
+struct rio_msg_rx_ring {
+ void *virt;
+ dma_addr_t phys;
+ void *virt_buffer[RIO_MAX_RX_RING_SIZE];
+ int rx_slot;
+ int size;
+ void *dev_id;
+};
+
+struct fsl_rmu {
+ struct rio_atmu_regs __iomem *dbell_atmu_regs;
+ void __iomem *dbell_win;
+ struct rio_msg_regs __iomem *msg_regs;
+ struct rio_dbell_ring dbell_ring;
+ struct rio_msg_tx_ring msg_tx_ring;
+ struct rio_msg_rx_ring msg_rx_ring;
+ int bellirq;
+ int txirq;
+ int rxirq;
+};
+
+/**
+ * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles outbound message interrupts. Executes a register outbound
+ * mailbox event handler and acks the interrupt occurrence.
+ */
+static irqreturn_t
+fsl_rio_tx_handler(int irq, void *dev_instance)
+{
+ int osr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
+
+ osr = in_be32(&rmu->msg_regs->osr);
+
+ if (osr & RIO_MSG_OSR_TE) {
+ pr_info("RIO: outbound message transmission error\n");
+ out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_TE);
+ goto out;
+ }
+
+ if (osr & RIO_MSG_OSR_QOI) {
+ pr_info("RIO: outbound message queue overflow\n");
+ out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_QOI);
+ goto out;
+ }
+
+ if (osr & RIO_MSG_OSR_EOMI) {
+ u32 dqp = in_be32(&rmu->msg_regs->odqdpar);
+ int slot = (dqp - rmu->msg_tx_ring.phys) >> 5;
+ port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id, -1,
+ slot);
+
+ /* Ack the end-of-message interrupt */
+ out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_EOMI);
+ }
+
+out:
+ return IRQ_HANDLED;
+}
+
+/**
+ * fsl_rio_rx_handler - MPC85xx inbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles inbound message interrupts. Executes a registered inbound
+ * mailbox event handler and acks the interrupt occurrence.
+ */
+static irqreturn_t
+fsl_rio_rx_handler(int irq, void *dev_instance)
+{
+ int isr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
+
+ isr = in_be32(&rmu->msg_regs->isr);
+
+ if (isr & RIO_MSG_ISR_TE) {
+ pr_info("RIO: inbound message reception error\n");
+ out_be32((void *)&rmu->msg_regs->isr, RIO_MSG_ISR_TE);
+ goto out;
+ }
+
+ /* XXX Need to check/dispatch until queue empty */
+ if (isr & RIO_MSG_ISR_DIQI) {
+ /*
+ * We implement *only* mailbox 0, but can receive messages
+ * for any mailbox/letter to that mailbox destination. So,
+ * make the callback with an unknown/invalid mailbox number
+ * argument.
+ */
+ port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id, -1, -1);
+
+ /* Ack the queueing interrupt */
+ out_be32(&rmu->msg_regs->isr, RIO_MSG_ISR_DIQI);
+ }
+
+out:
+ return IRQ_HANDLED;
+}
+
+/**
+ * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles doorbell interrupts. Parses a list of registered
+ * doorbell event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+fsl_rio_dbell_handler(int irq, void *dev_instance)
+{
+ int dsr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
+
+ dsr = in_be32(&rmu->msg_regs->dsr);
+
+ if (dsr & DOORBELL_DSR_TE) {
+ pr_info("RIO: doorbell reception error\n");
+ out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_TE);
+ goto out;
+ }
+
+ if (dsr & DOORBELL_DSR_QFI) {
+ pr_info("RIO: doorbell queue full\n");
+ out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_QFI);
+ }
+
+ /* XXX Need to check/dispatch until queue empty */
+ if (dsr & DOORBELL_DSR_DIQI) {
+ u32 dmsg =
+ (u32) rmu->dbell_ring.virt +
+ (in_be32(&rmu->msg_regs->dqdpar) & 0xfff);
+ struct rio_dbell *dbell;
+ int found = 0;
+
+ pr_debug
+ ("RIO: processing doorbell,"
+ " sid %2.2x tid %2.2x info %4.4x\n",
+ DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+
+ list_for_each_entry(dbell, &port->dbells, node) {
+ if ((dbell->res->start <= DBELL_INF(dmsg)) &&
+ (dbell->res->end >= DBELL_INF(dmsg))) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ dbell->dinb(port, dbell->dev_id,
+ DBELL_SID(dmsg),
+ DBELL_TID(dmsg), DBELL_INF(dmsg));
+ } else {
+ pr_debug
+ ("RIO: spurious doorbell,"
+ " sid %2.2x tid %2.2x info %4.4x\n",
+ DBELL_SID(dmsg), DBELL_TID(dmsg),
+ DBELL_INF(dmsg));
+ }
+ setbits32(&rmu->msg_regs->dmr, DOORBELL_DMR_DI);
+ out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_DIQI);
+ }
+
+out:
+ return IRQ_HANDLED;
+}
+
+void msg_unit_error_handler(struct rio_mport *port)
+{
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(port);
+
+ /*XXX: Error recovery is not implemented, we just clear errors */
+ out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
+
+ out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR);
+ out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR);
+ out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR);
+ out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR);
+
+ out_be32(&rmu->msg_regs->odsr, ODSR_CLEAR);
+ out_be32(&rmu->msg_regs->dsr, IDSR_CLEAR);
+
+ out_be32(&rmu->msg_regs->pwsr, IPWSR_CLEAR);
+}
+
+/**
+ * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles port write interrupts. Parses a list of registered
+ * port write event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+fsl_rio_port_write_handler(int irq, void *dev_instance)
+{
+ u32 ipwmr, ipwsr;
+ struct rio_mport *port = (struct rio_mport *)dev_instance;
+ struct rio_priv *priv = port->priv;
+ struct fsl_rmu *rmu;
+ u32 epwisr, tmp;
+
+ rmu = GET_RMM_HANDLE(port);
+ epwisr = in_be32(priv->regs_win + RIO_EPWISR);
+ if (!(epwisr & RIO_EPWISR_PW))
+ goto pw_done;
+
+ ipwmr = in_be32(&rmu->msg_regs->pwmr);
+ ipwsr = in_be32(&rmu->msg_regs->pwsr);
+
+#ifdef DEBUG_PW
+ pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
+ if (ipwsr & RIO_IPWSR_QF)
+ pr_debug(" QF");
+ if (ipwsr & RIO_IPWSR_TE)
+ pr_debug(" TE");
+ if (ipwsr & RIO_IPWSR_QFI)
+ pr_debug(" QFI");
+ if (ipwsr & RIO_IPWSR_PWD)
+ pr_debug(" PWD");
+ if (ipwsr & RIO_IPWSR_PWB)
+ pr_debug(" PWB");
+ pr_debug(" )\n");
+#endif
+ /* Schedule deferred processing if PW was received */
+ if (ipwsr & RIO_IPWSR_QFI) {
+ /* Save PW message (if there is room in FIFO),
+ * otherwise discard it.
+ */
+ if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) {
+ priv->port_write_msg.msg_count++;
+ kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt,
+ RIO_PW_MSG_SIZE);
+ } else {
+ priv->port_write_msg.discard_count++;
+ pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
+ priv->port_write_msg.discard_count);
+ }
+ /* Clear interrupt and issue Clear Queue command. This allows
+ * another port-write to be received.
+ */
+ out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_QFI);
+ out_be32(&rmu->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+
+ schedule_work(&priv->pw_work);
+ }
+
+ if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
+ priv->port_write_msg.err_count++;
+ pr_debug("RIO: Port-Write Transaction Err (%d)\n",
+ priv->port_write_msg.err_count);
+ /* Clear Transaction Error: port-write controller should be
+ * disabled when clearing this error
+ */
+ out_be32(&rmu->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
+ out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_TE);
+ out_be32(&rmu->msg_regs->pwmr, ipwmr);
+ }
+
+ if (ipwsr & RIO_IPWSR_PWD) {
+ priv->port_write_msg.discard_count++;
+ pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
+ priv->port_write_msg.discard_count);
+ out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_PWD);
+ }
+
+pw_done:
+ if (epwisr & RIO_EPWISR_PINT1) {
+ tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+ fsl_rio_port_error_handler(port, 0);
+ }
+
+ if (epwisr & RIO_EPWISR_PINT2) {
+ tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+ fsl_rio_port_error_handler(port, 1);
+ }
+
+ if (epwisr & RIO_EPWISR_MU) {
+ tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+ msg_unit_error_handler(port);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void fsl_pw_dpc(struct work_struct *work)
+{
+ struct rio_priv *priv = container_of(work, struct rio_priv, pw_work);
+ unsigned long flags;
+ u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
+
+ /*
+ * Process port-write messages
+ */
+ spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+ while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
+ RIO_PW_MSG_SIZE)) {
+ /* Process one message */
+ spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+#ifdef DEBUG_PW
+ {
+ u32 i;
+ pr_debug("%s : Port-Write Message:", __func__);
+ for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
+ if ((i%4) == 0)
+ pr_debug("\n0x%02x: 0x%08x", i*4,
+ msg_buffer[i]);
+ else
+ pr_debug(" 0x%08x", msg_buffer[i]);
+ }
+ pr_debug("\n");
+ }
+#endif
+ /* Pass the port-write message to RIO core for processing */
+ rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
+ spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+}
+
+/**
+ * fsl_rio_pw_enable - enable/disable port-write interface init
+ * @mport: Master port implementing the port write unit
+ * @enable: 1=enable; 0=disable port-write message handling
+ */
+int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
+{
+ struct fsl_rmu *rmu;
+ u32 rval;
+
+ rmu = GET_RMM_HANDLE(mport);
+
+ rval = in_be32(&rmu->msg_regs->pwmr);
+
+ if (enable)
+ rval |= RIO_IPWMR_PWE;
+ else
+ rval &= ~RIO_IPWMR_PWE;
+
+ out_be32(&rmu->msg_regs->pwmr, rval);
+
+ return 0;
+}
+
+/**
+ * fsl_rio_port_write_init - MPC85xx port write interface init
+ * @mport: Master port implementing the port write unit
+ *
+ * Initializes port write unit hardware and DMA buffer
+ * ring. Called from fsl_rio_setup(). Returns %0 on success
+ * or %-ENOMEM on failure.
+ */
+
+int fsl_rio_port_write_init(struct rio_mport *mport)
+{
+ struct rio_priv *priv = mport->priv;
+ struct fsl_rmu *rmu;
+ int rc = 0;
+
+ rmu = GET_RMM_HANDLE(mport);
+
+ /* Following configurations require a disabled port write controller */
+ out_be32(&rmu->msg_regs->pwmr,
+ in_be32(&rmu->msg_regs->pwmr) & ~RIO_IPWMR_PWE);
+
+ /* Initialize port write */
+ priv->port_write_msg.virt = dma_alloc_coherent(priv->dev,
+ RIO_PW_MSG_SIZE,
+ &priv->port_write_msg.phys, GFP_KERNEL);
+ if (!priv->port_write_msg.virt) {
+ pr_err("RIO: unable allocate port write queue\n");
+ return -ENOMEM;
+ }
+
+ priv->port_write_msg.err_count = 0;
+ priv->port_write_msg.discard_count = 0;
+
+ /* Point dequeue/enqueue pointers at first entry */
+ out_be32(&rmu->msg_regs->epwqbar, 0);
+ out_be32(&rmu->msg_regs->pwqbar, (u32) priv->port_write_msg.phys);
+
+ pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
+ in_be32(&rmu->msg_regs->epwqbar),
+ in_be32(&rmu->msg_regs->pwqbar));
+
+ /* Clear interrupt status IPWSR */
+ out_be32(&rmu->msg_regs->pwsr,
+ (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
+
+ /* Configure port write contoller for snooping enable all reporting,
+ clear queue full */
+ out_be32(&rmu->msg_regs->pwmr,
+ RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
+
+
+ /* Hook up port-write handler */
+ rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler,
+ IRQF_SHARED, "port-write", (void *)mport);
+ if (rc < 0) {
+ pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
+ goto err_out;
+ }
+ /* Enable Error Interrupt */
+ out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
+
+ INIT_WORK(&priv->pw_work, fsl_pw_dpc);
+ spin_lock_init(&priv->pw_fifo_lock);
+ if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
+ pr_err("FIFO allocation failed\n");
+ rc = -ENOMEM;
+ goto err_out_irq;
+ }
+
+ pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
+ in_be32(&rmu->msg_regs->pwmr),
+ in_be32(&rmu->msg_regs->pwsr));
+
+ return rc;
+
+err_out_irq:
+ free_irq(IRQ_RIO_PW(mport), (void *)mport);
+err_out:
+ dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE,
+ priv->port_write_msg.virt,
+ priv->port_write_msg.phys);
+ return rc;
+}
+
+/**
+ * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @mport: RapidIO master port info
+ * @index: ID of RapidIO interface
+ * @destid: Destination ID of target device
+ * @data: 16-bit info field of RapidIO doorbell message
+ *
+ * Sends a MPC85xx doorbell message. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+static int fsl_rio_doorbell_send(struct rio_mport *mport,
+ int index, u16 destid, u16 data)
+{
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+
+ pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
+ index, destid, data);
+ switch (mport->phy_type) {
+ case RIO_PHY_PARALLEL:
+ out_be32(&rmu->dbell_atmu_regs->rowtar, destid << 22);
+ out_be16(rmu->dbell_win, data);
+ break;
+ case RIO_PHY_SERIAL:
+ /* In the serial version silicons, such as MPC8548, MPC8641,
+ * below operations is must be.
+ */
+ out_be32(&rmu->msg_regs->odmr, 0x00000000);
+ out_be32(&rmu->msg_regs->odretcr, 0x00000004);
+ out_be32(&rmu->msg_regs->oddpr, destid << 16);
+ out_be32(&rmu->msg_regs->oddatr, data);
+ out_be32(&rmu->msg_regs->odmr, 0x00000001);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * fsl_add_outb_message - Add message to the MPC85xx outbound message queue
+ * @mport: Master port with outbound message queue
+ * @rdev: Target of outbound message
+ * @mbox: Outbound mailbox
+ * @buffer: Message to add to outbound queue
+ * @len: Length of message
+ *
+ * Adds the @buffer message to the MPC85xx outbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+static int
+fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
+ void *buffer, size_t len)
+{
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+ u32 omr;
+ struct rio_tx_desc *desc = (struct rio_tx_desc *)rmu->msg_tx_ring.virt
+ + rmu->msg_tx_ring.tx_slot;
+ int ret = 0;
+
+ pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \
+ "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len);
+
+ if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Copy and clear rest of buffer */
+ memcpy(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot], buffer,
+ len);
+ if (len < (RIO_MAX_MSG_SIZE - 4))
+ memset(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot]
+ + len, 0, RIO_MAX_MSG_SIZE - len);
+
+ switch (mport->phy_type) {
+ case RIO_PHY_PARALLEL:
+ /* Set mbox field for message */
+ desc->dport = mbox & 0x3;
+
+ /* Enable EOMI interrupt, set priority, and set destid */
+ desc->dattr = 0x28000000 | (rdev->destid << 2);
+ break;
+ case RIO_PHY_SERIAL:
+ /* Set mbox field for message, and set destid */
+ desc->dport = (rdev->destid << 16) | (mbox & 0x3);
+
+ /* Enable EOMI interrupt and priority */
+ desc->dattr = 0x28000000;
+ break;
+ }
+
+ /* Set transfer size aligned to next power of 2 (in double words) */
+ desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
+
+ /* Set snooping and source buffer address */
+ desc->saddr = 0x00000004
+ | rmu->msg_tx_ring.phys_buffer[rmu->msg_tx_ring.tx_slot];
+
+ /* Increment enqueue pointer */
+ omr = in_be32(&rmu->msg_regs->omr);
+ out_be32(&rmu->msg_regs->omr, omr | RIO_MSG_OMR_MUI);
+
+ /* Go to next descriptor */
+ if (++rmu->msg_tx_ring.tx_slot == rmu->msg_tx_ring.size)
+ rmu->msg_tx_ring.tx_slot = 0;
+
+out:
+ return ret;
+}
+
+/**
+ * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @dev_id: Device specific pointer to pass on event
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the outbound mailbox ring
+ *
+ * Initializes buffer ring, request the outbound message interrupt,
+ * and enables the outbound message unit. Returns %0 on success and
+ * %-EINVAL or %-ENOMEM on failure.
+ */
+static int
+fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
+{
+ int i, j, rc = 0;
+ struct rio_priv *priv = mport->priv;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+
+ if ((entries < RIO_MIN_TX_RING_SIZE) ||
+ (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* Initialize shadow copy ring */
+ rmu->msg_tx_ring.dev_id = dev_id;
+ rmu->msg_tx_ring.size = entries;
+
+ for (i = 0; i < rmu->msg_tx_ring.size; i++) {
+ rmu->msg_tx_ring.virt_buffer[i] =
+ dma_alloc_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
+ &rmu->msg_tx_ring.phys_buffer[i], GFP_KERNEL);
+ if (!rmu->msg_tx_ring.virt_buffer[i]) {
+ rc = -ENOMEM;
+ for (j = 0; j < rmu->msg_tx_ring.size; j++)
+ if (rmu->msg_tx_ring.virt_buffer[j])
+ dma_free_coherent(priv->dev,
+ RIO_MSG_BUFFER_SIZE,
+ rmu->msg_tx_ring.
+ virt_buffer[j],
+ rmu->msg_tx_ring.
+ phys_buffer[j]);
+ goto out;
+ }
+ }
+
+ /* Initialize outbound message descriptor ring */
+ rmu->msg_tx_ring.virt = dma_alloc_coherent(priv->dev,
+ rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+ &rmu->msg_tx_ring.phys, GFP_KERNEL);
+ if (!rmu->msg_tx_ring.virt) {
+ rc = -ENOMEM;
+ goto out_dma;
+ }
+ memset(rmu->msg_tx_ring.virt, 0,
+ rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE);
+ rmu->msg_tx_ring.tx_slot = 0;
+
+ /* Point dequeue/enqueue pointers at first entry in ring */
+ out_be32(&rmu->msg_regs->odqdpar, rmu->msg_tx_ring.phys);
+ out_be32(&rmu->msg_regs->odqepar, rmu->msg_tx_ring.phys);
+
+ /* Configure for snooping */
+ out_be32(&rmu->msg_regs->osar, 0x00000004);
+
+ /* Clear interrupt status */
+ out_be32(&rmu->msg_regs->osr, 0x000000b3);
+
+ /* Hook up outbound message handler */
+ rc = request_irq(IRQ_RIO_TX(mport), fsl_rio_tx_handler, 0,
+ "msg_tx", (void *)mport);
+ if (rc < 0)
+ goto out_irq;
+
+ /*
+ * Configure outbound message unit
+ * Snooping
+ * Interrupts (all enabled, except QEIE)
+ * Chaining mode
+ * Disable
+ */
+ out_be32(&rmu->msg_regs->omr, 0x00100220);
+
+ /* Set number of entries */
+ out_be32(&rmu->msg_regs->omr,
+ in_be32(&rmu->msg_regs->omr) |
+ ((get_bitmask_order(entries) - 2) << 12));
+
+ /* Now enable the unit */
+ out_be32(&rmu->msg_regs->omr, in_be32(&rmu->msg_regs->omr) | 0x1);
+
+out:
+ return rc;
+
+out_irq:
+ dma_free_coherent(priv->dev,
+ rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+ rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys);
+
+out_dma:
+ for (i = 0; i < rmu->msg_tx_ring.size; i++)
+ dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
+ rmu->msg_tx_ring.virt_buffer[i],
+ rmu->msg_tx_ring.phys_buffer[i]);
+
+ return rc;
+}
+
+/**
+ * fsl_close_outb_mbox - Shut down MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the outbound message unit, free all buffers, and
+ * frees the outbound message interrupt.
+ */
+static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
+{
+ struct rio_priv *priv = mport->priv;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+
+ /* Disable inbound message unit */
+ out_be32(&rmu->msg_regs->omr, 0);
+
+ /* Free ring */
+ dma_free_coherent(priv->dev,
+ rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+ rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys);
+
+ /* Free interrupt */
+ free_irq(IRQ_RIO_TX(mport), (void *)mport);
+}
+
+/**
+ * fsl_open_inb_mbox - Initialize MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @dev_id: Device specific pointer to pass on event
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the inbound mailbox ring
+ *
+ * Initializes buffer ring, request the inbound message interrupt,
+ * and enables the inbound message unit. Returns %0 on success
+ * and %-EINVAL or %-ENOMEM on failure.
+ */
+static int
+fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
+{
+ int i, rc = 0;
+ struct rio_priv *priv = mport->priv;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+
+ if ((entries < RIO_MIN_RX_RING_SIZE) ||
+ (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* Initialize client buffer ring */
+ rmu->msg_rx_ring.dev_id = dev_id;
+ rmu->msg_rx_ring.size = entries;
+ rmu->msg_rx_ring.rx_slot = 0;
+ for (i = 0; i < rmu->msg_rx_ring.size; i++)
+ rmu->msg_rx_ring.virt_buffer[i] = NULL;
+
+ /* Initialize inbound message ring */
+ rmu->msg_rx_ring.virt = dma_alloc_coherent(priv->dev,
+ rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+ &rmu->msg_rx_ring.phys, GFP_KERNEL);
+ if (!rmu->msg_rx_ring.virt) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Point dequeue/enqueue pointers at first entry in ring */
+ out_be32(&rmu->msg_regs->ifqdpar, (u32) rmu->msg_rx_ring.phys);
+ out_be32(&rmu->msg_regs->ifqepar, (u32) rmu->msg_rx_ring.phys);
+
+ /* Clear interrupt status */
+ out_be32(&rmu->msg_regs->isr, 0x00000091);
+
+ /* Hook up inbound message handler */
+ rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
+ "msg_rx", (void *)mport);
+ if (rc < 0) {
+ dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
+ rmu->msg_tx_ring.virt_buffer[i],
+ rmu->msg_tx_ring.phys_buffer[i]);
+ goto out;
+ }
+
+ /*
+ * Configure inbound message unit:
+ * Snooping
+ * 4KB max message size
+ * Unmask all interrupt sources
+ * Disable
+ */
+ out_be32(&rmu->msg_regs->imr, 0x001b0060);
+
+ /* Set number of queue entries */
+ setbits32(&rmu->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12);
+
+ /* Now enable the unit */
+ setbits32(&rmu->msg_regs->imr, 0x1);
+
+out:
+ return rc;
+}
+
+/**
+ * fsl_close_inb_mbox - Shut down MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the inbound message unit, free all buffers, and
+ * frees the inbound message interrupt.
+ */
+static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
+{
+ struct rio_priv *priv = mport->priv;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+
+ /* Disable inbound message unit */
+ out_be32(&rmu->msg_regs->imr, 0);
+
+ /* Free ring */
+ dma_free_coherent(priv->dev, rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+ rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
+
+ /* Free interrupt */
+ free_irq(IRQ_RIO_RX(mport), (void *)mport);
+}
+
+/**
+ * fsl_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ * @buf: Buffer to add to inbound queue
+ *
+ * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+static int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
+{
+ int rc = 0;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+
+ pr_debug("RIO: fsl_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+ rmu->msg_rx_ring.rx_slot);
+
+ if (rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot]) {
+ printk(KERN_ERR
+ "RIO: error adding inbound buffer %d, buffer exists\n",
+ rmu->msg_rx_ring.rx_slot);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot] = buf;
+ if (++rmu->msg_rx_ring.rx_slot == rmu->msg_rx_ring.size)
+ rmu->msg_rx_ring.rx_slot = 0;
+
+out:
+ return rc;
+}
+
+/**
+ * fsl_get_inb_message - Fetch inbound message from the MPC85xx message unit
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ *
+ * Gets the next available inbound message from the inbound message queue.
+ * A pointer to the message is returned on success or NULL on failure.
+ */
+static void *fsl_get_inb_message(struct rio_mport *mport, int mbox)
+{
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+ u32 phys_buf, virt_buf;
+ void *buf = NULL;
+ int buf_idx;
+
+ phys_buf = in_be32(&rmu->msg_regs->ifqdpar);
+
+ /* If no more messages, then bail out */
+ if (phys_buf == in_be32(&rmu->msg_regs->ifqepar))
+ goto out2;
+
+ virt_buf = (u32) rmu->msg_rx_ring.virt + (phys_buf
+ - rmu->msg_rx_ring.phys);
+ buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
+ buf = rmu->msg_rx_ring.virt_buffer[buf_idx];
+
+ if (!buf) {
+ printk(KERN_ERR
+ "RIO: inbound message copy failed, no buffers\n");
+ goto out1;
+ }
+
+ /* Copy max message size, caller is expected to allocate that big */
+ memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+
+ /* Clear the available buffer */
+ rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL;
+
+out1:
+ setbits32(&rmu->msg_regs->imr, RIO_MSG_IMR_MI);
+
+out2:
+ return buf;
+}
+
+/**
+ * fsl_rio_doorbell_init - MPC85xx doorbell interface init
+ * @mport: Master port implementing the inbound doorbell unit
+ *
+ * Initializes doorbell unit hardware and inbound DMA buffer
+ * ring. Called from fsl_rio_setup(). Returns %0 on success
+ * or %-ENOMEM on failure.
+ */
+static int fsl_rio_doorbell_init(struct rio_mport *mport)
+{
+ struct rio_priv *priv = mport->priv;
+ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
+ int rc = 0;
+
+ /* Map outbound doorbell window immediately after maintenance window */
+ rmu->dbell_win = ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
+ RIO_DBELL_WIN_SIZE);
+ if (!rmu->dbell_win) {
+ printk(KERN_ERR
+ "RIO: unable to map outbound doorbell window\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Initialize inbound doorbells */
+ rmu->dbell_ring.virt = dma_alloc_coherent(priv->dev, 512 *
+ DOORBELL_MESSAGE_SIZE, &rmu->dbell_ring.phys, GFP_KERNEL);
+ if (!rmu->dbell_ring.virt) {
+ printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
+ rc = -ENOMEM;
+ iounmap(rmu->dbell_win);
+ goto out;
+ }
+
+ /* Point dequeue/enqueue pointers at first entry in ring */
+ out_be32(&rmu->msg_regs->dqdpar, (u32) rmu->dbell_ring.phys);
+ out_be32(&rmu->msg_regs->dqepar, (u32) rmu->dbell_ring.phys);
+
+ /* Clear interrupt status */
+ out_be32(&rmu->msg_regs->dsr, 0x00000091);
+
+ /* Hook up doorbell handler */
+ rc = request_irq(IRQ_RIO_BELL(mport), fsl_rio_dbell_handler, 0,
+ "dbell_rx", (void *)mport);
+ if (rc < 0) {
+ iounmap(rmu->dbell_win);
+ dma_free_coherent(priv->dev, 512 * DOORBELL_MESSAGE_SIZE,
+ rmu->dbell_ring.virt, rmu->dbell_ring.phys);
+ printk(KERN_ERR
+ "MPC85xx RIO: unable to request inbound doorbell irq");
+ goto out;
+ }
+
+ /* Configure doorbells for snooping, 512 entries, and enable */
+ out_be32(&rmu->msg_regs->dmr, 0x00108161);
+
+out:
+ return rc;
+}
+
+int fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node)
+{
+ struct rio_priv *priv;
+ struct fsl_rmu *rmu;
+ struct rio_ops *ops;
+
+ if (!mport || !mport->priv || !node)
+ return -1;
+
+ rmu = kzalloc(sizeof(struct fsl_rmu), GFP_KERNEL);
+ if (!rmu)
+ return -ENOMEM;
+
+ priv = mport->priv;
+ priv->rmm_handle = rmu;
+ rmu->dbell_atmu_regs = priv->atmu_regs + 2;
+ rmu->msg_regs = (struct rio_msg_regs *)(priv->regs_win +
+ ((mport->phy_type == RIO_PHY_SERIAL) ?
+ RIO_S_MSG_REGS_OFFSET : RIO_P_MSG_REGS_OFFSET));
+
+ rmu->bellirq = irq_of_parse_and_map(node, 2);
+ rmu->txirq = irq_of_parse_and_map(node, 3);
+ rmu->rxirq = irq_of_parse_and_map(node, 4);
+ dev_info(priv->dev, "bellirq: %d, txirq: %d, rxirq %d\n",
+ rmu->bellirq, rmu->txirq, rmu->rxirq);
+
+ ops = mport->ops;
+
+ ops->dsend = fsl_rio_doorbell_send;
+ ops->open_outb_mbox = fsl_open_outb_mbox;
+ ops->open_inb_mbox = fsl_open_inb_mbox;
+ ops->close_outb_mbox = fsl_close_outb_mbox;
+ ops->close_inb_mbox = fsl_close_inb_mbox;
+ ops->add_outb_message = fsl_add_outb_message;
+ ops->add_inb_buffer = fsl_add_inb_buffer;
+ ops->get_inb_message = fsl_get_inb_message;
+
+ rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
+ rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
+ rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
+
+ /* Configure outbound doorbell window */
+ out_be32(&rmu->dbell_atmu_regs->rowbar,
+ (mport->iores.start + RIO_MAINT_WIN_SIZE) >> 12);
+ /* 4k window size */
+ out_be32(&rmu->dbell_atmu_regs->rowar, 0x8004200b);
+
+ fsl_rio_doorbell_init(mport);
+
+ return 0;
+}
--
1.7.3.1
^ permalink raw reply related
* [PATCH 4/4] powerpc/fsl: Document rapidio node binding-information
From: Liu Gang @ 2011-09-29 2:29 UTC (permalink / raw)
To: linuxppc-dev
Cc: Jin Qing, r58472, r61911, linux-kernel, Liu Gang, akpm, B11780
In-Reply-To: <1317263341-19010-1-git-send-email-Gang.Liu@freescale.com>
This document is created for powerpc rapidio and rmu nodes in dts file. These nodes
can support two rapidio ports and message units. In addition, It explicates the properties
and gives examples about rapidio and rmu nodes.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Liu Gang <Gang.Liu@freescale.com>
---
.../devicetree/bindings/powerpc/fsl/srio.txt | 85 ++++++++++++++++++++
1 files changed, 85 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/srio.txt
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/srio.txt b/Documentation/devicetree/bindings/powerpc/fsl/srio.txt
new file mode 100644
index 0000000..01f2da1
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/srio.txt
@@ -0,0 +1,85 @@
+* Freescale Rapidio Controller
+
+Rapidio port node:
+Properties:
+ - compatible: "fsl,rapidio-delta".
+ "fsl,rapidio-delta" should be listed for any chip whose rapidio controller is compatible.
+ At first, rapidio controller was introduced with the version of delta and has no revision
+ register. Rapidio driver and controller were matched by "fsl,rapidio-delta". After the
+ addition of two revision registers in rapidio controller, we can read some revision and
+ configuration information about rapidio controller IP block, and the compatible with
+ "fsl,rapidio-delta" was still used.
+
+ - reg: For devices compatible with "fsl,rapidio-delta", should contain the address and
+ the length about all the rapidio controller's registers.
+
+ - ranges: Should be defined according to the u-boot settings about SRIO. Describe the memory
+ mapped I/O space used by the rapidio controller.
+
+ - interrupts: Interrupt mapping for rapidio IRQ. Three interrupts in the group, and starting
+ with SRIO error/port-write IRQ, an error interrupt and with interrupt type 1. The other
+ two interrupts are doorbell outbound IRQ and doorbell inbound IRQ, and they are external
+ interrupts.
+
+ - fsl,rio-num-ports: The number of rapidio ports supported by this controller.
+
+ - fsl,liodn: The logical I/O device number for the PAMU to be correctly configured for SRIO
+ accesses. This property is added in SRIO node by u-boot and usually used by hypervisor.
+ The number of elements may either be 2 or 4 LIODN values. For HW that only supports LIODNs
+ for ALL memory & maintenance transactions we have 2 cells. For HW that has separate LIODNs
+ for memory & maintenance transaction we utilize 4 cells.
+
+ - rmu-handle: The phandle for the rmu connected to this rapidio controller.
+
+Example:
+
+ rapidio: rapidio@ffe0c0000 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "fsl,rapidio-delta";
+ interrupts = <
+ 16 2 1 11 /* err_irq */
+ 56 2 0 0 /* bell_outb_irq */
+ 57 2 0 0>;/* bell_inb_irq */
+ fsl,rio-num-ports = <2>;
+ rmu-handle = <&rmu>;
+ };
+
+Message unit node:
+Properties:
+ - compatible: "fsl,rmu".
+ "fsl,rmu" should be listed for any chip whose message unit is compatible. In addition,
+ RMAN will replace RMU for rapidio message transaction in some chips using DPAA architecture.
+ Then instead of RMU node, RMAN node will be used in dts file and the compatible property
+ "fsl,rmu" should be replaced.
+
+ - reg: Registers mapping for message unit.
+
+ - interrupts: Interrupt mapping for message unit controller. Every message
+ unit controller has two external interrupts: message outbound IRQ and
+ message inbound IRQ.
+
+ - fsl,liodn: The logical I/O device number for rmuliodnr and added by u-boot.
+
+Example:
+
+ rmu: rmu@d3000 {
+ fsl,liodn = <0xc8>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,rmu";
+ reg = <0xd3000 0x200>;
+
+ message-unit@0 {
+ reg = <0x0 0x100>;
+ interrupts = <
+ 60 2 0 0 /* msg1_tx_irq */
+ 61 2 0 0>;/* msg1_rx_irq */
+ };
+ message-unit@1 {
+ reg = <0x100 0x100>;
+ interrupts = <
+ 62 2 0 0 /* msg2_tx_irq */
+ 63 2 0 0>;/* msg2_rx_irq */
+ };
+ };
--
1.7.3.1
^ permalink raw reply related
* Re: [PATCH REPOST] perf event, POWER 6: L1 cache read and write access event code fix]
From: Paul Mackerras @ 2011-09-29 4:06 UTC (permalink / raw)
To: Carl E. Love; +Cc: linuxppc-dev, bherren, pmac
In-Reply-To: <1317245013.5461.11.camel@oc5652146517.ibm.com>
On Wed, Sep 28, 2011 at 02:23:33PM -0700, Carl E. Love wrote:
> The current L1 cache read event code 0x80082 only counts for thread 0. The
> event code 0x280030 should be used to count events on thread 0 and 1. The
> patch fixes the event code for the L1 cache read.
>
> The current L1 cache write event code 0x80086 only counts for thread 0. The
> event code 0x180032 should be used to count events on thread 0 and 1. The
> patch fixes the event code for the L1 cache write.
Acked-by: Paul Mackerras <paulus@samba.org>
^ permalink raw reply
* powerpc: Fix device-tree matching for Apple U4 bridge
From: Benjamin Herrenschmidt @ 2011-09-29 5:57 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linuxppc-dev
Apple Quad G5 has some oddity in it's device-tree which causes the new
generic matching code to fail to relate nodes for PCI-E devices below
U4 with their respective struct pci_dev. This breaks graphics on those
machines among others.
This fixes it using a quirk which copies the node pointer from the host
bridge for the root complex, which makes the generic code work for the
children afterward.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Linus, please apply, this is a 3.1 regression. Thanks !
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index abe8d7e..8635694 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -561,6 +561,20 @@ static struct pci_ops u4_pcie_pci_ops =
.write = u4_pcie_write_config,
};
+static void __devinit pmac_pci_fixup_u4_of_node(struct pci_dev *dev)
+{
+ /* Apple's device-tree "hides" the root complex virtual P2P bridge
+ * on U4. However, Linux sees it, causing the PCI <-> OF matching
+ * code to fail to properly match devices below it. This works around
+ * it by setting the node of the bridge to point to the PHB node,
+ * which is not entirely correct but fixes the matching code and
+ * doesn't break anything else. It's also the simplest possible fix.
+ */
+ if (dev->dev.of_node == NULL)
+ dev->dev.of_node = pcibios_get_phb_of_node(dev->bus);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, 0x5b, pmac_pci_fixup_u4_of_node);
+
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_PPC32
^ permalink raw reply related
* [PATCH] powerpc: Don't try OPAL takeover on old 970 blades
From: Benjamin Herrenschmidt @ 2011-09-29 6:51 UTC (permalink / raw)
To: linuxppc-dev
The firmware on old 970 blades supports some kind of takeover called
"TNK takeover" which will crash if we try to probe for OPAL takeover,
so don't do it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index e96f5d0..b4fa661 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -1313,6 +1313,16 @@ static void prom_query_opal(void)
{
long rc;
+ /* We must not query for OPAL presence on a machine that
+ * supports TNK takeover (970 blades), as this uses the same
+ * h-call with different arguments and will crash
+ */
+ if (PHANDLE_VALID(call_prom("finddevice", 1, 1,
+ ADDR("/tnk-memory-map")))) {
+ prom_printf("TNK takeover detected, skipping OPAL check\n");
+ return;
+ }
+
prom_printf("Querying for OPAL presence... ");
rc = opal_query_takeover(&RELOC(prom_opal_size),
&RELOC(prom_opal_align));
^ permalink raw reply related
* Re: [PATCH 1/3 v2] powerpc: Split ICSWX ACOP and PID processing
From: Benjamin Herrenschmidt @ 2011-09-29 7:02 UTC (permalink / raw)
To: Anton Blanchard, Jimi Xenidis; +Cc: linuxppc-dev
In-Reply-To: <20110927200521.2df1276b@kryten>
On Tue, 2011-09-27 at 20:05 +1000, Anton Blanchard wrote:
> Hi Jimi,
>
> > Some processors, like embedded, that already have a PID register that
> > is managed by the system. This patch separates the ACOP and PID
> > processing into separate files so that the ACOP code can be shared.
> >
> > Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>
> Looks good.
>
> Acked-by: Anton Blanchard <anton@samba.org>
Please, update the patch so that it applies :-)
(IE. Anton's patch to fix deadlocks in the icswx code broke it, you
need to rebase and apply Anton's fix to your new copy of the code)
Cheers,
Ben.
> Anton
>
> > ---
> > Re: galak@kernel.crashing.org
> > Fix typo in arch/powerpc/mm/Makefile
> >
> > Re: anton@samba.org
> > merge in: powerpc: Fix deadlock in icswx code
> > ---
> > arch/powerpc/mm/Makefile | 2 +
> > arch/powerpc/mm/icswx.c | 162
> > ++++++++++++++++++++++++++ arch/powerpc/mm/icswx.h |
> > 34 ++++++ arch/powerpc/mm/icswx_pid.c | 87 ++++++++++++++
> > arch/powerpc/mm/mmu_context_hash64.c | 195
> > --------------------------------
> > arch/powerpc/platforms/Kconfig.cputype | 10 ++- 6 files changed,
> > 294 insertions(+), 196 deletions(-) create mode 100644
> > arch/powerpc/mm/icswx.c create mode 100644 arch/powerpc/mm/icswx.h
> > create mode 100644 arch/powerpc/mm/icswx_pid.c
> >
> > diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
> > index bdca46e..fb7976f 100644
> > --- a/arch/powerpc/mm/Makefile
> > +++ b/arch/powerpc/mm/Makefile
> > @@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o
> > obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \
> > tlb_hash$(CONFIG_WORD_SIZE).o \
> > mmu_context_hash$(CONFIG_WORD_SIZE).o
> > +obj-$(CONFIG_PPC_ICSWX) += icswx.o
> > +obj-$(CONFIG_PPC_ICSWX_PID) += icswx_pid.o
> > obj-$(CONFIG_40x) += 40x_mmu.o
> > obj-$(CONFIG_44x) += 44x_mmu.o
> > obj-$(CONFIG_PPC_FSL_BOOK3E) += fsl_booke_mmu.o
> > diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
> > new file mode 100644
> > index 0000000..2f1dd29
> > --- /dev/null
> > +++ b/arch/powerpc/mm/icswx.c
> > @@ -0,0 +1,162 @@
> > +/*
> > + * ICSWX and ACOP Management
> > + *
> > + * Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation; either version
> > + * 2 of the License, or (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/sched.h>
> > +#include <linux/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +#include <linux/mm.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/module.h>
> > +#include "icswx.h"
> > +
> > +
> > +/*
> > + * The processor and its L2 cache cause the icswx instruction to
> > + * generate a COP_REQ transaction on PowerBus. The transaction has no
> > + * address, and the processor does not perform an MMU access to
> > + * authenticate the transaction. The command portion of the PowerBus
> > + * COP_REQ transaction includes the LPAR_ID (LPID) and the
> > coprocessor
> > + * Process ID (PID), which the coprocessor compares to the authorized
> > + * LPID and PID held in the coprocessor, to determine if the process
> > + * is authorized to generate the transaction. The data of the
> > COP_REQ
> > + * transaction is cache block or less, typically 64 or 128 bytes in
> > + * size, and is placed in cacheable memory on a 128-byte boundary
> > + * _always_.
> > + *
> > + * The task to use a coprocessor should use use_cop() mark the use of
> > + * the coprocessor type (CT) and context swithing. On a server
> > + * processor the PID register is used only for coprocessor management
> > + * and so a coprocessor PID is allocated before executing icswx
> > + * instruction. Drop_cop() is used to free the resources created by
> > + * use_cop().
> > + *
> > + * Example:
> > + * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> > + * Each HFI have multiple windows. Each HFI window serves as a
> > + * network device sending to and receiving from HFI network.
> > + * HFI immediate send function uses icswx instruction. The immediate
> > + * send function allows small (single cache-line) packets be sent
> > + * without using the regular HFI send FIFO and doorbell, which are
> > + * much slower than immediate send.
> > + *
> > + * For each task intending to use HFI immediate send, the HFI driver
> > + * calls use_cop() to obtain a coprocessor PID for the task.
> > + * The HFI driver then allocate a free HFI window and save the
> > + * coprocessor PID to the HFI window to allow the task to use the
> > + * HFI window.
> > + *
> > + * The HFI driver repeatedly creates immediate send packets and
> > + * issues icswx instruction to send data through the HFI window.
> > + * The HFI compares the coprocessor PID in the CPU PID register
> > + * to the PID held in the HFI window to determine if the transaction
> > + * is allowed.
> > + *
> > + * When the task to release the HFI window, the HFI driver calls
> > + * drop_cop() to release the coprocessor PID.
> > + */
> > +
> > +void switch_cop(struct mm_struct *next)
> > +{
> > +#ifdef CONFIG_ICSWX_PID
> > + mtspr(SPRN_PID, next->context.cop_pid);
> > +#endif
> > + mtspr(SPRN_ACOP, next->context.acop);
> > +}
> > +
> > +/**
> > + * Start using a coprocessor.
> > + * @acop: mask of coprocessor to be used.
> > + * @mm: The mm the coprocessor to associate with. Most likely
> > current mm.
> > + *
> > + * Return a positive PID if successful. Negative errno otherwise.
> > + * The returned PID will be fed to the coprocessor to determine if an
> > + * icswx transaction is authenticated.
> > + */
> > +int use_cop(unsigned long acop, struct mm_struct *mm)
> > +{
> > + int ret;
> > +
> > + if (!cpu_has_feature(CPU_FTR_ICSWX))
> > + return -ENODEV;
> > +
> > + if (!mm || !acop)
> > + return -EINVAL;
> > +
> > + /* The page_table_lock ensures mm_users won't change under
> > us */
> > + spin_lock(&mm->page_table_lock);
> > + spin_lock(mm->context.cop_lockp);
> > +
> > + ret = get_cop_pid(mm);
> > + if (ret < 0)
> > + goto out;
> > +
> > + /* update acop */
> > + mm->context.acop |= acop;
> > +
> > + sync_cop(mm);
> > +
> > + /*
> > + * If this is a threaded process then there might be other
> > threads
> > + * running. We need to send an IPI to force them to pick up
> > any
> > + * change in PID and ACOP.
> > + */
> > + if (atomic_read(&mm->mm_users) > 1)
> > + smp_call_function(sync_cop, mm, 1);
> > +
> > +out:
> > + spin_unlock(mm->context.cop_lockp);
> > + spin_unlock(&mm->page_table_lock);
> > +
> > + return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(use_cop);
> > +
> > +/**
> > + * Stop using a coprocessor.
> > + * @acop: mask of coprocessor to be stopped.
> > + * @mm: The mm the coprocessor associated with.
> > + */
> > +void drop_cop(unsigned long acop, struct mm_struct *mm)
> > +{
> > + int free_pid;
> > +
> > + if (!cpu_has_feature(CPU_FTR_ICSWX))
> > + return;
> > +
> > + if (WARN_ON_ONCE(!mm))
> > + return;
> > +
> > + /* The page_table_lock ensures mm_users won't change under
> > us */
> > + spin_lock(&mm->page_table_lock);
> > + spin_lock(mm->context.cop_lockp);
> > +
> > + mm->context.acop &= ~acop;
> > +
> > + free_pid = disable_cop_pid(mm);
> > + sync_cop(mm);
> > +
> > + /*
> > + * If this is a threaded process then there might be other
> > threads
> > + * running. We need to send an IPI to force them to pick up
> > any
> > + * change in PID and ACOP.
> > + */
> > + if (atomic_read(&mm->mm_users) > 1)
> > + smp_call_function(sync_cop, mm, 1);
> > +
> > + if (free_pid != COP_PID_NONE)
> > + free_cop_pid(free_pid);
> > +
> > + spin_unlock(mm->context.cop_lockp);
> > + spin_unlock(&mm->page_table_lock);
> > +}
> > +EXPORT_SYMBOL_GPL(drop_cop);
> > diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
> > new file mode 100644
> > index 0000000..5121ddd
> > --- /dev/null
> > +++ b/arch/powerpc/mm/icswx.h
> > @@ -0,0 +1,34 @@
> > +/*
> > + * ICSWX and ACOP Management
> > + *
> > + * Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation; either version
> > + * 2 of the License, or (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <asm/mmu_context.h>
> > +
> > +/* also used to denote that PIDs are not used */
> > +#define COP_PID_NONE 0
> > +
> > +static inline void sync_cop(void *arg)
> > +{
> > + struct mm_struct *mm = arg;
> > +
> > + if (mm == current->active_mm)
> > + switch_cop(current->active_mm);
> > +}
> > +
> > +#ifdef CONFIG_PPC_ICSWX_PID
> > +extern int get_cop_pid(struct mm_struct *mm);
> > +extern int disable_cop_pid(struct mm_struct *mm);
> > +extern void free_cop_pid(int free_pid);
> > +#else
> > +#define get_cop_pid(m) (COP_PID_NONE)
> > +#define disable_cop_pid(m) (COP_PID_NONE)
> > +#define free_cop_pid(p)
> > +#endif
> > diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c
> > new file mode 100644
> > index 0000000..91e30eb
> > --- /dev/null
> > +++ b/arch/powerpc/mm/icswx_pid.c
> > @@ -0,0 +1,87 @@
> > +/*
> > + * ICSWX and ACOP/PID Management
> > + *
> > + * Copyright (C) 2011 Anton Blanchard, IBM Corp. <anton@samba.org>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * as published by the Free Software Foundation; either version
> > + * 2 of the License, or (at your option) any later version.
> > + *
> > + */
> > +
> > +#include <linux/sched.h>
> > +#include <linux/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +#include <linux/mm.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/idr.h>
> > +#include <linux/module.h>
> > +#include "icswx.h"
> > +
> > +#define COP_PID_MIN (COP_PID_NONE + 1)
> > +#define COP_PID_MAX (0xFFFF)
> > +
> > +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> > +static DEFINE_IDA(cop_ida);
> > +
> > +static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> > + spinlock_t *lock)
> > +{
> > + int index;
> > + int err;
> > +
> > +again:
> > + if (!ida_pre_get(ida, GFP_KERNEL))
> > + return -ENOMEM;
> > +
> > + spin_lock(lock);
> > + err = ida_get_new_above(ida, min_id, &index);
> > + spin_unlock(lock);
> > +
> > + if (err == -EAGAIN)
> > + goto again;
> > + else if (err)
> > + return err;
> > +
> > + if (index > max_id) {
> > + spin_lock(lock);
> > + ida_remove(ida, index);
> > + spin_unlock(lock);
> > + return -ENOMEM;
> > + }
> > +
> > + return index;
> > +}
> > +
> > +int get_cop_pid(struct mm_struct *mm)
> > +{
> > + int pid;
> > +
> > + if (mm->context.cop_pid == COP_PID_NONE) {
> > + pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> > + &mmu_context_acop_lock);
> > + if (pid >= 0)
> > + mm->context.cop_pid = pid;
> > + }
> > + return mm->context.cop_pid;
> > +}
> > +
> > +int disable_cop_pid(struct mm_struct *mm)
> > +{
> > + int free_pid = COP_PID_NONE;
> > +
> > + if ((!mm->context.acop) && (mm->context.cop_pid !=
> > COP_PID_NONE)) {
> > + free_pid = mm->context.cop_pid;
> > + mm->context.cop_pid = COP_PID_NONE;
> > + }
> > + return free_pid;
> > +}
> > +
> > +void free_cop_pid(int free_pid)
> > +{
> > + spin_lock(&mmu_context_acop_lock);
> > + ida_remove(&cop_ida, free_pid);
> > + spin_unlock(&mmu_context_acop_lock);
> > +}
> > diff --git a/arch/powerpc/mm/mmu_context_hash64.c
> > b/arch/powerpc/mm/mmu_context_hash64.c index 3bafc3d..a75832c 100644
> > --- a/arch/powerpc/mm/mmu_context_hash64.c
> > +++ b/arch/powerpc/mm/mmu_context_hash64.c
> > @@ -24,201 +24,6 @@
> >
> > #include <asm/mmu_context.h>
> >
> > -#ifdef CONFIG_PPC_ICSWX
> > -/*
> > - * The processor and its L2 cache cause the icswx instruction to
> > - * generate a COP_REQ transaction on PowerBus. The transaction has
> > - * no address, and the processor does not perform an MMU access
> > - * to authenticate the transaction. The command portion of the
> > - * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
> > - * the coprocessor Process ID (PID), which the coprocessor compares
> > - * to the authorized LPID and PID held in the coprocessor, to
> > determine
> > - * if the process is authorized to generate the transaction.
> > - * The data of the COP_REQ transaction is 128-byte or less and is
> > - * placed in cacheable memory on a 128-byte cache line boundary.
> > - *
> > - * The task to use a coprocessor should use use_cop() to allocate
> > - * a coprocessor PID before executing icswx instruction. use_cop()
> > - * also enables the coprocessor context switching. Drop_cop() is
> > - * used to free the coprocessor PID.
> > - *
> > - * Example:
> > - * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> > - * Each HFI have multiple windows. Each HFI window serves as a
> > - * network device sending to and receiving from HFI network.
> > - * HFI immediate send function uses icswx instruction. The immediate
> > - * send function allows small (single cache-line) packets be sent
> > - * without using the regular HFI send FIFO and doorbell, which are
> > - * much slower than immediate send.
> > - *
> > - * For each task intending to use HFI immediate send, the HFI driver
> > - * calls use_cop() to obtain a coprocessor PID for the task.
> > - * The HFI driver then allocate a free HFI window and save the
> > - * coprocessor PID to the HFI window to allow the task to use the
> > - * HFI window.
> > - *
> > - * The HFI driver repeatedly creates immediate send packets and
> > - * issues icswx instruction to send data through the HFI window.
> > - * The HFI compares the coprocessor PID in the CPU PID register
> > - * to the PID held in the HFI window to determine if the transaction
> > - * is allowed.
> > - *
> > - * When the task to release the HFI window, the HFI driver calls
> > - * drop_cop() to release the coprocessor PID.
> > - */
> > -
> > -#define COP_PID_NONE 0
> > -#define COP_PID_MIN (COP_PID_NONE + 1)
> > -#define COP_PID_MAX (0xFFFF)
> > -
> > -static DEFINE_SPINLOCK(mmu_context_acop_lock);
> > -static DEFINE_IDA(cop_ida);
> > -
> > -void switch_cop(struct mm_struct *next)
> > -{
> > - mtspr(SPRN_PID, next->context.cop_pid);
> > - mtspr(SPRN_ACOP, next->context.acop);
> > -}
> > -
> > -static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> > - spinlock_t *lock)
> > -{
> > - int index;
> > - int err;
> > -
> > -again:
> > - if (!ida_pre_get(ida, GFP_KERNEL))
> > - return -ENOMEM;
> > -
> > - spin_lock(lock);
> > - err = ida_get_new_above(ida, min_id, &index);
> > - spin_unlock(lock);
> > -
> > - if (err == -EAGAIN)
> > - goto again;
> > - else if (err)
> > - return err;
> > -
> > - if (index > max_id) {
> > - spin_lock(lock);
> > - ida_remove(ida, index);
> > - spin_unlock(lock);
> > - return -ENOMEM;
> > - }
> > -
> > - return index;
> > -}
> > -
> > -static void sync_cop(void *arg)
> > -{
> > - struct mm_struct *mm = arg;
> > -
> > - if (mm == current->active_mm)
> > - switch_cop(current->active_mm);
> > -}
> > -
> > -/**
> > - * Start using a coprocessor.
> > - * @acop: mask of coprocessor to be used.
> > - * @mm: The mm the coprocessor to associate with. Most likely
> > current mm.
> > - *
> > - * Return a positive PID if successful. Negative errno otherwise.
> > - * The returned PID will be fed to the coprocessor to determine if an
> > - * icswx transaction is authenticated.
> > - */
> > -int use_cop(unsigned long acop, struct mm_struct *mm)
> > -{
> > - int ret;
> > -
> > - if (!cpu_has_feature(CPU_FTR_ICSWX))
> > - return -ENODEV;
> > -
> > - if (!mm || !acop)
> > - return -EINVAL;
> > -
> > - /* We need to make sure mm_users doesn't change */
> > - down_read(&mm->mmap_sem);
> > - spin_lock(mm->context.cop_lockp);
> > -
> > - if (mm->context.cop_pid == COP_PID_NONE) {
> > - ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> > - &mmu_context_acop_lock);
> > - if (ret < 0)
> > - goto out;
> > -
> > - mm->context.cop_pid = ret;
> > - }
> > - mm->context.acop |= acop;
> > -
> > - sync_cop(mm);
> > -
> > - /*
> > - * If this is a threaded process then there might be other
> > threads
> > - * running. We need to send an IPI to force them to pick up
> > any
> > - * change in PID and ACOP.
> > - */
> > - if (atomic_read(&mm->mm_users) > 1)
> > - smp_call_function(sync_cop, mm, 1);
> > -
> > - ret = mm->context.cop_pid;
> > -
> > -out:
> > - spin_unlock(mm->context.cop_lockp);
> > - up_read(&mm->mmap_sem);
> > -
> > - return ret;
> > -}
> > -EXPORT_SYMBOL_GPL(use_cop);
> > -
> > -/**
> > - * Stop using a coprocessor.
> > - * @acop: mask of coprocessor to be stopped.
> > - * @mm: The mm the coprocessor associated with.
> > - */
> > -void drop_cop(unsigned long acop, struct mm_struct *mm)
> > -{
> > - int free_pid = COP_PID_NONE;
> > -
> > - if (!cpu_has_feature(CPU_FTR_ICSWX))
> > - return;
> > -
> > - if (WARN_ON_ONCE(!mm))
> > - return;
> > -
> > - /* We need to make sure mm_users doesn't change */
> > - down_read(&mm->mmap_sem);
> > - spin_lock(mm->context.cop_lockp);
> > -
> > - mm->context.acop &= ~acop;
> > -
> > - if ((!mm->context.acop) && (mm->context.cop_pid !=
> > COP_PID_NONE)) {
> > - free_pid = mm->context.cop_pid;
> > - mm->context.cop_pid = COP_PID_NONE;
> > - }
> > -
> > - sync_cop(mm);
> > -
> > - /*
> > - * If this is a threaded process then there might be other
> > threads
> > - * running. We need to send an IPI to force them to pick up
> > any
> > - * change in PID and ACOP.
> > - */
> > - if (atomic_read(&mm->mm_users) > 1)
> > - smp_call_function(sync_cop, mm, 1);
> > -
> > - if (free_pid != COP_PID_NONE) {
> > - spin_lock(&mmu_context_acop_lock);
> > - ida_remove(&cop_ida, free_pid);
> > - spin_unlock(&mmu_context_acop_lock);
> > - }
> > -
> > - spin_unlock(mm->context.cop_lockp);
> > - up_read(&mm->mmap_sem);
> > -}
> > -EXPORT_SYMBOL_GPL(drop_cop);
> > -
> > -#endif /* CONFIG_PPC_ICSWX */
> > -
> > static DEFINE_SPINLOCK(mmu_context_lock);
> > static DEFINE_IDA(mmu_context_ida);
> >
> > diff --git a/arch/powerpc/platforms/Kconfig.cputype
> > b/arch/powerpc/platforms/Kconfig.cputype index e06e395..3cd22e5 100644
> > --- a/arch/powerpc/platforms/Kconfig.cputype
> > +++ b/arch/powerpc/platforms/Kconfig.cputype
> > @@ -234,7 +234,7 @@ config VSX
> >
> > config PPC_ICSWX
> > bool "Support for PowerPC icswx coprocessor instruction"
> > - depends on POWER4
> > + depends on POWER4 || PPC_A2
> > default n
> > ---help---
> >
> > @@ -250,6 +250,14 @@ config PPC_ICSWX
> >
> > If in doubt, say N here.
> >
> > +config PPC_ICSWX_PID
> > + bool "icswx requires direct PID management"
> > + depends on PPC_ICSWX && POWER4
> > + default y
> > + ---help---
> > + PID register in server is used explicitly for ICSWX. In
> > + embedded systems PID managment is done by the system.
> > +
> > config SPE
> > bool "SPE Support"
> > depends on E200 || (E500 && !PPC_E500MC)
^ permalink raw reply
* Re: [PATCH REPOST] perf event, POWER 6: L1 cache read and write access event code fix]
From: Benjamin Herrenschmidt @ 2011-09-29 7:04 UTC (permalink / raw)
To: Carl E. Love; +Cc: linuxppc-dev, Benjamin Herrenschmidt, Paul Mackerras
In-Reply-To: <1317245013.5461.11.camel@oc5652146517.ibm.com>
On Wed, 2011-09-28 at 14:23 -0700, Carl E. Love wrote:
> Ben, Paul:
>
> I posted this patch to lkml but did not copy the linuxppc-dev@ozlabs.org
> mailing list.
Patch is also completely damaged. I'm fixing it up myself this time
around but by now you should know how to send patches correctly :-(
Ben.
> Carl Love
> ---------------------------------------------------------------------
>
> The current L1 cache read event code 0x80082 only counts for thread 0. The
> event code 0x280030 should be used to count events on thread 0 and 1. The
> patch fixes the event code for the L1 cache read.
>
> The current L1 cache write event code 0x80086 only counts for thread 0. The
> event code 0x180032 should be used to count events on thread 0 and 1. The
> patch fixes the event code for the L1 cache write.
>
> FYI, the documentation lists three event codes for the L1 cache read event
> and three event codes for the L1 cache write event. The event description
> for the event codes is as follows:
>
> L1 cache read requests 0x80082 LSU 0 only
> L1 cache read requests 0x8008A LSU 1 only
> L1 cache read requests 0x80030 LSU 1 or LSU 0, counter 2 only.
>
> L1 cache store requests 0x80086 LSU 0 only
> L1 cache store requests 0x8008E LSU 1 only
> L1 cache store requests 0x80032 LSU 0 or LSU 1, counter 1 only.
>
> There can only be one request from either LSU 0 or 1 active at a time.
>
> Signed-off-by: Carl Love <cel@us.ibm.com>
> ---
> arch/powerpc/kernel/power6-pmu.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c
> index 03b95e2..0bbc901 100644
> --- a/arch/powerpc/kernel/power6-pmu.c
> +++ b/arch/powerpc/kernel/power6-pmu.c
> @@ -487,8 +487,8 @@ static int power6_generic_events[] = {
> */
> static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
> [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
> - [C(OP_READ)] = { 0x80082, 0x80080 },
> - [C(OP_WRITE)] = { 0x80086, 0x80088 },
> + [C(OP_READ)] = { 0x280030, 0x80080 },
> + [C(OP_WRITE)] = { 0x180032, 0x80088 },
> [C(OP_PREFETCH)] = { 0x810a4, 0 },
> },
> [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
>
>
^ permalink raw reply
* MMC on SPI (MPC8313) slow reading
From: Jean-Michel Hautbois @ 2011-09-29 9:19 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Jean-Michel Hautbois
SGkgbGlzdCwKCkkgYW0gY3VycmVudGx5IHVzaW5nIGEgTVBDODMxMyB3aXRoIGFuIE1NQyBzbG90
IG9uIFNQSSBidXMuCk15IGZzbCBpcyB0aGUgZm9sbG93aW5nIDoKc3BpQDcwMDAgewrCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICNhZGRyZXNzLWNlbGxzID0g
PDE+OwrCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgICNzaXpl
LWNlbGxzID0gPDA+OwrCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgIGNlbGwtaW5kZXggPSA8MD47CsKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqAgY29tcGF0aWJsZSA9ICJmc2wsc3BpIjsKwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZWcgPSA8MHg3MDAwIDB4MTAwMD47CsKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgaW50ZXJydXB0cyA9IDwxNiAw
eDg+OwrCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIGludGVy
cnVwdC1wYXJlbnQgPSA8JmlwaWM+OwrCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgIG1vZGUgPSAiY3B1IjsKwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoCAvKiBDaGlwIFNlbGVjdHMgKi8KwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBncGlvcyA9IDwmZ3BpbzEgMTUgMD47CsKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgYnVzLW51bSA9ICIwIjsKCsKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgbW1jLXNsb3RAMCB7
CsKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgIGNvbXBhdGlibGUgPSAiZnNsLG1wYzgzMTMtbW1jLXNsb3QiLArCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgICJtbWMtc3BpLXNsb3QiOwrCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCByZWcgPSA8MD47CsKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
IC8qIENhcmQtRGV0ZWN0IEdQSU8gKi8KwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZ3Bpb3MgPSA8JmVwbGRfc3RhdDYgNyAxPjsK
CsKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgIHZvbHRhZ2UtcmFuZ2VzID0gPDMzMDAgMzMwMD47CsKgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgIHNwaS1tYXgtZnJlcXVl
bmN5ID0gPDQxNjY1MDAwPjsKwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoCB9Owp9OwoKV2hlbiBJIHJlYWQgYSBmaWxlIChzb21lIE1CeXRlcykgZnJvbSBhbiBT
RCBjYXJkLCBJIHJlYWQgYXQgc29tZXRoaW5nCmxpa2UgMjQwa0J5dGVzL3NlYy4KVGhpcyBpcyBy
ZWFsbHkgc2xvdywgYW5kIEkgd291bGQgbGlrZSB0byBiZSBzdXJlIHRoYXQgSSBjYW5ub3QgaGF2
ZQpiZXR0ZXIgcGVyZm9ybWFuY2VzLgpGWUkgdGhlIHJlYWRpbmcgdGltZSBvbiB0aGUgc2FtZSBT
RCBjYXJkIG9uIGEgbGFwdG9wIGlzIGFib3V0IDIwTUJ5dGVzL3NlYy4KClRoYW5rcyBpbiBhZHZh
bmNlIGZvciB5b3VyIGhlbHAgIQpSZWdhcmRzLApKTQo=
^ permalink raw reply
* Please pull 'next' branch of 5xxx tree
From: Anatolij Gustschin @ 2011-09-29 9:30 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
Hi Ben,
please pull another two mpc5xxx patches for next. These patches were
queued in Grant's 'powerpc/next' branch a while ago, but a pull request
have never been submitted for them. Thanks!
Anatolij
The following changes since commit 7680057cc4c7d9caada12767831bfd9738dd7b43:
powerpc: Don't try OPAL takeover on old 970 blades (2011-09-29 17:04:59 +1000)
are available in the git repository at:
git://git.denx.de/linux-2.6-agust.git next
Grant Likely (1):
powerpc/5200: add support for charon board
Heiko Schocher (1):
powerpc, tqm5200: update tqm5200_defconfig to fit for charon board.
arch/powerpc/boot/dts/charon.dts | 236 ++++++++++++++++++++++++++
arch/powerpc/configs/52xx/tqm5200_defconfig | 20 ++-
arch/powerpc/platforms/52xx/mpc5200_simple.c | 1 +
3 files changed, 249 insertions(+), 8 deletions(-)
create mode 100644 arch/powerpc/boot/dts/charon.dts
^ 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