LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 02/15] [POWERPC] 52xx: Remove support for PCI bus_offset
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070063989-git-send-email-galak@kernel.crashing.org>

The hose->bus_offset is only used for PCI config cycles and the 52xx PCI
config code doesn't actually ever set bus_offset to a non-zero value.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/52xx/mpc52xx_pci.c |    9 ++++-----
 1 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index 51164c8..57ca2fe 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -117,13 +117,13 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
 
 	out_be32(hose->cfg_addr,
 		(1 << 31) |
-		((bus->number - hose->bus_offset) << 16) |
+		(bus->number << 16) |
 		(devfn << 8) |
 		(offset & 0xfc));
 	mb();
 
 #if defined(CONFIG_PPC_MPC5200_BUGFIX)
-	if (bus->number != hose->bus_offset) {
+	if (bus->number) {
 		/* workaround for the bug 435 of the MPC5200 (L25R);
 		 * Don't do 32 bits config access during type-1 cycles */
 		switch (len) {
@@ -174,13 +174,13 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
 
 	out_be32(hose->cfg_addr,
 		(1 << 31) |
-		((bus->number - hose->bus_offset) << 16) |
+		(bus->number << 16) |
 		(devfn << 8) |
 		(offset & 0xfc));
 	mb();
 
 #if defined(CONFIG_PPC_MPC5200_BUGFIX)
-	if (bus->number != hose->bus_offset) {
+	if (bus->number) {
 		/* workaround for the bug 435 of the MPC5200 (L25R);
 		 * Don't do 32 bits config access during type-1 cycles */
 		switch (len) {
@@ -394,7 +394,6 @@ mpc52xx_add_bridge(struct device_node *node)
 	hose->first_busno = bus_range ? bus_range[0] : 0;
 	hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
-	hose->bus_offset = 0;
 	hose->ops = &mpc52xx_pci_ops;
 
 	pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 03/15] [POWERPC] Pass the pci_controller into pci_exclude_device
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070073637-git-send-email-galak@kernel.crashing.org>

There are times that we need to know which controller we are on to decide
how to exclude devices properly.  We now pass the pci_controller that we
are going to use down to the pci_exclude_device function. This will
greatly simplify being able to exclude the PHBs in multiple controller
setups.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/82xx/mpc82xx_ads.c         |    3 +-
 arch/powerpc/platforms/83xx/mpc83xx.h             |    4 +-
 arch/powerpc/platforms/83xx/pci.c                 |    2 +-
 arch/powerpc/platforms/85xx/mpc85xx_ads.c         |    3 +-
 arch/powerpc/platforms/85xx/mpc85xx_cds.c         |    3 +-
 arch/powerpc/platforms/86xx/mpc86xx.h             |    3 +-
 arch/powerpc/platforms/86xx/pci.c                 |    2 +-
 arch/powerpc/platforms/embedded6xx/holly.c        |    2 +-
 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c |    3 +-
 arch/powerpc/sysdev/Makefile                      |    2 +-
 arch/powerpc/sysdev/fsl_pcie.c                    |    4 +-
 arch/powerpc/sysdev/indirect_pci.c                |    8 +-
 arch/powerpc/sysdev/tsi108_pci.c                  |    6 +-
 arch/ppc/syslib/Makefile                          |    1 +
 arch/ppc/syslib/indirect_pci.c                    |  134 +++++++++++++++++++++
 include/asm-powerpc/machdep.h                     |    2 +-
 16 files changed, 163 insertions(+), 19 deletions(-)
 create mode 100644 arch/ppc/syslib/indirect_pci.c

diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index 04bf570..715107b 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -507,7 +507,8 @@ void m82xx_pci_init_irq(void)
 	return;
 }
 
-static int m82xx_pci_exclude_device(u_char bus, u_char devfn)
+static int m82xx_pci_exclude_device(struct pci_controller *hose,
+				    u_char bus, u_char devfn)
 {
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
index 9bd85f5..f5c5034 100644
--- a/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -3,6 +3,7 @@
 
 #include <linux/init.h>
 #include <linux/device.h>
+#include <asm/pci-bridge.h>
 
 /* System Clock Control Register */
 #define MPC83XX_SCCR_OFFS          0xA08
@@ -28,7 +29,8 @@
  */
 
 extern int mpc83xx_add_bridge(struct device_node *dev);
-extern int mpc83xx_exclude_device(u_char bus, u_char devfn);
+extern int mpc83xx_exclude_device(struct pci_controller *hose,
+				  u_char bus, u_char devfn);
 extern void mpc83xx_restart(char *cmd);
 extern long mpc83xx_time_init(void);
 
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 3471602..f92e71f 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -35,7 +35,7 @@
 
 int mpc83xx_pci2_busno;
 
-int mpc83xx_exclude_device(u_char bus, u_char devfn)
+int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
 {
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 4100e17..1262d1b 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -39,7 +39,8 @@
 #endif
 
 #ifdef CONFIG_PCI
-static int mpc85xx_exclude_device(u_char bus, u_char devfn)
+static int mpc85xx_exclude_device(struct pci_controller *hose,
+				   u_char bus, u_char devfn)
 {
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index fa6b6be..fcea5ab 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -57,7 +57,8 @@ static volatile u8 *cadmus;
 
 extern int mpc85xx_pci2_busno;
 
-static int mpc85xx_exclude_device(u_char bus, u_char devfn)
+static int mpc85xx_exclude_device(struct pci_controller *hose,
+				  u_char bus, u_char devfn)
 {
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h
index dc2f6fd..4c2789d 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx.h
+++ b/arch/powerpc/platforms/86xx/mpc86xx.h
@@ -17,7 +17,8 @@
 
 extern int mpc86xx_add_bridge(struct device_node *dev);
 
-extern int mpc86xx_exclude_device(u_char bus, u_char devfn);
+extern int mpc86xx_exclude_device(struct pci_controller *hose,
+				  u_char bus, u_char devfn);
 
 extern void setup_indirect_pcie(struct pci_controller *hose,
 				       u32 cfg_addr, u32 cfg_data);
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 1e47c14..7659259 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -140,7 +140,7 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
 	early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps);
 }
 
-int mpc86xx_exclude_device(u_char bus, u_char devfn)
+int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
 {
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c
index 3a0b4a0..6292e36 100644
--- a/arch/powerpc/platforms/embedded6xx/holly.c
+++ b/arch/powerpc/platforms/embedded6xx/holly.c
@@ -45,7 +45,7 @@
 
 #define HOLLY_PCI_CFG_PHYS 0x7c000000
 
-int holly_exclude_device(u_char bus, u_char devfn)
+int holly_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
 {
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index 69eab17..1e3cc69 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -56,7 +56,8 @@
 
 extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
 
-int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
+int mpc7448_hpc2_exclude_device(struct pci_controller *hose,
+				u_char bus, u_char devfn)
 {
 	if (bus == 0 && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index c3ce0bd..43fd7e0 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -5,7 +5,6 @@ endif
 mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
 
-obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
 obj-$(CONFIG_PPC_DCR)		+= dcr.o
 obj-$(CONFIG_PPC_DCR_NATIVE)	+= dcr-low.o
@@ -23,6 +22,7 @@ obj-$(CONFIG_MV64X60)		+= $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o
 obj-$(CONFIG_PM)		+= timer.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
+obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
 obj-$(CONFIG_PPC_I8259)		+= i8259.o
 obj-$(CONFIG_PPC_83xx)		+= ipic.o
 obj-$(CONFIG_4xx)		+= uic.o
diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c
index 041c07e..6bbd7f8 100644
--- a/arch/powerpc/sysdev/fsl_pcie.c
+++ b/arch/powerpc/sysdev/fsl_pcie.c
@@ -39,7 +39,7 @@ indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
 	u32 temp;
 
 	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 
 	/* Possible artifact of CDCpp50937 needs further investigation */
@@ -90,7 +90,7 @@ indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
 	u32 temp;
 
 	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 
 	/* Possible artifact of CDCpp50937 needs further investigation */
diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c
index e714884..3dedf8f 100644
--- a/arch/powerpc/sysdev/indirect_pci.c
+++ b/arch/powerpc/sysdev/indirect_pci.c
@@ -35,14 +35,14 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 	u8 cfg_type = 0;
 
 	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 	
 	if (hose->set_cfg_type)
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
-	PCI_CFG_OUT(hose->cfg_addr, 					 
+	PCI_CFG_OUT(hose->cfg_addr,
 		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
 		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
 
@@ -74,14 +74,14 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 	u8 cfg_type = 0;
 
 	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (hose->set_cfg_type)
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
-	PCI_CFG_OUT(hose->cfg_addr, 					 
+	PCI_CFG_OUT(hose->cfg_addr,
 		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
 		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
 
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index 33177b6..298e2dd 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -64,9 +64,10 @@ tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfunc,
 			   int offset, int len, u32 val)
 {
 	volatile unsigned char *cfg_addr;
+	struct pci_controller *hose = bus->sysdata;
 
 	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfunc))
+		if (ppc_md.pci_exclude_device(hose, bus->number, devfunc))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 
 	cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
@@ -149,10 +150,11 @@ tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 			  int len, u32 * val)
 {
 	volatile unsigned char *cfg_addr;
+	struct pci_controller *hose = bus->sysdata;
 	u32 temp;
 
 	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 
 	cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 9569415..543795b 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -7,6 +7,7 @@ CFLAGS_btext.o          += -fPIC
 
 wdt-mpc8xx-$(CONFIG_8xx_WDT)	+= m8xx_wdt.o
 
+obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
 obj-$(CONFIG_PPCBUG_NVRAM)	+= prep_nvram.o
 obj-$(CONFIG_PPC_OCP)		+= ocp.o
 obj-$(CONFIG_IBM_OCP)		+= ibm_ocp.o
diff --git a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c
new file mode 100644
index 0000000..e714884
--- /dev/null
+++ b/arch/ppc/syslib/indirect_pci.c
@@ -0,0 +1,134 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#ifdef CONFIG_PPC_INDIRECT_PCI_BE
+#define PCI_CFG_OUT out_be32
+#else
+#define PCI_CFG_OUT out_le32
+#endif
+
+static int
+indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+		     int len, u32 *val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile void __iomem *cfg_data;
+	u8 cfg_type = 0;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	
+	if (hose->set_cfg_type)
+		if (bus->number != hose->first_busno)
+			cfg_type = 1;
+
+	PCI_CFG_OUT(hose->cfg_addr, 					 
+		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	cfg_data = hose->cfg_data + (offset & 3);
+	switch (len) {
+	case 1:
+		*val = in_8(cfg_data);
+		break;
+	case 2:
+		*val = in_le16(cfg_data);
+		break;
+	default:
+		*val = in_le32(cfg_data);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+		      int len, u32 val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile void __iomem *cfg_data;
+	u8 cfg_type = 0;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (hose->set_cfg_type)
+		if (bus->number != hose->first_busno)
+			cfg_type = 1;
+
+	PCI_CFG_OUT(hose->cfg_addr, 					 
+		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	cfg_data = hose->cfg_data + (offset & 3);
+	switch (len) {
+	case 1:
+		out_8(cfg_data, val);
+		break;
+	case 2:
+		out_le16(cfg_data, val);
+		break;
+	default:
+		out_le32(cfg_data, val);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pci_ops =
+{
+	indirect_read_config,
+	indirect_write_config
+};
+
+void __init
+setup_indirect_pci_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
+	void __iomem * cfg_data)
+{
+	hose->cfg_addr = cfg_addr;
+	hose->cfg_data = cfg_data;
+	hose->ops = &indirect_pci_ops;
+}
+
+void __init
+setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+	unsigned long base = cfg_addr & PAGE_MASK;
+	void __iomem *mbase, *addr, *data;
+
+	mbase = ioremap(base, PAGE_SIZE);
+	addr = mbase + (cfg_addr & ~PAGE_MASK);
+	if ((cfg_data & PAGE_MASK) != base)
+		mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
+	data = mbase + (cfg_data & ~PAGE_MASK);
+	setup_indirect_pci_nomap(hose, addr, data);
+}
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 6cf1a83..71c6e7e 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -218,7 +218,7 @@ struct machdep_calls {
 	int  (*pcibios_enable_device_hook)(struct pci_dev *, int initial);
 
 	/* Called in indirect_* to avoid touching devices */
-	int (*pci_exclude_device)(unsigned char, unsigned char);
+	int (*pci_exclude_device)(struct pci_controller *, unsigned char, unsigned char);
 
 	/* Called at then very end of pcibios_init() */
 	void (*pcibios_after_init)(void);
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 04/15] [POWERPC] Remove hack to determine the 2nd PHBs bus number
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070091056-git-send-email-galak@kernel.crashing.org>

Now that we have the pci_controller in the exclude function we can easy
figure out if the bus number is the PHB or not.  The old style of using a
variable setup at init time was actually broken and would only work in
specific cases.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/83xx/pci.c         |    8 +-------
 arch/powerpc/platforms/85xx/mpc85xx_cds.c |    7 +------
 arch/powerpc/platforms/85xx/pci.c         |    3 ---
 3 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index f92e71f..8da935c 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -33,15 +33,10 @@
 #define DBG(x...)
 #endif
 
-int mpc83xx_pci2_busno;
-
 int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
 {
-	if (bus == 0 && PCI_SLOT(devfn) == 0)
+	if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (mpc83xx_pci2_busno)
-		if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
-			return PCIBIOS_DEVICE_NOT_FOUND;
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -86,7 +81,6 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
 		setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384);
 		primary = 0;
 		hose->bus_offset = hose->first_busno;
-		mpc83xx_pci2_busno = hose->first_busno;
 	}
 
 	printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. "
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index fcea5ab..04a1eaa 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -55,16 +55,11 @@ static volatile u8 *cadmus;
 #define ARCADIA_HOST_BRIDGE_IDSEL	17
 #define ARCADIA_2ND_BRIDGE_IDSEL	3
 
-extern int mpc85xx_pci2_busno;
-
 static int mpc85xx_exclude_device(struct pci_controller *hose,
 				  u_char bus, u_char devfn)
 {
-	if (bus == 0 && PCI_SLOT(devfn) == 0)
+	if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (mpc85xx_pci2_busno)
-		if (bus == (mpc85xx_pci2_busno) && PCI_SLOT(devfn) == 0)
-			return PCIBIOS_DEVICE_NOT_FOUND;
 	/* We explicitly do not go past the Tundra 320 Bridge */
 	if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
 		return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c
index 72a1bc5..be67f67 100644
--- a/arch/powerpc/platforms/85xx/pci.c
+++ b/arch/powerpc/platforms/85xx/pci.c
@@ -33,8 +33,6 @@
 #define DBG(x...)
 #endif
 
-int mpc85xx_pci2_busno = 0;
-
 #ifdef CONFIG_PCI
 int __init mpc85xx_add_bridge(struct device_node *dev)
 {
@@ -74,7 +72,6 @@ int __init mpc85xx_add_bridge(struct device_node *dev)
 		setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004);
 		primary = 0;
 		hose->bus_offset = hose->first_busno;
-		mpc85xx_pci2_busno = hose->first_busno;
 	}
 
 	printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. "
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 05/15] [POWERPC] Remove bus_offset in places its not really used
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070102887-git-send-email-galak@kernel.crashing.org>

The user of the fsl_pcie code doesn't set bus_offset and 82xx doesn't
require it either.  Remove the places in the code that reference it so
we can remove it all together.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/82xx/mpc82xx_ads.c |    1 -
 arch/powerpc/sysdev/fsl_pcie.c            |    8 ++++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index 715107b..d1e0919 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -552,7 +552,6 @@ static void __init mpc82xx_add_bridge(struct device_node *np)
 
 	hose->first_busno = bus_range ? bus_range[0] : 0;
 	hose->last_busno = bus_range ? bus_range[1] : 0xff;
-	hose->bus_offset = 0;
 
 	setup_indirect_pci(hose,
 			   r.start + offsetof(pci_cpm2_t, pci_cfg_addr),
diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c
index 6bbd7f8..ea3ec6b 100644
--- a/arch/powerpc/sysdev/fsl_pcie.c
+++ b/arch/powerpc/sysdev/fsl_pcie.c
@@ -50,12 +50,12 @@ indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
 	if (bus->number == 0xff) {
 		PCI_CFG_OUT(hose->cfg_addr,
 			    (0x80000000 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
+			     (bus->number<< 16)
 			     | (devfn << 8) | ((offset & 0xfc) )));
 	} else {
 		PCI_CFG_OUT(hose->cfg_addr,
 			    (0x80000001 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
+			     (bus->number<< 16)
 			     | (devfn << 8) | ((offset & 0xfc) )));
 	}
 
@@ -101,12 +101,12 @@ indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
 	if (bus->number == 0xff) {
 		PCI_CFG_OUT(hose->cfg_addr,
 			    (0x80000000 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
+			     (bus->number << 16)
 			     | (devfn << 8) | ((offset & 0xfc) )));
 	} else {
 		PCI_CFG_OUT(hose->cfg_addr,
 			    (0x80000001 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
+			     (bus->number << 16)
 			     | (devfn << 8) | ((offset & 0xfc) )));
         }
 
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 06/15] [POWERPC] Added self_busno to indicate which bus number the PHB is
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070111239-git-send-email-galak@kernel.crashing.org>

Added self_busno to pci_controller and indirect PCI ops to be set by
board code to indicate which bus number to use when talking to the PHB.
By default we use zero since the majority of controllers that have
implicit mechanisms to talk to the PHBs use a bus number of zero.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/sysdev/indirect_pci.c |   12 ++++++++++--
 include/asm-ppc/pci-bridge.h       |    1 +
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c
index 3dedf8f..d490e71 100644
--- a/arch/powerpc/sysdev/indirect_pci.c
+++ b/arch/powerpc/sysdev/indirect_pci.c
@@ -33,6 +33,7 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 	struct pci_controller *hose = bus->sysdata;
 	volatile void __iomem *cfg_data;
 	u8 cfg_type = 0;
+	u32 bus_no;
 
 	if (ppc_md.pci_exclude_device)
 		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
@@ -42,8 +43,11 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
+	bus_no = (bus->number == hose->first_busno) ?
+			hose->self_busno : bus->number - hose->bus_offset;
+
 	PCI_CFG_OUT(hose->cfg_addr,
-		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+		 (0x80000000 | (bus_no << 16)
 		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
 
 	/*
@@ -72,6 +76,7 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 	struct pci_controller *hose = bus->sysdata;
 	volatile void __iomem *cfg_data;
 	u8 cfg_type = 0;
+	u32 bus_no;
 
 	if (ppc_md.pci_exclude_device)
 		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
@@ -81,8 +86,11 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
+	bus_no = (bus->number == hose->first_busno) ?
+			hose->self_busno : bus->number - hose->bus_offset;
+
 	PCI_CFG_OUT(hose->cfg_addr,
-		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+		 (0x80000000 | (bus_no << 16)
 		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
 
 	/*
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index 4d35b84..2c2abda 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -47,6 +47,7 @@ struct pci_controller {
 
 	int first_busno;
 	int last_busno;
+	int self_busno;
 	int bus_offset;
 
 	void __iomem *io_base_virt;
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 07/15] [POWERPC] Removed remnants of bus_offset
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1182907013252-git-send-email-galak@kernel.crashing.org>

Removed the remants of bus_offset and use self_busno in the mv64x60 case
and use pci_assign_all_buses on 83xx/85xx.

83xx/85xx have multiple PHBs and the firmwares on these devices tend not
to handle topologies with P2P bridges well so we let Linux just reassign
the bus numbers to match.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/83xx/pci.c  |    2 +-
 arch/powerpc/platforms/85xx/pci.c  |    2 +-
 arch/powerpc/sysdev/indirect_pci.c |    4 ++--
 arch/powerpc/sysdev/mv64x60_pci.c  |    2 +-
 include/asm-ppc/pci-bridge.h       |    1 +
 5 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 8da935c..f49ed27 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -61,6 +61,7 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
 		       " bus 0\n", dev->full_name);
 	}
 
+	pci_assign_all_buses = 1;
 	hose = pcibios_alloc_controller();
 	if (!hose)
 		return -ENOMEM;
@@ -80,7 +81,6 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
 	if ((rsrc.start & 0xfffff) == 0x8600) {
 		setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384);
 		primary = 0;
-		hose->bus_offset = hose->first_busno;
 	}
 
 	printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. "
diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c
index be67f67..a25b3e7 100644
--- a/arch/powerpc/platforms/85xx/pci.c
+++ b/arch/powerpc/platforms/85xx/pci.c
@@ -55,6 +55,7 @@ int __init mpc85xx_add_bridge(struct device_node *dev)
 		       " bus 0\n", dev->full_name);
 	}
 
+	pci_assign_all_buses = 1;
 	hose = pcibios_alloc_controller();
 	if (!hose)
 		return -ENOMEM;
@@ -71,7 +72,6 @@ int __init mpc85xx_add_bridge(struct device_node *dev)
 	if ((rsrc.start & 0xfffff) == 0x9000) {
 		setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004);
 		primary = 0;
-		hose->bus_offset = hose->first_busno;
 	}
 
 	printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. "
diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c
index d490e71..efe3cff 100644
--- a/arch/powerpc/sysdev/indirect_pci.c
+++ b/arch/powerpc/sysdev/indirect_pci.c
@@ -44,7 +44,7 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 			cfg_type = 1;
 
 	bus_no = (bus->number == hose->first_busno) ?
-			hose->self_busno : bus->number - hose->bus_offset;
+			hose->self_busno : bus->number;
 
 	PCI_CFG_OUT(hose->cfg_addr,
 		 (0x80000000 | (bus_no << 16)
@@ -87,7 +87,7 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 			cfg_type = 1;
 
 	bus_no = (bus->number == hose->first_busno) ?
-			hose->self_busno : bus->number - hose->bus_offset;
+			hose->self_busno : bus->number;
 
 	PCI_CFG_OUT(hose->cfg_addr,
 		 (0x80000000 | (bus_no << 16)
diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c
index 6b08e76..2e77384 100644
--- a/arch/powerpc/sysdev/mv64x60_pci.c
+++ b/arch/powerpc/sysdev/mv64x60_pci.c
@@ -147,7 +147,7 @@ static int __init mv64x60_add_bridge(struct device_node *dev)
 	hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
 	setup_indirect_pci(hose, rsrc.start, rsrc.start + 4);
-	hose->bus_offset = hose->first_busno;
+	hose->self_busno = hose->first_busno;
 
 	printk(KERN_INFO "Found MV64x60 PCI host bridge at 0x%016llx. "
 	       "Firmware bus number: %d->%d\n",
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index 2c2abda..70aab66 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -48,6 +48,7 @@ struct pci_controller {
 	int first_busno;
 	int last_busno;
 	int self_busno;
+	/* bus_offset is only used by ARCH=ppc */
 	int bus_offset;
 
 	void __iomem *io_base_virt;
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 12/15] [POWERPC] 86xx: Workaround PCI_PRIMARY_BUS usage
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070222511-git-send-email-galak@kernel.crashing.org>

The Freescale PCI-e controllers have an issue in that they use the
PCI_PRIMARY_BUS register in the virtual P2P bridge to determine which
bus number to match on when generating a type 0 config cycle.  The
issue is if we are renumbering bus numbers to match Linux we will try
setting the PCI_PRIMARY_BUS and will not know which bus number to use
for generating type 0 config cycles.  We surpress writing the register
in the P2P bridge and always keep it at zero.

In the future when proper PCI domain support is working we should be
able to remove this.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/86xx/pci.c  |    4 +++-
 arch/powerpc/sysdev/indirect_pci.c |    6 ++++++
 include/asm-ppc/pci-bridge.h       |    5 +++++
 3 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 3825e1a..6f3c0f6 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -158,11 +158,13 @@ int __init mpc86xx_add_bridge(struct device_node *dev)
 		printk(KERN_WARNING "Can't get bus-range for %s, assume"
 		       " bus 0\n", dev->full_name);
 
+	pci_assign_all_buses = 1;
 	hose = pcibios_alloc_controller();
 	if (!hose)
 		return -ENOMEM;
 	hose->arch_data = dev;
-	hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG;
+	hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG |
+				PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
 
 	hose->first_busno = bus_range ? bus_range[0] : 0x0;
 	hose->last_busno = bus_range ? bus_range[1] : 0xff;
diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c
index 3a16122..c7e6e85 100644
--- a/arch/powerpc/sysdev/indirect_pci.c
+++ b/arch/powerpc/sysdev/indirect_pci.c
@@ -103,6 +103,12 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 		 (0x80000000 | (bus_no << 16)
 		  | (devfn << 8) | reg | cfg_type));
 
+	/* surpress setting of PCI_PRIMARY_BUS */
+	if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
+		if ((offset == PCI_PRIMARY_BUS) &&
+			(bus->number == hose->first_busno))
+		val &= 0xffffff00;
+
 	/*
 	 * Note: the caller has already checked that offset is
 	 * suitably aligned and that len is 1, 2 or 4.
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index 0dee56b..c09fbf0 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -73,9 +73,14 @@ struct pci_controller {
 	 * Used for variants of PCI indirect handling and possible quirks:
 	 *  SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1
 	 *  EXT_REG - provides access to PCI-e extended registers
+	 *  SURPRESS_PRIMARY_BUS - we surpress the setting of PCI_PRIMARY_BUS
+	 *   on Freescale PCI-e controllers since they used the PCI_PRIMARY_BUS
+	 *   to determine which bus number to match on when generating type0
+	 *   config cycles
 	 */
 #define PPC_INDIRECT_TYPE_SET_CFG_TYPE		(0x00000001)
 #define PPC_INDIRECT_TYPE_EXT_REG		(0x00000002)
+#define PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS	(0x00000004)
 	u32 indirect_type;
 
 	/* Currently, we limit ourselves to 1 IO range and 3 mem
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 10/15] [POWERPC] Added indirect_type to handle variants of PCI ops
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070192461-git-send-email-galak@kernel.crashing.org>

The generic PCI config ops indirect support for ppc32 covers only two
cases (implicit vs explicit) type 0/1 config cycles via set_cfg_type.
Added a indirect_type bit mask to handle other variants.

Added support for PCI-e extended registers and moved the cfg_type
handling into the bit mask for ARCH=powerpc.  We can also use this to
handle indirect quirks.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/sysdev/indirect_pci.c |   22 ++++++++++++++++------
 include/asm-ppc/pci-bridge.h       |   10 ++++++++++
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c
index efe3cff..3a16122 100644
--- a/arch/powerpc/sysdev/indirect_pci.c
+++ b/arch/powerpc/sysdev/indirect_pci.c
@@ -33,22 +33,27 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 	struct pci_controller *hose = bus->sysdata;
 	volatile void __iomem *cfg_data;
 	u8 cfg_type = 0;
-	u32 bus_no;
+	u32 bus_no, reg;
 
 	if (ppc_md.pci_exclude_device)
 		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 	
-	if (hose->set_cfg_type)
+	if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
 	bus_no = (bus->number == hose->first_busno) ?
 			hose->self_busno : bus->number;
 
+	if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
+		reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+	else
+		reg = offset & 0xfc;
+
 	PCI_CFG_OUT(hose->cfg_addr,
 		 (0x80000000 | (bus_no << 16)
-		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+		  | (devfn << 8) | reg | cfg_type));
 
 	/*
 	 * Note: the caller has already checked that offset is
@@ -76,22 +81,27 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
 	struct pci_controller *hose = bus->sysdata;
 	volatile void __iomem *cfg_data;
 	u8 cfg_type = 0;
-	u32 bus_no;
+	u32 bus_no, reg;
 
 	if (ppc_md.pci_exclude_device)
 		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
 			return PCIBIOS_DEVICE_NOT_FOUND;
 
-	if (hose->set_cfg_type)
+	if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
 	bus_no = (bus->number == hose->first_busno) ?
 			hose->self_busno : bus->number;
 
+	if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
+		reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+	else
+		reg = offset & 0xfc;
+
 	PCI_CFG_OUT(hose->cfg_addr,
 		 (0x80000000 | (bus_no << 16)
-		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+		  | (devfn << 8) | reg | cfg_type));
 
 	/*
 	 * Note: the caller has already checked that offset is
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index 70aab66..0dee56b 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -65,9 +65,19 @@ struct pci_controller {
 	/*
 	 * If set, indirect method will set the cfg_type bit as
 	 * needed to generate type 1 configuration transactions.
+	 * use only on ARCH=ppc
 	 */
 	int set_cfg_type;
 
+	/*
+	 * Used for variants of PCI indirect handling and possible quirks:
+	 *  SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1
+	 *  EXT_REG - provides access to PCI-e extended registers
+	 */
+#define PPC_INDIRECT_TYPE_SET_CFG_TYPE		(0x00000001)
+#define PPC_INDIRECT_TYPE_EXT_REG		(0x00000002)
+	u32 indirect_type;
+
 	/* Currently, we limit ourselves to 1 IO range and 3 mem
 	 * ranges since the common pci_bus structure can't handle more
 	 */
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 14/15] [POWERPC] Let subordinate transparent bridges be transparent.
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: York Sun
In-Reply-To: <11829070241688-git-send-email-galak@kernel.crashing.org>

From: York Sun <yorksun@freescale.com>

In pcibios_fixup_bus(), bridges that are subordinate
to transparent bridges were still relocating their
IORESOURCE_IO and IO_RESOURCE_MEM start and end values.

Fix this by preventing the transparent bridge from
relocating the start and end values, thus allowing the
subordinate non-transparent bridge full molestation rights.

Signed-off-by: York Sun <yorksun@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/kernel/pci_32.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index e66064b..7738a28 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -1370,7 +1370,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
 		for (i = 0; i < 4; ++i) {
 			if ((res = bus->resource[i]) == NULL)
 				continue;
-			if (!res->flags)
+			if (!res->flags || bus->self->transparent)
 				continue;
 			if (io_offset && (res->flags & IORESOURCE_IO)) {
 				res->start += io_offset;
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 11/15] [POWERPC] 86xx: Avoid system halt if link training isn't at least L0.
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1182907020965-git-send-email-galak@kernel.crashing.org>

From: Zhang Wei <wei.zhang@freescale.com>

We check the Link Training and State Status register to make sure we
are at least at the L0 state.

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
Acked-by: Roy Zang <tie-fei.zang@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/86xx/pci.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 0db51e8..3825e1a 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -122,7 +122,6 @@ static void __init
 mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
 {
 	u16 cmd;
-	unsigned int temps;
 
 	DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n",
 			pcie_offset, pcie_size);
@@ -135,6 +134,9 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
 	early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
 }
 
+#define PCIE_LTSSM	0x404	/* PCIe Link Training and Status */
+#define PCIE_LTSSM_L0	0x16	/* L0 state */
+
 int __init mpc86xx_add_bridge(struct device_node *dev)
 {
 	int len;
@@ -143,6 +145,7 @@ int __init mpc86xx_add_bridge(struct device_node *dev)
 	const int *bus_range;
 	int has_address = 0;
 	int primary = 0;
+	u16 val;
 
 	DBG("Adding PCIE host bridge %s\n", dev->full_name);
 
@@ -159,12 +162,18 @@ int __init mpc86xx_add_bridge(struct device_node *dev)
 	if (!hose)
 		return -ENOMEM;
 	hose->arch_data = dev;
+	hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG;
 
 	hose->first_busno = bus_range ? bus_range[0] : 0x0;
 	hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
 	setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4);
 
+	/* Probe the hose link training status */
+	early_read_config_word(hose, 0, 0, PCIE_LTSSM, &val);
+	if (val < PCIE_LTSSM_L0)
+		return -ENXIO;
+
 	/* Setup the PCIE host controller. */
 	mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1);
 
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 15/15] [POWERPC] 86xx: Created quirk_fsl_pcie_transparent() to initialize bridge resources.
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1182907026390-git-send-email-galak@kernel.crashing.org>

From: Zhang Wei <wei.zhang@freescale.com>

The Freescale PCI-e RC poses as a transparent bridge, but does not
implement the IO_BASE or IO_LIMIT registers in the config space.  This
means that the code which initializes the bridge resources ends up
setting the IO resources erroneously.  Add quick_fsl_pcie_transparent()
to handle this.

This change sets RC of mpc8641 to be a transparent bridge
for legacy I/O access and initializes the RC bridge resources
from the device tree.

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/86xx/pci.c |   37 +++++++++++++++++++++++++++++++++++++
 1 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 6f3c0f6..2d7254c 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -134,6 +134,43 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
 	early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
 }
 
+static void __devinit quirk_fsl_pcie_transparent(struct pci_dev *dev)
+{
+	struct resource *res;
+	int i, res_idx = PCI_BRIDGE_RESOURCES;
+	struct pci_controller *hose;
+
+	/*
+	 * Make the bridge be transparent.
+	 */
+	dev->transparent = 1;
+
+	hose = pci_bus_to_hose(dev->bus->number);
+	if (!hose) {
+		printk(KERN_ERR "Can't find hose for bus %d\n",
+		       dev->bus->number);
+		return;
+	}
+
+	if (hose->io_resource.flags) {
+		res = &dev->resource[res_idx++];
+		res->start = hose->io_resource.start;
+		res->end = hose->io_resource.end;
+		res->flags = hose->io_resource.flags;
+	}
+
+	for (i = 0; i < 3; i++) {
+		res = &dev->resource[res_idx + i];
+		res->start = hose->mem_resources[i].start;
+		res->end = hose->mem_resources[i].end;
+		res->flags = hose->mem_resources[i].flags;
+	}
+}
+
+
+DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7010, quirk_fsl_pcie_transparent);
+DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7011, quirk_fsl_pcie_transparent);
+
 #define PCIE_LTSSM	0x404	/* PCIe Link Training and Status */
 #define PCIE_LTSSM_L0	0x16	/* L0 state */
 
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 13/15] [POWERPC] MPC8641HPCN: Set IDE in ULI1575 to not native mode.
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <11829070232635-git-send-email-galak@kernel.crashing.org>

From: Zhang Wei <wei.zhang@freescale.com>

Set IDE in ULI1575 to not 100% native mode, which forces
the IDE driver to probe the irq itself.

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/86xx/mpc86xx_hpcn.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index afa8237..62b8a14 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -312,6 +312,7 @@ static void __devinit quirk_uli5229(struct pci_dev *dev)
 {
 	unsigned short temp;
 	pci_write_config_word(dev, 0x04, 0x0405);
+	dev->class &= ~0x5;
 	pci_read_config_word(dev, 0x4a, &temp);
 	temp |= 0x1000;
 	pci_write_config_word(dev, 0x4a, temp);
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 08/15] [POWERPC] Remove PCI-e errata for MPC8641 silicon ver 1.0
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1182907014549-git-send-email-galak@kernel.crashing.org>

From: Zhang Wei <wei.zhang@freescale.com>

Remove errata for PCI-e support of Rev 1.0 of MPC8641 since its considered
obselete and is not production level silicon from Freescale.

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
Acked-by: Roy Zang <tie-fei.zang@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/Kconfig                       |    4 -
 arch/powerpc/boot/dts/mpc8641_hpcn.dts     |    2 +-
 arch/powerpc/platforms/86xx/mpc86xx.h      |    6 -
 arch/powerpc/platforms/86xx/mpc86xx_hpcn.c |    2 -
 arch/powerpc/platforms/86xx/pci.c          |   18 +---
 arch/powerpc/platforms/Kconfig             |    1 -
 arch/powerpc/sysdev/Makefile               |    1 -
 arch/powerpc/sysdev/fsl_pcie.c             |  171 ----------------------------
 8 files changed, 3 insertions(+), 202 deletions(-)
 delete mode 100644 arch/powerpc/sysdev/fsl_pcie.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 6324abd..b79256a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -424,10 +424,6 @@ config SBUS
 config FSL_SOC
 	bool
 
-config FSL_PCIE
-	bool
-	depends on PPC_86xx
-
 # Yes MCA RS/6000s exist but Linux-PPC does not currently support any
 config MCA
 	bool
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index 260b264..748f7b9 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -186,7 +186,7 @@
 			#size-cells = <2>;
 			#address-cells = <3>;
 			reg = <8000 1000>;
-			bus-range = <0 fe>;
+			bus-range = <0 ff>;
 			ranges = <02000000 0 80000000 80000000 0 20000000
 				  01000000 0 00000000 e2000000 0 00100000>;
 			clock-frequency = <1fca055>;
diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h
index 4c2789d..23f7ed2 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx.h
+++ b/arch/powerpc/platforms/86xx/mpc86xx.h
@@ -20,12 +20,6 @@ extern int mpc86xx_add_bridge(struct device_node *dev);
 extern int mpc86xx_exclude_device(struct pci_controller *hose,
 				  u_char bus, u_char devfn);
 
-extern void setup_indirect_pcie(struct pci_controller *hose,
-				       u32 cfg_addr, u32 cfg_data);
-extern void setup_indirect_pcie_nomap(struct pci_controller *hose,
-					     void __iomem *cfg_addr,
-					     void __iomem *cfg_data);
-
 extern void __init mpc86xx_smp_init(void);
 
 #endif	/* __MPC86XX_H__ */
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index 042dbce..afa8237 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -358,8 +358,6 @@ mpc86xx_hpcn_setup_arch(void)
 #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		mpc86xx_add_bridge(np);
-
-	ppc_md.pci_exclude_device = mpc86xx_exclude_device;
 #endif
 
 	printk("MPC86xx HPCN board from Freescale Semiconductor\n");
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 7659259..0db51e8 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -133,19 +133,6 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
 	early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
 
 	early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
-
-	/* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */
-	early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps);
-	temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16);
-	early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps);
-}
-
-int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
-{
-	if (bus == 0 && PCI_SLOT(devfn) == 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	return PCIBIOS_SUCCESSFUL;
 }
 
 int __init mpc86xx_add_bridge(struct device_node *dev)
@@ -173,11 +160,10 @@ int __init mpc86xx_add_bridge(struct device_node *dev)
 		return -ENOMEM;
 	hose->arch_data = dev;
 
-	/* last_busno = 0xfe cause by MPC8641 PCIE bug */
 	hose->first_busno = bus_range ? bus_range[0] : 0x0;
-	hose->last_busno = bus_range ? bus_range[1] : 0xfe;
+	hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
-	setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4);
+	setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4);
 
 	/* Setup the PCIE host controller. */
 	mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1);
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index df67ff5..33545d3 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -31,7 +31,6 @@ config PPC_86xx
 	bool "Freescale 86xx"
 	depends on 6xx
 	select FSL_SOC
