* [RFC PATCH v2 03/10] fadump: Register for firmware assisted dump.
From: Mahesh J Salgaonkar @ 2011-09-29 15:05 UTC (permalink / raw)
To: linuxppc-dev, Linux Kernel, Benjamin Herrenschmidt
Cc: Anton Blanchard, Milton Miller, Eric W. Biederman
In-Reply-To: <20110929150117.26689.62053.stgit@mars.in.ibm.com>
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
This patch registers for firmware-assisted dump using rtas token
ibm,configure-kernel-dump. During registration firmware is informed about
the reserved area where it saves the CPU state data, HPTE table and contents
of RMR region at the time of kernel crash. Apart from this, firmware also
preserves the contents of entire partition memory even if it is not specified
during registration.
This patch also populates sysfs files under /sys/kernel to display
fadump status and reserved memory regions.
Change in v2:
- Removed few debug print statements.
- Moved the setup_fadump() call from setup_system() and now calling it
subsys_initcall.
- Moved fadump_region attribute under debugfs.
- Clear the TCE entries if firmware assisted dump is active.
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/fadump.h | 57 ++++++++
arch/powerpc/kernel/fadump.c | 271 +++++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/iommu.c | 8 +
arch/powerpc/mm/hash_utils_64.c | 11 ++
4 files changed, 343 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h
index 0b040c1..1728718 100644
--- a/arch/powerpc/include/asm/fadump.h
+++ b/arch/powerpc/include/asm/fadump.h
@@ -42,6 +42,58 @@
#define FADUMP_HPTE_REGION 0x0002
#define FADUMP_REAL_MODE_REGION 0x0011
+/* Dump request flag */
+#define FADUMP_REQUEST_FLAG 0x00000001
+
+/* FAD commands */
+#define FADUMP_REGISTER 1
+#define FADUMP_UNREGISTER 2
+#define FADUMP_INVALIDATE 3
+
+/* Kernel Dump section info */
+struct fadump_section {
+ u32 request_flag;
+ u16 source_data_type;
+ u16 error_flags;
+ u64 source_address;
+ u64 source_len;
+ u64 bytes_dumped;
+ u64 destination_address;
+};
+
+/* ibm,configure-kernel-dump header. */
+struct fadump_section_header {
+ u32 dump_format_version;
+ u16 dump_num_sections;
+ u16 dump_status_flag;
+ u32 offset_first_dump_section;
+
+ /* Fields for disk dump option. */
+ u32 dd_block_size;
+ u64 dd_block_offset;
+ u64 dd_num_blocks;
+ u32 dd_offset_disk_path;
+
+ /* Maximum time allowed to prevent an automatic dump-reboot. */
+ u32 max_time_auto;
+};
+
+/*
+ * Firmware Assisted dump memory structure. This structure is required for
+ * registering future kernel dump with power firmware through rtas call.
+ *
+ * No disk dump option. Hence disk dump path string section is not included.
+ */
+struct fadump_mem_struct {
+ struct fadump_section_header header;
+
+ /* Kernel dump sections */
+ struct fadump_section cpu_state_data;
+ struct fadump_section hpte_region;
+ struct fadump_section rmr_region;
+};
+
+/* Firmware-assisted dump configuration details. */
struct fw_dump {
unsigned long cpu_state_data_size;
unsigned long hpte_region_size;
@@ -56,10 +108,15 @@ struct fw_dump {
unsigned long fadump_enabled:1;
unsigned long fadump_supported:1;
unsigned long dump_active:1;
+ unsigned long dump_registered:1;
};
extern int early_init_dt_scan_fw_dump(unsigned long node,
const char *uname, int depth, void *data);
extern int fadump_reserve_mem(void);
+extern int setup_fadump(void);
+extern int is_fadump_active(void);
+#else /* CONFIG_FA_DUMP */
+static inline int is_fadump_active(void) { return 0; }
#endif
#endif
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 05dffc0..5a1b304 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -29,6 +29,9 @@
#include <linux/string.h>
#include <linux/memblock.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <asm/page.h>
#include <asm/prom.h>
@@ -46,6 +49,8 @@ struct dump_section {
} __packed;
static struct fw_dump fw_dump;
+static struct fadump_mem_struct fdm;
+static const struct fadump_mem_struct *fdm_active;
/* Scan the Firmware Assisted dump configuration details. */
int __init early_init_dt_scan_fw_dump(unsigned long node,
@@ -74,7 +79,8 @@ int __init early_init_dt_scan_fw_dump(unsigned long node,
* The 'ibm,kernel-dump' rtas node is present only if there is
* dump data waiting for us.
*/
- if (of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL))
+ fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL);
+ if (fdm_active)
fw_dump.dump_active = 1;
/* Get the sizes required to store dump data for the firmware provided
@@ -101,6 +107,85 @@ int __init early_init_dt_scan_fw_dump(unsigned long node,
return 1;
}
+int is_fadump_active(void)
+{
+ return fw_dump.dump_active;
+}
+
+/* Print firmware assisted dump configurations for debugging purpose. */
+static void fadump_show_config(void)
+{
+ pr_debug("Support for firmware-assisted dump (fadump): %s\n",
+ (fw_dump.fadump_supported ? "present" : "no support"));
+
+ if (!fw_dump.fadump_supported)
+ return;
+
+ pr_debug("Fadump enabled : %s\n",
+ (fw_dump.fadump_enabled ? "yes" : "no"));
+ pr_debug("Dump Active : %s\n",
+ (fw_dump.dump_active ? "yes" : "no"));
+ pr_debug("Dump section sizes:\n");
+ pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size);
+ pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size);
+ pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size);
+}
+
+static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm,
+ unsigned long addr)
+{
+ if (!fdm)
+ return 0;
+
+ memset(fdm, 0, sizeof(struct fadump_mem_struct));
+ addr = addr & PAGE_MASK;
+
+ fdm->header.dump_format_version = 0x00000001;
+ fdm->header.dump_num_sections = 3;
+ fdm->header.dump_status_flag = 0;
+ fdm->header.offset_first_dump_section =
+ (u32)offsetof(struct fadump_mem_struct, cpu_state_data);
+
+ /*
+ * Fields for disk dump option.
+ * We are not using disk dump option, hence set these fields to 0.
+ */
+ fdm->header.dd_block_size = 0;
+ fdm->header.dd_block_offset = 0;
+ fdm->header.dd_num_blocks = 0;
+ fdm->header.dd_offset_disk_path = 0;
+
+ /* set 0 to disable an automatic dump-reboot. */
+ fdm->header.max_time_auto = 0;
+
+ /* Kernel dump sections */
+ /* cpu state data section. */
+ fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG;
+ fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA;
+ fdm->cpu_state_data.source_address = 0;
+ fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size;
+ fdm->cpu_state_data.destination_address = addr;
+ addr += fw_dump.cpu_state_data_size;
+
+ /* hpte region section */
+ fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG;
+ fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION;
+ fdm->hpte_region.source_address = 0;
+ fdm->hpte_region.source_len = fw_dump.hpte_region_size;
+ fdm->hpte_region.destination_address = addr;
+ addr += fw_dump.hpte_region_size;
+
+ /* RMR region section */
+ fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG;
+ fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION;
+ fdm->rmr_region.source_address = RMR_START;
+ fdm->rmr_region.source_len = fw_dump.boot_memory_size;
+ fdm->rmr_region.destination_address = addr;
+ addr += fw_dump.boot_memory_size;
+
+ return addr;
+}
+
/**
* calculate_reserve_size() - reserve variable boot area 5% of System RAM
*
@@ -170,8 +255,15 @@ int __init fadump_reserve_mem(void)
fw_dump.fadump_enabled = 0;
return 0;
}
- /* Initialize boot memory size */
- fw_dump.boot_memory_size = calculate_reserve_size();
+ /*
+ * Initialize boot memory size
+ * If dump is active then we have already calculated the size during
+ * first kernel.
+ */
+ if (fdm_active)
+ fw_dump.boot_memory_size = fdm_active->rmr_region.source_len;
+ else
+ fw_dump.boot_memory_size = calculate_reserve_size();
/*
* Calculate the memory boundary.
@@ -248,3 +340,176 @@ static int __init early_fadump_reserve_mem(char *p)
return 0;
}
early_param("fadump_reserve_mem", early_fadump_reserve_mem);
+
+static void register_fw_dump(struct fadump_mem_struct *fdm)
+{
+ int rc;
+ unsigned int wait_time;
+
+ pr_debug("Registering for firmware-assisted kernel dump...\n");
+
+ /* TODO: Add upper time limit for the delay */
+ do {
+ rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
+ FADUMP_REGISTER, fdm,
+ sizeof(struct fadump_mem_struct));
+
+ wait_time = rtas_busy_delay_time(rc);
+ if (wait_time)
+ mdelay(wait_time);
+
+ } while (wait_time);
+
+ switch (rc) {
+ case -1:
+ printk(KERN_ERR "Failed to register firmware-assisted kernel"
+ " dump. Hardware Error(%d).\n", rc);
+ break;
+ case -3:
+ printk(KERN_ERR "Failed to register firmware-assisted kernel"
+ " dump. Parameter Error(%d).\n", rc);
+ break;
+ case -9:
+ printk(KERN_ERR "firmware-assisted kernel dump is already "
+ " registered.");
+ fw_dump.dump_registered = 1;
+ break;
+ case 0:
+ printk(KERN_INFO "firmware-assisted kernel dump registration"
+ " is successful\n");
+ fw_dump.dump_registered = 1;
+ break;
+ }
+}
+
+static void register_fadump(void)
+{
+ /*
+ * If no memory is reserved then we can not register for firmware-
+ * assisted dump.
+ */
+ if (!fw_dump.reserve_dump_area_size)
+ return;
+
+ /* Initialize the kernel dump memory structure for FAD registration. */
+ init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
+
+ /* register the future kernel dump with firmware. */
+ register_fw_dump(&fdm);
+}
+
+static ssize_t fadump_enabled_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", fw_dump.fadump_enabled);
+}
+
+static int fadump_region_show(struct seq_file *m, void *private)
+{
+ const struct fadump_mem_struct *fdm_ptr;
+
+ if (!fw_dump.fadump_enabled)
+ return 0;
+
+ if (fdm_active)
+ fdm_ptr = fdm_active;
+ else
+ fdm_ptr = &fdm;
+
+ seq_printf(m,
+ "CPU : [%#016llx-%#016llx] %#llx bytes, "
+ "Dumped: %#llx\n",
+ fdm_ptr->cpu_state_data.destination_address,
+ fdm_ptr->cpu_state_data.destination_address +
+ fdm_ptr->cpu_state_data.source_len - 1,
+ fdm_ptr->cpu_state_data.source_len,
+ fdm_ptr->cpu_state_data.bytes_dumped);
+ seq_printf(m,
+ "HPTE: [%#016llx-%#016llx] %#llx bytes, "
+ "Dumped: %#llx\n",
+ fdm_ptr->hpte_region.destination_address,
+ fdm_ptr->hpte_region.destination_address +
+ fdm_ptr->hpte_region.source_len - 1,
+ fdm_ptr->hpte_region.source_len,
+ fdm_ptr->hpte_region.bytes_dumped);
+ seq_printf(m,
+ "DUMP: [%#016llx-%#016llx] %#llx bytes, "
+ "Dumped: %#llx\n",
+ fdm_ptr->rmr_region.destination_address,
+ fdm_ptr->rmr_region.destination_address +
+ fdm_ptr->rmr_region.source_len - 1,
+ fdm_ptr->rmr_region.source_len,
+ fdm_ptr->rmr_region.bytes_dumped);
+
+ if (!fdm_active ||
+ (fw_dump.reserve_dump_area_start ==
+ fdm_ptr->cpu_state_data.destination_address))
+ return 0;
+
+ /* Dump is active. Show reserved memory region. */
+ seq_printf(m,
+ " : [%#016llx-%#016llx] %#llx bytes, "
+ "Dumped: %#llx\n",
+ (unsigned long long)fw_dump.reserve_dump_area_start,
+ fdm_ptr->cpu_state_data.destination_address - 1,
+ fdm_ptr->cpu_state_data.destination_address -
+ fw_dump.reserve_dump_area_start,
+ fdm_ptr->cpu_state_data.destination_address -
+ fw_dump.reserve_dump_area_start);
+ return 0;
+}
+
+static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
+ 0444, fadump_enabled_show,
+ NULL);
+
+static int fadump_region_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, fadump_region_show, inode->i_private);
+}
+
+static const struct file_operations fadump_region_fops = {
+ .open = fadump_region_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void fadump_init_files(void)
+{
+ struct dentry *debugfs_file;
+ int rc = 0;
+
+ rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr);
+ if (rc)
+ printk(KERN_ERR "fadump: unable to create sysfs file"
+ " fadump_enabled (%d)\n", rc);
+
+ debugfs_file = debugfs_create_file("fadump_region", 0444,
+ powerpc_debugfs_root, NULL,
+ &fadump_region_fops);
+ if (!debugfs_file)
+ printk(KERN_ERR "fadump: unable to create debugfs file"
+ " fadump_region\n");
+ return;
+}
+
+/*
+ * Prepare for firmware-assisted dump.
+ */
+int __init setup_fadump(void)
+{
+ if (!fw_dump.fadump_supported) {
+ printk(KERN_ERR "Firmware-assisted dump is not supported on"
+ " this hardware\n");
+ return 0;
+ }
+
+ fadump_show_config();
+ register_fadump();
+ fadump_init_files();
+
+ return 1;
+}
+subsys_initcall(setup_fadump);
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 961bb03..2549b53 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -39,6 +39,7 @@
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/kdump.h>
+#include <asm/fadump.h>
#define DBG(...)
@@ -445,7 +446,12 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
static void iommu_table_clear(struct iommu_table *tbl)
{
- if (!is_kdump_kernel()) {
+ /*
+ * In case of firmware assisted dump system goes through clean
+ * reboot process at the time of system crash. Hence it's safe to
+ * clear the TCE entries if firmware assisted dump is active.
+ */
+ if (!is_kdump_kernel() || is_fadump_active()) {
/* Clear the table in case firmware left allocations in it */
ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
return;
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 26b2872..ba64f1a 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -54,6 +54,7 @@
#include <asm/spu.h>
#include <asm/udbg.h>
#include <asm/code-patching.h>
+#include <asm/fadump.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -627,6 +628,16 @@ static void __init htab_initialize(void)
/* Using a hypervisor which owns the htab */
htab_address = NULL;
_SDR1 = 0;
+#ifdef CONFIG_FA_DUMP
+ /*
+ * If firmware assisted dump is active firmware preserves
+ * the contents of htab along with entire partition memory.
+ * Clear the htab if firmware assisted dump is active so
+ * that we dont end up using old mappings.
+ */
+ if (is_fadump_active() && ppc_md.hpte_clear_all)
+ ppc_md.hpte_clear_all();
+#endif
} else {
/* Find storage for the HPT. Must be contiguous in
* the absolute address space. On cell we want it to be
^ permalink raw reply related
* [RFC PATCH v2 02/10] fadump: Reserve the memory for firmware assisted dump.
From: Mahesh J Salgaonkar @ 2011-09-29 15:04 UTC (permalink / raw)
To: linuxppc-dev, Linux Kernel, Benjamin Herrenschmidt
Cc: Anton Blanchard, Milton Miller, Eric W. Biederman
In-Reply-To: <20110929150117.26689.62053.stgit@mars.in.ibm.com>
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Reserve the memory during early boot to preserve CPU state data, HPTE region
and RMR region data in case of kernel crash. At the time of crash, powerpc
firmware will store CPU state data, HPTE region data and move RMR region
data to the reserved memory area.
If the firmware-assisted dump fails to reserve the memory, then fallback
to existing kexec-based kdump.
The most of the code implementation to reserve memory has been
adapted from phyp assisted dump implementation written by Linas Vepstas
and Manish Ahuja
Change in v2:
- Modified to use standard pr_debug() macro.
- Modified early_init_dt_scan_fw_dump() to get the size of
"ibm,configure-kernel-dump-sizes" property and use it to iterate through
an array of dump sections.
- Introduced boot option 'fadump_reserve_mem=' to let user specify the
fadump boot memory to be reserved.
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/fadump.h | 65 ++++++++++
arch/powerpc/kernel/Makefile | 1
arch/powerpc/kernel/fadump.c | 250 +++++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/prom.c | 15 ++
4 files changed, 330 insertions(+), 1 deletions(-)
create mode 100644 arch/powerpc/include/asm/fadump.h
create mode 100644 arch/powerpc/kernel/fadump.c
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h
new file mode 100644
index 0000000..0b040c1
--- /dev/null
+++ b/arch/powerpc/include/asm/fadump.h
@@ -0,0 +1,65 @@
+/*
+ * Firmware Assisted dump header file.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2011 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#ifndef __PPC64_FA_DUMP_H__
+#define __PPC64_FA_DUMP_H__
+
+#ifdef CONFIG_FA_DUMP
+
+/*
+ * The RMR region will be saved for later dumping when kernel crashes.
+ * Set this to 256MB.
+ */
+#define RMR_START 0x0
+#define RMR_END (ppc64_rma_size)
+
+/*
+ * On some Power systems where RMO is 128MB, it still requires minimum of
+ * 256MB for kernel to boot successfully.
+ */
+#define MIN_BOOT_MEM ((RMR_END < (0x1UL << 28)) ? (0x1UL << 28) : RMR_END)
+
+/* Firmware provided dump sections */
+#define FADUMP_CPU_STATE_DATA 0x0001
+#define FADUMP_HPTE_REGION 0x0002
+#define FADUMP_REAL_MODE_REGION 0x0011
+
+struct fw_dump {
+ unsigned long cpu_state_data_size;
+ unsigned long hpte_region_size;
+ unsigned long boot_memory_size;
+ unsigned long reserve_dump_area_start;
+ unsigned long reserve_dump_area_size;
+ /* cmd line option during boot */
+ unsigned long reserve_bootvar;
+
+ int ibm_configure_kernel_dump;
+
+ unsigned long fadump_enabled:1;
+ unsigned long fadump_supported:1;
+ unsigned long dump_active:1;
+};
+
+extern int early_init_dt_scan_fw_dump(unsigned long node,
+ const char *uname, int depth, void *data);
+extern int fadump_reserve_mem(void);
+#endif
+#endif
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index ce4f7f1..59b549c 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_IBMEBUS) += ibmebus.o
obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+obj-$(CONFIG_FA_DUMP) += fadump.o
ifeq ($(CONFIG_PPC32),y)
obj-$(CONFIG_E500) += idle_e500.o
endif
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
new file mode 100644
index 0000000..05dffc0
--- /dev/null
+++ b/arch/powerpc/kernel/fadump.c
@@ -0,0 +1,250 @@
+/*
+ * Firmware Assisted dump: A robust mechanism to get reliable kernel crash
+ * dump with assistance from firmware. This approach does not use kexec,
+ * instead firmware assists in booting the kdump kernel while preserving
+ * memory contents. The most of the code implementation has been adapted
+ * from phyp assisted dump implementation written by Linas Vepstas and
+ * Manish Ahuja
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2011 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "fadump: " fmt
+
+#include <linux/string.h>
+#include <linux/memblock.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/fadump.h>
+
+/*
+ * The RTAS property "ibm,configure-kernel-dump-sizes" returns dump
+ * sizes for the firmware provided dump sections (cpu state data
+ * and hpte region).
+ */
+struct dump_section {
+ u32 dump_section;
+ unsigned long section_size;
+} __packed;
+
+static struct fw_dump fw_dump;
+
+/* Scan the Firmware Assisted dump configuration details. */
+int __init early_init_dt_scan_fw_dump(unsigned long node,
+ const char *uname, int depth, void *data)
+{
+ const struct dump_section *sections;
+ int i, num_sections;
+ unsigned long size;
+ const int *token;
+
+ if (depth != 1 || strcmp(uname, "rtas") != 0)
+ return 0;
+
+ /*
+ * Check if Firmware Assisted dump is supported. if yes, check
+ * if dump has been initiated on last reboot.
+ */
+ token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
+ if (!token)
+ return 0;
+
+ fw_dump.fadump_supported = 1;
+ fw_dump.ibm_configure_kernel_dump = *token;
+
+ /*
+ * The 'ibm,kernel-dump' rtas node is present only if there is
+ * dump data waiting for us.
+ */
+ if (of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL))
+ fw_dump.dump_active = 1;
+
+ /* Get the sizes required to store dump data for the firmware provided
+ * dump sections.
+ */
+ sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
+ &size);
+
+ if (!sections)
+ return 0;
+
+ num_sections = size / sizeof(struct dump_section);
+
+ for (i = 0; i < num_sections; i++) {
+ switch (sections[i].dump_section) {
+ case FADUMP_CPU_STATE_DATA:
+ fw_dump.cpu_state_data_size = sections[i].section_size;
+ break;
+ case FADUMP_HPTE_REGION:
+ fw_dump.hpte_region_size = sections[i].section_size;
+ break;
+ }
+ }
+ return 1;
+}
+
+/**
+ * calculate_reserve_size() - reserve variable boot area 5% of System RAM
+ *
+ * Function to find the largest memory size we need to reserve during early
+ * boot process. This will be the size of the memory that is required for a
+ * kernel to boot successfully.
+ *
+ * This function has been taken from phyp-assisted dump feature implementation.
+ *
+ * returns larger of 256MB or 5% rounded down to multiples of 256MB.
+ *
+ * TODO: Come up with better approach to find out more accurate memory size
+ * that is required for a kernel to boot successfully.
+ *
+ */
+static inline unsigned long calculate_reserve_size(void)
+{
+ unsigned long size;
+
+ /*
+ * Check if the size is specified through fadump_reserve_mem= cmdline
+ * option. If yes, then use that.
+ */
+ if (fw_dump.reserve_bootvar)
+ return fw_dump.reserve_bootvar;
+
+ /* divide by 20 to get 5% of value */
+ size = memblock_end_of_DRAM();
+ do_div(size, 20);
+
+ /* round it down in multiples of 256 */
+ size = size & ~0x0FFFFFFFUL;
+
+ /* Truncate to memory_limit. We don't want to over reserve the memory.*/
+ if (memory_limit && size > memory_limit)
+ size = memory_limit;
+
+ return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM);
+}
+
+/*
+ * Calculate the total memory size required to be reserved for
+ * firmware-assisted dump registration.
+ */
+static unsigned long get_dump_area_size(void)
+{
+ unsigned long size = 0;
+
+ size += fw_dump.cpu_state_data_size;
+ size += fw_dump.hpte_region_size;
+ size += fw_dump.boot_memory_size;
+
+ size = PAGE_ALIGN(size);
+ return size;
+}
+
+int __init fadump_reserve_mem(void)
+{
+ unsigned long base, size, memory_boundary;
+
+ if (!fw_dump.fadump_enabled)
+ return 0;
+
+ if (!fw_dump.fadump_supported) {
+ printk(KERN_ERR "Firmware-assisted dump is not supported on"
+ " this hardware\n");
+ fw_dump.fadump_enabled = 0;
+ return 0;
+ }
+ /* Initialize boot memory size */
+ fw_dump.boot_memory_size = calculate_reserve_size();
+
+ /*
+ * Calculate the memory boundary.
+ * If memory_limit is less than actual memory boundary then reserve
+ * the memory for fadump beyond the memory_limit and adjust the
+ * memory_limit accordingly, so that the running kernel can run with
+ * specified memory_limit.
+ */
+ if (memory_limit && memory_limit < memblock_end_of_DRAM()) {
+ size = get_dump_area_size();
+ if ((memory_limit + size) < memblock_end_of_DRAM())
+ memory_limit += size;
+ else
+ memory_limit = memblock_end_of_DRAM();
+ printk(KERN_INFO "Adjusted memory_limit for firmware-assisted"
+ " dump, now %#016llx\n",
+ (unsigned long long)memory_limit);
+ }
+ if (memory_limit)
+ memory_boundary = memory_limit;
+ else
+ memory_boundary = memblock_end_of_DRAM();
+
+ if (fw_dump.dump_active) {
+ printk(KERN_INFO "Firmware-assisted dump is active.\n");
+ /*
+ * If last boot has crashed then reserve all the memory
+ * above boot_memory_size so that we don't touch it until
+ * dump is written to disk by userspace tool. This memory
+ * will be released for general use once the dump is saved.
+ */
+ base = fw_dump.boot_memory_size;
+ size = memory_boundary - base;
+ memblock_reserve(base, size);
+ printk(KERN_INFO "Reserved %ldMB of memory at %ldMB "
+ "for saving crash dump\n",
+ (unsigned long)(size >> 20),
+ (unsigned long)(base >> 20));
+ } else {
+ /* Reserve the memory at the top of memory. */
+ size = get_dump_area_size();
+ base = memory_boundary - size;
+ memblock_reserve(base, size);
+ printk(KERN_INFO "Reserved %ldMB of memory at %ldMB "
+ "for firmware-assisted dump\n",
+ (unsigned long)(size >> 20),
+ (unsigned long)(base >> 20));
+ }
+ fw_dump.reserve_dump_area_start = base;
+ fw_dump.reserve_dump_area_size = size;
+ return 1;
+}
+
+/* Look for fadump= cmdline option. */
+static int __init early_fadump_param(char *p)
+{
+ if (!p)
+ return 1;
+
+ if (p[0] == '1')
+ fw_dump.fadump_enabled = 1;
+ else if (p[0] == '0')
+ fw_dump.fadump_enabled = 0;
+
+ return 0;
+}
+early_param("fadump", early_fadump_param);
+
+/* Look for fadump_reserve_mem= cmdline option */
+static int __init early_fadump_reserve_mem(char *p)
+{
+ if (p)
+ fw_dump.reserve_bootvar = memparse(p, &p);
+ return 0;
+}
+early_param("fadump_reserve_mem", early_fadump_reserve_mem);
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 174e1e9..3fe75eb 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -54,6 +54,7 @@
#include <asm/pci-bridge.h>
#include <asm/phyp_dump.h>
#include <asm/kexec.h>
+#include <asm/fadump.h>
#include <mm/mmu_decl.h>
#ifdef DEBUG
@@ -712,6 +713,11 @@ void __init early_init_devtree(void *params)
of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
#endif
+#ifdef CONFIG_FA_DUMP
+ /* scan tree to see if dump is active during last boot */
+ of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL);
+#endif
+
/* Retrieve various informations from the /chosen node of the
* device-tree, including the platform type, initrd location and
* size, TCE reserve, and more ...
@@ -735,7 +741,14 @@ void __init early_init_devtree(void *params)
if (PHYSICAL_START > MEMORY_START)
memblock_reserve(MEMORY_START, 0x8000);
reserve_kdump_trampoline();
- reserve_crashkernel();
+#ifdef CONFIG_FA_DUMP
+ /*
+ * If we fail to reserve memory for firmware-assisted dump then
+ * fallback to kexec based kdump.
+ */
+ if (fadump_reserve_mem() == 0)
+#endif
+ reserve_crashkernel();
early_reserve_mem();
phyp_dump_reserve_mem();
^ permalink raw reply related
* [RFC PATCH v2 01/10] fadump: Add documentation for firmware-assisted dump.
From: Mahesh J Salgaonkar @ 2011-09-29 15:03 UTC (permalink / raw)
To: linuxppc-dev, Linux Kernel, Benjamin Herrenschmidt
Cc: Anton Blanchard, Milton Miller, Eric W. Biederman
In-Reply-To: <20110929150117.26689.62053.stgit@mars.in.ibm.com>
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Documentation for firmware-assisted dump. This document is based on the
original documentation written for phyp assisted dump by Linas Vepstas
and Manish Ahuja, with few changes to reflect the current implementation.
Change in v2:
- Modified the documentation to reflect the change of fadump_region
file under debugfs filesystem.
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
Documentation/powerpc/firmware-assisted-dump.txt | 237 ++++++++++++++++++++++
1 files changed, 237 insertions(+), 0 deletions(-)
create mode 100644 Documentation/powerpc/firmware-assisted-dump.txt
diff --git a/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt
new file mode 100644
index 0000000..f06f941
--- /dev/null
+++ b/Documentation/powerpc/firmware-assisted-dump.txt
@@ -0,0 +1,237 @@
+
+ Firmware-Assisted Dump
+ ------------------------
+ July 2011
+
+The goal of firmware-assisted dump is to enable the dump of
+a crashed system, and to do so from a fully-reset system, and
+to minimize the total elapsed time until the system is back
+in production use.
+
+As compared to kdump or other strategies, firmware-assisted
+dump offers several strong, practical advantages:
+
+-- Unlike kdump, the system has been reset, and loaded
+ with a fresh copy of the kernel. In particular,
+ PCI and I/O devices have been reinitialized and are
+ in a clean, consistent state.
+-- Once the dump is copied out, the memory that held the dump
+ is immediately available to the running kernel. A further
+ reboot isn't required.
+
+The above can only be accomplished by coordination with,
+and assistance from the Power firmware. The procedure is
+as follows:
+
+-- The first kernel registers the sections of memory with the
+ Power firmware for dump preservation during OS initialization.
+ This registered sections of memory is reserved by the first
+ kernel during early boot.
+
+-- When a system crashes, the Power firmware will save
+ the low memory (boot memory of size larger of 5% of system RAM
+ or 256MB) of RAM to a previously registered save region. It
+ will also save system registers, and hardware PTE's.
+
+ NOTE: The term 'boot memory' means size of the low memory chunk
+ that is required for a kernel to boot successfully when
+ booted with restricted memory.
+
+-- After the low memory (boot memory) area has been saved, the
+ firmware will reset PCI and other hardware state. It will
+ *not* clear the RAM. It will then launch the bootloader, as
+ normal.
+
+-- The freshly booted kernel will notice that there is a new
+ node (ibm,dump-kernel) in the device tree, indicating that
+ there is crash data available from a previous boot. During
+ the early boot OS will reserve rest of the memory above
+ boot memory size effectively booting with restricted memory
+ size. This will make sure that the second kernel will not
+ touch any of the dump memory area.
+
+-- Userspace tools will read /proc/vmcore to obtain the contents
+ of memory, which holds the previous crashed kernel dump in ELF
+ format. The userspace tools may copy this info to disk, or
+ network, nas, san, iscsi, etc. as desired.
+
+-- Once the userspace tool is done saving dump, it will echo
+ '1' to /sys/kernel/fadump_release_mem to release the reserved
+ memory back to general use, except the memory required for
+ next firmware-assisted dump registration.
+
+ e.g.
+ # echo 1 > /sys/kernel/fadump_release_mem
+
+Please note that the firmware-assisted dump feature
+is only available on Power6 and above systems with recent
+firmware versions.
+
+Implementation details:
+----------------------
+
+During boot, a check is made to see if firmware supports
+this feature on that particular machine. If it does, then
+we check to see if an active dump is waiting for us. If yes
+then everything but boot memory size of RAM is reserved during
+early boot (See Fig. 2). This area is released once we collect a
+dump from user land scripts (kdump scripts) that are run. If
+there is dump data, then the /sys/kernel/fadump_release_mem
+file is created, and the reserved memory is held.
+
+If there is no waiting dump data, then only the memory required
+to hold CPU state, HPTE region, boot memory dump and elfcore
+header, is reserved at the top of memory (see Fig. 1). This area
+is *not* released: this region will be kept permanently reserved,
+so that it can act as a receptacle for a copy of the boot memory
+content in addition to CPU state and HPTE region, in the case a
+crash does occur.
+
+ o Memory Reservation during first kernel
+
+ Low memory Top of memory
+ 0 boot memory size |
+ | | |<--Reserved dump area -->|
+ V V | Permanent Reservation V
+ +-----------+----------/ /----------+---+----+-----------+----+
+ | | |CPU|HPTE| DUMP |ELF |
+ +-----------+----------/ /----------+---+----+-----------+----+
+ | ^
+ | |
+ \ /
+ -------------------------------------------
+ Boot memory content gets transferred to
+ reserved area by firmware at the time of
+ crash
+ Fig. 1
+
+ o Memory Reservation during second kernel after crash
+
+ Low memory Top of memory
+ 0 boot memory size |
+ | |<------------- Reserved dump area ----------- -->|
+ V V V
+ +-----------+----------/ /----------+---+----+-----------+----+
+ | | |CPU|HPTE| DUMP |ELF |
+ +-----------+----------/ /----------+---+----+-----------+----+
+ | |
+ V V
+ Used by second /proc/vmcore
+ kernel to boot
+ Fig. 2
+
+Currently the dump will be copied from /proc/vmcore to a
+a new file upon user intervention. The dump data available through
+/proc/vmcore will be in ELF format. Hence the existing kdump
+infrastructure (kdump scripts) to save the dump works fine
+with minor modifications. The kdump script requires following
+modifications:
+-- During service kdump start if /proc/vmcore entry is not present,
+ look for the existence of /sys/kernel/fadump_enabled and read
+ value exported by it. If value is set to '1' then print
+ success otherwise fallback to existing kexec based kdump.
+
+-- During service kdump start if /proc/vmcore entry is present,
+ execute the existing routine to save the dump. Once the dump
+ is saved, echo 1 > /sys/kernel/fadump_release_mem (if the
+ file exists) to release the reserved memory for general use
+ and continue without rebooting. At this point the memory
+ reservation map will look like as shown in Fig. 1. If the file
+ /sys/kernel/fadump_release_mem is not present then follow
+ the existing routine to reboot into new kernel.
+
+The tools to examine the dump will be same as the ones
+used for kdump.
+
+How to enable firmware-assisted dump (fadump):
+-------------------------------------
+
+1. Set config option CONFIG_FA_DUMP=y and build kernel.
+2. Boot into linux kernel with 'fadump=1' kernel cmdline option.
+
+NOTE: If firmware-assisted dump fails to reserve memory then it will
+ fallback to existing kdump mechanism if 'crashkernel=' option
+ is set at kernel cmdline.
+
+Sysfs/debugfs files:
+------------
+
+Firmware-assisted dump feature uses sysfs file system to hold
+the control files and debugfs file to display memory reserved region.
+
+Here is the list of files under kernel sysfs:
+
+ /sys/kernel/fadump_enabled
+
+ This is used to display the fadump status.
+ 0 = fadump is disabled
+ 1 = fadump is enabled
+
+ /sys/kernel/fadump_release_mem
+
+ This file is available only when fadump is active during
+ second kernel. This is used to release the reserved memory
+ region that are held for saving crash dump. To release the
+ reserved memory echo 1 to it:
+
+ echo 1 > /sys/kernel/fadump_release_mem
+
+ After echo 1, the content of the /sys/kernel/fadump_region
+ file will change to reflect the new memory reservations.
+
+Here is the list of files under powerpc debugfs:
+(Assuming debugfs is mounted on /sys/kernel/debug directory.)
+
+ /sys/kernel/debug/powerpc/fadump_region
+
+ This file shows the reserved memory regions if fadump is
+ enabled otherwise this file is empty. The output format
+ is:
+ <region>: [<start>-<end>] <reserved-size> bytes, Dumped: <dump-size>
+
+ e.g.
+ Contents when fadump is registered during first kernel
+
+ # cat /sys/kernel/fadump_region
+ CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x0
+ HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x0
+ DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x0
+
+ Contents when fadump is active during second kernel
+
+ # cat /sys/kernel/fadump_region
+ CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x40020
+ HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x1000
+ DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x10000000
+ : [0x00000010000000-0x0000006ffaffff] 0x5ffb0000 bytes, Dumped: 0x5ffb0000
+
+NOTE: Please refer to debugfs documentation on how to mount the debugfs
+ filesystem.
+
+
+TODO:
+-----
+ o Need to come up with the better approach to find out more
+ accurate boot memory size that is required for a kernel to
+ boot successfully when booted with restricted memory.
+ o The fadump implementation introduces a fadump crash info structure
+ in the scratch area before the ELF core header. The idea of introducing
+ this structure is to pass some important crash info data to the second
+ kernel which will help second kernel to populate ELF core header with
+ correct data before it gets exported through /proc/vmcore. The current
+ design implementation does not address a possibility of introducing
+ additional fields (in future) to this structure without affecting
+ compatibility. Need to come up with the better approach to address this.
+ The possible approaches are:
+ 1. Introduce version field for version tracking, bump up the version
+ whenever a new field is added to the structure in future. The version
+ field can be used to find out what fields are valid for the current
+ version of the structure.
+ 2. Reserve the area of predefined size (say PAGE_SIZE) for this
+ structure and have unused area as reserved (initialized to zero)
+ for future field additions.
+ The advantage of approach 1 over 2 is we don't need to reserve extra space.
+---
+Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+This document is based on the original documentation written for phyp
+assisted dump by Linas Vepstas and Manish Ahuja.
^ permalink raw reply related
* [RFC PATCH v2 00/10] fadump: Firmware-assisted dump support for Powerpc.
From: Mahesh J Salgaonkar @ 2011-09-29 15:02 UTC (permalink / raw)
To: linuxppc-dev, Linux Kernel, Benjamin Herrenschmidt
Cc: Anton Blanchard, Milton Miller, Eric W. Biederman
Hi All,
Please find the version 2 of the patchset that implements firmware-assisted
dump mechanism to capture kernel crash dump for Powerpc architecture. The
firmware-assisted dump is a robust mechanism to get reliable kernel crash
dump with assistance from firmware. This approach does not use kexec, instead
firmware assists in booting the kdump kernel while preserving memory contents.
Changes in v2:
-------------
patch 01/10:
- Modified the documentation to reflect the change of fadump_region
file under debugfs filesystem.
patch 02/10:
- Modified to use standard pr_debug() macro.
- Modified early_init_dt_scan_fw_dump() to get the size of
"ibm,configure-kernel-dump-sizes" property and use it to iterate through
an array of dump sections.
- Introduced boot option 'fadump_reserve_mem=' to let user specify the
fadump boot memory to be reserved.
patch 03/10:
- Removed few debug print statements.
- Moved the setup_fadump() call from setup_system() and now calling it
subsys_initcall.
- Moved fadump_region attribute under debugfs.
- Clear the TCE entries if firmware assisted dump is active.
patch 05/10:
- Moved the crash_fadump() invocation from generic code to panic notifier.
- Introduced cpu_notes_buf_alloc() function to allocate cpu notes buffer
using get_free_pages().
patch 08/10:
- Introduced cpu_notes_buf_free() function to free memory allocated for
cpu notes buffer.
The most of the code implementation has been adapted from phyp assisted dump
implementation written by Linas Vepstas and Manish Ahuja.
The first patch is a documentation that talks about firmware-assisted dump
mechanism, implementation details and TODO list.
One of the important item from TODO list where I am looking forward for more
ideas/suggestions is regarding fadump crash info structure in the scratch
area before the ELF core header (see patch 4/10 and 5/10). The idea of
introducing this structure is to pass some important crash info data to the
second kernel which will help second kernel to populate ELF core header with
correct data before it gets exported through /proc/vmcore. The current design
implementation does not address the possibility of introducing additional
fields (in future) to this structure without affecting compatibility.
Following are the possible approaches I have in mind:
1. Introduce version field for version tracking, bump up the version
whenever a new field is added to the structure in future. The version
field can be used to find out what fields are valid for the current
version of the structure.
2. Reserve the area of predefined size (say PAGE_SIZE) for this
structure and have unused area as reserved (initialized to zero)
for future field additions.
The advantage of the approach 1 over 2 is, we don't need to reserve extra
space.
Please let me know if there is better solution available.
I have tested the patches on following system configuration:
1. LPAR on Power6 with 4GB RAM and 8 CPUs
2. LPAR on Power7 with 2GB RAM and 20 CPUs
3. LPAR on Power7 with 1TB RAM and 896 CPUs
These patches cleanly apply on commit 9e79e3e9 in linux-2.6 git tree.
Please review the patchset and let me know your comments.
Thanks,
-Mahesh.
---
Mahesh Salgaonkar (10):
fadump: Add documentation for firmware-assisted dump.
fadump: Reserve the memory for firmware assisted dump.
fadump: Register for firmware assisted dump.
fadump: Initialize elfcore header and add PT_LOAD program headers.
fadump: Convert firmware-assisted cpu state dump data into elf notes.
fadump: Add PT_NOTE program header for vmcoreinfo
fadump: Introduce cleanup routine to invalidate /proc/vmcore.
fadump: Invalidate registration and release reserved memory for general use.
fadump: Invalidate the fadump registration during machine shutdown.
fadump: Introduce config option for firmware assisted dump feature
Documentation/powerpc/firmware-assisted-dump.txt | 237 ++++
arch/powerpc/Kconfig | 13
arch/powerpc/include/asm/fadump.h | 205 ++++
arch/powerpc/kernel/Makefile | 1
arch/powerpc/kernel/fadump.c | 1200 ++++++++++++++++++++++
arch/powerpc/kernel/iommu.c | 8
arch/powerpc/kernel/prom.c | 15
arch/powerpc/kernel/setup-common.c | 16
arch/powerpc/kernel/traps.c | 5
arch/powerpc/mm/hash_utils_64.c | 11
fs/proc/vmcore.c | 23
include/linux/crash_dump.h | 1
include/linux/memblock.h | 1
kernel/crash_dump.c | 33 +
14 files changed, 1767 insertions(+), 2 deletions(-)
create mode 100644 Documentation/powerpc/firmware-assisted-dump.txt
create mode 100644 arch/powerpc/include/asm/fadump.h
create mode 100644 arch/powerpc/kernel/fadump.c
--
Signature
^ permalink raw reply
* Re: [PATCH 3/4] p4080ds-dts: Add two rapidio ports and message units support
From: Kumar Gala @ 2011-09-29 14:23 UTC (permalink / raw)
To: Liu Gang; +Cc: Jin Qing, r58472, linux-kernel, r61911, akpm, linuxppc-dev,
B11780
In-Reply-To: <1317263341-19010-3-git-send-email-Gang.Liu@freescale.com>
On Sep 28, 2011, at 9:29 PM, Liu Gang wrote:
> Add two message units and number of ports according to the p4080 =
reference manual.
>=20
> 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(-)
what about all the other .dts with SRIO nodes in them?
- k=
^ permalink raw reply
* Re: [PATCH 3/4] p4080ds-dts: Add two rapidio ports and message units support
From: Kumar Gala @ 2011-09-29 14:22 UTC (permalink / raw)
To: Liu Gang; +Cc: Jin Qing, r58472, linux-kernel, r61911, akpm, linuxppc-dev,
B11780
In-Reply-To: <1317263341-19010-3-git-send-email-Gang.Liu@freescale.com>
On Sep 28, 2011, at 9:29 PM, Liu Gang wrote:
> Add two message units and number of ports according to the p4080 =
reference manual.
Explain why range size increased.
>=20
> 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(-)
>=20
> 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 @@
> };
> };
>=20
> - rapidio0: rapidio@ffe0c0000 {
> + rapidio: rapidio@ffe0c0000 {
> reg =3D <0xf 0xfe0c0000 0 0x20000>;
> - ranges =3D <0 0 0xc 0x20000000 0 0x01000000>;
> + ranges =3D <0 0 0xc 0x20000000 0 0x20000000>;
> };
>=20
> 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 =3D &rtic_c;
> rtic_d =3D &rtic_d;
> sec_mon =3D &sec_mon;
> + rmu =3D &rmu;
>=20
> - rio0 =3D &rapidio0;
> + rio =3D &rapidio;
> };
>=20
> cpus {
> @@ -555,20 +556,38 @@
> interrupt-parent =3D <&mpic>;
> interrupts =3D <93 2 0 0>;
> };
> +
> + rmu: rmu@d3000 {
> + #address-cells =3D <1>;
> + #size-cells =3D <1>;
> + compatible =3D "fsl,rmu";
> + reg =3D <0xd3000 0x200>;
> +
> + message-unit@0 {
> + reg =3D <0x0 0x100>;
> + interrupts =3D <
> + 60 2 0 0 /* msg1_tx_irq =
*/
> + 61 2 0 0>;/* msg1_rx_irq =
*/
> + };
> + message-unit@1 {
message-unit@100
> + reg =3D <0x100 0x100>;
> + interrupts =3D <
> + 62 2 0 0 /* msg2_tx_irq =
*/
> + 63 2 0 0>;/* msg2_rx_irq =
*/
> + };
> + };
> };
>=20
> - rapidio0: rapidio@ffe0c0000 {
> + rapidio: rapidio@ffe0c0000 {
> #address-cells =3D <2>;
> #size-cells =3D <2>;
> compatible =3D "fsl,rapidio-delta";
change to 'fsl,srio' per comments on binding patch.
> interrupts =3D <
> - 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 =3D <2>;
> + rmu-handle =3D <&rmu>;
> };
>=20
> localbus@ffe124000 {
> --=20
> 1.7.3.1
>=20
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 1/4] fsl-rio: Split rio driver into two parts, RapidIO endpoint and RapidIO message unit
From: Kumar Gala @ 2011-09-29 14:21 UTC (permalink / raw)
To: Liu Gang
Cc: r58472, linux-kernel, r61911, Lian Minghuan-B31939, B11780,
linuxppc-dev, akpm
In-Reply-To: <1317263341-19010-1-git-send-email-Gang.Liu@freescale.com>
On Sep 28, 2011, at 9:28 PM, Liu Gang wrote:
> 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.
>=20
> 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
Fix commit message so it doesn't go based 75 char column line wrap (same =
comment for other patches in the series)
- k=
^ permalink raw reply
* Re: [PATCH 4/4] powerpc/fsl: Document rapidio node binding-information
From: Kumar Gala @ 2011-09-29 14:20 UTC (permalink / raw)
To: Liu Gang; +Cc: Jin Qing, r58472, linux-kernel, r61911, B11780, linuxppc-dev,
akpm
In-Reply-To: <1317263341-19010-4-git-send-email-Gang.Liu@freescale.com>
On Sep 28, 2011, at 9:29 PM, Liu Gang wrote:
> 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.
>=20
> 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
You need to fix this for 80 char column line wrap.
>=20
> 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.
Lets go ahead and change this from 'fsl,rapdio-delta' to 'fsl,srio' =
since you're changing how the binding is defined completely. This way =
old .dts will fail graceful with the new code.
> +
> + - 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.
be clear about the order of the 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.
We need to add something like:
In this case, the first cell is the LIODN associated with the port 1 and =
the second LIODN is associated with port 2.
> For HW that has separate LIODNs
> + for memory & maintenance transaction we utilize 4 cells.
In this case, the first pair of cells are associated with port 1. The =
first cell is the LIODN associated with memory transactions, the second =
cell is the LIODN associated with maintenance transactions. The 3 and 4 =
cells follow the same pattern for port 2.
> +
> + - rmu-handle: The phandle for the rmu connected to this rapidio =
controller.
> +
> +Example:
> +
> + rapidio: rapidio@ffe0c0000 {
> + #address-cells =3D <2>;
> + #size-cells =3D <2>;
> + compatible =3D "fsl,rapidio-delta";
> + interrupts =3D <
> + 16 2 1 11 /* err_irq */
> + 56 2 0 0 /* bell_outb_irq */
> + 57 2 0 0>;/* bell_inb_irq */
> + fsl,rio-num-ports =3D <2>;
> + rmu-handle =3D <&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.
be clear about the order of the interrupts being TX first and RX second.
> +
> + - fsl,liodn: The logical I/O device number for rmuliodnr and =
added by u-boot.
> +
> +Example:
> +
> + rmu: rmu@d3000 {
> + fsl,liodn =3D <0xc8>;
> + #address-cells =3D <1>;
> + #size-cells =3D <1>;
> + compatible =3D "fsl,rmu";
> + reg =3D <0xd3000 0x200>;
> +
> + message-unit@0 {
> + reg =3D <0x0 0x100>;
> + interrupts =3D <
> + 60 2 0 0 /* msg1_tx_irq */
> + 61 2 0 0>;/* msg1_rx_irq */
> + };
> + message-unit@1 {
should be message-unit@100
> + reg =3D <0x100 0x100>;
> + interrupts =3D <
> + 62 2 0 0 /* msg2_tx_irq */
> + 63 2 0 0>;/* msg2_rx_irq */
> + };
> + };
> --=20
> 1.7.3.1
>=20
>=20
> --
> To unsubscribe from this list: send the line "unsubscribe =
linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: Please pull 'next' branch of 5xxx tree (updated)
From: Anatolij Gustschin @ 2011-09-29 13:45 UTC (permalink / raw)
To: Grant Likely, Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <CACxGe6s1K+rUbH7XinhHXqXvNzZ_QXwYfZHe8t1kzYj223ampg@mail.gmail.com>
Hi Grant,
On Thu, 29 Sep 2011 07:49:07 -0500
Grant Likely <grant.likely@secretlab.ca> wrote:
...
> > 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
>
> Hmmm, I didn't actually write this patch. It looks like the author credit
> got screwed up at some point.
Thanks for pointing this out. Actually Heiko is the author of
the original patch. I've updated the next branch accordingly, so
here is a new pull request:
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
Heiko Schocher (2):
powerpc/5200: add support for charon board
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
Anatolij
^ permalink raw reply
* Re: Please pull 'next' branch of 5xxx tree
From: Grant Likely @ 2011-09-29 12:49 UTC (permalink / raw)
To: Anatolij Gustschin; +Cc: linuxppc-dev list
In-Reply-To: <20110929113025.2b224cd3@wker>
[-- Attachment #1: Type: text/plain, Size: 1291 bytes --]
On Sep 29, 2011 4:31 AM, "Anatolij Gustschin" <agust@denx.de> wrote:
>
> 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
Hmmm, I didn't actually write this patch. It looks like the author credit
got screwed up at some point.
g.
>
> 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
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
[-- Attachment #2: Type: text/html, Size: 1811 bytes --]
^ permalink raw reply
* [PATCH] [PATCH v3] powerpc: Fix xmon for systems without MSR[RI]
From: Jimi Xenidis @ 2011-09-29 12:45 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Scott Wood, David Gibson
In-Reply-To: <1316792446-10599-1-git-send-email-jimix@pobox.com>
From: David Gibson <dwg@au1.ibm.com>
Based on patch by David Gibson <dwg@au1.ibm.com>
xmon has a longstanding bug on systems which are SMP-capable but lack
the MSR[RI] bit. In these cases, xmon invoked by IPI on secondary
CPUs will not properly keep quiet, but will print stuff, thereby
garbling the primary xmon's output. This patch fixes it, by ignoring
the RI bit if the processor does not support it.
There's already a version of this for 4xx upstream, which we'll need
to extend to other RI-lacking CPUs at some point. For now this adds
Book3e processors to the mix.
Signed-off-by: Jimi Xenidis <jimix@pobox.com>
---
Restricted it to Book3e
Fix typo, its supposed to be CONFIG_PPC_BOOK3E
---
arch/powerpc/xmon/xmon.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 42541bb..e88e7f5 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -340,8 +340,8 @@ int cpus_are_in_xmon(void)
static inline int unrecoverable_excp(struct pt_regs *regs)
{
-#ifdef CONFIG_4xx
- /* We have no MSR_RI bit on 4xx, so we simply return false */
+#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
+ /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
return 0;
#else
return ((regs->msr & MSR_RI) == 0);
--
1.7.0.4
^ permalink raw reply related
* Re: [RFC] CONFIG_RELOCATABLE : __va() & __pa() definitions
From: Suzuki Poulose @ 2011-09-29 9:40 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Mahesh Jagannath Salgaonkar, Paul Mackerras, linux ppc dev
In-Reply-To: <1317250996.29415.125.camel@pasglop>
On 09/29/11 04:33, Benjamin Herrenschmidt wrote:
> 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,
I am processing the relocations in my approach.
But even in that case, __va(), __pa() needs modification since , on BookE,
we depend on PHYSICAL_START(kernstart_addr) to do the translations.
So depending on the kernstart_addr, the __va() keeps changing, even though
the mappings doesn't change. (Virtual to Physical mapping). Please note that,
since we use 256M mappings, any address within the 256M will result in the same
mapping.
>> | Phys. Addr | Virt. Addr |
>> PageBoundary (256M) |-------------------------------|
>> | | |
>> | | |
>> | | |
>> (Phys. Start)%256M-> |_______________|_ _ _ _ _ _ _ _|<- Relocated. Kernel
>> | | ^ | Virtual Address
>> | | | |
>> | | | |
>> | | reloc_offset |
>> | | | |
>> | | | |
>> | |_______v_______|<-(KERNELBASE)%
>> | | | 256M
>> | | |
>> | | |
>> | | |
>> | | |
>> PageBoundary (256M) |---------------|---------------|
>> | | |
>> | | |
>>
Thanks
Suzuki
^ 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
* 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
* 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
* 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
* [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
* 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
* 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
* [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
* [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 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 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
* 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
* 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
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