-	select FSL_PCIE
 	select ALTIVEC
 	help
 	  The Freescale E600 SoCs have 74xx cores.
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 43fd7e0..b991b78 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_PPC_PMI)		+= pmi.o
 obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
-obj-$(CONFIG_FSL_PCIE)		+= fsl_pcie.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
 mv64x60-$(CONFIG_PCI)		+= mv64x60_pci.o
diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c
deleted file mode 100644
index ea3ec6b..0000000
--- a/arch/powerpc/sysdev/fsl_pcie.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Support for indirect PCI bridges.
- *
- * Copyright (C) 1998 Gabriel Paubert.
- *
- * 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.
- *
- * "Temporary" MPC8548 Errata file -
- * The standard indirect_pci code should work with future silicon versions.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-
-#define PCI_CFG_OUT out_be32
-
-/* ERRATA PCI-Ex 14 PCIE Controller timeout */
-#define PCIE_FIX		out_be32(hose->cfg_addr+0x4, 0x0400ffff)
-
-
-static int
-indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
-		     int len, u32 *val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	volatile void __iomem *cfg_data;
-	u32 temp;
-
-	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
-			return PCIBIOS_DEVICE_NOT_FOUND;
-
-	/* Possible artifact of CDCpp50937 needs further investigation */
-	if (devfn != 0x0 && bus->number == 0xff)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	PCIE_FIX;
-	if (bus->number == 0xff) {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000000 | ((offset & 0xf00) << 16) |
-			     (bus->number<< 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-	} else {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000001 | ((offset & 0xf00) << 16) |
-			     (bus->number<< 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-	}
-
-	/*
-	 * Note: the caller has already checked that offset is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
-	cfg_data = hose->cfg_data;
-	PCIE_FIX;
-	temp = in_le32(cfg_data);
-	switch (len) {
-	case 1:
-		*val = (temp >> (((offset & 3))*8)) & 0xff;
-		break;
-	case 2:
-		*val = (temp >> (((offset & 3))*8)) & 0xffff;
-		break;
-	default:
-		*val = temp;
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
-		      int len, u32 val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	volatile void __iomem *cfg_data;
-	u32 temp;
-
-	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
-			return PCIBIOS_DEVICE_NOT_FOUND;
-
-	/* Possible artifact of CDCpp50937 needs further investigation */
-	if (devfn != 0x0 && bus->number == 0xff)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	PCIE_FIX;
-	if (bus->number == 0xff) {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000000 | ((offset & 0xf00) << 16) |
-			     (bus->number << 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-	} else {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000001 | ((offset & 0xf00) << 16) |
-			     (bus->number << 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-        }
-
-	/*
-	 * Note: the caller has already checked that offset is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
-	cfg_data = hose->cfg_data;
-	switch (len) {
-	case 1:
-		PCIE_FIX;
-		temp = in_le32(cfg_data);
-		temp = (temp & ~(0xff << ((offset & 3) * 8))) |
-			(val << ((offset & 3) * 8));
-		PCIE_FIX;
-		out_le32(cfg_data, temp);
-		break;
-	case 2:
-		PCIE_FIX;
-		temp = in_le32(cfg_data);
-		temp = (temp & ~(0xffff << ((offset & 3) * 8)));
-		temp |= (val << ((offset & 3) * 8)) ;
-		PCIE_FIX;
-		out_le32(cfg_data, temp);
-		break;
-	default:
-		PCIE_FIX;
-		out_le32(cfg_data, val);
-		break;
-	}
-	PCIE_FIX;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops indirect_pcie_ops = {
-	indirect_read_config_pcie,
-	indirect_write_config_pcie
-};
-
-void __init
-setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
-	void __iomem * cfg_data)
-{
-	hose->cfg_addr = cfg_addr;
-	hose->cfg_data = cfg_data;
-	hose->ops = &indirect_pcie_ops;
-}
-
-void __init
-setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
-{
-	unsigned long base = cfg_addr & PAGE_MASK;
-	void __iomem *mbase, *addr, *data;
-
-	mbase = ioremap(base, PAGE_SIZE);
-	addr = mbase + (cfg_addr & ~PAGE_MASK);
-	if ((cfg_data & PAGE_MASK) != base)
-		mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
-	data = mbase + (cfg_data & ~PAGE_MASK);
-	setup_indirect_pcie_nomap(hose, addr, data);
-}
-- 
1.5.2.1

^ permalink raw reply related

* [PATCH 09/15] [POWERPC] 86xx: Add uli1575 pci-bridge sector to MPC8641HPCN dts file.
From: Kumar Gala @ 2007-06-27  1:16 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1182907015126-git-send-email-galak@kernel.crashing.org>

From: Wade Farnsworth <wfarnsworth@mvista.com>

This adds device nodes for the PCI bridges as well as the ISA devices on
the newer revision MPC8641HPCN.  It also adds the PCI ranges to the soc
node so that address translation for the ISA devices works properly.

Signed-off-by: Wade Farnsworth <wfarnsworth@mvista.com>
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/boot/dts/mpc8641_hpcn.dts |   97 +++++++++++++++++++++++++++----
 1 files changed, 84 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index 748f7b9..393cfdf 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -56,8 +56,12 @@
 		#size-cells = <1>;
 		#interrupt-cells = <2>;
 		device_type = "soc";
-		ranges = <0 f8000000 00100000>;
-		reg = <f8000000 00100000>;	// CCSRBAR 1M
+		ranges = <00001000 f8001000 000ff000
+			  80000000 80000000 20000000
+			  e2000000 e2000000 00100000
+			  a0000000 a0000000 20000000
+			  e3000000 e3000000 00100000>;
+		reg = <f8000000 00001000>;	// CCSRBAR
 		bus-frequency = <0>;
 
 		i2c@3000 {
@@ -285,17 +289,84 @@
 				f800 0 0 3 &i8259 0 0
 				f800 0 0 4 &i8259 0 0
 				>;
-			i8259: i8259@4d0 {
-				clock-frequency = <0>;
-				interrupt-controller;
-				device_type = "interrupt-controller";
-				#address-cells = <0>;
-				#interrupt-cells = <2>;
-				built-in;
-				compatible = "chrp,iic";
-                	        big-endian;
-				interrupts = <49 2>;
-				interrupt-parent = <&mpic>;
+			uli1575@0 {
+				reg = <0 0 0 0 0>;
+				#size-cells = <2>;
+				#address-cells = <3>;
+				ranges = <02000000 0 80000000
+					  02000000 0 80000000
+					  0 20000000
+					  01000000 0 00000000
+					  01000000 0 00000000
+					  0 00100000>;
+
+				pci_bridge@0 {
+					reg = <0 0 0 0 0>;
+					#size-cells = <2>;
+					#address-cells = <3>;
+					ranges = <02000000 0 80000000
+						  02000000 0 80000000
+						  0 20000000
+						  01000000 0 00000000
+						  01000000 0 00000000
+						  0 00100000>;
+
+					isa@1e {
+						device_type = "isa";
+						#interrupt-cells = <2>;
+						#size-cells = <1>;
+						#address-cells = <2>;
+						reg = <f000 0 0 0 0>;
+						ranges = <1 0 01000000 0 0
+							  00001000>;
+						interrupt-parent = <&i8259>;
+
+						i8259: interrupt-controller@20 {
+							reg = <1 20 2
+							       1 a0 2
+							       1 4d0 2>;
+							clock-frequency = <0>;
+							interrupt-controller;
+							device_type = "interrupt-controller";
+							#address-cells = <0>;
+							#interrupt-cells = <2>;
+							built-in;
+							compatible = "chrp,iic";
+							interrupts = <49 2>;
+							interrupt-parent =
+								<&mpic>;
+						};
+
+						i8042@60 {
+							#size-cells = <0>;
+							#address-cells = <1>;
+							reg = <1 60 1 1 64 1>;
+							interrupts = <1 3 c 3>;
+							interrupt-parent =
+								<&i8259>;
+
+							keyboard@0 {
+								reg = <0>;
+								compatible = "pnpPNP,303";
+							};
+
+							mouse@1 {
+								reg = <1>;
+								compatible = "pnpPNP,f03";
+							};
+						};
+
+						rtc@70 {
+							compatible =
+								"pnpPNP,b00";
+							reg = <1 70 2>;
+						};
+
+						gpio@400 {
+							reg = <1 400 80>;
+						};
+					};
+				};
 			};
 
 		};
-- 
1.5.2.1

^ permalink raw reply related

* Re: [PATCH 07/15] [POWERPC] Removed remnants of bus_offset
From: David Gibson @ 2007-06-27  1:22 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <1182907014549-git-send-email-galak@kernel.crashing.org>

On Tue, Jun 26, 2007 at 08:16:37PM -0500, Kumar Gala wrote:
> Removed the remants of bus_offset and use self_busno in the mv64x60 case
> and use pci_assign_all_buses on 83xx/85xx.
> 
> 83xx/85xx have multiple PHBs and the firmwares on these devices tend not
> to handle topologies with P2P bridges well so we let Linux just reassign
> the bus numbers to match.

[snip]
> diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
> index 2c2abda..70aab66 100644
> --- a/include/asm-ppc/pci-bridge.h
> +++ b/include/asm-ppc/pci-bridge.h
> @@ -48,6 +48,7 @@ struct pci_controller {
>  	int first_busno;
>  	int last_busno;
>  	int self_busno;
> +	/* bus_offset is only used by ARCH=ppc */
>  	int bus_offset;
>  
>  	void __iomem *io_base_virt;

Might be a good time to copy asm-ppc/pci-bridge.h to
asm-powerpc/pci-bridge-32.h, yeah?

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: [PATCH 07/15] [POWERPC] Removed remnants of bus_offset
From: Kumar Gala @ 2007-06-27  4:27 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20070627012206.GB11191@localhost.localdomain>


On Jun 26, 2007, at 8:22 PM, David Gibson wrote:

> On Tue, Jun 26, 2007 at 08:16:37PM -0500, Kumar Gala wrote:
>> Removed the remants of bus_offset and use self_busno in the  
>> mv64x60 case
>> and use pci_assign_all_buses on 83xx/85xx.
>>
>> 83xx/85xx have multiple PHBs and the firmwares on these devices  
>> tend not
>> to handle topologies with P2P bridges well so we let Linux just  
>> reassign
>> the bus numbers to match.
>
> [snip]
>> diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci- 
>> bridge.h
>> index 2c2abda..70aab66 100644
>> --- a/include/asm-ppc/pci-bridge.h
>> +++ b/include/asm-ppc/pci-bridge.h
>> @@ -48,6 +48,7 @@ struct pci_controller {
>>  	int first_busno;
>>  	int last_busno;
>>  	int self_busno;
>> +	/* bus_offset is only used by ARCH=ppc */
>>  	int bus_offset;
>>
>>  	void __iomem *io_base_virt;
>
> Might be a good time to copy asm-ppc/pci-bridge.h to
> asm-powerpc/pci-bridge-32.h, yeah?

Yeah I'll look at something towards that, seeing as its one of the  
few headers we are including directly.

- k

^ permalink raw reply

* Re: zImage on mpc5200
From: Grant Likely @ 2007-06-27  5:17 UTC (permalink / raw)
  To: sarpa; +Cc: linuxppc-embedded
In-Reply-To: <11307459.post@talk.nabble.com>

On 6/26/07, sarpa <vsarpangala@satline.net> wrote:
>
> I am building the Linux kernel target "zImage.elf" in PPC branch of Linux
> Kernel 2.6.16.11 and then converting it to zImage.bin using OBJCOPY so that
> i can flash it to my PPC based target using BDI. i am currently facing
> issues in booting this kernel using my own bootloader(i am not using
> u-boot). Before I flood mailing list with more detailed questions I just
> wish to know if the standalone kernel image type zImage.elf is know to work
> in Linux kernel 2.6.16.11 or not ? Has anyone ever tested standalone
> zImage.elf on PPC ? Note that I am able to boot uImage using U-boot for this
> kernel but now I am trying to use my own Bootloader to boot zImage.elf "

I can't say about it on the 5200, or on kernel 2.6.16 because I
haven't tried that exact configuration (without u-boot); but
zImage.elf do boot perfectly well without u-boot.  I frequently boot
my virtex platform in that way.

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* [PATCH 1/1] Turn off debugging in arch/powerpc/kernel/pci_64.c
From: Michael Ellerman @ 2007-06-27  6:02 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Commit 3d5134ee8341bffc4f539049abb9e90d469b448d left debugging turned on
in arch/powerpc/kernel/pci_64.c

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/kernel/pci_64.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 6ae67eb..9fa2ecb 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -11,7 +11,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#define DEBUG
+#undef DEBUG
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
-- 
1.5.1.3.g7a33b

^ permalink raw reply related

* [PATCH 0/3] PReP support
From: David Gibson @ 2007-06-27  6:53 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Here is a string of three patches which make a first cut at supporting
PReP machines under arch/powerpc.  The first two are, I think, ready
for merge.  The third, well, up to you whether we ought to do the
numerous necessary cleanups before or after merge.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* [PATCH 2/3] Make more OF-related bootwrapper functions available to non-OF platforms
From: David Gibson @ 2007-06-27  6:54 UTC (permalink / raw)
  To: Paul Mackerras, linuxppc-dev
In-Reply-To: <20070627065335.GD11191@localhost.localdomain>

Commit 2e6016133755eb3cc44e8efab92573d23ed75888 split up
arch/powerpc/boot/of.c so that some OF functions can be used on
platforms that don't want to use the overall OF platform boot code.
This is useful on things like PReP which can have an OF implementation
which is useful for debugging output, but inadequate for booting.

However, that commit didn't export quite enough things to make a
usable OF console on a non-OF system.  In particular, the device tree
manipulation performed to initialize the OF console code must
explicitly use the OF device tree, rather than the flattened device
tree, even if the system is otherwise booting using a flattened device
tree.  This patch makes it so.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---

 arch/powerpc/boot/of.c        |   30 ------------------------------
 arch/powerpc/boot/of.h        |    6 ++++++
 arch/powerpc/boot/ofconsole.c |    8 ++++----
 arch/powerpc/boot/oflib.c     |   40 +++++++++++++++++++++++++++++++++++-----
 4 files changed, 45 insertions(+), 39 deletions(-)

Index: working-2.6/arch/powerpc/boot/of.c
===================================================================
--- working-2.6.orig/arch/powerpc/boot/of.c	2007-06-15 13:24:11.000000000 +1000
+++ working-2.6/arch/powerpc/boot/of.c	2007-06-21 13:21:46.000000000 +1000
@@ -63,36 +63,6 @@ static void of_image_hdr(const void *hdr
 	}
 }
 
-static void *of_vmlinux_alloc(unsigned long size)
-{
-	void *p = malloc(size);
-
-	if (!p)
-		fatal("Can't allocate memory for kernel image!\n\r");
-
-	return p;
-}
-
-/*
- * OF device tree routines
- */
-static void *of_finddevice(const char *name)
-{
-	return (phandle) of_call_prom("finddevice", 1, 1, name);
-}
-
-static int of_getprop(const void *phandle, const char *name, void *buf,
-		const int buflen)
-{
-	return of_call_prom("getprop", 4, 1, phandle, name, buf, buflen);
-}
-
-static int of_setprop(const void *phandle, const char *name, const void *buf,
-		const int buflen)
-{
-	return of_call_prom("setprop", 4, 1, phandle, name, buf, buflen);
-}
-
 void platform_init(unsigned long a1, unsigned long a2, void *promptr)
 {
 	platform_ops.image_hdr = of_image_hdr;
Index: working-2.6/arch/powerpc/boot/of.h
===================================================================
--- working-2.6.orig/arch/powerpc/boot/of.h	2007-06-15 13:24:11.000000000 +1000
+++ working-2.6/arch/powerpc/boot/of.h	2007-06-21 13:22:14.000000000 +1000
@@ -7,7 +7,13 @@ typedef void *ihandle;
 void of_init(void *promptr);
 int of_call_prom(const char *service, int nargs, int nret, ...);
 void *of_claim(unsigned long virt, unsigned long size, unsigned long align);
+void *of_vmlinux_alloc(unsigned long size);
 void of_exit(void);
+void *of_finddevice(const char *name);
+int of_getprop(const void *phandle, const char *name, void *buf,
+	       const int buflen);
+int of_setprop(const void *phandle, const char *name, const void *buf,
+	       const int buflen);
 
 /* Console functions */
 void of_console_init(void);
Index: working-2.6/arch/powerpc/boot/oflib.c
===================================================================
--- working-2.6.orig/arch/powerpc/boot/oflib.c	2007-06-15 13:24:11.000000000 +1000
+++ working-2.6/arch/powerpc/boot/oflib.c	2007-06-21 13:21:58.000000000 +1000
@@ -110,25 +110,25 @@ static int check_of_version(void)
 	phandle oprom, chosen;
 	char version[64];
 
-	oprom = finddevice("/openprom");
+	oprom = of_finddevice("/openprom");
 	if (oprom == (phandle) -1)
 		return 0;
-	if (getprop(oprom, "model", version, sizeof(version)) <= 0)
+	if (of_getprop(oprom, "model", version, sizeof(version)) <= 0)
 		return 0;
 	version[sizeof(version)-1] = 0;
 	printf("OF version = '%s'\r\n", version);
 	if (!string_match(version, "Open Firmware, 1.")
 	    && !string_match(version, "FirmWorks,3."))
 		return 0;
-	chosen = finddevice("/chosen");
+	chosen = of_finddevice("/chosen");
 	if (chosen == (phandle) -1) {
-		chosen = finddevice("/chosen@0");
+		chosen = of_finddevice("/chosen@0");
 		if (chosen == (phandle) -1) {
 			printf("no chosen\n");
 			return 0;
 		}
 	}
-	if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
+	if (of_getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
 		printf("no mmu\n");
 		return 0;
 	}
@@ -166,7 +166,37 @@ void *of_claim(unsigned long virt, unsig
 	return (void *) virt;
 }
 
+void *of_vmlinux_alloc(unsigned long size)
+{
+	void *p = malloc(size);
+
+	if (!p)
+		fatal("Can't allocate memory for kernel image!\n\r");
+
+	return p;
+}
+
 void of_exit(void)
 {
 	of_call_prom("exit", 0, 0);
 }
+
+/*
+ * OF device tree routines
+ */
+void *of_finddevice(const char *name)
+{
+	return (phandle) of_call_prom("finddevice", 1, 1, name);
+}
+
+int of_getprop(const void *phandle, const char *name, void *buf,
+	       const int buflen)
+{
+	return of_call_prom("getprop", 4, 1, phandle, name, buf, buflen);
+}
+
+int of_setprop(const void *phandle, const char *name, const void *buf,
+	       const int buflen)
+{
+	return of_call_prom("setprop", 4, 1, phandle, name, buf, buflen);
+}
Index: working-2.6/arch/powerpc/boot/ofconsole.c
===================================================================
--- working-2.6.orig/arch/powerpc/boot/ofconsole.c	2007-06-15 13:24:11.000000000 +1000
+++ working-2.6/arch/powerpc/boot/ofconsole.c	2007-06-21 10:30:18.000000000 +1000
@@ -24,10 +24,10 @@ static int of_console_open(void)
 {
 	void *devp;
 
-	if (((devp = finddevice("/chosen")) != NULL)
-			&& (getprop(devp, "stdout", &of_stdout_handle,
-				sizeof(of_stdout_handle))
-				== sizeof(of_stdout_handle)))
+	if (((devp = of_finddevice("/chosen")) != NULL)
+	    && (of_getprop(devp, "stdout", &of_stdout_handle,
+			   sizeof(of_stdout_handle))
+		== sizeof(of_stdout_handle)))
 		return 0;
 
 	return -1;

^ permalink raw reply

* [PATCH 1/3] Abolish unused ucBoardRev variables
From: David Gibson @ 2007-06-27  6:54 UTC (permalink / raw)
  To: Paul Mackerras, linuxppc-dev
In-Reply-To: <20070627065335.GD11191@localhost.localdomain>

asm-powerpc/processor.h declares, and arch/ppc/platforms/prep_setup.c
defines variables ucBoardRev, ucBoardRevMaj and ucBoardRevMin which
are used nowhere in the current kernel (neither in arch/ppc nor
arch/powerpc).  This patch removes them.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---

 arch/ppc/platforms/prep_setup.c |    3 ---
 include/asm-powerpc/processor.h |    8 --------
 2 files changed, 11 deletions(-)

Index: working-2.6/arch/ppc/platforms/prep_setup.c
===================================================================
--- working-2.6.orig/arch/ppc/platforms/prep_setup.c	2007-06-19 16:38:20.000000000 +1000
+++ working-2.6/arch/ppc/platforms/prep_setup.c	2007-06-19 16:38:23.000000000 +1000
@@ -69,9 +69,6 @@
 
 TODC_ALLOC();
 
-unsigned char ucBoardRev;
-unsigned char ucBoardRevMaj, ucBoardRevMin;
-
 extern unsigned char prep_nvram_read_val(int addr);
 extern void prep_nvram_write_val(int addr,
 				 unsigned char val);
Index: working-2.6/include/asm-powerpc/processor.h
===================================================================
--- working-2.6.orig/include/asm-powerpc/processor.h	2007-06-19 16:38:03.000000000 +1000
+++ working-2.6/include/asm-powerpc/processor.h	2007-06-19 16:38:09.000000000 +1000
@@ -43,14 +43,6 @@ extern int _chrp_type;
 /* what kind of prep workstation we are */
 extern int _prep_type;
 
-/*
- * This is used to identify the board type from a given PReP board
- * vendor. Board revision is also made available. This will be moved
- * elsewhere soon
- */
-extern unsigned char ucBoardRev;
-extern unsigned char ucBoardRevMaj, ucBoardRevMin;
-
 #endif /* CONFIG_PPC_PREP */
 
 #endif /* defined(__KERNEL__) && defined(CONFIG_PPC32) */

^ permalink raw reply

* [PATCH 3/3] First cut at PReP support for arch/powerpc
From: David Gibson @ 2007-06-27  7:10 UTC (permalink / raw)
  To: Paul Mackerras, linuxppc-dev
In-Reply-To: <20070627065335.GD11191@localhost.localdomain>

Here is an implementation to allow PReP systems to boot under the
arch/powerpc codebase, one of the few remaining platforms supported in
arch/ppc but not so far in arch/powerpc.

This support is still fairly incomplete - it needs to obtain a lot
more device information from the residual data and put it into the
device tree, rather than relying on hardcoded values (both in the code
and in prep.dts).  Likewise many peripherals will not be supported -
in particular the RTC is not yet supported, so the time will generally
be wrong.

Still, it should do enough to boot on a number of PReP machines, and
makes a reasonable start.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Too big for the list, the patch is at:
	http://ozlabs.org/~dgibson/home/prep-support

 arch/powerpc/Kconfig.debug           |    7 
 arch/powerpc/boot/Makefile           |    8 
 arch/powerpc/boot/dts/prep.dts       |  130 ++++
 arch/powerpc/boot/mkprep.c           |  178 ++++++
 arch/powerpc/boot/pnp.h              |  640 ++++++++++++++++++++++
 arch/powerpc/boot/prep.c             |  150 +++++
 arch/powerpc/boot/residual.h         |  313 ++++++++++
 arch/powerpc/boot/wrapper            |    7 
 arch/powerpc/configs/prep_defconfig  | 1006 +++++++++++++++++++++++++++++++++++
 arch/powerpc/kernel/misc_32.S        |   27 
 arch/powerpc/kernel/setup_32.c       |    1 
 arch/powerpc/kernel/udbg.c           |    2 
 arch/powerpc/kernel/udbg_16550.c     |   28 
 arch/powerpc/platforms/Makefile      |    1 
 arch/powerpc/platforms/prep/Kconfig  |    3 
 arch/powerpc/platforms/prep/Makefile |    4 
 arch/powerpc/platforms/prep/nvram.c  |  135 ++++
 arch/powerpc/platforms/prep/pci.c    |   66 ++
 arch/powerpc/platforms/prep/setup.c  |  720 +++++++++++++++++++++++++
 include/asm-powerpc/residual.h       |  350 ++++++++++++
 include/asm-powerpc/udbg.h           |    1 
 21 files changed, 3772 insertions(+), 5 deletions(-)

^ permalink raw reply

* [PATCH 1/5 v2] Add the explanation and a sample of RapidIO DTS sector to the document of booting-without-of.txt file.
From: Zhang Wei @ 2007-06-27  8:35 UTC (permalink / raw)
  To: mporter; +Cc: linuxppc-dev, paulus, linux-kernel
In-Reply-To: <11829333481420-git-send-email-wei.zhang@freescale.com>

Add the explanation and a sample of RapidIO DTS sector to the document of booting-without-of.txt file.

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
---
 Documentation/powerpc/booting-without-of.txt |   34 ++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index b49ce16..98692ca 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1727,6 +1727,40 @@ platforms are moved over to use the flattened-device-tree model.
  		partition-names = "fs\0firmware";
  	};
 
+   k) RapidIO
+
+   Required properties:
+
+    - compatible : Should be "fsl,rapidio-delta" for Freescale
+      PowerPC RapidIO controller.
+    - #address-cells : Address representation for "rapidio" devices.
+      This field represents the number of cells needed to represent
+      the RapidIO address of the registers.  For supporting more than
+      32-bits RapidIO address, this field should be <2>.
+      See 1) above for more details on defining #address-cells.
+    - reg : Offset and length of the register set for the device
+    - ranges : Should be defined as specified in 1) to describe the
+      translation of addresses for memory mapped RapidIO memory
+      space.
+    - interrupts : binding interrupts for this device sector,
+      please follow below orders:
+      <err_irq bell_outb_irq bell_inb_irq msg1_tx_irq msg1_rx_irq
+      msg2_tx_irq msg2_rx_irq ... msgN_tx_irq msgN_rx_irq>.
+
+  Example:
+
+	srio@c0000{
+		compatible = "fsl,rapidio-delta";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		reg = <c0000 20000>;
+		ranges = <0 0 c0000000 20000000>;
+		interrupt-parent = <&mpic>;
+		/* err_irq bell_outb_irq bell_inb_irq msg1_tx_irq msg1_rx_irq
+						      msg2_tx_irq msg2_rx_irq */
+		interrupts = <30 2 31 2 32 2 35 2 36 2 37 2 38 2>;
+	};
+
    More devices will be defined as this spec matures.
 
 VII - Specifying interrupt information for devices
-- 
1.5.1

^ permalink raw reply related

* [PATCH 2/5 v2] Add RapidIO sector to the MPC8641HPCN board dts file.
From: Zhang Wei @ 2007-06-27  8:35 UTC (permalink / raw)
  To: mporter; +Cc: linuxppc-dev, paulus, linux-kernel
In-Reply-To: <11829333481977-git-send-email-wei.zhang@freescale.com>

Add RapidIO sector to the MPC8641HPCN board dts file.

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
---
 arch/powerpc/boot/dts/mpc8641_hpcn.dts |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index 04626b1..abc9ff3 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -329,6 +329,19 @@
 				>;
 		};
 
+		srio@c0000 {
+			compatible = "fsl,rapidio-delta";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			reg = <c0000 20000>;
+			ranges = <0 0 c0000000 20000000>;
+			interrupt-parent = <&mpic>;
+			/* err_irq bell_outb_irq bell_inb_irq
+						msg1_tx_irq msg1_rx_irq
+						msg2_tx_irq msg2_rx_irq */
+			interrupts = <30 2 31 2 32 2 35 2 36 2 37 2 38 2>;
+		};
+
 		mpic: pic@40000 {
 			clock-frequency = <0>;
 			interrupt-controller;
-- 
1.5.1

^ permalink raw reply related

* [PATCH 4/5 v2] Add RapidIO support to powerpc architecture.
From: Zhang Wei @ 2007-06-27  8:35 UTC (permalink / raw)
  To: mporter; +Cc: linuxppc-dev, paulus, linux-kernel
In-Reply-To: <1182933348216-git-send-email-wei.zhang@freescale.com>

This patch adds the RapidIO support to the powerpc architecture.
Some files are moved from ppc. OF-tree and OF-device supports are added.
New silicons such as MPC8548, MPC8641 with serial RapidIO controller are
all supported.
Memory driver hardware operations are added.
Global mport variables are changed to master port private variables.
Multi master ports are supported.

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
---
 arch/powerpc/Kconfig          |    8 +
 arch/powerpc/kernel/Makefile  |    1 +
 arch/powerpc/kernel/rio.c     |   64 ++
 arch/powerpc/sysdev/Makefile  |    1 +
 arch/powerpc/sysdev/fsl_rio.c | 1455 +++++++++++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_rio.h |   20 +
 6 files changed, 1549 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/kernel/rio.c
 create mode 100644 arch/powerpc/sysdev/fsl_rio.c
 create mode 100644 arch/powerpc/sysdev/fsl_rio.h

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index e683668..a41aaac 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -742,6 +742,14 @@ source "drivers/pci/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
 
+config RAPIDIO
+	bool "RapidIO support" if MPC8540 || MPC8560 || MPC8641 || MPC8548
+	help
+	  If you say Y here, the kernel will include drivers and
+	  infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rapidio/Kconfig"
+
 source "drivers/pci/hotplug/Kconfig"
 
 endmenu
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 3e779f0..9ed2367 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -69,6 +69,7 @@ pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o
 pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
 obj-$(CONFIG_PCI_MSI)		+= msi.o
+obj-$(CONFIG_RAPIDIO)		+= rio.o
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
 kexec-$(CONFIG_PPC32)		:= machine_kexec_32.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o crash.o $(kexec-y)
diff --git a/arch/powerpc/kernel/rio.c b/arch/powerpc/kernel/rio.c
new file mode 100644
index 0000000..8d41e93
--- /dev/null
+++ b/arch/powerpc/kernel/rio.c
@@ -0,0 +1,64 @@
+/*
+ * RapidIO PowerPC support
+ *
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Zhang Wei <wei.zhang@freescale.com>, Jun 2007
+ *
+ * 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.
+ *
+ * New RapidIO peer-to-peer network initialize with of-device supoort.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/rio.h>
+
+#include <asm/rio.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+
+#include <../sysdev/fsl_rio.h>
+
+
+/* The probe function for RapidIO peer-to-peer network.
+ */
+static int __devinit of_rio_rpn_probe(struct of_device *dev,
+				     const struct of_device_id *match)
+{
+	int rc;
+	printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n",
+			dev->node->full_name);
+
+	rc = fsl_rio_setup(dev);
+	if (rc)
+		goto out;
+
+	/* Enumerate all registered ports */
+	rc = rio_init_mports();
+out:
+	return rc;
+};
+
+static struct of_device_id of_rio_rpn_ids[] = {
+	{
+		.compatible = "fsl,rapidio-delta",
+	},
+	{},
+};
+
+static struct of_platform_driver of_rio_rpn_driver = {
+	.name = "of-rio",
+	.match_table = of_rio_rpn_ids,
+	.probe = of_rio_rpn_probe,
+};
+
+static __init int of_rio_rpn_init(void)
+{
+	return of_register_platform_driver(&of_rio_rpn_driver);
+}
+
+subsys_initcall(of_rio_rpn_init);
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index c3ce0bd..5d6d66b 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
 obj-$(CONFIG_FSL_PCIE)		+= fsl_pcie.o
+obj-$(CONFIG_RAPIDIO)		+= fsl_rio.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
 mv64x60-$(CONFIG_PCI)		+= mv64x60_pci.o
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
new file mode 100644
index 0000000..1608138
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -0,0 +1,1455 @@
+/*
+ * PowerPC RapidIO support
+ *
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Zhang Wei <wei.zhang@freescale.com>, Jun 2007
+ *
+ * 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.
+ *
+ * Changelog:
+ * Jun 2007 Zhang Wei <wei.zhang@freescale.com>
+ * - This file is moved from arch/ppc/ppc85xx_rio.c. And the OF-tree support
+ *   is added. New silicons such as MPC8548, MPC8641 are all supported.
+ *   Memory driver hardware operations are added.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include "fsl_soc.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 ERR(fmt, arg...) \
+	printk(KERN_ERR "RIO %s: " fmt, __FUNCTION__, ## arg)
+#define INFO(fmt...) printk(KERN_INFO "RIO: " fmt)
+#define IS_64BIT_RES ((sizeof(resource_size_t) == 8) ? 1 : 0)
+
+#define RIO_ATMU_REGS_OFFSET	0x10c00
+#define RIO_P_MSG_REGS_OFFSET	0x11000
+#define RIO_S_MSG_REGS_OFFSET	0x13000
+#define RIO_ESCSR		0x158
+#define RIO_CCSR		0x15c
+#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_MAX_INB_ATMU	4
+#define RIO_MAX_OUTB_ATMU	8
+#define RIO_INB_ATMU_REGS_OFFSET	0x10de0
+#define RIO_ATMU_EN_MASK	0x80000000
+
+#define RIO_NREAD		0x4
+#define RIO_NWRITE		0x4
+#define RIO_NWRITE_R		0x5
+#define RIO_NREAD_R		0x5
+
+#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 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_inb_atmu_regs {
+	u32 riwtar;
+	u32 pad1;
+	u32 riwbar;
+	u32 pad2;
+	u32 riwar;
+	u32 pad3[3];
+};
+
+struct rio_msg_regs {
+	u32 omr;
+	u32 osr;
+	u32 pad1;
+	u32 odqdpar;
+	u32 pad2;
+	u32 osar;
+	u32 odpr;
+	u32 odatr;
+	u32 odcr;
+	u32 pad3;
+	u32 odqepar;
+	u32 pad4[13];
+	u32 imr;
+	u32 isr;
+	u32 pad5;
+	u32 ifqdpar;
+	u32 pad6;
+	u32 ifqepar;
+	u32 pad7[226];
+	u32 odmr;
+	u32 odsr;
+	u32 res0[4];
+	u32 oddpr;
+	u32 oddatr;
+	u32 res1[3];
+	u32 odretcr;
+	u32 res2[12];
+	u32 dmr;
+	u32 dsr;
+	u32 pad8;
+	u32 dqdpar;
+	u32 pad9;
+	u32 dqepar;
+	u32 pad10[26];
+	u32 pwmr;
+	u32 pwsr;
+	u32 pad11;
+	u32 pwqbar;
+};
+
+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_priv {
+	volatile void __iomem *regs_win;
+	volatile struct rio_atmu_regs __iomem *atmu_regs;
+	volatile struct rio_atmu_regs __iomem *maint_atmu_regs;
+	volatile struct rio_atmu_regs __iomem *dbell_atmu_regs;
+	volatile void __iomem *dbell_win;
+	volatile void __iomem *maint_win;
+	volatile 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_doorbell_send - Send a PowerPC doorbell message
+ * @index: ID of RapidIO interface
+ * @destid: Destination ID of target device
+ * @data: 16-bit info field of RapidIO doorbell message
+ *
+ * Sends a PowerPC 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 0x%04x data 0x%04x\n",
+			index, destid, data);
+
+	switch (mport->phy_type) {
+	case RIO_PHY_SERIAL:
+		/* In the later 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;
+	case RIO_PHY_PARALLEL:
+		out_be32(&priv->dbell_atmu_regs->rowtar, destid << 22);
+		out_be16(priv->dbell_win, data);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * fsl_local_config_read - Generate a PowerPC local config space read
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be read into
+ *
+ * Generates a PowerPC local configuration space read. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int fsl_local_config_read(struct rio_mport *mport, int index, u32 offset, int len, u32 * data)
+{
+	struct rio_priv *priv = mport->priv;
+	pr_debug("fsl_local_config_read: index %d offset 0x%08x\n", index,
+			offset);
+	*data = in_be32(priv->regs_win + offset);
+
+	return 0;
+}
+
+/**
+ * fsl_local_config_write - Generate a PowerPC local config space write
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be written
+ *
+ * Generates a PowerPC local configuration space write. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int fsl_local_config_write(struct rio_mport *mport, int index, u32 offset, int len, u32 data)
+{
+	struct rio_priv *priv = mport->priv;
+	pr_debug("fsl_local_config_write: index %d offset 0x%08x data 0x%08x\n",
+			index, offset, data);
+	out_be32(priv->regs_win + offset, data);
+
+	return 0;
+}
+
+/**
+ * fsl_rio_config_read - Generate a PowerPC read maintenance transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Location to be read into
+ *
+ * Generates a PowerPC read maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
+		u8 hopcount, u32 offset, int len, u32 * val)
+{
+	void *data;
+	struct rio_priv *priv = mport->priv;
+
+	pr_debug("fsl_rio_config_read: index %d destid %d hopcount %d "
+			"offset 0x%08x len %d\n",
+			index, destid, hopcount, offset, len);
+	out_be32(&priv->maint_atmu_regs->rowtar,
+		 ((destid & 0x3ff) << 22) | (hopcount << 12)
+		 | ((offset & ~0x3) >> 9));
+	out_be32(&priv->maint_atmu_regs->rowtear, (destid & 0xfc00) >> 10);
+
+	data = priv->maint_win + offset;
+	switch (len) {
+	case 1:
+		*val = in_8(data);
+		break;
+	case 2:
+		*val = in_be16(data);
+		break;
+	default:
+		*val = in_be32(data);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * fsl_rio_config_write - Generate a PowerPC write maintenance transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Value to be written
+ *
+ * Generates an PowerPC write maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
+		u8 hopcount, u32 offset, int len, u32 val)
+{
+	void *data;
+	struct rio_priv *priv = mport->priv;
+	pr_debug("fsl_rio_config_write: index %d destid %d hopcount %d"
+			"offset 0x%08x len %d val 0x%08x\n",
+			index, destid, hopcount, offset, len, val);
+	out_be32(&priv->maint_atmu_regs->rowtar,
+		 ((destid & 0x3ff) << 22) | (hopcount << 12)
+		 | ((offset & ~0x3) >> 9));
+	out_be32(&priv->maint_atmu_regs->rowtear, (destid & 0xfc00) >> 10);
+
+	data = priv->maint_win + offset;
+	switch (len) {
+	case 1:
+		out_8(data, val);
+		break;
+	case 2:
+		out_be16(data, val);
+		break;
+	default:
+		out_be32(data, val);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * fsl_rio_map_inb_mem -- Mapping inbound memory region.
+ * @lstart: Local memory space start address.
+ * @rstart: RapidIO space start address.
+ * @size: The mapping region size.
+ * @flags: Flags for mapping. 0 for using default flags.
+ *
+ * Return: 0 -- Success.
+ *
+ * This function will create the inbound mapping
+ * from rstart to lstart.
+ */
+static int fsl_rio_map_inb_mem(struct rio_mport *mport, resource_size_t lstart,
+		resource_size_t rstart,	resource_size_t size,
+		u32 flags)
+{
+	int i;
+	struct rio_priv *priv = mport->priv;
+	volatile struct rio_inb_atmu_regs __iomem *inbatmu =
+				(struct rio_inb_atmu_regs *)
+				(priv->regs_win + RIO_INB_ATMU_REGS_OFFSET) - 1;
+	int size_ffs;
+	resource_size_t align;
+
+	if (flags == 0)
+		flags = (RIO_NREAD_R << 4) | RIO_NWRITE_R;
+
+	align = (size < 0x1000) ? 0x1000 : 1 << (__ilog2(size - 1) + 1);
+
+	/* Align the size */
+	if ((lstart + size) > (_ALIGN_DOWN(lstart, align) + align)) {
+		size_ffs = __ffs(_ALIGN_DOWN(lstart + size - 1, align));
+		size = 1 << (size_ffs +	(((_ALIGN_DOWN(lstart, 1 << size_ffs) +
+				(1 << size_ffs)) < (lstart + size)) ? 1 : 0));
+	} else
+		size = align;
+
+	if ((lstart & (size - 1)) != (rstart & (size - 1))) {
+		ERR("The local address 0x%x can not be aligned to the same size"
+			" 0x%x with the RapidIO space address 0x%x!\n", lstart,
+			size, rstart);
+		return -EINVAL;
+	}
+
+	/* Search for free inbound ATMU */
+	for (i = 1;
+		(i <= RIO_MAX_INB_ATMU) && (inbatmu->riwar & RIO_ATMU_EN_MASK);
+		i++, inbatmu--)
+		;
+
+	if (i > RIO_MAX_INB_ATMU) {
+		ERR("No free inbound ATMU!\n");
+		return -EBUSY;
+	}
+	out_be32(&inbatmu->riwtar, ((IS_64BIT_RES ? (lstart >> 32)
+				& 0xf : 0) << 20) | ((lstart >> 12) & 0xfffff));
+	out_be32(&inbatmu->riwbar, ((IS_64BIT_RES ? (rstart >> 32)
+				& 0x3 : 0) << 20) | ((rstart >> 12) & 0xfffff));
+	out_be32(&inbatmu->riwar, 0x80000000 | (0xf << 20)
+				| ((flags & 0xff) << 12)
+				| (__ilog2(size) - 1));
+	return 0;
+}
+
+/**
+ * fsl_rio_map_outb_mem -- Mapping outbound memory region.
+ * @lstart: Local memory space start address.
+ * @rstart: RapidIO space start address.
+ * @size: The mapping region size.
+ * @tid: The target RapidIO device id.
+ * @flags: Flags for mapping. 0 for using default flags.
+ *
+ * Return: 0 -- Success.
+ *
+ * This function will create the outbound mapping
+ * from lstart to rstart.
+ */
+static int fsl_rio_map_outb_mem(struct rio_mport *mport, resource_size_t lstart,
+		resource_size_t rstart,	resource_size_t size,
+		u16 tid, u32 flags)
+{
+	int i;
+	struct rio_priv *priv = mport->priv;
+	volatile struct rio_atmu_regs __iomem *outbatmu =
+			(struct rio_atmu_regs *)
+			(priv->regs_win + RIO_ATMU_REGS_OFFSET) + 1;
+	int size_ffs;
+	resource_size_t align;
+
+	if (flags == 0)
+		flags = (RIO_NREAD << 4) | RIO_NWRITE_R;
+
+	align = (size < 0x1000) ? 0x1000 : 1 << (__ilog2(size - 1) + 1);
+
+	/* Align the size */
+	if ((lstart + size) > (_ALIGN_DOWN(lstart, align) + align)) {
+		size_ffs = __ffs(_ALIGN_DOWN(lstart + size - 1, align));
+		size = 1 << (size_ffs +	(((_ALIGN_DOWN(lstart, 1 << size_ffs) +
+				(1 << size_ffs)) < (lstart + size)) ? 1 : 0));
+	} else
+		size = align;
+
+	if ((lstart & (size - 1)) != (rstart & (size - 1))) {
+		ERR("The local address 0x%x can not be aligned to the same size"
+			" 0x%x with the RapidIO space address 0x%x!\n", lstart,
+			size, rstart);
+		return -EINVAL;
+	}
+
+	/* Search for free outbound ATMU */
+	for (i = 1;
+	      (i <= RIO_MAX_OUTB_ATMU) && (outbatmu->rowar & RIO_ATMU_EN_MASK);
+	      i++, outbatmu++)
+		;
+
+	if (i > RIO_MAX_OUTB_ATMU) {
+		ERR("No free outbound ATMU!\n");
+		return -EBUSY;
+	}
+	out_be32(&outbatmu->rowtar, ((tid & 0x3ff) << 22)
+			| ((IS_64BIT_RES ? (rstart >> 32) & 0x3 : 0) << 20)
+			| ((rstart >> 12) & 0xfffff));
+	if (mport->phy_type == RIO_PHY_SERIAL)
+		out_be32(&outbatmu->rowtear, tid >> 10);
+	out_be32(&outbatmu->rowbar, ((IS_64BIT_RES ?
+					(lstart >> 32) & 0xf : 0) << 20)
+					| ((lstart >> 12) & 0xfffff));
+	out_be32(&outbatmu->rowar, 0x80000000
+				| ((flags & 0xff) << 12)
+				| (__ilog2(size) - 1));
+	return 0;
+}
+
+/**
+ * fsl_rio_unmap_inb_mem -- Unmapping inbound memory region.
+ * @lstart: Local memory space start address.
+ */
+static void fsl_rio_unmap_inb_mem(struct rio_mport *mport, resource_size_t lstart)
+{
+	int i;
+	struct rio_priv *priv = mport->priv;
+	volatile struct rio_inb_atmu_regs __iomem *inbatmu = (struct rio_inb_atmu_regs *)
+			(priv->regs_win + RIO_INB_ATMU_REGS_OFFSET) - 1;
+
+	/* Search for inbound ATMU */
+	for (i = 1; i <= RIO_MAX_INB_ATMU ; i++, inbatmu--) {
+		u32 tar = ((IS_64BIT_RES ? (lstart >> 32) & 0xf : 0) << 20)
+			| ((lstart >> 12) & 0xfffff);
+		if (inbatmu->riwtar == tar) {
+			out_be32(&inbatmu->riwar, ~(RIO_ATMU_EN_MASK));
+			return;
+		}
+	}
+}
+
+/**
+ * fsl_rio_unmap_inb_mem -- Unmapping outbound memory region.
+ * @lstart: Local memory space start address.
+ */
+static void fsl_rio_unmap_outb_mem(struct rio_mport *mport, resource_size_t lstart)
+{
+	int i;
+	struct rio_priv *priv = mport->priv;
+	volatile struct rio_atmu_regs __iomem *outbatmu = (struct rio_atmu_regs *)
+			(priv->regs_win + RIO_ATMU_REGS_OFFSET) + 1;
+
+	/* Search for outbound ATMU */
+	for (i = 1; i <= RIO_MAX_OUTB_ATMU ; i++, outbatmu++) {
+		u32 bar = ((IS_64BIT_RES ? (lstart >> 32) & 0xf : 0) << 20)
+			| ((lstart >> 12) & 0xfffff);
+		if (outbatmu->rowbar == bar) {
+			out_be32(&outbatmu->rowar, ~(RIO_ATMU_EN_MASK));
+			return;
+		}
+	}
+}
+
+/**
+ * rio_hw_add_outb_message - Add message to the PowerPC 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 PowerPC outbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev,
+		int mbox, void *buffer, size_t len)
+{
+	struct rio_priv *priv = mport->priv;
+	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: rio_hw_add_outb_message(): "
+			"destid 0x%04x mbox %d buffer %p len 0x%08x\n",
+			rdev->destid, mbox, 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_SERIAL:
+		/* Set mbox field for message, and set destid */
+		desc->dport = (rdev->destid << 16) | ( mbox & 0x3);
+
+		/* Enable EOMI interrupt and priority */
+		desc->dattr = 0x28000000;
+
+		/* Set mbox field for message */
+		desc->dport = mbox & 0x3;
+		break;
+	case RIO_PHY_PARALLEL:
+		/* Enable EOMI interrupt, set priority, and set destid */
+		desc->dattr = 0x28000000 | (rdev->destid << 2);
+		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 */
+	setbits32(&priv->msg_regs->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;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
+
+/**
+ * fsl_rio_tx_handler - PowerPC 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 occurence.
+ */
+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 (unlikely(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 (unlikely(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;
+}
+
+/**
+ * rio_open_outb_mbox - Initialize PowerPC 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.
+ */
+int rio_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(NULL, 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(NULL,
+							  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(NULL,
+						    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;
+	}
+	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",
+			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 */
+	setbits32(&priv->msg_regs->omr,
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	setbits32(&priv->msg_regs->omr, 0x1);
+
+      out:
+	return rc;
+
+      out_irq:
+	dma_free_coherent(NULL, 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(NULL, RIO_MSG_BUFFER_SIZE,
+				  priv->msg_tx_ring.virt_buffer[i],
+				  priv->msg_tx_ring.phys_buffer[i]);
+
+	return rc;
+}
+
+/**
+ * rio_close_outb_mbox - Shut down PowerPC 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.
+ */
+void rio_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(NULL, 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), mport);
+}
+
+/**
+ * fsl_rio_rx_handler - PowerPC 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 occurence.
+ */
+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 (unlikely(isr & RIO_MSG_ISR_TE)) {
+		pr_info("RIO: inbound message reception error\n");
+		out_be32(&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;
+}
+
+/**
+ * rio_open_inb_mbox - Initialize PowerPC 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.
+ */
+int rio_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(NULL,
+						    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", mport);
+	if (rc < 0) {
+		dma_free_coherent(NULL, 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;
+}
+
+/**
+ * rio_close_inb_mbox - Shut down PowerPC 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.
+ */
+void rio_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(NULL, 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), mport);
+}
+
+/**
+ * rio_hw_add_inb_buffer - Add buffer to the PowerPC 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 PowerPC inbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
+{
+	int rc = 0;
+	struct rio_priv *priv = mport->priv;
+
+	pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+		 priv->msg_rx_ring.rx_slot);
+
+	if (unlikely(priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot])) {
+		ERR("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;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);
+
+/**
+ * rio_hw_get_inb_message - Fetch inbound message from the PowerPC 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.
+ */
+void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
+{
+	u32 phys_buf;
+	void *virt_buf = NULL;
+	void *buf = NULL;
+	int buf_idx;
+	struct rio_priv *priv = mport->priv;
+
+	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 = 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 (unlikely(!buf)) {
+		ERR("inbound message copy failed, no buffers\n");
+		goto out1;
+	}
+
+	/* Copy max message size, caller is expected to allocate that big */
+	memcpy(buf, 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;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
+
+/**
+ * fsl_rio_dbell_handler - PowerPC 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);
+		goto out;
+	}
+
+	/* 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 0x%02x tid 0x%02x "
+				"info 0x%04x\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 0x%02x "
+					"tid 0x%02x 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 - PowerPC 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, phys_addr_t dbaddr)
+{
+	int rc = 0;
+	struct rio_priv *priv = mport->priv;
+
+	/* Map outbound doorbell window immediately after maintenance window */
+	priv->dbell_win = ioremap(dbaddr, RIO_DBELL_WIN_SIZE);
+	if (!priv->dbell_win) {
+		ERR("unable to map outbound doorbell window\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Initialize inbound doorbells */
+	priv->dbell_ring.virt = dma_alloc_coherent(NULL,
+						   512 * DOORBELL_MESSAGE_SIZE,
+						   &priv->dbell_ring.phys,
+						   GFP_KERNEL);
+	if (!priv->dbell_ring.virt) {
+		ERR("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", mport);
+	if (rc < 0) {
+		iounmap(priv->dbell_win);
+		dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE,
+				  priv->dbell_ring.virt, priv->dbell_ring.phys);
+		ERR("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;
+}
+
+u32 rio_get_mport_id(struct rio_mport *mport)
+{
+	u32 mport_id = 0;
+
+	rio_local_read_config_32(mport, 0x60, &mport_id);
+	mport_id = mport->sys_size ? (mport_id & 0xffff) : ((mport_id >> 16) & 0xff);
+	return mport_id;
+
+}
+
+static char *cmdline = NULL;
+
+static int fsl_rio_get_hdid(int index)
+{
+	/* XXX Need to parse multiple entries in some format */
+	if (!cmdline)
+		return -1;
+
+	return simple_strtol(cmdline, NULL, 0);
+}
+
+static int fsl_rio_get_cmdline(char *s)
+{
+	if (!s)
+		return 0;
+
+	cmdline = s;
+	return 1;
+}
+
+__setup("riohdid=", fsl_rio_get_cmdline);
+
+static struct rio_mem_ops fsl_mem_ops = {
+	.map_inb = fsl_rio_map_inb_mem,
+	.map_outb = fsl_rio_map_outb_mem,
+	.unmap_inb = fsl_rio_unmap_inb_mem,
+	.unmap_outb = fsl_rio_unmap_outb_mem,
+};
+
+static inline void fsl_rio_info(u32 ccsr)
+{
+	if (ccsr & 1) {
+		/* Serial phy */
+		INFO("Hardware port width: ");
+		switch (ccsr >> 30) {
+		case 0:
+			printk("1\n");
+			break;
+		case 1:
+			printk("4\n");
+			break;
+		default:
+			printk("Unknown\n");
+			break;;
+		}
+
+		INFO("Training connection status: ");
+		switch ((ccsr >> 27) & 7) {
+		case 0:
+			printk("Single-lane 0\n");
+			break;
+		case 1:
+			printk("Single-lane 2\n");
+			break;
+		case 2:
+			printk("Four-lane 2\n");
+			break;
+		default:
+			printk("Unknown\n");
+		}
+	} else {
+		/* Parallel phy */
+		if (ccsr & 0x80000000)
+			INFO("Output port operating in 8-bit mode\n");
+		if (ccsr & 0x08000000)
+			INFO("Input port operating in 8-bit mode\n");
+	}
+
+}
+
+static inline u8 hw_port_width(u32 ccsr)
+{
+	u8 pw = ccsr >> 30;
+	switch (pw) {
+	case 0:
+		return 1;
+	case 1:
+		return 4;
+	default:
+		return 0;
+	}
+}
+
+static int of_cells_get(struct device_node *np, const char *str)
+{
+	struct device_node *tmp = NULL;
+	const int *var = NULL;
+
+	var = of_get_property(np, str, NULL);
+	tmp = of_get_parent(np);
+
+	while (!var && tmp) {
+		var = (int *)of_get_property(tmp, str, NULL);
+		of_node_put(tmp);
+		tmp = of_get_parent(np);
+	}
+
+	return (var ? *var : 0);
+}
+
+/**
+ * fsl_rio_setup - Setup PowerPC RapidIO interface
+ *
+ * Initializes PowerPC RapidIO hardware interface, configures
+ * master port with system-specific info, and registers the
+ * master port with the RapidIO subsystem.
+ */
+int fsl_rio_setup(struct of_device *dev)
+{
+	struct rio_ops *ops = NULL;
+	struct rio_mport *port = NULL;
+	const u32 *dt_range;
+	int rlen = 0;
+	resource_size_t law_start = 0, law_size = 0;
+	struct resource regs;
+	int rc;
+	enum rio_phy_type phy_type;
+	volatile void __iomem *regs_win = NULL;
+	struct rio_priv *priv = NULL;
+	u32 ccsr;
+	int paw, aw, psw;
+	struct device_node *pa;
+
+	if (!dev->node) {
+		ERR("Dev ofnode is NULL\n");
+		return -EFAULT;
+	}
+
+	dt_range = of_get_property(dev->node, "ranges", &rlen);
+	if (!dt_range) {
+		ERR("Can't get %s property 'ranges'\n", dev->node->full_name);
+		return -EFAULT;
+	}
+
+	aw = of_cells_get(dev->node, "#address-cells");
+	pa = of_get_parent(dev->node);
+	paw = of_cells_get(pa, "#address-cells");
+	psw = of_cells_get(pa, "#size-cells");
+	of_node_put(pa);
+
+	law_start = of_read_number(dt_range + aw, paw);
+	law_size = of_read_number(dt_range + aw + paw, psw);
+
+	rc = of_address_to_resource(dev->node, 0, &regs);
+	if (rc) {
+		ERR("Can't get %s property 'reg'\n", dev->node->full_name);
+		return -EFAULT;
+	}
+	INFO("Of-device full name %s\n", dev->node->full_name);
+	INFO("LAW start 0x%016llx, size 0x%016llx.\n", (u64)law_start,
+						(u64)law_size);
+	INFO("Regs start 0x%08x size 0x%08x\n",	regs.start,
+						regs.end - regs.start + 1);
+
+	regs_win = ioremap(regs.start, regs.end - regs.start + 1);
+	if (!regs_win) {
+		ERR("Can't remap io for 'regs_win'\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	/* Probe the RapidIO phy type */
+	ccsr = in_be32(regs_win + RIO_CCSR);
+	if (ccsr & 1)
+		phy_type = RIO_PHY_SERIAL;
+	else
+		phy_type = RIO_PHY_PARALLEL;
+	INFO("Phy type: ");
+	switch (phy_type) {
+	case RIO_PHY_SERIAL:
+		printk("serial\n");
+		break;
+	case RIO_PHY_PARALLEL:
+		printk("parallel");
+		break;
+	default:
+		printk("Unknown type %d\n", phy_type);
+		rc = -EINVAL;
+		goto err;
+	};
+	fsl_rio_info(ccsr);
+
+
+	/* Checking the port training status */
+	if (in_be32((regs_win + RIO_ESCSR)) & 1) {
+		ERR("Port is not ready. Try to restart connection...\n");
+		switch (phy_type) {
+		case RIO_PHY_SERIAL:
+			/* Disable ports */
+			out_be32(regs_win + RIO_CCSR, 0);
+			/* Set 1x lane */
+			setbits32(regs_win + RIO_CCSR, 0x02000000);
+			/* Enable ports */
+			setbits32(regs_win + RIO_CCSR, 0x00600000);
+			break;
+		case RIO_PHY_PARALLEL:
+			/* Disable ports */
+			out_be32(regs_win + RIO_CCSR, 0x22000000);
+			/* Enable ports */
+			out_be32(regs_win + RIO_CCSR, 0x44000000);
+			break;
+		}
+		if (in_be32((regs_win + RIO_ESCSR)) & 1) {
+			ERR("Port restart failed.\n");
+			rc = -ENOLINK;
+			goto err;
+		}
+		INFO("Port restart success!");
+		ccsr = in_be32(regs_win + RIO_CCSR);
+		fsl_rio_info(ccsr);
+	}
+
+	ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL);
+	ops->lcread = fsl_local_config_read;
+	ops->lcwrite = fsl_local_config_write;
+	ops->cread = fsl_rio_config_read;
+	ops->cwrite = fsl_rio_config_write;
+	ops->dsend = fsl_rio_doorbell_send;
+
+	port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
+	if (!port) {
+		ERR("Can't alloc memory for 'port'\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	port->id = 0;
+	port->index = 0;
+
+	port->sys_size = (in_be32((regs_win + RIO_PEF_CAR))
+				& RIO_PEF_CTLS) >> 4;
+	INFO("RapidIO Common Transport System size: %d\n",
+			port->sys_size ? 65536 : 256);
+
+	port->phy_type = phy_type;
+
+	priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL);
+	if (!priv) {
+		ERR("Can't alloc memory for 'priv'\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	port->priv = priv;
+	priv->regs_win = regs_win;
+	INIT_LIST_HEAD(&port->dbells);
+	port->iores.start = law_start;
+	port->iores.end = law_start + law_size;
+	port->iores.flags = IORESOURCE_MEM;
+	port->iores.name = "rio_io_win";
+
+	priv->bellirq = irq_of_parse_and_map(dev->node, 2);
+	priv->txirq = irq_of_parse_and_map(dev->node, 3);
+	priv->rxirq = irq_of_parse_and_map(dev->node, 4);
+	INFO("bellirq: %d, txirq: %d, rxirq %d\n", 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);
+
+	strcpy(port->name, "RIO0 mport");
+
+	port->ops = ops;
+	port->mops = &fsl_mem_ops;
+	port->host_deviceid = fsl_rio_get_hdid(port->id);
+
+	rio_register_mport(port);
+
+	priv->atmu_regs = (struct rio_atmu_regs *)(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 *)(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)
+		out_be32((regs_win + RIO_ISR_AACR), RIO_ISR_AACR_AA);
+
+	/* Configure maintenance transaction window */
+	if (!rio_request_io_region(port, NULL, law_start, RIO_MAINT_WIN_SIZE,
+				"maint_win", RIO_RESOURCE_MAINT, NULL)) {
+		rc = -EPERM;
+		ERR("request maint win error!\n");
+		goto err;
+	}
+	out_be32(&priv->maint_atmu_regs->rowbar,
+				(law_start >> 12) & 0xffffff);
+	out_be32(&priv->maint_atmu_regs->rowar, 0x80077000
+			| (__ilog2(RIO_MAINT_WIN_SIZE) - 1));
+
+	priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE);
+
+	/* Configure outbound doorbell window */
+	if (!rio_request_io_region(port, NULL, law_start + RIO_MAINT_WIN_SIZE,
+			RIO_DBELL_WIN_SIZE,
+			"dbell_win", RIO_RESOURCE_DOORBELL, NULL)) {
+		rc = -EPERM;
+		ERR("request doorbell win error!\n");
+		goto err;
+	}
+	out_be32(&priv->dbell_atmu_regs->rowbar, ((law_start +
+					RIO_MAINT_WIN_SIZE) >> 12) & 0xfffff);
+	out_be32(&priv->dbell_atmu_regs->rowar, 0x80042000
+			| (__ilog2(RIO_DBELL_WIN_SIZE) - 1));
+	rc = fsl_rio_doorbell_init(port, law_start + RIO_MAINT_WIN_SIZE);
+	if (rc)
+		goto err;
+
+	return 0;
+
+err:
+	if (regs_win)
+		iounmap(regs_win);
+	if (ops)
+		kfree(ops);
+	if (port)
+		kfree(port);
+	if (priv)
+		kfree(priv);
+	return rc;
+}
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h
new file mode 100644
index 0000000..34231df
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rio.h
@@ -0,0 +1,20 @@
+/*
+ * Freescale PowerPC RapidIO definitions
+ *
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Zhang Wei <wei.zhang@freescale.com>, Jun 2007
+ *
+ * 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 __POWERPC_SYSDEV_FSL_RIO_H
+#define __POWERPC_SYSDEV_FSL_RIO_H
+
+#include <linux/init.h>
+
+extern int fsl_rio_setup(struct of_device *of_dev);
+
+#endif				/* __POWERPC_SYSDEV_FSL_RIO_H */
-- 
1.5.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox