diff options
Diffstat (limited to 'arch/mips/pci')
71 files changed, 6396 insertions, 2318 deletions
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index c9209ca6c8e..ff8a5539b36 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -18,29 +18,31 @@ obj-$(CONFIG_PCI_TX4927)	+= ops-tx4927.o  obj-$(CONFIG_BCM47XX)		+= pci-bcm47xx.o  obj-$(CONFIG_BCM63XX)		+= pci-bcm63xx.o fixup-bcm63xx.o \  					ops-bcm63xx.o - +obj-$(CONFIG_MIPS_ALCHEMY)	+= pci-alchemy.o +obj-$(CONFIG_SOC_AR71XX)	+= pci-ar71xx.o +obj-$(CONFIG_PCI_AR724X)	+= pci-ar724x.o +obj-$(CONFIG_MIPS_PCI_VIRTIO)	+= pci-virtio-guest.o  #  # These are still pretty much in the old state, watch, go blind.  #  obj-$(CONFIG_LASAT)		+= pci-lasat.o  obj-$(CONFIG_MIPS_COBALT)	+= fixup-cobalt.o -obj-$(CONFIG_SOC_AU1500)	+= fixup-au1000.o ops-au1000.o -obj-$(CONFIG_SOC_AU1550)	+= fixup-au1000.o ops-au1000.o -obj-$(CONFIG_SOC_PNX8550)	+= fixup-pnx8550.o ops-pnx8550.o  obj-$(CONFIG_LEMOTE_FULOONG2E)	+= fixup-fuloong2e.o ops-loongson2.o  obj-$(CONFIG_LEMOTE_MACH2F)	+= fixup-lemote2f.o ops-loongson2.o -obj-$(CONFIG_MIPS_MALTA)	+= fixup-malta.o +obj-$(CONFIG_LEMOTE_MACH3A)	+= fixup-loongson3.o ops-loongson3.o +obj-$(CONFIG_MIPS_MALTA)	+= fixup-malta.o pci-malta.o  obj-$(CONFIG_PMC_MSP7120_GW)	+= fixup-pmcmsp.o ops-pmcmsp.o  obj-$(CONFIG_PMC_MSP7120_EVAL)	+= fixup-pmcmsp.o ops-pmcmsp.o  obj-$(CONFIG_PMC_MSP7120_FPGA)	+= fixup-pmcmsp.o ops-pmcmsp.o -obj-$(CONFIG_PMC_YOSEMITE)	+= fixup-yosemite.o ops-titan.o ops-titan-ht.o \ -				   pci-yosemite.o  obj-$(CONFIG_SGI_IP27)		+= ops-bridge.o pci-ip27.o  obj-$(CONFIG_SGI_IP32)		+= fixup-ip32.o ops-mace.o pci-ip32.o  obj-$(CONFIG_SIBYTE_SB1250)	+= fixup-sb1250.o pci-sb1250.o  obj-$(CONFIG_SIBYTE_BCM112X)	+= fixup-sb1250.o pci-sb1250.o  obj-$(CONFIG_SIBYTE_BCM1x80)	+= pci-bcm1480.o pci-bcm1480ht.o  obj-$(CONFIG_SNI_RM)		+= fixup-sni.o ops-sni.o +obj-$(CONFIG_LANTIQ)		+= fixup-lantiq.o +obj-$(CONFIG_PCI_LANTIQ)	+= pci-lantiq.o ops-lantiq.o +obj-$(CONFIG_SOC_RT3883)	+= pci-rt3883.o  obj-$(CONFIG_TANBAC_TB0219)	+= fixup-tb0219.o  obj-$(CONFIG_TANBAC_TB0226)	+= fixup-tb0226.o  obj-$(CONFIG_TANBAC_TB0287)	+= fixup-tb0287.o @@ -52,10 +54,12 @@ obj-$(CONFIG_TOSHIBA_RBTX4927)	+= fixup-rbtx4927.o  obj-$(CONFIG_TOSHIBA_RBTX4938)	+= fixup-rbtx4938.o  obj-$(CONFIG_VICTOR_MPC30X)	+= fixup-mpc30x.o  obj-$(CONFIG_ZAO_CAPCELLA)	+= fixup-capcella.o -obj-$(CONFIG_WR_PPMC)		+= fixup-wrppmc.o  obj-$(CONFIG_MIKROTIK_RB532)	+= pci-rc32434.o ops-rc32434.o fixup-rc32434.o -obj-$(CONFIG_CPU_CAVIUM_OCTEON)	+= pci-octeon.o pcie-octeon.o +obj-$(CONFIG_CAVIUM_OCTEON_SOC) += pci-octeon.o pcie-octeon.o +obj-$(CONFIG_CPU_XLR)		+= pci-xlr.o +obj-$(CONFIG_CPU_XLP)		+= pci-xlp.o  ifdef CONFIG_PCI_MSI -obj-$(CONFIG_CPU_CAVIUM_OCTEON)	+= msi-octeon.o +obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o +obj-$(CONFIG_CPU_XLP)		+= msi-xlp.o  endif diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c deleted file mode 100644 index e2ddfc49237..00000000000 --- a/arch/mips/pci/fixup-au1000.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - *	Board specific PCI fixups. - * - * Copyright 2001-2003, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * - *  This program is free software; you can redistribute  it and/or modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. - * - *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED - *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF - *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN - *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, - *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF - *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT - *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *  You should have received a copy of the  GNU General Public License along - *  with this program; if not, write  to the Free Software Foundation, Inc., - *  675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/pci.h> -#include <linux/init.h> - -extern char irq_tab_alchemy[][5]; - -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ -	return irq_tab_alchemy[slot][pin]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ -	return 0; -} diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c index acacd1407c6..a138e8ee5cf 100644 --- a/arch/mips/pci/fixup-cobalt.c +++ b/arch/mips/pci/fixup-cobalt.c @@ -51,67 +51,6 @@ static void qube_raq_galileo_early_fixup(struct pci_dev *dev)  DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,  	 qube_raq_galileo_early_fixup); -static void __devinit cobalt_legacy_ide_resource_fixup(struct pci_dev *dev, -						       struct resource *res) -{ -	struct pci_controller *hose = (struct pci_controller *)dev->sysdata; -	unsigned long offset = hose->io_offset; -	struct resource orig = *res; - -	if (!(res->flags & IORESOURCE_IO) || -	    !(res->flags & IORESOURCE_PCI_FIXED)) -		return; - -	res->start -= offset; -	res->end -= offset; -	dev_printk(KERN_DEBUG, &dev->dev, "converted legacy %pR to bus %pR\n", -		   &orig, res); -} - -static void __devinit cobalt_legacy_ide_fixup(struct pci_dev *dev) -{ -	u32 class; -	u8 progif; - -	/* -	 * If the IDE controller is in legacy mode, pci_setup_device() fills in -	 * the resources with the legacy addresses that normally appear on the -	 * PCI bus, just as if we had read them from a BAR. -	 * -	 * However, with the GT-64111, those legacy addresses, e.g., 0x1f0, -	 * will never appear on the PCI bus because it converts memory accesses -	 * in the PCI I/O region (which is never at address zero) into I/O port -	 * accesses with no address translation. -	 * -	 * For example, if GT_DEF_PCI0_IO_BASE is 0x10000000, a load or store -	 * to physical address 0x100001f0 will become a PCI access to I/O port -	 * 0x100001f0.  There's no way to generate an access to I/O port 0x1f0, -	 * but the VT82C586 IDE controller does respond at 0x100001f0 because -	 * it only decodes the low 24 bits of the address. -	 * -	 * When this quirk runs, the pci_dev resources should contain bus -	 * addresses, not Linux I/O port numbers, so convert legacy addresses -	 * like 0x1f0 to bus addresses like 0x100001f0.  Later, we'll convert -	 * them back with pcibios_fixup_bus() or pcibios_bus_to_resource(). -	 */ -	class = dev->class >> 8; -	if (class != PCI_CLASS_STORAGE_IDE) -		return; - -	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); -	if ((progif & 1) == 0) { -		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[0]); -		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[1]); -	} -	if ((progif & 4) == 0) { -		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[2]); -		cobalt_legacy_ide_resource_fixup(dev, &dev->resource[3]); -	} -} - -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, -	  cobalt_legacy_ide_fixup); -  static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)  {  	unsigned short cfgword; @@ -155,14 +94,14 @@ static void qube_raq_galileo_fixup(struct pci_dev *dev)  	 * --x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--  	 *  	 * On all machines prior to Q2, we had the STOP line disconnected -	 * from Galileo to VIA on PCI.  The new Galileo does not function +	 * from Galileo to VIA on PCI.	The new Galileo does not function  	 * correctly unless we have it connected.  	 *  	 * Therefore we must set the disconnect/retry cycle values to  	 * something sensible when using the new Galileo.  	 */ - 	printk(KERN_INFO "Galileo: revision %u\n", dev->revision); +	printk(KERN_INFO "Galileo: revision %u\n", dev->revision);  #if 0  	if (dev->revision >= 0x10) { @@ -210,30 +149,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0,  	 qube_raq_via_board_id_fixup);  static char irq_tab_qube1[] __initdata = { -  [COBALT_PCICONF_CPU]     = 0, -  [COBALT_PCICONF_ETH0]    = QUBE1_ETH0_IRQ, +  [COBALT_PCICONF_CPU]	   = 0, +  [COBALT_PCICONF_ETH0]	   = QUBE1_ETH0_IRQ,    [COBALT_PCICONF_RAQSCSI] = SCSI_IRQ, -  [COBALT_PCICONF_VIA]     = 0, +  [COBALT_PCICONF_VIA]	   = 0,    [COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ, -  [COBALT_PCICONF_ETH1]    = 0 +  [COBALT_PCICONF_ETH1]	   = 0  };  static char irq_tab_cobalt[] __initdata = { -  [COBALT_PCICONF_CPU]     = 0, -  [COBALT_PCICONF_ETH0]    = ETH0_IRQ, +  [COBALT_PCICONF_CPU]	   = 0, +  [COBALT_PCICONF_ETH0]	   = ETH0_IRQ,    [COBALT_PCICONF_RAQSCSI] = SCSI_IRQ, -  [COBALT_PCICONF_VIA]     = 0, +  [COBALT_PCICONF_VIA]	   = 0,    [COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ, -  [COBALT_PCICONF_ETH1]    = ETH1_IRQ +  [COBALT_PCICONF_ETH1]	   = ETH1_IRQ  };  static char irq_tab_raq2[] __initdata = { -  [COBALT_PCICONF_CPU]     = 0, -  [COBALT_PCICONF_ETH0]    = ETH0_IRQ, +  [COBALT_PCICONF_CPU]	   = 0, +  [COBALT_PCICONF_ETH0]	   = ETH0_IRQ,    [COBALT_PCICONF_RAQSCSI] = RAQ2_SCSI_IRQ, -  [COBALT_PCICONF_VIA]     = 0, +  [COBALT_PCICONF_VIA]	   = 0,    [COBALT_PCICONF_PCISLOT] = PCISLOT_IRQ, -  [COBALT_PCICONF_ETH1]    = ETH1_IRQ +  [COBALT_PCICONF_ETH1]	   = ETH1_IRQ  };  int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/arch/mips/pci/fixup-emma2rh.c b/arch/mips/pci/fixup-emma2rh.c index 0d9ccf4dfc5..19caf775c20 100644 --- a/arch/mips/pci/fixup-emma2rh.c +++ b/arch/mips/pci/fixup-emma2rh.c @@ -42,7 +42,7 @@   *   */ -#define	MAX_SLOT_NUM 10 +#define MAX_SLOT_NUM 10  static unsigned char irq_map[][5] __initdata = {  	[3] = {0, MARKEINS_PCI_IRQ_INTB, MARKEINS_PCI_IRQ_INTC,  	       MARKEINS_PCI_IRQ_INTD, 0,}, @@ -52,7 +52,7 @@ static unsigned char irq_map[][5] __initdata = {  	       MARKEINS_PCI_IRQ_INTA, MARKEINS_PCI_IRQ_INTB,},  }; -static void __devinit nec_usb_controller_fixup(struct pci_dev *dev) +static void nec_usb_controller_fixup(struct pci_dev *dev)  {  	if (PCI_SLOT(dev->devfn) == EMMA2RH_USB_SLOT)  		/* on board USB controller configuration */ @@ -67,7 +67,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,   * if it is the host bridge by marking it as such.  These resources are of   * no consequence to the PCI layer (they are handled elsewhere).   */ -static void __devinit emma2rh_pci_host_fixup(struct pci_dev *dev) +static void emma2rh_pci_host_fixup(struct pci_dev *dev)  {  	int i; diff --git a/arch/mips/pci/fixup-fuloong2e.c b/arch/mips/pci/fixup-fuloong2e.c index d5d4c018fb0..50da773faed 100644 --- a/arch/mips/pci/fixup-fuloong2e.c +++ b/arch/mips/pci/fixup-fuloong2e.c @@ -6,9 +6,9 @@   * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology   * Author: Fuxin Zhang, zhangfx@lemote.com   * - *  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 + *  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/init.h> @@ -48,7 +48,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  	return 0;  } -static void __init loongson2e_nec_fixup(struct pci_dev *pdev) +static void loongson2e_nec_fixup(struct pci_dev *pdev)  {  	unsigned int val; @@ -60,7 +60,7 @@ static void __init loongson2e_nec_fixup(struct pci_dev *pdev)  	pci_write_config_dword(pdev, 0xe4, 1 << 5);  } -static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev) +static void loongson2e_686b_func0_fixup(struct pci_dev *pdev)  {  	unsigned char c; @@ -135,7 +135,7 @@ static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev)  	printk(KERN_INFO"via686b fix: ISA bridge done\n");  } -static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev) +static void loongson2e_686b_func1_fixup(struct pci_dev *pdev)  {  	printk(KERN_INFO"via686b fix: IDE\n"); @@ -152,7 +152,7 @@ static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)  	/* disable read prefetch/write post buffers */  	pci_write_config_byte(pdev, 0x41, 0x02); -	/* use 3/4 as fifo thresh hold  */ +	/* use 3/4 as fifo thresh hold	*/  	pci_write_config_byte(pdev, 0x43, 0x0a);  	pci_write_config_byte(pdev, 0x44, 0x00); @@ -168,19 +168,19 @@ static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)  	printk(KERN_INFO"via686b fix: IDE done\n");  } -static void __init loongson2e_686b_func2_fixup(struct pci_dev *pdev) +static void loongson2e_686b_func2_fixup(struct pci_dev *pdev)  {  	/* irq routing */  	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 10);  } -static void __init loongson2e_686b_func3_fixup(struct pci_dev *pdev) +static void loongson2e_686b_func3_fixup(struct pci_dev *pdev)  {  	/* irq routing */  	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 11);  } -static void __init loongson2e_686b_func5_fixup(struct pci_dev *pdev) +static void loongson2e_686b_func5_fixup(struct pci_dev *pdev)  {  	unsigned int val;  	unsigned char c; diff --git a/arch/mips/pci/fixup-ip32.c b/arch/mips/pci/fixup-ip32.c index 190fffd08d3..133685e215e 100644 --- a/arch/mips/pci/fixup-ip32.c +++ b/arch/mips/pci/fixup-ip32.c @@ -22,13 +22,13 @@  #define INTC   MACEPCI_SHARED1_IRQ  #define INTD   MACEPCI_SHARED2_IRQ  static char irq_tab_mace[][5] __initdata = { -      /* Dummy  INT#A  INT#B  INT#C  INT#D */ -	{0,         0,     0,     0,     0}, /* This is placeholder row - never used */ -	{0,     SCSI0, SCSI0, SCSI0, SCSI0}, -	{0,     SCSI1, SCSI1, SCSI1, SCSI1}, -	{0,     INTA0,  INTB,  INTC,  INTD}, -	{0,     INTA1,  INTC,  INTD,  INTB}, -	{0,     INTA2,  INTD,  INTB,  INTC}, +      /* Dummy	INT#A  INT#B  INT#C  INT#D */ +	{0,	    0,	   0,	  0,	 0}, /* This is placeholder row - never used */ +	{0,	SCSI0, SCSI0, SCSI0, SCSI0}, +	{0,	SCSI1, SCSI1, SCSI1, SCSI1}, +	{0,	INTA0,	INTB,  INTC,  INTD}, +	{0,	INTA1,	INTC,  INTD,  INTB}, +	{0,	INTA2,	INTD,  INTB,  INTC},  }; diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c new file mode 100644 index 00000000000..c2ce41ea61d --- /dev/null +++ b/arch/mips/pci/fixup-lantiq.c @@ -0,0 +1,29 @@ +/* + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + * + *  Copyright (C) 2012 John Crispin <blogic@openwrt.org> + */ + +#include <linux/of_irq.h> +#include <linux/of_pci.h> + +int (*ltq_pci_plat_arch_init)(struct pci_dev *dev) = NULL; +int (*ltq_pci_plat_dev_init)(struct pci_dev *dev) = NULL; + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	if (ltq_pci_plat_arch_init) +		return ltq_pci_plat_arch_init(dev); + +	if (ltq_pci_plat_dev_init) +		return ltq_pci_plat_dev_init(dev); + +	return 0; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	return of_irq_parse_and_map_pci(dev, slot, pin); +} diff --git a/arch/mips/pci/fixup-lemote2f.c b/arch/mips/pci/fixup-lemote2f.c index 4b9768d5d72..95ab9a1bd01 100644 --- a/arch/mips/pci/fixup-lemote2f.c +++ b/arch/mips/pci/fixup-lemote2f.c @@ -31,7 +31,7 @@  /* all the pci device has the PCIA pin, check the datasheet. */  static char irq_tab[][5] __initdata = { -	/*      INTA    INTB    INTC    INTD */ +	/*	INTA	INTB	INTC	INTD */  	{0, 0, 0, 0, 0},	/*  11: Unused */  	{0, 0, 0, 0, 0},	/*  12: Unused */  	{0, 0, 0, 0, 0},	/*  13: Unused */ @@ -69,15 +69,15 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  		case 2:  			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,  					      CS5536_IDE_INTR); -			return CS5536_IDE_INTR;	/*  for IDE */ +			return CS5536_IDE_INTR; /*  for IDE */  		case 3:  			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,  					      CS5536_ACC_INTR); -			return CS5536_ACC_INTR;	/*  for AUDIO */ -		case 4:	/*  for OHCI */ -		case 5:	/*  for EHCI */ -		case 6:	/*  for UDC */ -		case 7:	/*  for OTG */ +			return CS5536_ACC_INTR; /*  for AUDIO */ +		case 4: /*  for OHCI */ +		case 5: /*  for EHCI */ +		case 6: /*  for UDC */ +		case 7: /*  for OTG */  			pci_write_config_byte(dev, PCI_INTERRUPT_LINE,  					      CS5536_USB_INTR);  			return CS5536_USB_INTR; @@ -96,21 +96,21 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  }  /* CS5536 SPEC. fixup */ -static void __init loongson_cs5536_isa_fixup(struct pci_dev *pdev) +static void loongson_cs5536_isa_fixup(struct pci_dev *pdev)  {  	/* the uart1 and uart2 interrupt in PIC is enabled as default */  	pci_write_config_dword(pdev, PCI_UART1_INT_REG, 1);  	pci_write_config_dword(pdev, PCI_UART2_INT_REG, 1);  } -static void __init loongson_cs5536_ide_fixup(struct pci_dev *pdev) +static void loongson_cs5536_ide_fixup(struct pci_dev *pdev)  {  	/* setting the mutex pin as IDE function */  	pci_write_config_dword(pdev, PCI_IDE_CFG_REG,  			       CS5536_IDE_FLASH_SIGNATURE);  } -static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev) +static void loongson_cs5536_acc_fixup(struct pci_dev *pdev)  {  	/* enable the AUDIO interrupt in PIC  */  	pci_write_config_dword(pdev, PCI_ACC_INT_REG, 1); @@ -118,14 +118,14 @@ static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)  	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xc0);  } -static void __init loongson_cs5536_ohci_fixup(struct pci_dev *pdev) +static void loongson_cs5536_ohci_fixup(struct pci_dev *pdev)  {  	/* enable the OHCI interrupt in PIC */  	/* THE OHCI, EHCI, UDC, OTG are shared with interrupt in PIC */  	pci_write_config_dword(pdev, PCI_OHCI_INT_REG, 1);  } -static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev) +static void loongson_cs5536_ehci_fixup(struct pci_dev *pdev)  {  	u32 hi, lo; @@ -137,7 +137,7 @@ static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)  	pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000);  } -static void __init loongson_nec_fixup(struct pci_dev *pdev) +static void loongson_nec_fixup(struct pci_dev *pdev)  {  	unsigned int val; diff --git a/arch/mips/pci/fixup-loongson3.c b/arch/mips/pci/fixup-loongson3.c new file mode 100644 index 00000000000..d708ae46d32 --- /dev/null +++ b/arch/mips/pci/fixup-loongson3.c @@ -0,0 +1,66 @@ +/* + * fixup-loongson3.c + * + * Copyright (C) 2012 Lemote, Inc. + * Author: Xiang Yu, xiangy@lemote.com + *         Chen Huacai, chenhc@lemote.com + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + * + * THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED + * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN + * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF + * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <linux/pci.h> +#include <boot_param.h> + +static void print_fixup_info(const struct pci_dev *pdev) +{ +	dev_info(&pdev->dev, "Device %x:%x, irq %d\n", +			pdev->vendor, pdev->device, pdev->irq); +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	print_fixup_info(dev); +	return dev->irq; +} + +static void pci_fixup_radeon(struct pci_dev *pdev) +{ +	if (pdev->resource[PCI_ROM_RESOURCE].start) +		return; + +	if (!loongson_sysconf.vgabios_addr) +		return; + +	pdev->resource[PCI_ROM_RESOURCE].start = +		loongson_sysconf.vgabios_addr; +	pdev->resource[PCI_ROM_RESOURCE].end   = +		loongson_sysconf.vgabios_addr + 256*1024 - 1; +	pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_COPY; + +	dev_info(&pdev->dev, "BAR %d: assigned %pR for Radeon ROM\n", +			PCI_ROM_RESOURCE, &pdev->resource[PCI_ROM_RESOURCE]); +} + +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID, +				PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_radeon); + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	return 0; +} diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c index 0f48498bc23..40e920c653c 100644 --- a/arch/mips/pci/fixup-malta.c +++ b/arch/mips/pci/fixup-malta.c @@ -1,5 +1,6 @@  #include <linux/init.h>  #include <linux/pci.h> +#include <asm/mips-boards/piix4.h>  /* PCI interrupt pins */  #define PCIA		1 @@ -8,10 +9,11 @@  #define PCID		4  /* This table is filled in by interrogating the PIIX4 chip */ -static char pci_irq[5] __initdata; +static char pci_irq[5] = { +};  static char irq_tab[][5] __initdata = { -	/*      INTA    INTB    INTC    INTD */ +	/*	INTA	INTB	INTC	INTD */  	{0,	0,	0,	0,	0 },	/*  0: GT64120 PCI bridge */  	{0,	0,	0,	0,	0 },	/*  1: Unused */  	{0,	0,	0,	0,	0 },	/*  2: Unused */ @@ -22,7 +24,7 @@ static char irq_tab[][5] __initdata = {  	{0,	0,	0,	0,	0 },	/*  7: Unused */  	{0,	0,	0,	0,	0 },	/*  8: Unused */  	{0,	0,	0,	0,	0 },	/*  9: Unused */ -	{0,	0,	0,	0,	PCID },	/* 10: PIIX4 USB */ +	{0,	0,	0,	0,	PCID }, /* 10: PIIX4 USB */  	{0,	PCIB,	0,	0,	0 },	/* 11: AMD 79C973 Ethernet */  	{0,	PCIC,	0,	0,	0 },	/* 12: Crystal 4281 Sound */  	{0,	0,	0,	0,	0 },	/* 13: Unused */ @@ -30,9 +32,9 @@ static char irq_tab[][5] __initdata = {  	{0,	0,	0,	0,	0 },	/* 15: Unused */  	{0,	0,	0,	0,	0 },	/* 16: Unused */  	{0,	0,	0,	0,	0 },	/* 17: Bonito/SOC-it PCI Bridge*/ -	{0,	PCIA,	PCIB,	PCIC,	PCID },	/* 18: PCI Slot 1 */ -	{0,	PCIB,	PCIC,	PCID,	PCIA },	/* 19: PCI Slot 2 */ -	{0,	PCIC,	PCID,	PCIA,	PCIB },	/* 20: PCI Slot 3 */ +	{0,	PCIA,	PCIB,	PCIC,	PCID }, /* 18: PCI Slot 1 */ +	{0,	PCIB,	PCIC,	PCID,	PCIA }, /* 19: PCI Slot 2 */ +	{0,	PCIC,	PCID,	PCIA,	PCIB }, /* 20: PCI Slot 3 */  	{0,	PCID,	PCIA,	PCIB,	PCIC }	/* 21: PCI Slot 4 */  }; @@ -49,12 +51,28 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  	return 0;  } -static void __init malta_piix_func0_fixup(struct pci_dev *pdev) +static void malta_piix_func3_base_fixup(struct pci_dev *dev) +{ +	/* Set a sane PM I/O base address */ +	pci_write_config_word(dev, PIIX4_FUNC3_PMBA, 0x1000); + +	/* Enable access to the PM I/O region */ +	pci_write_config_byte(dev, PIIX4_FUNC3_PMREGMISC, +			      PIIX4_FUNC3_PMREGMISC_EN); +} + +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, +			malta_piix_func3_base_fixup); + +static void malta_piix_func0_fixup(struct pci_dev *pdev)  {  	unsigned char reg_val; -	static int piixirqmap[16] __initdata = {  /* PIIX PIRQC[A:D] irq mappings */ -		0,  0, 	0,  3, -		4,  5,  6,  7, +	u32 reg_val32; +	u16 reg_val16; +	/* PIIX PIRQC[A:D] irq mappings */ +	static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = { +		0,  0,	0,  3, +		4,  5,	6,  7,  		0,  9, 10, 11,  		12, 0, 14, 15  	}; @@ -62,11 +80,12 @@ static void __init malta_piix_func0_fixup(struct pci_dev *pdev)  	/* Interrogate PIIX4 to get PCI IRQ mapping */  	for (i = 0; i <= 3; i++) { -		pci_read_config_byte(pdev, 0x60+i, ®_val); -		if (reg_val & 0x80) +		pci_read_config_byte(pdev, PIIX4_FUNC0_PIRQRC+i, ®_val); +		if (reg_val & PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_DISABLE)  			pci_irq[PCIA+i] = 0;	/* Disabled */  		else -			pci_irq[PCIA+i] = piixirqmap[reg_val & 15]; +			pci_irq[PCIA+i] = piixirqmap[reg_val & +				PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MASK];  	}  	/* Done by YAMON 2.00 onwards */ @@ -75,15 +94,31 @@ static void __init malta_piix_func0_fixup(struct pci_dev *pdev)  		 * Set top of main memory accessible by ISA or DMA  		 * devices to 16 Mb.  		 */ -		pci_read_config_byte(pdev, 0x69, ®_val); -		pci_write_config_byte(pdev, 0x69, reg_val | 0xf0); +		pci_read_config_byte(pdev, PIIX4_FUNC0_TOM, ®_val); +		pci_write_config_byte(pdev, PIIX4_FUNC0_TOM, reg_val | +				PIIX4_FUNC0_TOM_TOP_OF_MEMORY_MASK);  	} + +	/* Mux SERIRQ to its pin */ +	pci_read_config_dword(pdev, PIIX4_FUNC0_GENCFG, ®_val32); +	pci_write_config_dword(pdev, PIIX4_FUNC0_GENCFG, +			       reg_val32 | PIIX4_FUNC0_GENCFG_SERIRQ); + +	/* Enable SERIRQ */ +	pci_read_config_byte(pdev, PIIX4_FUNC0_SERIRQC, ®_val); +	reg_val |= PIIX4_FUNC0_SERIRQC_EN | PIIX4_FUNC0_SERIRQC_CONT; +	pci_write_config_byte(pdev, PIIX4_FUNC0_SERIRQC, reg_val); + +	/* Enable response to special cycles */ +	pci_read_config_word(pdev, PCI_COMMAND, ®_val16); +	pci_write_config_word(pdev, PCI_COMMAND, +			      reg_val16 | PCI_COMMAND_SPECIAL);  }  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,  	 malta_piix_func0_fixup); -static void __init malta_piix_func1_fixup(struct pci_dev *pdev) +static void malta_piix_func1_fixup(struct pci_dev *pdev)  {  	unsigned char reg_val; @@ -92,12 +127,32 @@ static void __init malta_piix_func1_fixup(struct pci_dev *pdev)  		/*  		 * IDE Decode enable.  		 */ -		pci_read_config_byte(pdev, 0x41, ®_val); -		pci_write_config_byte(pdev, 0x41, reg_val|0x80); -		pci_read_config_byte(pdev, 0x43, ®_val); -		pci_write_config_byte(pdev, 0x43, reg_val|0x80); +		pci_read_config_byte(pdev, PIIX4_FUNC1_IDETIM_PRIMARY_HI, +			®_val); +		pci_write_config_byte(pdev, PIIX4_FUNC1_IDETIM_PRIMARY_HI, +			reg_val|PIIX4_FUNC1_IDETIM_PRIMARY_HI_IDE_DECODE_EN); +		pci_read_config_byte(pdev, PIIX4_FUNC1_IDETIM_SECONDARY_HI, +			®_val); +		pci_write_config_byte(pdev, PIIX4_FUNC1_IDETIM_SECONDARY_HI, +			reg_val|PIIX4_FUNC1_IDETIM_SECONDARY_HI_IDE_DECODE_EN);  	}  }  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,  	 malta_piix_func1_fixup); + +/* Enable PCI 2.1 compatibility in PIIX4 */ +static void quirk_dlcsetup(struct pci_dev *dev) +{ +	u8 odlc, ndlc; + +	(void) pci_read_config_byte(dev, PIIX4_FUNC0_DLC, &odlc); +	/* Enable passive releases and delayed transaction */ +	ndlc = odlc | PIIX4_FUNC0_DLC_USBPR_EN | +		      PIIX4_FUNC0_DLC_PASSIVE_RELEASE_EN | +		      PIIX4_FUNC0_DLC_DELAYED_TRANSACTION_EN; +	(void) pci_write_config_byte(dev, PIIX4_FUNC0_DLC, ndlc); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, +	quirk_dlcsetup); diff --git a/arch/mips/pci/fixup-mpc30x.c b/arch/mips/pci/fixup-mpc30x.c index e08f49cb687..8e4f8288eca 100644 --- a/arch/mips/pci/fixup-mpc30x.c +++ b/arch/mips/pci/fixup-mpc30x.c @@ -22,13 +22,13 @@  #include <asm/vr41xx/mpc30x.h> -static const int internal_func_irqs[] __initdata = { +static const int internal_func_irqs[] __initconst = {  	VRC4173_CASCADE_IRQ,  	VRC4173_AC97_IRQ,  	VRC4173_USB_IRQ,  }; -static const int irq_tab_mpc30x[] __initdata = { +static const int irq_tab_mpc30x[] __initconst = {   [12] = VRC4173_PCMCIA1_IRQ,   [13] = VRC4173_PCMCIA2_IRQ,   [29] = MQ200_IRQ, diff --git a/arch/mips/pci/fixup-pmcmsp.c b/arch/mips/pci/fixup-pmcmsp.c index 65735b1b766..fab405c21c2 100644 --- a/arch/mips/pci/fixup-pmcmsp.c +++ b/arch/mips/pci/fixup-pmcmsp.c @@ -48,117 +48,117 @@  #if defined(CONFIG_PMC_MSP7120_GW)  /* Garibaldi Board IRQ wiring to PCI slots */  static char irq_tab[][5] __initdata = { -	/* INTA    INTB    INTC    INTD */ -	{0,     0,      0,      0,      0 },    /*    (AD[0]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[1]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[2]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[3]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[4]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[5]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[6]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[7]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[8]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[9]): Unused */ -	{0,     0,      0,      0,      0 },    /*  0 (AD[10]): Unused */ -	{0,     0,      0,      0,      0 },    /*  1 (AD[11]): Unused */ -	{0,     0,      0,      0,      0 },    /*  2 (AD[12]): Unused */ -	{0,     0,      0,      0,      0 },    /*  3 (AD[13]): Unused */ -	{0,     0,      0,      0,      0 },    /*  4 (AD[14]): Unused */ -	{0,     0,      0,      0,      0 },    /*  5 (AD[15]): Unused */ -	{0,     0,      0,      0,      0 },    /*  6 (AD[16]): Unused */ -	{0,     0,      0,      0,      0 },    /*  7 (AD[17]): Unused */ -	{0,     0,      0,      0,      0 },    /*  8 (AD[18]): Unused */ -	{0,     0,      0,      0,      0 },    /*  9 (AD[19]): Unused */ -	{0,     0,      0,      0,      0 },    /* 10 (AD[20]): Unused */ -	{0,     0,      0,      0,      0 },    /* 11 (AD[21]): Unused */ -	{0,     0,      0,      0,      0 },    /* 12 (AD[22]): Unused */ -	{0,     0,      0,      0,      0 },    /* 13 (AD[23]): Unused */ -	{0,     0,      0,      0,      0 },    /* 14 (AD[24]): Unused */ -	{0,     0,      0,      0,      0 },    /* 15 (AD[25]): Unused */ -	{0,     0,      0,      0,      0 },    /* 16 (AD[26]): Unused */ -	{0,     0,      0,      0,      0 },    /* 17 (AD[27]): Unused */ -	{0,     IRQ4,   IRQ4,   0,      0 },    /* 18 (AD[28]): slot 0 */ -	{0,     0,      0,      0,      0 },    /* 19 (AD[29]): Unused */ -	{0,     IRQ5,   IRQ5,   0,      0 },    /* 20 (AD[30]): slot 1 */ -	{0,     IRQ6,   IRQ6,   0,      0 }     /* 21 (AD[31]): slot 2 */ +	/* INTA	   INTB	   INTC	   INTD */ +	{0,	0,	0,	0,	0 },	/*    (AD[0]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[1]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[2]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[3]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[4]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[5]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[6]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[7]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[8]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[9]): Unused */ +	{0,	0,	0,	0,	0 },	/*  0 (AD[10]): Unused */ +	{0,	0,	0,	0,	0 },	/*  1 (AD[11]): Unused */ +	{0,	0,	0,	0,	0 },	/*  2 (AD[12]): Unused */ +	{0,	0,	0,	0,	0 },	/*  3 (AD[13]): Unused */ +	{0,	0,	0,	0,	0 },	/*  4 (AD[14]): Unused */ +	{0,	0,	0,	0,	0 },	/*  5 (AD[15]): Unused */ +	{0,	0,	0,	0,	0 },	/*  6 (AD[16]): Unused */ +	{0,	0,	0,	0,	0 },	/*  7 (AD[17]): Unused */ +	{0,	0,	0,	0,	0 },	/*  8 (AD[18]): Unused */ +	{0,	0,	0,	0,	0 },	/*  9 (AD[19]): Unused */ +	{0,	0,	0,	0,	0 },	/* 10 (AD[20]): Unused */ +	{0,	0,	0,	0,	0 },	/* 11 (AD[21]): Unused */ +	{0,	0,	0,	0,	0 },	/* 12 (AD[22]): Unused */ +	{0,	0,	0,	0,	0 },	/* 13 (AD[23]): Unused */ +	{0,	0,	0,	0,	0 },	/* 14 (AD[24]): Unused */ +	{0,	0,	0,	0,	0 },	/* 15 (AD[25]): Unused */ +	{0,	0,	0,	0,	0 },	/* 16 (AD[26]): Unused */ +	{0,	0,	0,	0,	0 },	/* 17 (AD[27]): Unused */ +	{0,	IRQ4,	IRQ4,	0,	0 },	/* 18 (AD[28]): slot 0 */ +	{0,	0,	0,	0,	0 },	/* 19 (AD[29]): Unused */ +	{0,	IRQ5,	IRQ5,	0,	0 },	/* 20 (AD[30]): slot 1 */ +	{0,	IRQ6,	IRQ6,	0,	0 }	/* 21 (AD[31]): slot 2 */  };  #elif defined(CONFIG_PMC_MSP7120_EVAL)  /* MSP7120 Eval Board IRQ wiring to PCI slots */  static char irq_tab[][5] __initdata = { -	/* INTA    INTB    INTC    INTD */ -	{0,     0,      0,      0,      0 },    /*    (AD[0]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[1]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[2]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[3]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[4]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[5]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[6]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[7]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[8]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[9]): Unused */ -	{0,     0,      0,      0,      0 },    /*  0 (AD[10]): Unused */ -	{0,     0,      0,      0,      0 },    /*  1 (AD[11]): Unused */ -	{0,     0,      0,      0,      0 },    /*  2 (AD[12]): Unused */ -	{0,     0,      0,      0,      0 },    /*  3 (AD[13]): Unused */ -	{0,     0,      0,      0,      0 },    /*  4 (AD[14]): Unused */ -	{0,     0,      0,      0,      0 },    /*  5 (AD[15]): Unused */ -	{0,     IRQ6,   IRQ6,   0,      0 },    /*  6 (AD[16]): slot 3 (mini) */ -	{0,     IRQ5,   IRQ5,   0,      0 },    /*  7 (AD[17]): slot 2 (mini) */ -	{0,     IRQ4,   IRQ4,   IRQ4,   IRQ4},  /*  8 (AD[18]): slot 0 (PCI) */ -	{0,     IRQ5,   IRQ5,   IRQ5,   IRQ5},  /*  9 (AD[19]): slot 1 (PCI) */ -	{0,     0,      0,      0,      0 },    /* 10 (AD[20]): Unused */ -	{0,     0,      0,      0,      0 },    /* 11 (AD[21]): Unused */ -	{0,     0,      0,      0,      0 },    /* 12 (AD[22]): Unused */ -	{0,     0,      0,      0,      0 },    /* 13 (AD[23]): Unused */ -	{0,     0,      0,      0,      0 },    /* 14 (AD[24]): Unused */ -	{0,     0,      0,      0,      0 },    /* 15 (AD[25]): Unused */ -	{0,     0,      0,      0,      0 },    /* 16 (AD[26]): Unused */ -	{0,     0,      0,      0,      0 },    /* 17 (AD[27]): Unused */ -	{0,     0,      0,      0,      0 },    /* 18 (AD[28]): Unused */ -	{0,     0,      0,      0,      0 },    /* 19 (AD[29]): Unused */ -	{0,     0,      0,      0,      0 },    /* 20 (AD[30]): Unused */ -	{0,     0,      0,      0,      0 }     /* 21 (AD[31]): Unused */ +	/* INTA	   INTB	   INTC	   INTD */ +	{0,	0,	0,	0,	0 },	/*    (AD[0]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[1]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[2]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[3]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[4]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[5]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[6]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[7]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[8]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[9]): Unused */ +	{0,	0,	0,	0,	0 },	/*  0 (AD[10]): Unused */ +	{0,	0,	0,	0,	0 },	/*  1 (AD[11]): Unused */ +	{0,	0,	0,	0,	0 },	/*  2 (AD[12]): Unused */ +	{0,	0,	0,	0,	0 },	/*  3 (AD[13]): Unused */ +	{0,	0,	0,	0,	0 },	/*  4 (AD[14]): Unused */ +	{0,	0,	0,	0,	0 },	/*  5 (AD[15]): Unused */ +	{0,	IRQ6,	IRQ6,	0,	0 },	/*  6 (AD[16]): slot 3 (mini) */ +	{0,	IRQ5,	IRQ5,	0,	0 },	/*  7 (AD[17]): slot 2 (mini) */ +	{0,	IRQ4,	IRQ4,	IRQ4,	IRQ4},	/*  8 (AD[18]): slot 0 (PCI) */ +	{0,	IRQ5,	IRQ5,	IRQ5,	IRQ5},	/*  9 (AD[19]): slot 1 (PCI) */ +	{0,	0,	0,	0,	0 },	/* 10 (AD[20]): Unused */ +	{0,	0,	0,	0,	0 },	/* 11 (AD[21]): Unused */ +	{0,	0,	0,	0,	0 },	/* 12 (AD[22]): Unused */ +	{0,	0,	0,	0,	0 },	/* 13 (AD[23]): Unused */ +	{0,	0,	0,	0,	0 },	/* 14 (AD[24]): Unused */ +	{0,	0,	0,	0,	0 },	/* 15 (AD[25]): Unused */ +	{0,	0,	0,	0,	0 },	/* 16 (AD[26]): Unused */ +	{0,	0,	0,	0,	0 },	/* 17 (AD[27]): Unused */ +	{0,	0,	0,	0,	0 },	/* 18 (AD[28]): Unused */ +	{0,	0,	0,	0,	0 },	/* 19 (AD[29]): Unused */ +	{0,	0,	0,	0,	0 },	/* 20 (AD[30]): Unused */ +	{0,	0,	0,	0,	0 }	/* 21 (AD[31]): Unused */  };  #else  /* Unknown board -- don't assign any IRQs */  static char irq_tab[][5] __initdata = { -	/* INTA    INTB    INTC    INTD */ -	{0,     0,      0,      0,      0 },    /*    (AD[0]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[1]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[2]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[3]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[4]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[5]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[6]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[7]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[8]): Unused */ -	{0,     0,      0,      0,      0 },    /*    (AD[9]): Unused */ -	{0,     0,      0,      0,      0 },    /*  0 (AD[10]): Unused */ -	{0,     0,      0,      0,      0 },    /*  1 (AD[11]): Unused */ -	{0,     0,      0,      0,      0 },    /*  2 (AD[12]): Unused */ -	{0,     0,      0,      0,      0 },    /*  3 (AD[13]): Unused */ -	{0,     0,      0,      0,      0 },    /*  4 (AD[14]): Unused */ -	{0,     0,      0,      0,      0 },    /*  5 (AD[15]): Unused */ -	{0,     0,      0,      0,      0 },    /*  6 (AD[16]): Unused */ -	{0,     0,      0,      0,      0 },    /*  7 (AD[17]): Unused */ -	{0,     0,      0,      0,      0 },    /*  8 (AD[18]): Unused */ -	{0,     0,      0,      0,      0 },    /*  9 (AD[19]): Unused */ -	{0,     0,      0,      0,      0 },    /* 10 (AD[20]): Unused */ -	{0,     0,      0,      0,      0 },    /* 11 (AD[21]): Unused */ -	{0,     0,      0,      0,      0 },    /* 12 (AD[22]): Unused */ -	{0,     0,      0,      0,      0 },    /* 13 (AD[23]): Unused */ -	{0,     0,      0,      0,      0 },    /* 14 (AD[24]): Unused */ -	{0,     0,      0,      0,      0 },    /* 15 (AD[25]): Unused */ -	{0,     0,      0,      0,      0 },    /* 16 (AD[26]): Unused */ -	{0,     0,      0,      0,      0 },    /* 17 (AD[27]): Unused */ -	{0,     0,      0,      0,      0 },    /* 18 (AD[28]): Unused */ -	{0,     0,      0,      0,      0 },    /* 19 (AD[29]): Unused */ -	{0,     0,      0,      0,      0 },    /* 20 (AD[30]): Unused */ -	{0,     0,      0,      0,      0 }     /* 21 (AD[31]): Unused */ +	/* INTA	   INTB	   INTC	   INTD */ +	{0,	0,	0,	0,	0 },	/*    (AD[0]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[1]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[2]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[3]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[4]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[5]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[6]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[7]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[8]): Unused */ +	{0,	0,	0,	0,	0 },	/*    (AD[9]): Unused */ +	{0,	0,	0,	0,	0 },	/*  0 (AD[10]): Unused */ +	{0,	0,	0,	0,	0 },	/*  1 (AD[11]): Unused */ +	{0,	0,	0,	0,	0 },	/*  2 (AD[12]): Unused */ +	{0,	0,	0,	0,	0 },	/*  3 (AD[13]): Unused */ +	{0,	0,	0,	0,	0 },	/*  4 (AD[14]): Unused */ +	{0,	0,	0,	0,	0 },	/*  5 (AD[15]): Unused */ +	{0,	0,	0,	0,	0 },	/*  6 (AD[16]): Unused */ +	{0,	0,	0,	0,	0 },	/*  7 (AD[17]): Unused */ +	{0,	0,	0,	0,	0 },	/*  8 (AD[18]): Unused */ +	{0,	0,	0,	0,	0 },	/*  9 (AD[19]): Unused */ +	{0,	0,	0,	0,	0 },	/* 10 (AD[20]): Unused */ +	{0,	0,	0,	0,	0 },	/* 11 (AD[21]): Unused */ +	{0,	0,	0,	0,	0 },	/* 12 (AD[22]): Unused */ +	{0,	0,	0,	0,	0 },	/* 13 (AD[23]): Unused */ +	{0,	0,	0,	0,	0 },	/* 14 (AD[24]): Unused */ +	{0,	0,	0,	0,	0 },	/* 15 (AD[25]): Unused */ +	{0,	0,	0,	0,	0 },	/* 16 (AD[26]): Unused */ +	{0,	0,	0,	0,	0 },	/* 17 (AD[27]): Unused */ +	{0,	0,	0,	0,	0 },	/* 18 (AD[28]): Unused */ +	{0,	0,	0,	0,	0 },	/* 19 (AD[29]): Unused */ +	{0,	0,	0,	0,	0 },	/* 20 (AD[30]): Unused */ +	{0,	0,	0,	0,	0 }	/* 21 (AD[31]): Unused */  };  #endif @@ -168,14 +168,14 @@ static char irq_tab[][5] __initdata = {   *  _________________________________________________________________________   *   *  DESCRIPTION: Perform platform specific device initialization at - *               pci_enable_device() time. - *               None are needed for the MSP7120 PCI Controller. + *		 pci_enable_device() time. + *		 None are needed for the MSP7120 PCI Controller.   * - *  INPUTS:      dev     - structure describing the PCI device + *  INPUTS:	 dev	 - structure describing the PCI device   * - *  OUTPUTS:     none + *  OUTPUTS:	 none   * - *  RETURNS:     PCIBIOS_SUCCESSFUL + *  RETURNS:	 PCIBIOS_SUCCESSFUL   *   ****************************************************************************/  int pcibios_plat_dev_init(struct pci_dev *dev) @@ -190,16 +190,16 @@ int pcibios_plat_dev_init(struct pci_dev *dev)   *   *  DESCRIPTION: Perform board supplied PCI IRQ mapping routine.   * - *  INPUTS:      dev     - unused - *               slot    - PCI slot. Identified by which bit of the AD[] bus - *                         drives the IDSEL line. AD[10] is 0, AD[31] is - *                         slot 21. - *               pin     - numbered using the scheme of the PCI_INTERRUPT_PIN - *                         field of the config header. + *  INPUTS:	 dev	 - unused + *		 slot	 - PCI slot. Identified by which bit of the AD[] bus + *			   drives the IDSEL line. AD[10] is 0, AD[31] is + *			   slot 21. + *		 pin	 - numbered using the scheme of the PCI_INTERRUPT_PIN + *			   field of the config header.   * - *  OUTPUTS:     none + *  OUTPUTS:	 none   * - *  RETURNS:     IRQ number + *  RETURNS:	 IRQ number   *   ****************************************************************************/  int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) diff --git a/arch/mips/pci/fixup-pnx8550.c b/arch/mips/pci/fixup-pnx8550.c deleted file mode 100644 index 96857ac63bf..00000000000 --- a/arch/mips/pci/fixup-pnx8550.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - *  Philips PNX8550 pci fixups. - * - *  Copyright 2005 Embedded Alley Solutions, Inc - *  source@embeddealley.com - * - *  This program is free software; you can distribute it and/or modify it - *  under the terms of the GNU General Public License (Version 2) as - *  published by the Free Software Foundation. - * - *  This program is distributed in the hope it will be useful, but WITHOUT - *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License - *  for more details. - * - *  You should have received a copy of the GNU General Public License along - *  with this program; if not, write to the Free Software Foundation, Inc., - *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - */ -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/mach-pnx8550/pci.h> -#include <asm/mach-pnx8550/int.h> - - -#undef	DEBUG -#ifdef 	DEBUG -#define	DBG(x...)	printk(x) -#else -#define	DBG(x...) -#endif - -extern char pnx8550_irq_tab[][5]; - -void __init pcibios_fixup_resources(struct pci_dev *dev) -{ -	/* no need to fixup IO resources */ -} - -void __init pcibios_fixup(void) -{ -	/* nothing to do here */ -} - -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ -	return pnx8550_irq_tab[slot][pin]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ -	return 0; -} diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c index 3d86823d03a..7fcafd5da7d 100644 --- a/arch/mips/pci/fixup-rc32434.c +++ b/arch/mips/pci/fixup-rc32434.c @@ -27,17 +27,16 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <asm/mach-rc32434/rc32434.h>  #include <asm/mach-rc32434/irq.h> -static int __devinitdata irq_map[2][12] = { +static int irq_map[2][12] = {  	{0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1},  	{0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3}  }; -int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  {  	int irq = 0; diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c index f0bb9146e6c..8feae9154ba 100644 --- a/arch/mips/pci/fixup-sb1250.c +++ b/arch/mips/pci/fixup-sb1250.c @@ -8,14 +8,13 @@   *	2 of the License, or (at your option) any later version.   */ -#include <linux/init.h>  #include <linux/pci.h>  /*   * Set the BCM1250, etc. PCI host bridge's TRDY timeout   * to the finite max.   */ -static void __init quirk_sb1250_pci(struct pci_dev *dev) +static void quirk_sb1250_pci(struct pci_dev *dev)  {  	pci_write_config_byte(dev, 0x40, 0xff);  } @@ -25,7 +24,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,  /*   * The BCM1250, etc. PCI/HT bridge reports as a host bridge.   */ -static void __init quirk_sb1250_ht(struct pci_dev *dev) +static void quirk_sb1250_ht(struct pci_dev *dev)  {  	dev->class = PCI_CLASS_BRIDGE_PCI << 8;  } @@ -35,7 +34,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,  /*   * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.   */ -static void __init quirk_sp1011(struct pci_dev *dev) +static void quirk_sp1011(struct pci_dev *dev)  {  	pci_write_config_byte(dev, 0x64, 0xff);  } diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c index 5c8a79bb266..f67ebeeb420 100644 --- a/arch/mips/pci/fixup-sni.c +++ b/arch/mips/pci/fixup-sni.c @@ -41,12 +41,12 @@   * Logic CL-GD5434 VGA is device 3.   */  static char irq_tab_rm200[8][5] __initdata = { -	/*       INTA  INTB  INTC  INTD */ -	{     0,    0,    0,    0,    0 },	/* EISA bridge */ +	/*	 INTA  INTB  INTC  INTD */ +	{     0,    0,	  0,	0,    0 },	/* EISA bridge */  	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */ -	{   ETH,  ETH,  ETH,  ETH,  ETH },	/* Ethernet */ +	{   ETH,  ETH,	ETH,  ETH,  ETH },	/* Ethernet */  	{  INTB, INTB, INTB, INTB, INTB },	/* VGA */ -	{     0,    0,    0,    0,    0 },	/* Unused */ +	{     0,    0,	  0,	0,    0 },	/* Unused */  	{     0, INTB, INTC, INTD, INTA },	/* Slot 2 */  	{     0, INTC, INTD, INTA, INTB },	/* Slot 3 */  	{     0, INTD, INTA, INTB, INTC },	/* Slot 4 */ @@ -58,20 +58,20 @@ static char irq_tab_rm200[8][5] __initdata = {   * The VGA card is optional for RM300 systems.   */  static char irq_tab_rm300d[8][5] __initdata = { -	/*       INTA  INTB  INTC  INTD */ -	{     0,    0,    0,    0,    0 },	/* EISA bridge */ +	/*	 INTA  INTB  INTC  INTD */ +	{     0,    0,	  0,	0,    0 },	/* EISA bridge */  	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */  	{     0, INTC, INTD, INTA, INTB },	/* Slot 1 */  	{  INTB, INTB, INTB, INTB, INTB },	/* VGA */ -	{     0,    0,    0,    0,    0 },	/* Unused */ +	{     0,    0,	  0,	0,    0 },	/* Unused */  	{     0, INTB, INTC, INTD, INTA },	/* Slot 2 */  	{     0, INTC, INTD, INTA, INTB },	/* Slot 3 */  	{     0, INTD, INTA, INTB, INTC },	/* Slot 4 */  };  static char irq_tab_rm300e[5][5] __initdata = { -	/*       INTA  INTB  INTC  INTD */ -	{     0,    0,    0,    0,    0 },	/* HOST bridge */ +	/*	 INTA  INTB  INTC  INTD */ +	{     0,    0,	  0,	0,    0 },	/* HOST bridge */  	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */  	{     0, INTC, INTD, INTA, INTB },	/* Bridge/i960 */  	{     0, INTD, INTA, INTB, INTC },	/* Slot 1 */ @@ -97,30 +97,30 @@ static char irq_tab_rm300e[5][5] __initdata = {  #define INTD	PCIT_IRQ_INTD  static char irq_tab_pcit[13][5] __initdata = { -	/*       INTA  INTB  INTC  INTD */ -	{     0,     0,     0,     0,     0 },	/* HOST bridge */ +	/*	 INTA  INTB  INTC  INTD */ +	{     0,     0,	    0,	   0,	  0 },	/* HOST bridge */  	{ SCSI0, SCSI0, SCSI0, SCSI0, SCSI0 },	/* SCSI */  	{ SCSI1, SCSI1, SCSI1, SCSI1, SCSI1 },	/* SCSI */ -	{   ETH,   ETH,   ETH,   ETH,   ETH },	/* Ethernet */ -	{     0,  INTA,  INTB,  INTC,  INTD },	/* PCI-PCI bridge */ -	{     0,     0,     0,     0,     0 },	/* Unused */ -	{     0,     0,     0,     0,     0 },	/* Unused */ -	{     0,     0,     0,     0,     0 },	/* Unused */ -	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 1 */ -	{     0,  INTB,  INTC,  INTD,  INTA },	/* Slot 2 */ -	{     0,  INTC,  INTD,  INTA,  INTB },	/* Slot 3 */ -	{     0,  INTD,  INTA,  INTB,  INTC },	/* Slot 4 */ -	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 5 */ +	{   ETH,   ETH,	  ETH,	 ETH,	ETH },	/* Ethernet */ +	{     0,  INTA,	 INTB,	INTC,  INTD },	/* PCI-PCI bridge */ +	{     0,     0,	    0,	   0,	  0 },	/* Unused */ +	{     0,     0,	    0,	   0,	  0 },	/* Unused */ +	{     0,     0,	    0,	   0,	  0 },	/* Unused */ +	{     0,  INTA,	 INTB,	INTC,  INTD },	/* Slot 1 */ +	{     0,  INTB,	 INTC,	INTD,  INTA },	/* Slot 2 */ +	{     0,  INTC,	 INTD,	INTA,  INTB },	/* Slot 3 */ +	{     0,  INTD,	 INTA,	INTB,  INTC },	/* Slot 4 */ +	{     0,  INTA,	 INTB,	INTC,  INTD },	/* Slot 5 */  };  static char irq_tab_pcit_cplus[13][5] __initdata = { -	/*       INTA  INTB  INTC  INTD */ -	{     0,     0,     0,     0,     0 },	/* HOST bridge */ -	{     0,  INTB,  INTC,  INTD,  INTA },	/* PCI Slot 9 */ -	{     0,     0,     0,     0,     0 },	/* PCI-EISA */ -	{     0,     0,     0,     0,     0 },	/* Unused */ -	{     0,  INTA,  INTB,  INTC,  INTD },	/* PCI-PCI bridge */ -	{     0,  INTB,  INTC,  INTD,  INTA },	/* fixup */ +	/*	 INTA  INTB  INTC  INTD */ +	{     0,     0,	    0,	   0,	  0 },	/* HOST bridge */ +	{     0,  INTB,	 INTC,	INTD,  INTA },	/* PCI Slot 9 */ +	{     0,     0,	    0,	   0,	  0 },	/* PCI-EISA */ +	{     0,     0,	    0,	   0,	  0 },	/* Unused */ +	{     0,  INTA,	 INTB,	INTC,  INTD },	/* PCI-PCI bridge */ +	{     0,  INTB,	 INTC,	INTD,  INTA },	/* fixup */  };  static inline int is_rm300_revd(void) @@ -146,18 +146,18 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  		}  		return irq_tab_pcit_cplus[slot][pin];  	case SNI_BRD_PCI_TOWER: -	        return irq_tab_pcit[slot][pin]; +		return irq_tab_pcit[slot][pin];  	case SNI_BRD_PCI_MTOWER: -	        if (is_rm300_revd()) -		        return irq_tab_rm300d[slot][pin]; -	        /* fall through */ +		if (is_rm300_revd()) +			return irq_tab_rm300d[slot][pin]; +		/* fall through */  	case SNI_BRD_PCI_DESKTOP: -	        return irq_tab_rm200[slot][pin]; +		return irq_tab_rm200[slot][pin];  	case SNI_BRD_PCI_MTOWER_CPLUS: -	        return irq_tab_rm300e[slot][pin]; +		return irq_tab_rm300e[slot][pin];  	}  	return 0; diff --git a/arch/mips/pci/fixup-tb0219.c b/arch/mips/pci/fixup-tb0219.c index 8084b17d440..d0b0083fbd2 100644 --- a/arch/mips/pci/fixup-tb0219.c +++ b/arch/mips/pci/fixup-tb0219.c @@ -1,7 +1,7 @@  /*   *  fixup-tb0219.c, The TANBAC TB0219 specific PCI fixups.   * - *  Copyright (C) 2003  Megasolution Inc. <matsu@megasolution.jp> + *  Copyright (C) 2003	Megasolution Inc. <matsu@megasolution.jp>   *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.org>   *   *  This program is free software; you can redistribute it and/or modify diff --git a/arch/mips/pci/fixup-tb0287.c b/arch/mips/pci/fixup-tb0287.c index 2fe29db4372..8c5039ed75d 100644 --- a/arch/mips/pci/fixup-tb0287.c +++ b/arch/mips/pci/fixup-tb0287.c @@ -1,7 +1,7 @@  /*   *  fixup-tb0287.c, The TANBAC TB0287 specific PCI fixups.   * - *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.org> + *  Copyright (C) 2005	Yoichi Yuasa <yuasa@linux-mips.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 diff --git a/arch/mips/pci/fixup-wrppmc.c b/arch/mips/pci/fixup-wrppmc.c deleted file mode 100644 index 3d277549d5d..00000000000 --- a/arch/mips/pci/fixup-wrppmc.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * fixup-wrppmc.c: PPMC board specific PCI fixup - * - * This file is subject to the terms and conditions of the GNU General Public - * License.  See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2006, Wind River Inc. Rongkai.zhan (rongkai.zhan@windriver.com) - */ -#include <linux/init.h> -#include <linux/pci.h> -#include <asm/gt64120.h> - -/* PCI interrupt pins */ -#define PCI_INTA		1 -#define PCI_INTB		2 -#define PCI_INTC		3 -#define PCI_INTD		4 - -#define PCI_SLOT_MAXNR	32 /* Each PCI bus has 32 physical slots */ - -static char pci_irq_tab[PCI_SLOT_MAXNR][5] __initdata = { -	/* 0    INTA   INTB   INTC   INTD */ -	[0] = {0, 0, 0, 0, 0},		/* Slot 0: GT64120 PCI bridge */ -	[6] = {0, WRPPMC_PCI_INTA_IRQ, 0, 0, 0}, -}; - -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ -	return pci_irq_tab[slot][pin]; -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ -	return 0; -} diff --git a/arch/mips/pci/fixup-yosemite.c b/arch/mips/pci/fixup-yosemite.c deleted file mode 100644 index fdafb13a793..00000000000 --- a/arch/mips/pci/fixup-yosemite.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2003 PMC-Sierra - * Author: Manish Lachwani (lachwani@pmc-sierra.com) - * - * This program is free software; you can redistribute  it and/or modify it - * under  the terms of  the GNU General  Public License as published by the - * Free Software Foundation;  either version 2 of the  License, or (at your - * option) any later version. - * - *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED - *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF - *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN - *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, - *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF - *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT - *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *  You should have received a copy of the  GNU General Public License along - *  with this program; if not, write  to the Free Software Foundation, Inc., - *  675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/pci.h> - -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ -	if (pin == 0) -		return -1; - -	return 3;			/* Everything goes to one irq bit */ -} - -/* Do platform specific device initialization at pci_enable_device() time */ -int pcibios_plat_dev_init(struct pci_dev *dev) -{ -	return 0; -} diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index d8080499872..ab0c5d14c6f 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -15,6 +15,7 @@  #include <asm/octeon/cvmx-npi-defs.h>  #include <asm/octeon/cvmx-pci-defs.h>  #include <asm/octeon/cvmx-npei-defs.h> +#include <asm/octeon/cvmx-sli-defs.h>  #include <asm/octeon/cvmx-pexp-defs.h>  #include <asm/octeon/pci-octeon.h> @@ -150,6 +151,7 @@ msi_irq_allocated:  		msg.address_lo =  			((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;  		msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32; +		break;  	case OCTEON_DMA_BAR_TYPE_BIG:  		/* When using big bar, Bar 0 is based at 0 */  		msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff; @@ -161,8 +163,13 @@ msi_irq_allocated:  		msg.address_lo = (0 + CVMX_NPEI_PCIE_MSI_RCV) & 0xffffffff;  		msg.address_hi = (0 + CVMX_NPEI_PCIE_MSI_RCV) >> 32;  		break; +	case OCTEON_DMA_BAR_TYPE_PCIE2: +		/* When using PCIe2, Bar 0 is based at 0 */ +		msg.address_lo = (0 + CVMX_SLI_PCIE_MSI_RCV) & 0xffffffff; +		msg.address_hi = (0 + CVMX_SLI_PCIE_MSI_RCV) >> 32; +		break;  	default: -		panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type\n"); +		panic("arch_setup_msi_irq: Invalid octeon_dma_bar_type");  	}  	msg.data = irq - OCTEON_IRQ_MSI_BIT0; @@ -172,7 +179,7 @@ msi_irq_allocated:  	pci_write_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,  			      control); -	set_irq_msi(irq, desc); +	irq_set_msi_desc(irq, desc);  	write_msi_msg(irq, &msg);  	return 0;  } @@ -259,11 +266,11 @@ static DEFINE_RAW_SPINLOCK(octeon_irq_msi_lock);  static u64 msi_rcv_reg[4];  static u64 mis_ena_reg[4]; -static void octeon_irq_msi_enable_pcie(unsigned int irq) +static void octeon_irq_msi_enable_pcie(struct irq_data *data)  {  	u64 en;  	unsigned long flags; -	int msi_number = irq - OCTEON_IRQ_MSI_BIT0; +	int msi_number = data->irq - OCTEON_IRQ_MSI_BIT0;  	int irq_index = msi_number >> 6;  	int irq_bit = msi_number & 0x3f; @@ -275,11 +282,11 @@ static void octeon_irq_msi_enable_pcie(unsigned int irq)  	raw_spin_unlock_irqrestore(&octeon_irq_msi_lock, flags);  } -static void octeon_irq_msi_disable_pcie(unsigned int irq) +static void octeon_irq_msi_disable_pcie(struct irq_data *data)  {  	u64 en;  	unsigned long flags; -	int msi_number = irq - OCTEON_IRQ_MSI_BIT0; +	int msi_number = data->irq - OCTEON_IRQ_MSI_BIT0;  	int irq_index = msi_number >> 6;  	int irq_bit = msi_number & 0x3f; @@ -293,11 +300,11 @@ static void octeon_irq_msi_disable_pcie(unsigned int irq)  static struct irq_chip octeon_irq_chip_msi_pcie = {  	.name = "MSI", -	.enable = octeon_irq_msi_enable_pcie, -	.disable = octeon_irq_msi_disable_pcie, +	.irq_enable = octeon_irq_msi_enable_pcie, +	.irq_disable = octeon_irq_msi_disable_pcie,  }; -static void octeon_irq_msi_enable_pci(unsigned int irq) +static void octeon_irq_msi_enable_pci(struct irq_data *data)  {  	/*  	 * Octeon PCI doesn't have the ability to mask/unmask MSI @@ -308,15 +315,15 @@ static void octeon_irq_msi_enable_pci(unsigned int irq)  	 */  } -static void octeon_irq_msi_disable_pci(unsigned int irq) +static void octeon_irq_msi_disable_pci(struct irq_data *data)  {  	/* See comment in enable */  }  static struct irq_chip octeon_irq_chip_msi_pci = {  	.name = "MSI", -	.enable = octeon_irq_msi_enable_pci, -	.disable = octeon_irq_msi_disable_pci, +	.irq_enable = octeon_irq_msi_enable_pci, +	.irq_disable = octeon_irq_msi_disable_pci,  };  /* @@ -388,7 +395,7 @@ int __init octeon_msi_initialize(void)  	}  	for (irq = OCTEON_IRQ_MSI_BIT0; irq <= OCTEON_IRQ_MSI_LAST; irq++) -		set_irq_chip_and_handler(irq, msi, handle_simple_irq); +		irq_set_chip_and_handler(irq, msi, handle_simple_irq);  	if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {  		if (request_irq(OCTEON_IRQ_PCI_MSI0, octeon_msi_interrupt0, diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c new file mode 100644 index 00000000000..fa374fe3746 --- /dev/null +++ b/arch/mips/pci/msi-xlp.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in + *    the documentation and/or other materials provided with the + *    distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/msi.h> +#include <linux/mm.h> +#include <linux/irq.h> +#include <linux/irqdesc.h> +#include <linux/console.h> + +#include <asm/io.h> + +#include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/mips-extns.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/pcibus.h> +#include <asm/netlogic/xlp-hal/bridge.h> + +#define XLP_MSIVEC_PER_LINK	32 +#define XLP_MSIXVEC_TOTAL	(cpu_is_xlp9xx() ? 128 : 32) +#define XLP_MSIXVEC_PER_LINK	(cpu_is_xlp9xx() ? 32 : 8) + +/* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */ +static inline int nlm_link_msiirq(int link, int msivec) +{ +	return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec; +} + +/* get the link MSI vector from irq number */ +static inline int nlm_irq_msivec(int irq) +{ +	return (irq - NLM_MSI_VEC_BASE) % XLP_MSIVEC_PER_LINK; +} + +/* get the link from the irq number */ +static inline int nlm_irq_msilink(int irq) +{ +	int total_msivec = XLP_MSIVEC_PER_LINK * PCIE_NLINKS; + +	return ((irq - NLM_MSI_VEC_BASE) % total_msivec) / +		XLP_MSIVEC_PER_LINK; +} + +/* + * For XLP 8xx/4xx/3xx/2xx, only 32 MSI-X vectors are possible because + * there are only 32 PIC interrupts for MSI. We split them statically + * and use 8 MSI-X vectors per link - this keeps the allocation and + * lookup simple. + * On XLP 9xx, there are 32 vectors per link, and the interrupts are + * not routed thru PIC, so we can use all 128 MSI-X vectors. + */ +static inline int nlm_link_msixirq(int link, int bit) +{ +	return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit; +} + +/* get the link MSI vector from irq number */ +static inline int nlm_irq_msixvec(int irq) +{ +	return (irq - NLM_MSIX_VEC_BASE) % XLP_MSIXVEC_TOTAL; +} + +/* get the link from MSIX vec */ +static inline int nlm_irq_msixlink(int msixvec) +{ +	return msixvec / XLP_MSIXVEC_PER_LINK; +} + +/* + * Per link MSI and MSI-X information, set as IRQ handler data for + * MSI and MSI-X interrupts. + */ +struct xlp_msi_data { +	struct nlm_soc_info *node; +	uint64_t	lnkbase; +	uint32_t	msi_enabled_mask; +	uint32_t	msi_alloc_mask; +	uint32_t	msix_alloc_mask; +	spinlock_t	msi_lock; +}; + +/* + * MSI Chip definitions + * + * On XLP, there is a PIC interrupt associated with each PCIe link on the + * chip (which appears as a PCI bridge to us). This gives us 32 MSI irqa + * per link and 128 overall. + * + * When a device connected to the link raises a MSI interrupt, we get a + * link interrupt and we then have to look at PCIE_MSI_STATUS register at + * the bridge to map it to the IRQ + */ +static void xlp_msi_enable(struct irq_data *d) +{ +	struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); +	unsigned long flags; +	int vec; + +	vec = nlm_irq_msivec(d->irq); +	spin_lock_irqsave(&md->msi_lock, flags); +	md->msi_enabled_mask |= 1u << vec; +	if (cpu_is_xlp9xx()) +		nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN, +				md->msi_enabled_mask); +	else +		nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); +	spin_unlock_irqrestore(&md->msi_lock, flags); +} + +static void xlp_msi_disable(struct irq_data *d) +{ +	struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); +	unsigned long flags; +	int vec; + +	vec = nlm_irq_msivec(d->irq); +	spin_lock_irqsave(&md->msi_lock, flags); +	md->msi_enabled_mask &= ~(1u << vec); +	if (cpu_is_xlp9xx()) +		nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_EN, +				md->msi_enabled_mask); +	else +		nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); +	spin_unlock_irqrestore(&md->msi_lock, flags); +} + +static void xlp_msi_mask_ack(struct irq_data *d) +{ +	struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); +	int link, vec; + +	link = nlm_irq_msilink(d->irq); +	vec = nlm_irq_msivec(d->irq); +	xlp_msi_disable(d); + +	/* Ack MSI on bridge */ +	if (cpu_is_xlp9xx()) +		nlm_write_reg(md->lnkbase, PCIE_9XX_MSI_STATUS, 1u << vec); +	else +		nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec); + +	/* Ack at eirr and PIC */ +	ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link)); +	if (cpu_is_xlp9xx()) +		nlm_pic_ack(md->node->picbase, +				PIC_9XX_IRT_PCIE_LINK_INDEX(link)); +	else +		nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); +} + +static struct irq_chip xlp_msi_chip = { +	.name		= "XLP-MSI", +	.irq_enable	= xlp_msi_enable, +	.irq_disable	= xlp_msi_disable, +	.irq_mask_ack	= xlp_msi_mask_ack, +	.irq_unmask	= xlp_msi_enable, +}; + +/* + * XLP8XX/4XX/3XX/2XX: + * The MSI-X interrupt handling is different from MSI, there are 32 MSI-X + * interrupts generated by the PIC and each of these correspond to a MSI-X + * vector (0-31) that can be assigned. + * + * We divide the MSI-X vectors to 8 per link and do a per-link allocation + * + * XLP9XX: + * 32 MSI-X vectors are available per link, and the interrupts are not routed + * thru the PIC. PIC ack not needed. + * + * Enable and disable done using standard MSI functions. + */ +static void xlp_msix_mask_ack(struct irq_data *d) +{ +	struct xlp_msi_data *md; +	int link, msixvec; +	uint32_t status_reg, bit; + +	msixvec = nlm_irq_msixvec(d->irq); +	link = nlm_irq_msixlink(msixvec); +	mask_msi_irq(d); +	md = irq_data_get_irq_handler_data(d); + +	/* Ack MSI on bridge */ +	if (cpu_is_xlp9xx()) { +		status_reg = PCIE_9XX_MSIX_STATUSX(link); +		bit = msixvec % XLP_MSIXVEC_PER_LINK; +	} else { +		status_reg = PCIE_MSIX_STATUS; +		bit = msixvec; +	} +	nlm_write_reg(md->lnkbase, status_reg, 1u << bit); + +	/* Ack at eirr and PIC */ +	ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link)); +	if (!cpu_is_xlp9xx()) +		nlm_pic_ack(md->node->picbase, +				PIC_IRT_PCIE_MSIX_INDEX(msixvec)); +} + +static struct irq_chip xlp_msix_chip = { +	.name		= "XLP-MSIX", +	.irq_enable	= unmask_msi_irq, +	.irq_disable	= mask_msi_irq, +	.irq_mask_ack	= xlp_msix_mask_ack, +	.irq_unmask	= unmask_msi_irq, +}; + +void arch_teardown_msi_irq(unsigned int irq) +{ +} + +/* + * Setup a PCIe link for MSI.  By default, the links are in + * legacy interrupt mode.  We will switch them to MSI mode + * at the first MSI request. + */ +static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr) +{ +	u32 val; + +	if (cpu_is_xlp9xx()) { +		val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0); +		if ((val & 0x200) == 0) { +			val |= 0x200;		/* MSI Interrupt enable */ +			nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val); +		} +	} else { +		val = nlm_read_reg(lnkbase, PCIE_INT_EN0); +		if ((val & 0x200) == 0) { +			val |= 0x200; +			nlm_write_reg(lnkbase, PCIE_INT_EN0, val); +		} +	} + +	val = nlm_read_reg(lnkbase, 0x1);	/* CMD */ +	if ((val & 0x0400) == 0) { +		val |= 0x0400; +		nlm_write_reg(lnkbase, 0x1, val); +	} + +	/* Update IRQ in the PCI irq reg */ +	val = nlm_read_pci_reg(lnkbase, 0xf); +	val &= ~0x1fu; +	val |= (1 << 8) | lirq; +	nlm_write_pci_reg(lnkbase, 0xf, val); + +	/* MSI addr */ +	nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRH, msiaddr >> 32); +	nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRL, msiaddr & 0xffffffff); + +	/* MSI cap for bridge */ +	val = nlm_read_reg(lnkbase, PCIE_BRIDGE_MSI_CAP); +	if ((val & (1 << 16)) == 0) { +		val |= 0xb << 16;		/* mmc32, msi enable */ +		nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_CAP, val); +	} +} + +/* + * Allocate a MSI vector on a link + */ +static int xlp_setup_msi(uint64_t lnkbase, int node, int link, +	struct msi_desc *desc) +{ +	struct xlp_msi_data *md; +	struct msi_msg msg; +	unsigned long flags; +	int msivec, irt, lirq, xirq, ret; +	uint64_t msiaddr; + +	/* Get MSI data for the link */ +	lirq = PIC_PCIE_LINK_MSI_IRQ(link); +	xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); +	md = irq_get_handler_data(xirq); +	msiaddr = MSI_LINK_ADDR(node, link); + +	spin_lock_irqsave(&md->msi_lock, flags); +	if (md->msi_alloc_mask == 0) { +		xlp_config_link_msi(lnkbase, lirq, msiaddr); +		/* switch the link IRQ to MSI range */ +		if (cpu_is_xlp9xx()) +			irt = PIC_9XX_IRT_PCIE_LINK_INDEX(link); +		else +			irt = PIC_IRT_PCIE_LINK_INDEX(link); +		nlm_setup_pic_irq(node, lirq, lirq, irt); +		nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, +				 node * nlm_threads_per_node(), 1 /*en */); +	} + +	/* allocate a MSI vec, and tell the bridge about it */ +	msivec = fls(md->msi_alloc_mask); +	if (msivec == XLP_MSIVEC_PER_LINK) { +		spin_unlock_irqrestore(&md->msi_lock, flags); +		return -ENOMEM; +	} +	md->msi_alloc_mask |= (1u << msivec); +	spin_unlock_irqrestore(&md->msi_lock, flags); + +	msg.address_hi = msiaddr >> 32; +	msg.address_lo = msiaddr & 0xffffffff; +	msg.data = 0xc00 | msivec; + +	xirq = xirq + msivec;		/* msi mapped to global irq space */ +	ret = irq_set_msi_desc(xirq, desc); +	if (ret < 0) +		return ret; + +	write_msi_msg(xirq, &msg); +	return 0; +} + +/* + * Switch a link to MSI-X mode + */ +static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr) +{ +	u32 val; + +	val = nlm_read_reg(lnkbase, 0x2C); +	if ((val & 0x80000000U) == 0) { +		val |= 0x80000000U; +		nlm_write_reg(lnkbase, 0x2C, val); +	} + +	if (cpu_is_xlp9xx()) { +		val = nlm_read_reg(lnkbase, PCIE_9XX_INT_EN0); +		if ((val & 0x200) == 0) { +			val |= 0x200;		/* MSI Interrupt enable */ +			nlm_write_reg(lnkbase, PCIE_9XX_INT_EN0, val); +		} +	} else { +		val = nlm_read_reg(lnkbase, PCIE_INT_EN0); +		if ((val & 0x200) == 0) { +			val |= 0x200;		/* MSI Interrupt enable */ +			nlm_write_reg(lnkbase, PCIE_INT_EN0, val); +		} +	} + +	val = nlm_read_reg(lnkbase, 0x1);	/* CMD */ +	if ((val & 0x0400) == 0) { +		val |= 0x0400; +		nlm_write_reg(lnkbase, 0x1, val); +	} + +	/* Update IRQ in the PCI irq reg */ +	val = nlm_read_pci_reg(lnkbase, 0xf); +	val &= ~0x1fu; +	val |= (1 << 8) | lirq; +	nlm_write_pci_reg(lnkbase, 0xf, val); + +	if (cpu_is_xlp9xx()) { +		/* MSI-X addresses */ +		nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_BASE, +				msixaddr >> 8); +		nlm_write_reg(lnkbase, PCIE_9XX_BRIDGE_MSIX_ADDR_LIMIT, +				(msixaddr + MSI_ADDR_SZ) >> 8); +	} else { +		/* MSI-X addresses */ +		nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE, +				msixaddr >> 8); +		nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT, +				(msixaddr + MSI_ADDR_SZ) >> 8); +	} +} + +/* + *  Allocate a MSI-X vector + */ +static int xlp_setup_msix(uint64_t lnkbase, int node, int link, +	struct msi_desc *desc) +{ +	struct xlp_msi_data *md; +	struct msi_msg msg; +	unsigned long flags; +	int t, msixvec, lirq, xirq, ret; +	uint64_t msixaddr; + +	/* Get MSI data for the link */ +	lirq = PIC_PCIE_MSIX_IRQ(link); +	xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); +	md = irq_get_handler_data(xirq); +	msixaddr = MSIX_LINK_ADDR(node, link); + +	spin_lock_irqsave(&md->msi_lock, flags); +	/* switch the PCIe link to MSI-X mode at the first alloc */ +	if (md->msix_alloc_mask == 0) +		xlp_config_link_msix(lnkbase, lirq, msixaddr); + +	/* allocate a MSI-X vec, and tell the bridge about it */ +	t = fls(md->msix_alloc_mask); +	if (t == XLP_MSIXVEC_PER_LINK) { +		spin_unlock_irqrestore(&md->msi_lock, flags); +		return -ENOMEM; +	} +	md->msix_alloc_mask |= (1u << t); +	spin_unlock_irqrestore(&md->msi_lock, flags); + +	xirq += t; +	msixvec = nlm_irq_msixvec(xirq); + +	msg.address_hi = msixaddr >> 32; +	msg.address_lo = msixaddr & 0xffffffff; +	msg.data = 0xc00 | msixvec; + +	ret = irq_set_msi_desc(xirq, desc); +	if (ret < 0) { +		destroy_irq(xirq); +		return ret; +	} + +	write_msi_msg(xirq, &msg); +	return 0; +} + +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) +{ +	struct pci_dev *lnkdev; +	uint64_t lnkbase; +	int node, link, slot; + +	lnkdev = xlp_get_pcie_link(dev); +	if (lnkdev == NULL) { +		dev_err(&dev->dev, "Could not find bridge\n"); +		return 1; +	} +	slot = PCI_SLOT(lnkdev->devfn); +	link = PCI_FUNC(lnkdev->devfn); +	node = slot / 8; +	lnkbase = nlm_get_pcie_base(node, link); + +	if (desc->msi_attrib.is_msix) +		return xlp_setup_msix(lnkbase, node, link, desc); +	else +		return xlp_setup_msi(lnkbase, node, link, desc); +} + +void __init xlp_init_node_msi_irqs(int node, int link) +{ +	struct nlm_soc_info *nodep; +	struct xlp_msi_data *md; +	int irq, i, irt, msixvec, val; + +	pr_info("[%d %d] Init node PCI IRT\n", node, link); +	nodep = nlm_get_node(node); + +	/* Alloc an MSI block for the link */ +	md = kzalloc(sizeof(*md), GFP_KERNEL); +	spin_lock_init(&md->msi_lock); +	md->msi_enabled_mask = 0; +	md->msi_alloc_mask = 0; +	md->msix_alloc_mask = 0; +	md->node = nodep; +	md->lnkbase = nlm_get_pcie_base(node, link); + +	/* extended space for MSI interrupts */ +	irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); +	for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { +		irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq); +		irq_set_handler_data(i, md); +	} + +	for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) { +		if (cpu_is_xlp9xx()) { +			val = ((node * nlm_threads_per_node()) << 7 | +				PIC_PCIE_MSIX_IRQ(link) << 1 | 0 << 0); +			nlm_write_pcie_reg(md->lnkbase, PCIE_9XX_MSIX_VECX(i + +					(link * XLP_MSIXVEC_PER_LINK)), val); +		} else { +			/* Initialize MSI-X irts to generate one interrupt +			 * per link +			 */ +			msixvec = link * XLP_MSIXVEC_PER_LINK + i; +			irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec); +			nlm_pic_init_irt(nodep->picbase, irt, +					PIC_PCIE_MSIX_IRQ(link), +					node * nlm_threads_per_node(), 1); +		} + +		/* Initialize MSI-X extended irq space for the link  */ +		irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); +		irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); +		irq_set_handler_data(irq, md); +	} +} + +void nlm_dispatch_msi(int node, int lirq) +{ +	struct xlp_msi_data *md; +	int link, i, irqbase; +	u32 status; + +	link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; +	irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); +	md = irq_get_handler_data(irqbase); +	if (cpu_is_xlp9xx()) +		status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & +						md->msi_enabled_mask; +	else +		status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) & +						md->msi_enabled_mask; +	while (status) { +		i = __ffs(status); +		do_IRQ(irqbase + i); +		status &= status - 1; +	} +} + +void nlm_dispatch_msix(int node, int lirq) +{ +	struct xlp_msi_data *md; +	int link, i, irqbase; +	u32 status; + +	link = lirq - PIC_PCIE_MSIX_IRQ_BASE; +	irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); +	md = irq_get_handler_data(irqbase); +	if (cpu_is_xlp9xx()) +		status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); +	else +		status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS); + +	/* narrow it down to the MSI-x vectors for our link */ +	if (!cpu_is_xlp9xx()) +		status = (status >> (link * XLP_MSIXVEC_PER_LINK)) & +			((1 << XLP_MSIXVEC_PER_LINK) - 1); + +	while (status) { +		i = __ffs(status); +		do_IRQ(irqbase + i); +		status &= status - 1; +	} +} diff --git a/arch/mips/pci/ops-au1000.c b/arch/mips/pci/ops-au1000.c deleted file mode 100644 index 9a57c5ab91d..00000000000 --- a/arch/mips/pci/ops-au1000.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - *	Alchemy/AMD Au1xx0 PCI support. - * - * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * - *  Support for all devices (greater than 16) added by David Gathright. - * - *  This program is free software; you can redistribute  it and/or modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. - * - *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED - *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF - *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN - *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, - *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF - *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT - *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *  You should have received a copy of the  GNU General Public License along - *  with this program; if not, write  to the Free Software Foundation, Inc., - *  675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/vmalloc.h> - -#include <asm/mach-au1x00/au1000.h> - -#undef	DEBUG -#ifdef	DEBUG -#define DBG(x...) printk(KERN_DEBUG x) -#else -#define DBG(x...) -#endif - -#define PCI_ACCESS_READ  0 -#define PCI_ACCESS_WRITE 1 - -int (*board_pci_idsel)(unsigned int devsel, int assert); - -void mod_wired_entry(int entry, unsigned long entrylo0, -		unsigned long entrylo1, unsigned long entryhi, -		unsigned long pagemask) -{ -	unsigned long old_pagemask; -	unsigned long old_ctx; - -	/* Save old context and create impossible VPN2 value */ -	old_ctx = read_c0_entryhi() & 0xff; -	old_pagemask = read_c0_pagemask(); -	write_c0_index(entry); -	write_c0_pagemask(pagemask); -	write_c0_entryhi(entryhi); -	write_c0_entrylo0(entrylo0); -	write_c0_entrylo1(entrylo1); -	tlb_write_indexed(); -	write_c0_entryhi(old_ctx); -	write_c0_pagemask(old_pagemask); -} - -static struct vm_struct *pci_cfg_vm; -static int pci_cfg_wired_entry; -static unsigned long last_entryLo0, last_entryLo1; - -/* - * We can't ioremap the entire pci config space because it's too large. - * Nor can we call ioremap dynamically because some device drivers use - * the PCI config routines from within interrupt handlers and that - * becomes a problem in get_vm_area().  We use one wired TLB to handle - * all config accesses for all busses. - */ -void __init au1x_pci_cfg_init(void) -{ -	/* Reserve a wired entry for PCI config accesses */ -	pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); -	if (!pci_cfg_vm) -		panic(KERN_ERR "PCI unable to get vm area\n"); -	pci_cfg_wired_entry = read_c0_wired(); -	add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K); -	last_entryLo0 = last_entryLo1 = 0xffffffff; -} - -static int config_access(unsigned char access_type, struct pci_bus *bus, -			 unsigned int dev_fn, unsigned char where, u32 *data) -{ -#if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) -	unsigned int device = PCI_SLOT(dev_fn); -	unsigned int function = PCI_FUNC(dev_fn); -	unsigned long offset, status; -	unsigned long cfg_base; -	unsigned long flags; -	int error = PCIBIOS_SUCCESSFUL; -	unsigned long entryLo0, entryLo1; - -	if (device > 19) { -		*data = 0xffffffff; -		return -1; -	} - -	local_irq_save(flags); -	au_writel(((0x2000 << 16) | (au_readl(Au1500_PCI_STATCMD) & 0xffff)), -			Au1500_PCI_STATCMD); -	au_sync_udelay(1); - -	/* -	 * Allow board vendors to implement their own off-chip IDSEL. -	 * If it doesn't succeed, may as well bail out at this point. -	 */ -	if (board_pci_idsel && board_pci_idsel(device, 1) == 0) { -		*data = 0xffffffff; -		local_irq_restore(flags); -		return -1; -	} - -	/* Setup the config window */ -	if (bus->number == 0) -		cfg_base = (1 << device) << 11; -	else -		cfg_base = 0x80000000 | (bus->number << 16) | (device << 11); - -	/* Setup the lower bits of the 36-bit address */ -	offset = (function << 8) | (where & ~0x3); -	/* Pick up any address that falls below the page mask */ -	offset |= cfg_base & ~PAGE_MASK; - -	/* Page boundary */ -	cfg_base = cfg_base & PAGE_MASK; - -	/* -	 * To improve performance, if the current device is the same as -	 * the last device accessed, we don't touch the TLB. -	 */ -	entryLo0 = (6 << 26) | (cfg_base >> 6) | (2 << 3) | 7; -	entryLo1 = (6 << 26) | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7; -	if ((entryLo0 != last_entryLo0) || (entryLo1 != last_entryLo1)) { -		mod_wired_entry(pci_cfg_wired_entry, entryLo0, entryLo1, -				(unsigned long)pci_cfg_vm->addr, PM_4K); -		last_entryLo0 = entryLo0; -		last_entryLo1 = entryLo1; -	} - -	if (access_type == PCI_ACCESS_WRITE) -		au_writel(*data, (int)(pci_cfg_vm->addr + offset)); -	else -		*data = au_readl((int)(pci_cfg_vm->addr + offset)); - -	au_sync_udelay(2); - -	DBG("cfg_access %d bus->number %u dev %u at %x *data %x conf %lx\n", -	    access_type, bus->number, device, where, *data, offset); - -	/* Check master abort */ -	status = au_readl(Au1500_PCI_STATCMD); - -	if (status & (1 << 29)) { -		*data = 0xffffffff; -		error = -1; -		DBG("Au1x Master Abort\n"); -	} else if ((status >> 28) & 0xf) { -		DBG("PCI ERR detected: device %u, status %lx\n", -		    device, (status >> 28) & 0xf); - -		/* Clear errors */ -		au_writel(status & 0xf000ffff, Au1500_PCI_STATCMD); - -		*data = 0xffffffff; -		error = -1; -	} - -	/* Take away the IDSEL. */ -	if (board_pci_idsel) -		(void)board_pci_idsel(device, 0); - -	local_irq_restore(flags); -	return error; -#endif -} - -static int read_config_byte(struct pci_bus *bus, unsigned int devfn, -			    int where,	u8 *val) -{ -	u32 data; -	int ret; - -	ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); -	if (where & 1) -		data >>= 8; -	if (where & 2) -		data >>= 16; -	*val = data & 0xff; -	return ret; -} - -static int read_config_word(struct pci_bus *bus, unsigned int devfn, -			    int where, u16 *val) -{ -	u32 data; -	int ret; - -	ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); -	if (where & 2) -		data >>= 16; -	*val = data & 0xffff; -	return ret; -} - -static int read_config_dword(struct pci_bus *bus, unsigned int devfn, -			     int where, u32 *val) -{ -	int ret; - -	ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val); -	return ret; -} - -static int write_config_byte(struct pci_bus *bus, unsigned int devfn, -			     int where, u8 val) -{ -	u32 data = 0; - -	if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) -		return -1; - -	data = (data & ~(0xff << ((where & 3) << 3))) | -	       (val << ((where & 3) << 3)); - -	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) -		return -1; - -	return PCIBIOS_SUCCESSFUL; -} - -static int write_config_word(struct pci_bus *bus, unsigned int devfn, -			     int where, u16 val) -{ -	u32 data = 0; - -	if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) -		return -1; - -	data = (data & ~(0xffff << ((where & 3) << 3))) | -	       (val << ((where & 3) << 3)); - -	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) -		return -1; - -	return PCIBIOS_SUCCESSFUL; -} - -static int write_config_dword(struct pci_bus *bus, unsigned int devfn, -			      int where, u32 val) -{ -	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val)) -		return -1; - -	return PCIBIOS_SUCCESSFUL; -} - -static int config_read(struct pci_bus *bus, unsigned int devfn, -		       int where, int size, u32 *val) -{ -	switch (size) { -	case 1: { -			u8 _val; -			int rc = read_config_byte(bus, devfn, where, &_val); - -			*val = _val; -			return rc; -		} -	case 2: { -			u16 _val; -			int rc = read_config_word(bus, devfn, where, &_val); - -			*val = _val; -			return rc; -		} -	default: -		return read_config_dword(bus, devfn, where, val); -	} -} - -static int config_write(struct pci_bus *bus, unsigned int devfn, -			int where, int size, u32 val) -{ -	switch (size) { -	case 1: -		return write_config_byte(bus, devfn, where, (u8) val); -	case 2: -		return write_config_word(bus, devfn, where, (u16) val); -	default: -		return write_config_dword(bus, devfn, where, val); -	} -} - -struct pci_ops au1x_pci_ops = { -	config_read, -	config_write -}; diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index 822ae179bc5..13eea696bbe 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -9,7 +9,6 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/io.h> @@ -174,8 +173,8 @@ static int bcm63xx_pci_write(struct pci_bus *bus, unsigned int devfn,  }  struct pci_ops bcm63xx_pci_ops = { -	.read   = bcm63xx_pci_read, -	.write  = bcm63xx_pci_write +	.read	= bcm63xx_pci_read, +	.write	= bcm63xx_pci_write  };  #ifdef CONFIG_CARDBUS @@ -370,8 +369,8 @@ static int bcm63xx_cb_read(struct pci_bus *bus, unsigned int devfn,  		return fake_cb_bridge_read(where, size, val);  	} -	/* a  configuration  cycle for  the  device  behind the  cardbus -	 * bridge is  actually done as a  type 0 cycle  on the primary +	/* a  configuration  cycle for	the  device  behind the	 cardbus +	 * bridge is  actually done as a  type 0 cycle	on the primary  	 * bus. This means that only  one device can be on the cardbus  	 * bus */  	if (fake_cb_bridge_regs.bus_assigned && @@ -403,8 +402,8 @@ static int bcm63xx_cb_write(struct pci_bus *bus, unsigned int devfn,  }  struct pci_ops bcm63xx_cb_ops = { -	.read   = bcm63xx_cb_read, -	.write   = bcm63xx_cb_write, +	.read	= bcm63xx_cb_read, +	.write	 = bcm63xx_cb_write,  };  /* @@ -465,3 +464,64 @@ static void bcm63xx_fixup(struct pci_dev *dev)  DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup);  #endif + +static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn) +{ +	switch (bus->number) { +	case PCIE_BUS_BRIDGE: +		return (PCI_SLOT(devfn) == 0); +	case PCIE_BUS_DEVICE: +		if (PCI_SLOT(devfn) == 0) +			return bcm_pcie_readl(PCIE_DLSTATUS_REG) +					& DLSTATUS_PHYLINKUP; +	default: +		return false; +	} +} + +static int bcm63xx_pcie_read(struct pci_bus *bus, unsigned int devfn, +			     int where, int size, u32 *val) +{ +	u32 data; +	u32 reg = where & ~3; + +	if (!bcm63xx_pcie_can_access(bus, devfn)) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	if (bus->number == PCIE_BUS_DEVICE) +		reg += PCIE_DEVICE_OFFSET; + +	data = bcm_pcie_readl(reg); + +	*val = postprocess_read(data, where, size); + +	return PCIBIOS_SUCCESSFUL; + +} + +static int bcm63xx_pcie_write(struct pci_bus *bus, unsigned int devfn, +			      int where, int size, u32 val) +{ +	u32 data; +	u32 reg = where & ~3; + +	if (!bcm63xx_pcie_can_access(bus, devfn)) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	if (bus->number == PCIE_BUS_DEVICE) +		reg += PCIE_DEVICE_OFFSET; + + +	data = bcm_pcie_readl(reg); + +	data = preprocess_write(data, val, where, size); +	bcm_pcie_writel(data, reg); + +	return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops bcm63xx_pcie_ops = { +	.read	= bcm63xx_pcie_read, +	.write	= bcm63xx_pcie_write +}; diff --git a/arch/mips/pci/ops-bonito64.c b/arch/mips/pci/ops-bonito64.c index 1b3e03f20c5..c06205a8734 100644 --- a/arch/mips/pci/ops-bonito64.c +++ b/arch/mips/pci/ops-bonito64.c @@ -22,11 +22,10 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <asm/mips-boards/bonito64.h> -#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_READ	 0  #define PCI_ACCESS_WRITE 1  #define CFG_SPACE_REG(offset) (void *)CKSEG1ADDR(_pcictrl_bonito_pcicfg + (offset)) @@ -137,7 +136,7 @@ static int bonito64_pcibios_write(struct pci_bus *bus, unsigned int devfn,  		data = val;  	else {  		if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, -		                               where, &data)) +					       where, &data))  			return -1;  		if (size == 1) diff --git a/arch/mips/pci/ops-bridge.c b/arch/mips/pci/ops-bridge.c index b46b3e21177..438319465cb 100644 --- a/arch/mips/pci/ops-bridge.c +++ b/arch/mips/pci/ops-bridge.c @@ -56,7 +56,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,  		return PCIBIOS_DEVICE_NOT_FOUND;  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to look at it for real ...  	 */  	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) @@ -76,7 +76,7 @@ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,  oh_my_gawd:  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to look at the wrong register.  	 */  	if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) { @@ -85,7 +85,7 @@ oh_my_gawd:  	}  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't try to access +	 * IOC3 is fucking fucked beyond belief ...  Don't try to access  	 * anything but 32-bit words ...  	 */  	addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; @@ -118,7 +118,7 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,  		return PCIBIOS_DEVICE_NOT_FOUND;  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to look at it for real ...  	 */  	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) @@ -139,7 +139,7 @@ static int pci_conf1_read_config(struct pci_bus *bus, unsigned int devfn,  oh_my_gawd:  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to look at the wrong register.  	 */  	if ((where >= 0x14 && where < 0x40) || (where >= 0x48)) { @@ -148,7 +148,7 @@ oh_my_gawd:  	}  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't try to access +	 * IOC3 is fucking fucked beyond belief ...  Don't try to access  	 * anything but 32-bit words ...  	 */  	bridge->b_pci_cfg = (busno << 16) | (slot << 11); @@ -189,7 +189,7 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,  		return PCIBIOS_DEVICE_NOT_FOUND;  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to look at it for real ...  	 */  	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) @@ -213,14 +213,14 @@ static int pci_conf0_write_config(struct pci_bus *bus, unsigned int devfn,  oh_my_gawd:  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to touch the wrong register.  	 */  	if ((where >= 0x14 && where < 0x40) || (where >= 0x48))  		return PCIBIOS_SUCCESSFUL;  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't try to access +	 * IOC3 is fucking fucked beyond belief ...  Don't try to access  	 * anything but 32-bit words ...  	 */  	addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; @@ -257,7 +257,7 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,  		return PCIBIOS_DEVICE_NOT_FOUND;  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to look at it for real ...  	 */  	if (cf == (PCI_VENDOR_ID_SGI | (PCI_DEVICE_ID_SGI_IOC3 << 16))) @@ -281,14 +281,14 @@ static int pci_conf1_write_config(struct pci_bus *bus, unsigned int devfn,  oh_my_gawd:  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't even give the +	 * IOC3 is fucking fucked beyond belief ...  Don't even give the  	 * generic PCI code a chance to touch the wrong register.  	 */  	if ((where >= 0x14 && where < 0x40) || (where >= 0x48))  		return PCIBIOS_SUCCESSFUL;  	/* -	 * IOC3 is fucked fucked beyond believe ...  Don't try to access +	 * IOC3 is fucking fucked beyond belief ...  Don't try to access  	 * anything but 32-bit words ...  	 */  	addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; diff --git a/arch/mips/pci/ops-gt64xxx_pci0.c b/arch/mips/pci/ops-gt64xxx_pci0.c index 3d896c5f413..effcbda9f52 100644 --- a/arch/mips/pci/ops-gt64xxx_pci0.c +++ b/arch/mips/pci/ops-gt64xxx_pci0.c @@ -23,21 +23,21 @@  #include <asm/gt64120.h> -#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_READ	 0  #define PCI_ACCESS_WRITE 1  /*   *  PCI configuration cycle AD bus definition   */  /* Type 0 */ -#define PCI_CFG_TYPE0_REG_SHF           0 -#define PCI_CFG_TYPE0_FUNC_SHF          8 +#define PCI_CFG_TYPE0_REG_SHF		0 +#define PCI_CFG_TYPE0_FUNC_SHF		8  /* Type 1 */ -#define PCI_CFG_TYPE1_REG_SHF           0 -#define PCI_CFG_TYPE1_FUNC_SHF          8 -#define PCI_CFG_TYPE1_DEV_SHF           11 -#define PCI_CFG_TYPE1_BUS_SHF           16 +#define PCI_CFG_TYPE1_REG_SHF		0 +#define PCI_CFG_TYPE1_FUNC_SHF		8 +#define PCI_CFG_TYPE1_DEV_SHF		11 +#define PCI_CFG_TYPE1_BUS_SHF		16  static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,  		struct pci_bus *bus, unsigned int devfn, int where, u32 * data) @@ -50,7 +50,7 @@ static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,  	/* Clear cause register bits */  	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | -	                             GT_INTRCAUSE_TARABORT0_BIT)); +				     GT_INTRCAUSE_TARABORT0_BIT));  	/* Setup address */  	GT_WRITE(GT_PCI0_CFGADDR_OFS, @@ -87,7 +87,7 @@ static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,  		/* Clear bits */  		GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | -		                             GT_INTRCAUSE_TARABORT0_BIT)); +					     GT_INTRCAUSE_TARABORT0_BIT));  		return -1;  	} @@ -106,7 +106,7 @@ static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn,  	u32 data = 0;  	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, -	                                       where, &data)) +					       where, &data))  		return PCIBIOS_DEVICE_NOT_FOUND;  	if (size == 1) @@ -128,7 +128,7 @@ static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn,  		data = val;  	else {  		if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, -		                                       devfn, where, &data)) +						       devfn, where, &data))  			return PCIBIOS_DEVICE_NOT_FOUND;  		if (size == 1) @@ -140,7 +140,7 @@ static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn,  	}  	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, -	                                       where, &data)) +					       where, &data))  		return PCIBIOS_DEVICE_NOT_FOUND;  	return PCIBIOS_SUCCESSFUL; diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c new file mode 100644 index 00000000000..e5738ee26f4 --- /dev/null +++ b/arch/mips/pci/ops-lantiq.c @@ -0,0 +1,115 @@ +/* + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + * + *  Copyright (C) 2010 John Crispin <blogic@openwrt.org> + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <asm/addrspace.h> +#include <linux/vmalloc.h> + +#include <lantiq_soc.h> + +#include "pci-lantiq.h" + +#define LTQ_PCI_CFG_BUSNUM_SHF 16 +#define LTQ_PCI_CFG_DEVNUM_SHF 11 +#define LTQ_PCI_CFG_FUNNUM_SHF 8 + +#define PCI_ACCESS_READ	 0 +#define PCI_ACCESS_WRITE 1 + +static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, +	unsigned int devfn, unsigned int where, u32 *data) +{ +	unsigned long cfg_base; +	unsigned long flags; +	u32 temp; + +	/* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the +	   SoC itself */ +	if ((bus->number != 0) || ((devfn & 0xf8) > 0x78) +		|| ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68)) +		return 1; + +	spin_lock_irqsave(&ebu_lock, flags); + +	cfg_base = (unsigned long) ltq_pci_mapped_cfg; +	cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << +			LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); + +	/* Perform access */ +	if (access_type == PCI_ACCESS_WRITE) { +		ltq_w32(swab32(*data), ((u32 *)cfg_base)); +	} else { +		*data = ltq_r32(((u32 *)(cfg_base))); +		*data = swab32(*data); +	} +	wmb(); + +	/* clean possible Master abort */ +	cfg_base = (unsigned long) ltq_pci_mapped_cfg; +	cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; +	temp = ltq_r32(((u32 *)(cfg_base))); +	temp = swab32(temp); +	cfg_base = (unsigned long) ltq_pci_mapped_cfg; +	cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; +	ltq_w32(temp, ((u32 *)cfg_base)); + +	spin_unlock_irqrestore(&ebu_lock, flags); + +	if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ)) +		return 1; + +	return 0; +} + +int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn, +	int where, int size, u32 *val) +{ +	u32 data = 0; + +	if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	if (size == 1) +		*val = (data >> ((where & 3) << 3)) & 0xff; +	else if (size == 2) +		*val = (data >> ((where & 3) << 3)) & 0xffff; +	else +		*val = data; + +	return PCIBIOS_SUCCESSFUL; +} + +int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn, +	int where, int size, u32 val) +{ +	u32 data = 0; + +	if (size == 4) { +		data = val; +	} else { +		if (ltq_pci_config_access(PCI_ACCESS_READ, bus, +				devfn, where, &data)) +			return PCIBIOS_DEVICE_NOT_FOUND; + +		if (size == 1) +			data = (data & ~(0xff << ((where & 3) << 3))) | +				(val << ((where & 3) << 3)); +		else if (size == 2) +			data = (data & ~(0xffff << ((where & 3) << 3))) | +				(val << ((where & 3) << 3)); +	} + +	if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	return PCIBIOS_SUCCESSFUL; +} diff --git a/arch/mips/pci/ops-loongson2.c b/arch/mips/pci/ops-loongson2.c index d657ee0bc13..24138bb0cbe 100644 --- a/arch/mips/pci/ops-loongson2.c +++ b/arch/mips/pci/ops-loongson2.c @@ -14,7 +14,7 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/kernel.h> -#include <linux/init.h> +#include <linux/export.h>  #include <loongson.h> @@ -23,7 +23,7 @@  #include <cs5536/cs5536.h>  #endif -#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_READ	 0  #define PCI_ACCESS_WRITE 1  #define CFG_SPACE_REG(offset) \ diff --git a/arch/mips/pci/ops-loongson3.c b/arch/mips/pci/ops-loongson3.c new file mode 100644 index 00000000000..46ed541a3ec --- /dev/null +++ b/arch/mips/pci/ops-loongson3.c @@ -0,0 +1,101 @@ +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> + +#include <asm/mips-boards/bonito64.h> + +#include <loongson.h> + +#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_WRITE 1 + +#define HT1LO_PCICFG_BASE      0x1a000000 +#define HT1LO_PCICFG_BASE_TP1  0x1b000000 + +static int loongson3_pci_config_access(unsigned char access_type, +		struct pci_bus *bus, unsigned int devfn, +		int where, u32 *data) +{ +	unsigned char busnum = bus->number; +	u_int64_t addr, type; +	void *addrp; +	int device = PCI_SLOT(devfn); +	int function = PCI_FUNC(devfn); +	int reg = where & ~3; + +	addr = (busnum << 16) | (device << 11) | (function << 8) | reg; +	if (busnum == 0) { +		if (device > 31) +			return PCIBIOS_DEVICE_NOT_FOUND; +		addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE) | (addr & 0xffff)); +		type = 0; + +	} else { +		addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE_TP1) | (addr)); +		type = 0x10000; +	} + +	if (access_type == PCI_ACCESS_WRITE) +		writel(*data, addrp); +	else { +		*data = readl(addrp); +		if (*data == 0xffffffff) { +			*data = -1; +			return PCIBIOS_DEVICE_NOT_FOUND; +		} +	} +	return PCIBIOS_SUCCESSFUL; +} + +static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn, +				 int where, int size, u32 *val) +{ +	u32 data = 0; +	int ret = loongson3_pci_config_access(PCI_ACCESS_READ, +			bus, devfn, where, &data); + +	if (ret != PCIBIOS_SUCCESSFUL) +		return ret; + +	if (size == 1) +		*val = (data >> ((where & 3) << 3)) & 0xff; +	else if (size == 2) +		*val = (data >> ((where & 3) << 3)) & 0xffff; +	else +		*val = data; + +	return PCIBIOS_SUCCESSFUL; +} + +static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn, +				  int where, int size, u32 val) +{ +	u32 data = 0; +	int ret; + +	if (size == 4) +		data = val; +	else { +		ret = loongson3_pci_config_access(PCI_ACCESS_READ, +				bus, devfn, where, &data); +		if (ret != PCIBIOS_SUCCESSFUL) +			return ret; + +		if (size == 1) +			data = (data & ~(0xff << ((where & 3) << 3))) | +			    (val << ((where & 3) << 3)); +		else if (size == 2) +			data = (data & ~(0xffff << ((where & 3) << 3))) | +			    (val << ((where & 3) << 3)); +	} + +	ret = loongson3_pci_config_access(PCI_ACCESS_WRITE, +			bus, devfn, where, &data); + +	return ret; +} + +struct pci_ops loongson_pci_ops = { +	.read = loongson3_pci_pcibios_read, +	.write = loongson3_pci_pcibios_write +}; diff --git a/arch/mips/pci/ops-mace.c b/arch/mips/pci/ops-mace.c index 1cfb5588699..6b5821febc3 100644 --- a/arch/mips/pci/ops-mace.c +++ b/arch/mips/pci/ops-mace.c @@ -6,7 +6,6 @@   * Copyright (C) 2000, 2001 Keith M Wesolowski   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/pci.h>  #include <linux/types.h>  #include <asm/pci.h> diff --git a/arch/mips/pci/ops-msc.c b/arch/mips/pci/ops-msc.c index 5d9fbb0f467..dbbf3657896 100644 --- a/arch/mips/pci/ops-msc.c +++ b/arch/mips/pci/ops-msc.c @@ -1,8 +1,8 @@  /* - * Copyright (C) 1999, 2000, 2004, 2005  MIPS Technologies, Inc. + * Copyright (C) 1999, 2000, 2004, 2005	 MIPS Technologies, Inc.   *    All rights reserved.   *    Authors: Carsten Langgaard <carstenl@mips.com> - *             Maciej W. Rozycki <macro@mips.com> + *	       Maciej W. Rozycki <macro@mips.com>   * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)   *   *  This program is free software; you can distribute it and/or modify it @@ -24,25 +24,24 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <asm/mips-boards/msc01_pci.h> -#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_READ	 0  #define PCI_ACCESS_WRITE 1  /*   *  PCI configuration cycle AD bus definition   */  /* Type 0 */ -#define PCI_CFG_TYPE0_REG_SHF           0 -#define PCI_CFG_TYPE0_FUNC_SHF          8 +#define PCI_CFG_TYPE0_REG_SHF		0 +#define PCI_CFG_TYPE0_FUNC_SHF		8  /* Type 1 */ -#define PCI_CFG_TYPE1_REG_SHF           0 -#define PCI_CFG_TYPE1_FUNC_SHF          8 -#define PCI_CFG_TYPE1_DEV_SHF           11 -#define PCI_CFG_TYPE1_BUS_SHF           16 +#define PCI_CFG_TYPE1_REG_SHF		0 +#define PCI_CFG_TYPE1_FUNC_SHF		8 +#define PCI_CFG_TYPE1_DEV_SHF		11 +#define PCI_CFG_TYPE1_BUS_SHF		16  static int msc_pcibios_config_access(unsigned char access_type,  	struct pci_bus *bus, unsigned int devfn, int where, u32 * data) @@ -97,7 +96,7 @@ static int msc_pcibios_read(struct pci_bus *bus, unsigned int devfn,  		return PCIBIOS_BAD_REGISTER_NUMBER;  	if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, -	                              &data)) +				      &data))  		return -1;  	if (size == 1) @@ -124,7 +123,7 @@ static int msc_pcibios_write(struct pci_bus *bus, unsigned int devfn,  		data = val;  	else {  		if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, -		                              where, &data)) +					      where, &data))  			return -1;  		if (size == 1) diff --git a/arch/mips/pci/ops-nile4.c b/arch/mips/pci/ops-nile4.c index b7f0fb0210f..a1a7c9f4096 100644 --- a/arch/mips/pci/ops-nile4.c +++ b/arch/mips/pci/ops-nile4.c @@ -1,13 +1,11 @@  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/pci.h>  #include <asm/bootinfo.h>  #include <asm/lasat/lasat.h> -#include <asm/gt64120.h>  #include <asm/nile4.h> -#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_READ	 0  #define PCI_ACCESS_WRITE 1  #define LO(reg) (reg / 4) diff --git a/arch/mips/pci/ops-pmcmsp.c b/arch/mips/pci/ops-pmcmsp.c index b7c03d80c88..50034f985be 100644 --- a/arch/mips/pci/ops-pmcmsp.c +++ b/arch/mips/pci/ops-pmcmsp.c @@ -7,10 +7,10 @@   * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net   *   * Much of the code is derived from the original DDB5074 port by - * Geert Uytterhoeven <geert@sonycom.com> + * Geert Uytterhoeven <geert@linux-m68k.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 + * 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.   * @@ -53,96 +53,84 @@ static void pci_proc_init(void);  /*****************************************************************************   * - *  FUNCTION: read_msp_pci_counts + *  FUNCTION: show_msp_pci_counts   *  _________________________________________________________________________   *   *  DESCRIPTION: Prints the count of how many times each PCI - *               interrupt has asserted. Can be invoked by the - *               /proc filesystem. + *		 interrupt has asserted. Can be invoked by the + *		 /proc filesystem.   * - *  INPUTS:      page    - part of STDOUT calculation - *               off     - part of STDOUT calculation - *               count   - part of STDOUT calculation - *               data    - unused + *  INPUTS:	 m	 - synthetic file construction data + *		 v	 - iterator   * - *  OUTPUTS:     start   - new start location - *               eof     - end of file pointer - * - *  RETURNS:     len     - STDOUT length + *  RETURNS:	 0 or error   *   ****************************************************************************/ -static int read_msp_pci_counts(char *page, char **start, off_t off, -				int count, int *eof, void *data) +static int show_msp_pci_counts(struct seq_file *m, void *v)  {  	int i; -	int len = 0;  	unsigned int intcount, total = 0;  	for (i = 0; i < 32; ++i) {  		intcount = pci_int_count[i];  		if (intcount != 0) { -			len += sprintf(page + len, "[%d] = %u\n", i, intcount); +			seq_printf(m, "[%d] = %u\n", i, intcount);  			total += intcount;  		}  	} -	len += sprintf(page + len, "total = %u\n", total); -	if (len <= off+count) -		*eof = 1; - -	*start = page + off; -	len -= off; -	if (len > count) -		len = count; -	if (len < 0) -		len = 0; +	seq_printf(m, "total = %u\n", total); +	return 0; +} -	return len; +static int msp_pci_rd_cnt_open(struct inode *inode, struct file *file) +{ +	return single_open(file, show_msp_pci_counts, NULL);  } +static const struct file_operations msp_pci_rd_cnt_fops = { +	.open		= msp_pci_rd_cnt_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +}; +  /*****************************************************************************   * - *  FUNCTION: gen_pci_cfg_wr + *  FUNCTION: gen_pci_cfg_wr_show   *  _________________________________________________________________________   *   *  DESCRIPTION: Generates a configuration write cycle for debug purposes. - *               The IDSEL line asserted and location and data written are - *               immaterial. Just want to be able to prove that a - *               configuration write can be correctly generated on the - *               PCI bus.  Intent is that this function by invocable from - *               the /proc filesystem. - * - *  INPUTS:      page    - part of STDOUT calculation - *               off     - part of STDOUT calculation - *               count   - part of STDOUT calculation - *               data    - unused + *		 The IDSEL line asserted and location and data written are + *		 immaterial. Just want to be able to prove that a + *		 configuration write can be correctly generated on the + *		 PCI bus.  Intent is that this function by invocable from + *		 the /proc filesystem.   * - *  OUTPUTS:     start   - new start location - *               eof     - end of file pointer + *  INPUTS:	 m	 - synthetic file construction data + *		 v	 - iterator   * - *  RETURNS:     len     - STDOUT length + *  RETURNS:	 0 or error   *   ****************************************************************************/ -static int gen_pci_cfg_wr(char *page, char **start, off_t off, -				int count, int *eof, void *data) +static int gen_pci_cfg_wr_show(struct seq_file *m, void *v)  {  	unsigned char where = 0; /* Write to static Device/Vendor ID */  	unsigned char bus_num = 0; /* Bus 0 */  	unsigned char dev_fn = 0xF; /* Arbitrary device number */  	u32 wr_data = 0xFF00AA00; /* Arbitrary data */  	struct msp_pci_regs *preg = (void *)PCI_BASE_REG; -	int len = 0;  	unsigned long value;  	int intr; -	len += sprintf(page + len, "PMC MSP PCI: Beginning\n"); +	seq_puts(m, "PMC MSP PCI: Beginning\n");  	if (proc_init == 0) {  		pci_proc_init();  		proc_init = ~0;  	} -	len += sprintf(page + len, "PMC MSP PCI: Before Cfg Wr\n"); +	seq_puts(m, "PMC MSP PCI: Before Cfg Wr\n");  	/*  	 * Generate PCI Configuration Write Cycle @@ -168,21 +156,22 @@ static int gen_pci_cfg_wr(char *page, char **start, off_t off,  	 */  	intr = preg->if_status; -	len += sprintf(page + len, "PMC MSP PCI: After Cfg Wr\n"); - -	/* Handle STDOUT calculations */ -	if (len <= off+count) -		*eof = 1; -	*start = page + off; -	len -= off; -	if (len > count) -		len = count; -	if (len < 0) -		len = 0; +	seq_puts(m, "PMC MSP PCI: After Cfg Wr\n"); +	return 0; +} -	return len; +static int gen_pci_cfg_wr_open(struct inode *inode, struct file *file) +{ +	return single_open(file, gen_pci_cfg_wr_show, NULL);  } +static const struct file_operations gen_pci_cfg_wr_fops = { +	.open		= gen_pci_cfg_wr_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +}; +  /*****************************************************************************   *   *  FUNCTION: pci_proc_init @@ -190,19 +179,17 @@ static int gen_pci_cfg_wr(char *page, char **start, off_t off,   *   *  DESCRIPTION: Create entries in the /proc filesystem for debug access.   * - *  INPUTS:      none + *  INPUTS:	 none   * - *  OUTPUTS:     none + *  OUTPUTS:	 none   * - *  RETURNS:     none + *  RETURNS:	 none   *   ****************************************************************************/  static void pci_proc_init(void)  { -	create_proc_read_entry("pmc_msp_pci_rd_cnt", 0, NULL, -				read_msp_pci_counts, NULL); -	create_proc_read_entry("pmc_msp_pci_cfg_wr", 0, NULL, -				gen_pci_cfg_wr, NULL); +	proc_create("pmc_msp_pci_rd_cnt", 0, NULL, &msp_pci_rd_cnt_fops); +	proc_create("pmc_msp_pci_cfg_wr", 0, NULL, &gen_pci_cfg_wr_fops);  }  #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ @@ -214,44 +201,44 @@ static DEFINE_SPINLOCK(bpci_lock);   *  _________________________________________________________________________   *   *  DESCRIPTION: Defines the address range that pciauto() will use to - *               assign to the I/O BARs of PCI devices. - * - *               Use the start and end addresses of the MSP7120 PCI Host - *               Controller I/O space, in the form that they appear on the - *               PCI bus AFTER MSP7120 has performed address translation. - * - *               For I/O accesses, MSP7120 ignores OATRAN and maps I/O - *               accesses into the bottom 0xFFF region of address space, - *               so that is the range to put into the pci_io_resource - *               struct. - * - *               In MSP4200, the start address was 0x04 instead of the - * 		 expected 0x00. Will just assume there was a good reason - * 		 for this! - * - *  NOTES:       Linux, by default, will assign I/O space to the lowest - *               region of address space. Since MSP7120 and Linux, - *               by default, have no offset in between how they map, the - *               io_offset element of pci_controller struct should be set - *               to zero. + *		 assign to the I/O BARs of PCI devices. + * + *		 Use the start and end addresses of the MSP7120 PCI Host + *		 Controller I/O space, in the form that they appear on the + *		 PCI bus AFTER MSP7120 has performed address translation. + * + *		 For I/O accesses, MSP7120 ignores OATRAN and maps I/O + *		 accesses into the bottom 0xFFF region of address space, + *		 so that is the range to put into the pci_io_resource + *		 struct. + * + *		 In MSP4200, the start address was 0x04 instead of the + *		 expected 0x00. Will just assume there was a good reason + *		 for this! + * + *  NOTES:	 Linux, by default, will assign I/O space to the lowest + *		 region of address space. Since MSP7120 and Linux, + *		 by default, have no offset in between how they map, the + *		 io_offset element of pci_controller struct should be set + *		 to zero.   *  ELEMENTS: - *    name       - String used for a meaningful name. + *    name	 - String used for a meaningful name.   * - *    start      - Start address of MSP7120's I/O space, as MSP7120 presents - *                 the address on the PCI bus. + *    start	 - Start address of MSP7120's I/O space, as MSP7120 presents + *		   the address on the PCI bus.   * - *    end        - End address of MSP7120's I/O space, as MSP7120 presents - *                 the address on the PCI bus. + *    end	 - End address of MSP7120's I/O space, as MSP7120 presents + *		   the address on the PCI bus.   * - *    flags      - Attributes indicating the type of resource. In this case, - *                 indicate I/O space. + *    flags	 - Attributes indicating the type of resource. In this case, + *		   indicate I/O space.   *   ****************************************************************************/  static struct resource pci_io_resource = {  	.name	= "pci IO space",  	.start	= 0x04,  	.end	= 0x0FFF, -	.flags	= IORESOURCE_IO	/* I/O space */ +	.flags	= IORESOURCE_IO /* I/O space */  };  /***************************************************************************** @@ -260,26 +247,26 @@ static struct resource pci_io_resource = {   *  _________________________________________________________________________   *   *  DESCRIPTION: Defines the address range that pciauto() will use to - *               assign to the memory BARs of PCI devices. + *		 assign to the memory BARs of PCI devices.   * - *               The .start and .end values are dependent upon how address - *               translation is performed by the OATRAN regiser. + *		 The .start and .end values are dependent upon how address + *		 translation is performed by the OATRAN regiser.   * - *               The values to use for .start and .end are the values - *               in the form they appear on the PCI bus AFTER MSP7120 has - *               performed OATRAN address translation. + *		 The values to use for .start and .end are the values + *		 in the form they appear on the PCI bus AFTER MSP7120 has + *		 performed OATRAN address translation.   *   *  ELEMENTS: - *    name       - String used for a meaningful name. + *    name	 - String used for a meaningful name.   * - *    start      - Start address of MSP7120's memory space, as MSP7120 presents - *                 the address on the PCI bus. + *    start	 - Start address of MSP7120's memory space, as MSP7120 presents + *		   the address on the PCI bus.   * - *    end        - End address of MSP7120's memory space, as MSP7120 presents - *                 the address on the PCI bus. + *    end	 - End address of MSP7120's memory space, as MSP7120 presents + *		   the address on the PCI bus.   * - *    flags      - Attributes indicating the type of resource. In this case, - *                 indicate memory space. + *    flags	 - Attributes indicating the type of resource. In this case, + *		   indicate memory space.   *   ****************************************************************************/  static struct resource pci_mem_resource = { @@ -295,20 +282,20 @@ static struct resource pci_mem_resource = {   *  _________________________________________________________________________   *   *  DESCRIPTION: PCI status interrupt handler. Updates the count of how - *               many times each status bit has been set, then clears - *               the status bits. If the appropriate macros are defined, - *               these counts can be viewed via the /proc filesystem. + *		 many times each status bit has been set, then clears + *		 the status bits. If the appropriate macros are defined, + *		 these counts can be viewed via the /proc filesystem.   * - *  INPUTS:      irq     - unused - *               dev_id  - unused - *               pt_regs - unused + *  INPUTS:	 irq	 - unused + *		 dev_id	 - unused + *		 pt_regs - unused   * - *  OUTPUTS:     none + *  OUTPUTS:	 none   * - *  RETURNS:     PCIBIOS_SUCCESSFUL  - success + *  RETURNS:	 PCIBIOS_SUCCESSFUL  - success   *   ****************************************************************************/ -static int bpci_interrupt(int irq, void *dev_id) +static irqreturn_t bpci_interrupt(int irq, void *dev_id)  {  	struct msp_pci_regs *preg = (void *)PCI_BASE_REG;  	unsigned int stat = preg->if_status; @@ -326,7 +313,7 @@ static int bpci_interrupt(int irq, void *dev_id)  	/* write to clear all asserted interrupts */  	preg->if_status = stat; -	return PCIBIOS_SUCCESSFUL; +	return IRQ_HANDLED;  }  /***************************************************************************** @@ -335,41 +322,41 @@ static int bpci_interrupt(int irq, void *dev_id)   *  _________________________________________________________________________   *   *  DESCRIPTION: Performs a PCI configuration access (rd or wr), then - *               checks that the access succeeded by querying MSP7120's - *               PCI status bits. + *		 checks that the access succeeded by querying MSP7120's + *		 PCI status bits.   *   *  INPUTS: - *               access_type  - kind of PCI configuration cycle to perform - *                              (read or write). Legal values are - *                              PCI_ACCESS_WRITE and PCI_ACCESS_READ. - * - *               bus          - pointer to the bus number of the device to - *                              be targetted for the configuration cycle. - *                              The only element of the pci_bus structure - *                              used is bus->number. This argument determines - *                              if the configuration access will be Type 0 or - *                              Type 1. Since MSP7120 assumes itself to be the - *                              PCI Host, any non-zero bus->number generates - *                              a Type 1 access. - * - *               devfn        - this is an 8-bit field. The lower three bits - *                              specify the function number of the device to - *                              be targetted for the configuration cycle, with - *                              all three-bit combinations being legal. The - *                              upper five bits specify the device number, - *                              with legal values being 10 to 31. - * - *               where        - address within the Configuration Header - *                              space to access. - * - *               data         - for write accesses, contains the data to - *                              write. + *		 access_type  - kind of PCI configuration cycle to perform + *				(read or write). Legal values are + *				PCI_ACCESS_WRITE and PCI_ACCESS_READ. + * + *		 bus	      - pointer to the bus number of the device to + *				be targeted for the configuration cycle. + *				The only element of the pci_bus structure + *				used is bus->number. This argument determines + *				if the configuration access will be Type 0 or + *				Type 1. Since MSP7120 assumes itself to be the + *				PCI Host, any non-zero bus->number generates + *				a Type 1 access. + * + *		 devfn	      - this is an 8-bit field. The lower three bits + *				specify the function number of the device to + *				be targeted for the configuration cycle, with + *				all three-bit combinations being legal. The + *				upper five bits specify the device number, + *				with legal values being 10 to 31. + * + *		 where	      - address within the Configuration Header + *				space to access. + * + *		 data	      - for write accesses, contains the data to + *				write.   *   *  OUTPUTS: - *               data         - for read accesses, contains the value read. + *		 data	      - for read accesses, contains the value read.   * - *  RETURNS:     PCIBIOS_SUCCESSFUL  - success - *               -1                  - access failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL  - success + *		 -1		     - access failure   *   ****************************************************************************/  int msp_pcibios_config_access(unsigned char access_type, @@ -405,7 +392,7 @@ int msp_pcibios_config_access(unsigned char access_type,  	if (pciirqflag == 0) {  		ret = request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */  				bpci_interrupt, -				IRQF_SHARED | IRQF_DISABLED, +				IRQF_SHARED,  				"PMC MSP PCI Host",  				preg);  		if (ret != 0) @@ -429,7 +416,7 @@ int msp_pcibios_config_access(unsigned char access_type,  	 * for this Block Copy, called Block Copy 0 Fault (BC0F) and  	 * Block Copy 1 Fault (BC1F). MSP4200 and MSP7120 don't have this  	 * dedicated Block Copy block, so these two interrupts are now -	 * marked reserved. In case the  Block Copy is resurrected in a +	 * marked reserved. In case the	 Block Copy is resurrected in a  	 * future design, maintain the code that treats these two interrupts  	 * specially.  	 * @@ -439,7 +426,7 @@ int msp_pcibios_config_access(unsigned char access_type,  	preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F);  	/* Setup address that is to appear on PCI bus */ -	preg->config_addr = BPCI_CFGADDR_ENABLE	| +	preg->config_addr = BPCI_CFGADDR_ENABLE |  		(bus_num << BPCI_CFGADDR_BUSNUM_SHF) |  		(dev_fn << BPCI_CFGADDR_FUNCTNUM_SHF) |  		(where & 0xFC); @@ -494,21 +481,21 @@ int msp_pcibios_config_access(unsigned char access_type,   *  _________________________________________________________________________   *   *  DESCRIPTION: Read a byte from PCI configuration address spac - *               Since the hardware can't address 8 bit chunks - *               directly, read a 32-bit chunk, then mask off extraneous - *               bits. + *		 Since the hardware can't address 8 bit chunks + *		 directly, read a 32-bit chunk, then mask off extraneous + *		 bits.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the read is destined for. - *               devfn  - device/function combination that the read is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the read is destined for. + *		 devfn	- device/function combination that the read is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access.   * - *  OUTPUTS      val    - read data + *  OUTPUTS	 val	- read data   * - *  RETURNS:     PCIBIOS_SUCCESSFUL  - success - *               -1                  - read access failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL  - success + *		 -1		     - read access failure   *   ****************************************************************************/  static int @@ -541,22 +528,22 @@ msp_pcibios_read_config_byte(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: Read a word (16 bits) from PCI configuration address space. - *               Since the hardware can't address 16 bit chunks - *               directly, read a 32-bit chunk, then mask off extraneous - *               bits. + *		 Since the hardware can't address 16 bit chunks + *		 directly, read a 32-bit chunk, then mask off extraneous + *		 bits.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the read is destined for. - *               devfn  - device/function combination that the read is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the read is destined for. + *		 devfn	- device/function combination that the read is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access.   * - *  OUTPUTS      val    - read data + *  OUTPUTS	 val	- read data   * - *  RETURNS:     PCIBIOS_SUCCESSFUL           - success - *               PCIBIOS_BAD_REGISTER_NUMBER  - bad register address - *               -1                           - read access failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL	      - success + *		 PCIBIOS_BAD_REGISTER_NUMBER  - bad register address + *		 -1			      - read access failure   *   ****************************************************************************/  static int @@ -600,20 +587,20 @@ msp_pcibios_read_config_word(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: Read a double word (32 bits) from PCI configuration - *               address space. + *		 address space.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the read is destined for. - *               devfn  - device/function combination that the read is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the read is destined for. + *		 devfn	- device/function combination that the read is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access.   * - *  OUTPUTS      val    - read data + *  OUTPUTS	 val	- read data   * - *  RETURNS:     PCIBIOS_SUCCESSFUL           - success - *               PCIBIOS_BAD_REGISTER_NUMBER  - bad register address - *               -1                           - read access failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL	      - success + *		 PCIBIOS_BAD_REGISTER_NUMBER  - bad register address + *		 -1			      - read access failure   *   ****************************************************************************/  static int @@ -652,21 +639,21 @@ msp_pcibios_read_config_dword(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: Write a byte to PCI configuration address space. - *               Since the hardware can't address 8 bit chunks - *               directly, a read-modify-write is performed. + *		 Since the hardware can't address 8 bit chunks + *		 directly, a read-modify-write is performed.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the write is destined for. - *               devfn  - device/function combination that the write is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. - *               val    - value to write + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the write is destined for. + *		 devfn	- device/function combination that the write is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access. + *		 val	- value to write   * - *  OUTPUTS      none + *  OUTPUTS	 none   * - *  RETURNS:     PCIBIOS_SUCCESSFUL  - success - *               -1                  - write access failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL  - success + *		 -1		     - write access failure   *   ****************************************************************************/  static int @@ -700,22 +687,22 @@ msp_pcibios_write_config_byte(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: Write a word (16-bits) to PCI configuration address space. - *               Since the hardware can't address 16 bit chunks - *               directly, a read-modify-write is performed. + *		 Since the hardware can't address 16 bit chunks + *		 directly, a read-modify-write is performed.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the write is destined for. - *               devfn  - device/function combination that the write is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. - *               val    - value to write + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the write is destined for. + *		 devfn	- device/function combination that the write is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access. + *		 val	- value to write   * - *  OUTPUTS      none + *  OUTPUTS	 none   * - *  RETURNS:     PCIBIOS_SUCCESSFUL           - success - *               PCIBIOS_BAD_REGISTER_NUMBER  - bad register address - *               -1                           - write access failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL	      - success + *		 PCIBIOS_BAD_REGISTER_NUMBER  - bad register address + *		 -1			      - write access failure   *   ****************************************************************************/  static int @@ -753,21 +740,21 @@ msp_pcibios_write_config_word(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: Write a double word (32-bits) to PCI configuration address - *               space. + *		 space.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the write is destined for. - *               devfn  - device/function combination that the write is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. - *               val    - value to write + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the write is destined for. + *		 devfn	- device/function combination that the write is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access. + *		 val	- value to write   * - *  OUTPUTS      none + *  OUTPUTS	 none   * - *  RETURNS:     PCIBIOS_SUCCESSFUL           - success - *               PCIBIOS_BAD_REGISTER_NUMBER  - bad register address - *               -1                           - write access failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL	      - success + *		 PCIBIOS_BAD_REGISTER_NUMBER  - bad register address + *		 -1			      - write access failure   *   ****************************************************************************/  static int @@ -794,22 +781,22 @@ msp_pcibios_write_config_dword(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: Interface the PCI configuration read request with - *               the appropriate function, based on how many bytes - *               the read request is. + *		 the appropriate function, based on how many bytes + *		 the read request is.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the write is destined for. - *               devfn  - device/function combination that the write is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. - *               size   - in units of bytes, should be 1, 2, or 4. + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the write is destined for. + *		 devfn	- device/function combination that the write is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access. + *		 size	- in units of bytes, should be 1, 2, or 4.   * - *  OUTPUTS      val    - value read, with any extraneous bytes masked - *                        to zero. + *  OUTPUTS	 val	- value read, with any extraneous bytes masked + *			  to zero.   * - *  RETURNS:     PCIBIOS_SUCCESSFUL   - success - *               -1                   - failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL   - success + *		 -1		      - failure   *   ****************************************************************************/  int @@ -845,22 +832,22 @@ msp_pcibios_read_config(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: Interface the PCI configuration write request with - *               the appropriate function, based on how many bytes - *               the read request is. + *		 the appropriate function, based on how many bytes + *		 the read request is.   * - *  INPUTS       bus    - structure containing attributes for the PCI bus - *                        that the write is destined for. - *               devfn  - device/function combination that the write is - *                        destined for. - *               where  - register within the Configuration Header space - *                        to access. - *               size   - in units of bytes, should be 1, 2, or 4. - *               val    - value to write + *  INPUTS	 bus	- structure containing attributes for the PCI bus + *			  that the write is destined for. + *		 devfn	- device/function combination that the write is + *			  destined for. + *		 where	- register within the Configuration Header space + *			  to access. + *		 size	- in units of bytes, should be 1, 2, or 4. + *		 val	- value to write   * - *  OUTPUTS:     none + *  OUTPUTS:	 none   * - *  RETURNS:     PCIBIOS_SUCCESSFUL   - success - *               -1                   - failure + *  RETURNS:	 PCIBIOS_SUCCESSFUL   - success + *		 -1		      - failure   *   ****************************************************************************/  int @@ -897,11 +884,11 @@ msp_pcibios_write_config(struct pci_bus *bus,   *  _________________________________________________________________________   *   *  DESCRIPTION: structure to abstract the hardware specific PCI - *               configuration accesses. + *		 configuration accesses.   *   *  ELEMENTS: - *    read      - function for Linux to generate PCI Configuration reads. - *    write     - function for Linux to generate PCI Configuration writes. + *    read	- function for Linux to generate PCI Configuration reads. + *    write	- function for Linux to generate PCI Configuration writes.   *   ****************************************************************************/  struct pci_ops msp_pci_ops = { @@ -917,27 +904,27 @@ struct pci_ops msp_pci_ops = {   *  Describes the attributes of the MSP7120 PCI Host Controller   *   *  ELEMENTS: - *    pci_ops      - abstracts the hardware specific PCI configuration - *                   accesses. + *    pci_ops	   - abstracts the hardware specific PCI configuration + *		     accesses.   *   *    mem_resource - address range pciauto() uses to assign to PCI device - *                   memory BARs. + *		     memory BARs.   *   *    mem_offset   - offset between how MSP7120 outbound PCI memory - *                   transaction addresses appear on the PCI bus and how Linux - *                   wants to configure memory BARs of the PCI devices. - *                   MSP7120 does nothing funky, so just set to zero. + *		     transaction addresses appear on the PCI bus and how Linux + *		     wants to configure memory BARs of the PCI devices. + *		     MSP7120 does nothing funky, so just set to zero.   *   *    io_resource  - address range pciauto() uses to assign to PCI device - *                   I/O BARs. + *		     I/O BARs.   * - *    io_offset    - offset between how MSP7120 outbound PCI I/O - *                   transaction addresses appear on the PCI bus and how - *                   Linux defaults to configure I/O BARs of the PCI devices. - *                   MSP7120 maps outbound I/O accesses into the bottom - *                   bottom 4K of PCI address space (and ignores OATRAN). - *                   Since the Linux default is to configure I/O BARs to the - *                   bottom 4K, no special offset is needed. Just set to zero. + *    io_offset	   - offset between how MSP7120 outbound PCI I/O + *		     transaction addresses appear on the PCI bus and how + *		     Linux defaults to configure I/O BARs of the PCI devices. + *		     MSP7120 maps outbound I/O accesses into the bottom + *		     bottom 4K of PCI address space (and ignores OATRAN). + *		     Since the Linux default is to configure I/O BARs to the + *		     bottom 4K, no special offset is needed. Just set to zero.   *   ****************************************************************************/  static struct pci_controller msp_pci_controller = { @@ -955,7 +942,7 @@ static struct pci_controller msp_pci_controller = {   *  _________________________________________________________________________   *   *  DESCRIPTION: Initialize the PCI Host Controller and register it with - *               Linux so Linux can seize control of the PCI bus. + *		 Linux so Linux can seize control of the PCI bus.   *   ****************************************************************************/  void __init msp_pci_init(void) @@ -979,7 +966,7 @@ void __init msp_pci_init(void)  	*(unsigned long *)QFLUSH_REG_1 = 3;  	/* Configure PCI Host Controller. */ -	preg->if_status	= ~0;		/* Clear cause register bits */ +	preg->if_status = ~0;		/* Clear cause register bits */  	preg->config_addr = 0;		/* Clear config access */  	preg->oatran	= MSP_PCI_OATRAN; /* PCI outbound addr translation */  	preg->if_mask	= 0xF8BF87C0;	/* Enable all PCI status interrupts */ diff --git a/arch/mips/pci/ops-pnx8550.c b/arch/mips/pci/ops-pnx8550.c deleted file mode 100644 index 1e6213fa7bd..00000000000 --- a/arch/mips/pci/ops-pnx8550.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * - *  BRIEF MODULE DESCRIPTION - * - *  2.6 port, Embedded Alley Solutions, Inc - * - *  Based on: - *  Author: source@mvista.com - * - *  This program is free software; you can distribute it and/or modify it - *  under the terms of the GNU General Public License (Version 2) as - *  published by the Free Software Foundation. - * - *  This program is distributed in the hope it will be useful, but WITHOUT - *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License - *  for more details. - * - *  You should have received a copy of the GNU General Public License along - *  with this program; if not, write to the Free Software Foundation, Inc., - *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - */ -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> - -#include <asm/mach-pnx8550/pci.h> -#include <asm/mach-pnx8550/glb.h> - -static inline void clear_status(void) -{ -	unsigned long pci_stat; - -	pci_stat = inl(PCI_BASE | PCI_GPPM_STATUS); -	outl(pci_stat, PCI_BASE | PCI_GPPM_ICLR); -} - -static inline unsigned int -calc_cfg_addr(struct pci_bus *bus, unsigned int devfn, int where) -{ -	unsigned int addr; - -	addr = ((bus->number > 0) ? (((bus->number & 0xff) << PCI_CFG_BUS_SHIFT) | 1) : 0); -	addr |= ((devfn & 0xff) << PCI_CFG_FUNC_SHIFT) | (where & 0xfc); - -	return addr; -} - -static int -config_access(unsigned int pci_cmd, struct pci_bus *bus, unsigned int devfn, int where, unsigned int pci_mode, unsigned int *val) -{ -	unsigned int flags; -	unsigned long loops = 0; -	unsigned long ioaddr = calc_cfg_addr(bus, devfn, where); - -	local_irq_save(flags); -	/*Clear pending interrupt status */ -	if (inl(PCI_BASE | PCI_GPPM_STATUS)) { -		clear_status(); -		while (!(inl(PCI_BASE | PCI_GPPM_STATUS) == 0)) ; -	} - -	outl(ioaddr, PCI_BASE | PCI_GPPM_ADDR); - -	if ((pci_cmd == PCI_CMD_IOW) || (pci_cmd == PCI_CMD_CONFIG_WRITE)) -		outl(*val, PCI_BASE | PCI_GPPM_WDAT); - -	outl(INIT_PCI_CYCLE | pci_cmd | (pci_mode & PCI_BYTE_ENABLE_MASK), -	     PCI_BASE | PCI_GPPM_CTRL); - -	loops = -	    ((loops_per_jiffy * -	      PCI_IO_JIFFIES_TIMEOUT) >> (PCI_IO_JIFFIES_SHIFT)); -	while (1) { -		if (inl(PCI_BASE | PCI_GPPM_STATUS) & GPPM_DONE) { -			if ((pci_cmd == PCI_CMD_IOR) || -			    (pci_cmd == PCI_CMD_CONFIG_READ)) -				*val = inl(PCI_BASE | PCI_GPPM_RDAT); -			clear_status(); -			local_irq_restore(flags); -			return PCIBIOS_SUCCESSFUL; -		} else if (inl(PCI_BASE | PCI_GPPM_STATUS) & GPPM_R_MABORT) { -			break; -		} - -		loops--; -		if (loops == 0) { -			printk("%s : Arbiter Locked.\n", __func__); -		} -	} - -	clear_status(); -	if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_IOW)) { -		printk("%s timeout (GPPM_CTRL=%X) ioaddr %lX pci_cmd %X\n", -		       __func__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr, -		       pci_cmd); -	} - -	if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_CONFIG_READ)) -		*val = 0xffffffff; -	local_irq_restore(flags); -	return PCIBIOS_DEVICE_NOT_FOUND; -} - -/* - * We can't address 8 and 16 bit words directly.  Instead we have to - * read/write a 32bit word and mask/modify the data we actually want. - */ -static int -read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val) -{ -	unsigned int data = 0; -	int err; - -	if (bus == NULL) -		return -1; - -	err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, ~(1 << (where & 3)), &data); -	switch (where & 0x03) { -	case 0: -		*val = (unsigned char)(data & 0x000000ff); -		break; -	case 1: -		*val = (unsigned char)((data & 0x0000ff00) >> 8); -		break; -	case 2: -		*val = (unsigned char)((data & 0x00ff0000) >> 16); -		break; -	case 3: -		*val = (unsigned char)((data & 0xff000000) >> 24); -		break; -	} - -	return err; -} - -static int -read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val) -{ -	unsigned int data = 0; -	int err; - -	if (bus == NULL) -		return -1; - -	if (where & 0x01) -		return PCIBIOS_BAD_REGISTER_NUMBER; - -	err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, ~(3 << (where & 3)), &data); -	switch (where & 0x02) { -	case 0: -		*val = (unsigned short)(data & 0x0000ffff); -		break; -	case 2: -		*val = (unsigned short)((data & 0xffff0000) >> 16); -		break; -	} - -	return err; -} - -static int -read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val) -{ -	int err; -	if (bus == NULL) -		return -1; - -	if (where & 0x03) -		return PCIBIOS_BAD_REGISTER_NUMBER; - -	err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, 0, val); - -	return err; -} - -static int -write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val) -{ -	unsigned int data = (unsigned int)val; -	int err; - -	if (bus == NULL) -		return -1; - -	switch (where & 0x03) { -	case 1: -		data = (data << 8); -		break; -	case 2: -		data = (data << 16); -		break; -	case 3: -		data = (data << 24); -		break; -	default: -		break; -	} - -	err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, ~(1 << (where & 3)), &data); - -	return err; -} - -static int -write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val) -{ -	unsigned int data = (unsigned int)val; -	int err; - -	if (bus == NULL) -		return -1; - -	if (where & 0x01) -		return PCIBIOS_BAD_REGISTER_NUMBER; - -	switch (where & 0x02) { -	case 2: -		data = (data << 16); -		break; -	default: -		break; -	} -	err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, ~(3 << (where & 3)), &data); - -	return err; -} - -static int -write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) -{ -	int err; -	if (bus == NULL) -		return -1; - -	if (where & 0x03) -		return PCIBIOS_BAD_REGISTER_NUMBER; - -	err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, 0, &val); - -	return err; -} - -static int config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) -{ -	switch (size) { -	case 1: { -			u8 _val; -			int rc = read_config_byte(bus, devfn, where, &_val); -			*val = _val; -			return rc; -		} -       case 2: { -			u16 _val; -			int rc = read_config_word(bus, devfn, where, &_val); -			*val = _val; -			return rc; -		} -	default: -		return read_config_dword(bus, devfn, where, val); -	} -} - -static int config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) -{ -	switch (size) { -	case 1: -		return write_config_byte(bus, devfn, where, (u8) val); -	case 2: -		return write_config_word(bus, devfn, where, (u16) val); -	default: -		return write_config_dword(bus, devfn, where, val); -	} -} - -struct pci_ops pnx8550_pci_ops = { -	config_read, -	config_write -}; diff --git a/arch/mips/pci/ops-rc32434.c b/arch/mips/pci/ops-rc32434.c index d1f8fa210ca..874ed6df976 100644 --- a/arch/mips/pci/ops-rc32434.c +++ b/arch/mips/pci/ops-rc32434.c @@ -26,7 +26,6 @@   *  675 Mass Ave, Cambridge, MA 02139, USA.   */  #include <linux/delay.h> -#include <linux/init.h>  #include <linux/io.h>  #include <linux/pci.h>  #include <linux/types.h> @@ -35,7 +34,7 @@  #include <asm/mach-rc32434/rc32434.h>  #include <asm/mach-rc32434/pci.h> -#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_READ	 0  #define PCI_ACCESS_WRITE 1 diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c index 97ed25b92ed..35daa7fe657 100644 --- a/arch/mips/pci/ops-sni.c +++ b/arch/mips/pci/ops-sni.c @@ -14,8 +14,8 @@  /*   * It seems that on the RM200 only lower 3 bits of the 5 bit PCI device - * address are decoded.  We therefore manually have to reject attempts at - * reading outside this range.  Being on the paranoid side we only do this + * address are decoded.	 We therefore manually have to reject attempts at + * reading outside this range.	Being on the paranoid side we only do this   * test for bus 0 and hope forwarding and decoding work properly for any   * subordinated busses.   * @@ -31,8 +31,8 @@ static int set_config_address(unsigned int busno, unsigned int devfn, int reg)  	*(volatile u32 *)PCIMT_CONFIG_ADDRESS =  		 ((busno    & 0xff) << 16) | -	         ((devfn    & 0xff) <<  8) | -	          (reg      & 0xfc); +		 ((devfn    & 0xff) <<	8) | +		  (reg	    & 0xfc);  	return PCIBIOS_SUCCESSFUL;  } diff --git a/arch/mips/pci/ops-titan-ht.c b/arch/mips/pci/ops-titan-ht.c deleted file mode 100644 index 57d54adc9e2..00000000000 --- a/arch/mips/pci/ops-titan-ht.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2003 PMC-Sierra - * Author: Manish Lachwani (lachwani@pmc-sierra.com) - * - *  This program is free software; you can redistribute  it and/or modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. - * - *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED - *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF - *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN - *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, - *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF - *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT - *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *  You should have received a copy of the  GNU General Public License along - *  with this program; if not, write  to the Free Software Foundation, Inc., - *  675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <asm/io.h> - -#include <asm/titan_dep.h> - -static int titan_ht_config_read_dword(struct pci_bus *bus, unsigned int devfn, -	int offset, u32 *val) -{ -	volatile uint32_t address; -	int busno; - -	busno = bus->number; - -	address = (busno << 16) | (devfn << 8) | (offset & 0xfc) | 0x80000000; -	if (busno != 0) -		address |= 1; - -	/* -	 * RM9000 HT Errata: Issue back to back HT config -	 * transcations. Issue a BIU sync before and -	 * after the HT cycle -	 */ - -	*(volatile int32_t *) 0xfb0000f0 |= 0x2; - -	udelay(30); - -	*(volatile int32_t *) 0xfb0006f8 = address; -	*(val) = *(volatile int32_t *) 0xfb0006fc; - -	udelay(30); - -	* (volatile int32_t *) 0xfb0000f0 |= 0x2; - -	return PCIBIOS_SUCCESSFUL; -} - -static int titan_ht_config_read(struct pci_bus *bus, unsigned int devfn, -	int offset, int size, u32 *val) -{ -	uint32_t dword; - -	titan_ht_config_read_dword(bus, devfn, offset, &dword); - -	dword >>= ((offset & 3) << 3); -	dword &= (0xffffffffU >> ((4 - size) << 8)); - -	return PCIBIOS_SUCCESSFUL; -} - -static inline int titan_ht_config_write_dword(struct pci_bus *bus, -	unsigned int devfn, int offset, u32 val) -{ -	volatile uint32_t address; -	int busno; - -	busno = bus->number; - -	address = (busno << 16) | (devfn << 8) | (offset & 0xfc) | 0x80000000; -	if (busno != 0) -		address |= 1; - -	*(volatile int32_t *) 0xfb0000f0 |= 0x2; - -	udelay(30); - -	*(volatile int32_t *) 0xfb0006f8 = address; -	*(volatile int32_t *) 0xfb0006fc = val; - -	udelay(30); - -	*(volatile int32_t *) 0xfb0000f0 |= 0x2; - -	return PCIBIOS_SUCCESSFUL; -} - -static int titan_ht_config_write(struct pci_bus *bus, unsigned int devfn, -	int offset, int size, u32 val) -{ -	uint32_t val1, val2, mask; - -	titan_ht_config_read_dword(bus, devfn, offset, &val2); - -	val1 = val << ((offset & 3) << 3); -	mask = ~(0xffffffffU >> ((4 - size) << 8)); -	val2 &= ~(mask << ((offset & 3) << 8)); - -	titan_ht_config_write_dword(bus, devfn, offset, val1 | val2); - -	return PCIBIOS_SUCCESSFUL; -} - -struct pci_ops titan_ht_pci_ops = { -	.read	= titan_ht_config_read, -	.write	= titan_ht_config_write, -}; diff --git a/arch/mips/pci/ops-titan.c b/arch/mips/pci/ops-titan.c deleted file mode 100644 index ebf8fc40e9b..00000000000 --- a/arch/mips/pci/ops-titan.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2003 PMC-Sierra - * Author: Manish Lachwani (lachwani@pmc-sierra.com) - * - *  This program is free software; you can redistribute	 it and/or modify it - *  under  the terms of	 the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the	License, or (at your - *  option) any later version. - * - *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED - *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF - *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN - *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT, - *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF - *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT - *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *  You should have received a copy of the  GNU General Public License along - *  with this program; if not, write  to the Free Software Foundation, Inc., - *  675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kernel.h> - -#include <asm/pci.h> -#include <asm/io.h> -#include <asm/rm9k-ocd.h> - -/* - * PCI specific defines - */ -#define	TITAN_PCI_0_CONFIG_ADDRESS	0x780 -#define	TITAN_PCI_0_CONFIG_DATA		0x784 - -/* - * Titan PCI Config Read Byte - */ -static int titan_read_config(struct pci_bus *bus, unsigned int devfn, int reg, -	int size, u32 * val) -{ -	uint32_t address, tmp; -	int dev, busno, func; - -	busno = bus->number; -	dev = PCI_SLOT(devfn); -	func = PCI_FUNC(devfn); - -	address = (busno << 16) | (dev << 11) | (func << 8) | -	          (reg & 0xfc) | 0x80000000; - - -	/* start the configuration cycle */ -	ocd_writel(address, TITAN_PCI_0_CONFIG_ADDRESS); -	tmp = ocd_readl(TITAN_PCI_0_CONFIG_DATA) >> ((reg & 3) << 3); - -	switch (size) { -	case 1: -		tmp &= 0xff; -	case 2: -		tmp &= 0xffff; -	} -	*val = tmp; - -	return PCIBIOS_SUCCESSFUL; -} - -static int titan_write_config(struct pci_bus *bus, unsigned int devfn, int reg, -	int size, u32 val) -{ -	uint32_t address; -	int dev, busno, func; - -	busno = bus->number; -	dev = PCI_SLOT(devfn); -	func = PCI_FUNC(devfn); - -	address = (busno << 16) | (dev << 11) | (func << 8) | -		(reg & 0xfc) | 0x80000000; - -	/* start the configuration cycle */ -	ocd_writel(address, TITAN_PCI_0_CONFIG_ADDRESS); - -	/* write the data */ -	switch (size) { -	case 1: -		ocd_writeb(val, TITAN_PCI_0_CONFIG_DATA + (~reg & 0x3)); -		break; - -	case 2: -		ocd_writew(val, TITAN_PCI_0_CONFIG_DATA + (~reg & 0x2)); -		break; - -	case 4: -		ocd_writel(val, TITAN_PCI_0_CONFIG_DATA); -		break; -	} - -	return PCIBIOS_SUCCESSFUL; -} - -/* - * Titan PCI structure - */ -struct pci_ops titan_pci_ops = { -	titan_read_config, -	titan_write_config, -}; diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c index 6a3bdb5ffa8..d35dc9c9ab9 100644 --- a/arch/mips/pci/ops-tx3927.c +++ b/arch/mips/pci/ops-tx3927.c @@ -11,7 +11,7 @@   *     Define the pci_ops for TX3927.   *   * Much of the code is derived from the original DDB5074 port by - * Geert Uytterhoeven <geert@sonycom.com> + * Geert Uytterhoeven <geert@linux-m68k.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 @@ -225,7 +225,7 @@ void __init tx3927_setup_pcierr_irq(void)  {  	if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI,  			tx3927_pcierr_interrupt, -			IRQF_DISABLED, "PCI error", +			0, "PCI error",  			(void *)TX3927_PCIC_REG))  		printk(KERN_WARNING "Failed to request irq for PCIERR\n");  } diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c index a1e7e6d80c8..0e046d82e4e 100644 --- a/arch/mips/pci/ops-tx4927.c +++ b/arch/mips/pci/ops-tx4927.c @@ -2,16 +2,16 @@   * Define the pci_ops for the PCIC on Toshiba TX4927, TX4938, etc.   *   * Based on linux/arch/mips/pci/ops-tx4938.c, - *          linux/arch/mips/pci/fixup-rbtx4938.c, - *          linux/arch/mips/txx9/rbtx4938/setup.c, + *	    linux/arch/mips/pci/fixup-rbtx4938.c, + *	    linux/arch/mips/txx9/rbtx4938/setup.c,   *	    and RBTX49xx patch from CELF patch archive.   *   * 2003-2005 (c) MontaVista Software, Inc.   * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)   * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-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 + * 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.   */ @@ -191,28 +191,31 @@ static struct {  	u8 trdyto;  	u8 retryto;  	u16 gbwc; -} tx4927_pci_opts __devinitdata = { +} tx4927_pci_opts = {  	.trdyto = 0,  	.retryto = 0,  	.gbwc = 0xfe0,	/* 4064 GBUSCLK for CCFG.GTOT=0b11 */  }; -char *__devinit tx4927_pcibios_setup(char *str) +char *tx4927_pcibios_setup(char *str)  {  	unsigned long val;  	if (!strncmp(str, "trdyto=", 7)) { -		if (strict_strtoul(str + 7, 0, &val) == 0) +		u8 val = 0; +		if (kstrtou8(str + 7, 0, &val) == 0)  			tx4927_pci_opts.trdyto = val;  		return NULL;  	}  	if (!strncmp(str, "retryto=", 8)) { -		if (strict_strtoul(str + 8, 0, &val) == 0) +		u8 val = 0; +		if (kstrtou8(str + 8, 0, &val) == 0)  			tx4927_pci_opts.retryto = val;  		return NULL;  	}  	if (!strncmp(str, "gbwc=", 5)) { -		if (strict_strtoul(str + 5, 0, &val) == 0) +		u16 val; +		if (kstrtou16(str + 5, 0, &val) == 0)  			tx4927_pci_opts.gbwc = val;  		return NULL;  	} @@ -495,7 +498,7 @@ irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id)  }  #ifdef CONFIG_TOSHIBA_FPCIB0 -static void __init tx4927_quirk_slc90e66_bridge(struct pci_dev *dev) +static void tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)  {  	struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(dev->bus); diff --git a/arch/mips/pci/ops-vr41xx.c b/arch/mips/pci/ops-vr41xx.c index 28962a7c660..551128c7d92 100644 --- a/arch/mips/pci/ops-vr41xx.c +++ b/arch/mips/pci/ops-vr41xx.c @@ -33,7 +33,7 @@  #define PCICONFAREG	(void __iomem *)KSEG1ADDR(0x0f000c18)  static inline int set_pci_configuration_address(unsigned char number, -                                                unsigned int devfn, int where) +						unsigned int devfn, int where)  {  	if (number == 0) {  		/* @@ -59,7 +59,7 @@ static inline int set_pci_configuration_address(unsigned char number,  }  static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, -                           int size, uint32_t *val) +			   int size, uint32_t *val)  {  	uint32_t data; @@ -87,7 +87,7 @@ static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,  }  static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, -                            int size, uint32_t val) +			    int size, uint32_t val)  {  	uint32_t data;  	int shift; diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c new file mode 100644 index 00000000000..563d1f61d6e --- /dev/null +++ b/arch/mips/pci/pci-alchemy.c @@ -0,0 +1,514 @@ +/* + * Alchemy PCI host mode support. + * + * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. + * Author: MontaVista Software, Inc. <source@mvista.com> + * + * Support for all devices (greater than 16) added by David Gathright. + */ + +#include <linux/export.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/syscore_ops.h> +#include <linux/vmalloc.h> + +#include <asm/dma-coherence.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/tlbmisc.h> + +#ifdef CONFIG_PCI_DEBUG +#define DBG(x...) printk(KERN_DEBUG x) +#else +#define DBG(x...) do {} while (0) +#endif + +#define PCI_ACCESS_READ		0 +#define PCI_ACCESS_WRITE	1 + +struct alchemy_pci_context { +	struct pci_controller alchemy_pci_ctrl; /* leave as first member! */ +	void __iomem *regs;			/* ctrl base */ +	/* tools for wired entry for config space access */ +	unsigned long last_elo0; +	unsigned long last_elo1; +	int wired_entry; +	struct vm_struct *pci_cfg_vm; + +	unsigned long pm[12]; + +	int (*board_map_irq)(const struct pci_dev *d, u8 slot, u8 pin); +	int (*board_pci_idsel)(unsigned int devsel, int assert); +}; + +/* for syscore_ops. There's only one PCI controller on Alchemy chips, so this + * should suffice for now. + */ +static struct alchemy_pci_context *__alchemy_pci_ctx; + + +/* IO/MEM resources for PCI. Keep the memres in sync with __fixup_bigphys_addr + * in arch/mips/alchemy/common/setup.c + */ +static struct resource alchemy_pci_def_memres = { +	.start	= ALCHEMY_PCI_MEMWIN_START, +	.end	= ALCHEMY_PCI_MEMWIN_END, +	.name	= "PCI memory space", +	.flags	= IORESOURCE_MEM +}; + +static struct resource alchemy_pci_def_iores = { +	.start	= ALCHEMY_PCI_IOWIN_START, +	.end	= ALCHEMY_PCI_IOWIN_END, +	.name	= "PCI IO space", +	.flags	= IORESOURCE_IO +}; + +static void mod_wired_entry(int entry, unsigned long entrylo0, +		unsigned long entrylo1, unsigned long entryhi, +		unsigned long pagemask) +{ +	unsigned long old_pagemask; +	unsigned long old_ctx; + +	/* Save old context and create impossible VPN2 value */ +	old_ctx = read_c0_entryhi() & 0xff; +	old_pagemask = read_c0_pagemask(); +	write_c0_index(entry); +	write_c0_pagemask(pagemask); +	write_c0_entryhi(entryhi); +	write_c0_entrylo0(entrylo0); +	write_c0_entrylo1(entrylo1); +	tlb_write_indexed(); +	write_c0_entryhi(old_ctx); +	write_c0_pagemask(old_pagemask); +} + +static void alchemy_pci_wired_entry(struct alchemy_pci_context *ctx) +{ +	ctx->wired_entry = read_c0_wired(); +	add_wired_entry(0, 0, (unsigned long)ctx->pci_cfg_vm->addr, PM_4K); +	ctx->last_elo0 = ctx->last_elo1 = ~0; +} + +static int config_access(unsigned char access_type, struct pci_bus *bus, +			 unsigned int dev_fn, unsigned char where, u32 *data) +{ +	struct alchemy_pci_context *ctx = bus->sysdata; +	unsigned int device = PCI_SLOT(dev_fn); +	unsigned int function = PCI_FUNC(dev_fn); +	unsigned long offset, status, cfg_base, flags, entryLo0, entryLo1, r; +	int error = PCIBIOS_SUCCESSFUL; + +	if (device > 19) { +		*data = 0xffffffff; +		return -1; +	} + +	local_irq_save(flags); +	r = __raw_readl(ctx->regs + PCI_REG_STATCMD) & 0x0000ffff; +	r |= PCI_STATCMD_STATUS(0x2000); +	__raw_writel(r, ctx->regs + PCI_REG_STATCMD); +	wmb(); + +	/* Allow board vendors to implement their own off-chip IDSEL. +	 * If it doesn't succeed, may as well bail out at this point. +	 */ +	if (ctx->board_pci_idsel(device, 1) == 0) { +		*data = 0xffffffff; +		local_irq_restore(flags); +		return -1; +	} + +	/* Setup the config window */ +	if (bus->number == 0) +		cfg_base = (1 << device) << 11; +	else +		cfg_base = 0x80000000 | (bus->number << 16) | (device << 11); + +	/* Setup the lower bits of the 36-bit address */ +	offset = (function << 8) | (where & ~0x3); +	/* Pick up any address that falls below the page mask */ +	offset |= cfg_base & ~PAGE_MASK; + +	/* Page boundary */ +	cfg_base = cfg_base & PAGE_MASK; + +	/* To improve performance, if the current device is the same as +	 * the last device accessed, we don't touch the TLB. +	 */ +	entryLo0 = (6 << 26) | (cfg_base >> 6) | (2 << 3) | 7; +	entryLo1 = (6 << 26) | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7; +	if ((entryLo0 != ctx->last_elo0) || (entryLo1 != ctx->last_elo1)) { +		mod_wired_entry(ctx->wired_entry, entryLo0, entryLo1, +				(unsigned long)ctx->pci_cfg_vm->addr, PM_4K); +		ctx->last_elo0 = entryLo0; +		ctx->last_elo1 = entryLo1; +	} + +	if (access_type == PCI_ACCESS_WRITE) +		__raw_writel(*data, ctx->pci_cfg_vm->addr + offset); +	else +		*data = __raw_readl(ctx->pci_cfg_vm->addr + offset); +	wmb(); + +	DBG("alchemy-pci: cfg access %d bus %u dev %u at %x dat %x conf %lx\n", +	    access_type, bus->number, device, where, *data, offset); + +	/* check for errors, master abort */ +	status = __raw_readl(ctx->regs + PCI_REG_STATCMD); +	if (status & (1 << 29)) { +		*data = 0xffffffff; +		error = -1; +		DBG("alchemy-pci: master abort on cfg access %d bus %d dev %d\n", +		    access_type, bus->number, device); +	} else if ((status >> 28) & 0xf) { +		DBG("alchemy-pci: PCI ERR detected: dev %d, status %lx\n", +		    device, (status >> 28) & 0xf); + +		/* clear errors */ +		__raw_writel(status & 0xf000ffff, ctx->regs + PCI_REG_STATCMD); + +		*data = 0xffffffff; +		error = -1; +	} + +	/* Take away the IDSEL. */ +	(void)ctx->board_pci_idsel(device, 0); + +	local_irq_restore(flags); +	return error; +} + +static int read_config_byte(struct pci_bus *bus, unsigned int devfn, +			    int where,	u8 *val) +{ +	u32 data; +	int ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); + +	if (where & 1) +		data >>= 8; +	if (where & 2) +		data >>= 16; +	*val = data & 0xff; +	return ret; +} + +static int read_config_word(struct pci_bus *bus, unsigned int devfn, +			    int where, u16 *val) +{ +	u32 data; +	int ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); + +	if (where & 2) +		data >>= 16; +	*val = data & 0xffff; +	return ret; +} + +static int read_config_dword(struct pci_bus *bus, unsigned int devfn, +			     int where, u32 *val) +{ +	return config_access(PCI_ACCESS_READ, bus, devfn, where, val); +} + +static int write_config_byte(struct pci_bus *bus, unsigned int devfn, +			     int where, u8 val) +{ +	u32 data = 0; + +	if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) +		return -1; + +	data = (data & ~(0xff << ((where & 3) << 3))) | +	       (val << ((where & 3) << 3)); + +	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) +		return -1; + +	return PCIBIOS_SUCCESSFUL; +} + +static int write_config_word(struct pci_bus *bus, unsigned int devfn, +			     int where, u16 val) +{ +	u32 data = 0; + +	if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) +		return -1; + +	data = (data & ~(0xffff << ((where & 3) << 3))) | +	       (val << ((where & 3) << 3)); + +	if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) +		return -1; + +	return PCIBIOS_SUCCESSFUL; +} + +static int write_config_dword(struct pci_bus *bus, unsigned int devfn, +			      int where, u32 val) +{ +	return config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val); +} + +static int alchemy_pci_read(struct pci_bus *bus, unsigned int devfn, +		       int where, int size, u32 *val) +{ +	switch (size) { +	case 1: { +			u8 _val; +			int rc = read_config_byte(bus, devfn, where, &_val); + +			*val = _val; +			return rc; +		} +	case 2: { +			u16 _val; +			int rc = read_config_word(bus, devfn, where, &_val); + +			*val = _val; +			return rc; +		} +	default: +		return read_config_dword(bus, devfn, where, val); +	} +} + +static int alchemy_pci_write(struct pci_bus *bus, unsigned int devfn, +			     int where, int size, u32 val) +{ +	switch (size) { +	case 1: +		return write_config_byte(bus, devfn, where, (u8) val); +	case 2: +		return write_config_word(bus, devfn, where, (u16) val); +	default: +		return write_config_dword(bus, devfn, where, val); +	} +} + +static struct pci_ops alchemy_pci_ops = { +	.read	= alchemy_pci_read, +	.write	= alchemy_pci_write, +}; + +static int alchemy_pci_def_idsel(unsigned int devsel, int assert) +{ +	return 1;	/* success */ +} + +/* save PCI controller register contents. */ +static int alchemy_pci_suspend(void) +{ +	struct alchemy_pci_context *ctx = __alchemy_pci_ctx; +	if (!ctx) +		return 0; + +	ctx->pm[0]  = __raw_readl(ctx->regs + PCI_REG_CMEM); +	ctx->pm[1]  = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff; +	ctx->pm[2]  = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH); +	ctx->pm[3]  = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID); +	ctx->pm[4]  = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID); +	ctx->pm[5]  = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV); +	ctx->pm[6]  = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL); +	ctx->pm[7]  = __raw_readl(ctx->regs + PCI_REG_ID); +	ctx->pm[8]  = __raw_readl(ctx->regs + PCI_REG_CLASSREV); +	ctx->pm[9]  = __raw_readl(ctx->regs + PCI_REG_PARAM); +	ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR); +	ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT); + +	return 0; +} + +static void alchemy_pci_resume(void) +{ +	struct alchemy_pci_context *ctx = __alchemy_pci_ctx; +	if (!ctx) +		return; + +	__raw_writel(ctx->pm[0],  ctx->regs + PCI_REG_CMEM); +	__raw_writel(ctx->pm[2],  ctx->regs + PCI_REG_B2BMASK_CCH); +	__raw_writel(ctx->pm[3],  ctx->regs + PCI_REG_B2BBASE0_VID); +	__raw_writel(ctx->pm[4],  ctx->regs + PCI_REG_B2BBASE1_SID); +	__raw_writel(ctx->pm[5],  ctx->regs + PCI_REG_MWMASK_DEV); +	__raw_writel(ctx->pm[6],  ctx->regs + PCI_REG_MWBASE_REV_CCL); +	__raw_writel(ctx->pm[7],  ctx->regs + PCI_REG_ID); +	__raw_writel(ctx->pm[8],  ctx->regs + PCI_REG_CLASSREV); +	__raw_writel(ctx->pm[9],  ctx->regs + PCI_REG_PARAM); +	__raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR); +	__raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT); +	wmb(); +	__raw_writel(ctx->pm[1],  ctx->regs + PCI_REG_CONFIG); +	wmb(); + +	/* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired +	 * on resume, making it necessary to recreate it as soon as possible. +	 */ +	ctx->wired_entry = 8191;	/* impossibly high value */ +	alchemy_pci_wired_entry(ctx);	/* install it */ +} + +static struct syscore_ops alchemy_pci_pmops = { +	.suspend	= alchemy_pci_suspend, +	.resume		= alchemy_pci_resume, +}; + +static int alchemy_pci_probe(struct platform_device *pdev) +{ +	struct alchemy_pci_platdata *pd = pdev->dev.platform_data; +	struct alchemy_pci_context *ctx; +	void __iomem *virt_io; +	unsigned long val; +	struct resource *r; +	int ret; + +	/* need at least PCI IRQ mapping table */ +	if (!pd) { +		dev_err(&pdev->dev, "need platform data for PCI setup\n"); +		ret = -ENODEV; +		goto out; +	} + +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); +	if (!ctx) { +		dev_err(&pdev->dev, "no memory for pcictl context\n"); +		ret = -ENOMEM; +		goto out; +	} + +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!r) { +		dev_err(&pdev->dev, "no	 pcictl ctrl regs resource\n"); +		ret = -ENODEV; +		goto out1; +	} + +	if (!request_mem_region(r->start, resource_size(r), pdev->name)) { +		dev_err(&pdev->dev, "cannot claim pci regs\n"); +		ret = -ENODEV; +		goto out1; +	} + +	ctx->regs = ioremap_nocache(r->start, resource_size(r)); +	if (!ctx->regs) { +		dev_err(&pdev->dev, "cannot map pci regs\n"); +		ret = -ENODEV; +		goto out2; +	} + +	/* map parts of the PCI IO area */ +	/* REVISIT: if this changes with a newer variant (doubt it) make this +	 * a platform resource. +	 */ +	virt_io = ioremap(AU1500_PCI_IO_PHYS_ADDR, 0x00100000); +	if (!virt_io) { +		dev_err(&pdev->dev, "cannot remap pci io space\n"); +		ret = -ENODEV; +		goto out3; +	} +	ctx->alchemy_pci_ctrl.io_map_base = (unsigned long)virt_io; + +	/* Au1500 revisions older than AD have borked coherent PCI */ +	if ((alchemy_get_cputype() == ALCHEMY_CPU_AU1500) && +	    (read_c0_prid() < 0x01030202) && !coherentio) { +		val = __raw_readl(ctx->regs + PCI_REG_CONFIG); +		val |= PCI_CONFIG_NC; +		__raw_writel(val, ctx->regs + PCI_REG_CONFIG); +		wmb(); +		dev_info(&pdev->dev, "non-coherent PCI on Au1500 AA/AB/AC\n"); +	} + +	if (pd->board_map_irq) +		ctx->board_map_irq = pd->board_map_irq; + +	if (pd->board_pci_idsel) +		ctx->board_pci_idsel = pd->board_pci_idsel; +	else +		ctx->board_pci_idsel = alchemy_pci_def_idsel; + +	/* fill in relevant pci_controller members */ +	ctx->alchemy_pci_ctrl.pci_ops = &alchemy_pci_ops; +	ctx->alchemy_pci_ctrl.mem_resource = &alchemy_pci_def_memres; +	ctx->alchemy_pci_ctrl.io_resource = &alchemy_pci_def_iores; + +	/* we can't ioremap the entire pci config space because it's too large, +	 * nor can we dynamically ioremap it because some drivers use the +	 * PCI config routines from within atomic contex and that becomes a +	 * problem in get_vm_area().  Instead we use one wired TLB entry to +	 * handle all config accesses for all busses. +	 */ +	ctx->pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); +	if (!ctx->pci_cfg_vm) { +		dev_err(&pdev->dev, "unable to get vm area\n"); +		ret = -ENOMEM; +		goto out4; +	} +	ctx->wired_entry = 8191;	/* impossibly high value */ +	alchemy_pci_wired_entry(ctx);	/* install it */ + +	set_io_port_base((unsigned long)ctx->alchemy_pci_ctrl.io_map_base); + +	/* board may want to modify bits in the config register, do it now */ +	val = __raw_readl(ctx->regs + PCI_REG_CONFIG); +	val &= ~pd->pci_cfg_clr; +	val |= pd->pci_cfg_set; +	val &= ~PCI_CONFIG_PD;		/* clear disable bit */ +	__raw_writel(val, ctx->regs + PCI_REG_CONFIG); +	wmb(); + +	__alchemy_pci_ctx = ctx; +	platform_set_drvdata(pdev, ctx); +	register_syscore_ops(&alchemy_pci_pmops); +	register_pci_controller(&ctx->alchemy_pci_ctrl); + +	return 0; + +out4: +	iounmap(virt_io); +out3: +	iounmap(ctx->regs); +out2: +	release_mem_region(r->start, resource_size(r)); +out1: +	kfree(ctx); +out: +	return ret; +} + +static struct platform_driver alchemy_pcictl_driver = { +	.probe		= alchemy_pci_probe, +	.driver = { +		.name	= "alchemy-pci", +		.owner	= THIS_MODULE, +	}, +}; + +static int __init alchemy_pci_init(void) +{ +	/* Au1500/Au1550 have PCI */ +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1500: +	case ALCHEMY_CPU_AU1550: +		return platform_driver_register(&alchemy_pcictl_driver); +	} +	return 0; +} +arch_initcall(alchemy_pci_init); + + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	struct alchemy_pci_context *ctx = dev->sysdata; +	if (ctx && ctx->board_map_irq) +		return ctx->board_map_irq(dev, slot, pin); +	return -1; +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	return 0; +} diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c new file mode 100644 index 00000000000..d471a26dd5f --- /dev/null +++ b/arch/mips/pci/pci-ar71xx.c @@ -0,0 +1,428 @@ +/* + *  Atheros AR71xx PCI host controller driver + * + *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + *  Parts of this file are based on Atheros' 2.6.15 BSP + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + */ + +#include <linux/resource.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/bitops.h> +#include <linux/pci.h> +#include <linux/pci_regs.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <asm/mach-ath79/ar71xx_regs.h> +#include <asm/mach-ath79/ath79.h> + +#define AR71XX_PCI_REG_CRP_AD_CBE	0x00 +#define AR71XX_PCI_REG_CRP_WRDATA	0x04 +#define AR71XX_PCI_REG_CRP_RDDATA	0x08 +#define AR71XX_PCI_REG_CFG_AD		0x0c +#define AR71XX_PCI_REG_CFG_CBE		0x10 +#define AR71XX_PCI_REG_CFG_WRDATA	0x14 +#define AR71XX_PCI_REG_CFG_RDDATA	0x18 +#define AR71XX_PCI_REG_PCI_ERR		0x1c +#define AR71XX_PCI_REG_PCI_ERR_ADDR	0x20 +#define AR71XX_PCI_REG_AHB_ERR		0x24 +#define AR71XX_PCI_REG_AHB_ERR_ADDR	0x28 + +#define AR71XX_PCI_CRP_CMD_WRITE	0x00010000 +#define AR71XX_PCI_CRP_CMD_READ		0x00000000 +#define AR71XX_PCI_CFG_CMD_READ		0x0000000a +#define AR71XX_PCI_CFG_CMD_WRITE	0x0000000b + +#define AR71XX_PCI_INT_CORE		BIT(4) +#define AR71XX_PCI_INT_DEV2		BIT(2) +#define AR71XX_PCI_INT_DEV1		BIT(1) +#define AR71XX_PCI_INT_DEV0		BIT(0) + +#define AR71XX_PCI_IRQ_COUNT		5 + +struct ar71xx_pci_controller { +	void __iomem *cfg_base; +	spinlock_t lock; +	int irq; +	int irq_base; +	struct pci_controller pci_ctrl; +	struct resource io_res; +	struct resource mem_res; +}; + +/* Byte lane enable bits */ +static const u8 ar71xx_pci_ble_table[4][4] = { +	{0x0, 0xf, 0xf, 0xf}, +	{0xe, 0xd, 0xb, 0x7}, +	{0xc, 0xf, 0x3, 0xf}, +	{0xf, 0xf, 0xf, 0xf}, +}; + +static const u32 ar71xx_pci_read_mask[8] = { +	0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0 +}; + +static inline u32 ar71xx_pci_get_ble(int where, int size, int local) +{ +	u32 t; + +	t = ar71xx_pci_ble_table[size & 3][where & 3]; +	BUG_ON(t == 0xf); +	t <<= (local) ? 20 : 4; + +	return t; +} + +static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn, +				      int where) +{ +	u32 ret; + +	if (!bus->number) { +		/* type 0 */ +		ret = (1 << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) | +		      (where & ~3); +	} else { +		/* type 1 */ +		ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11) | +		      (PCI_FUNC(devfn) << 8) | (where & ~3) | 1; +	} + +	return ret; +} + +static inline struct ar71xx_pci_controller * +pci_bus_to_ar71xx_controller(struct pci_bus *bus) +{ +	struct pci_controller *hose; + +	hose = (struct pci_controller *) bus->sysdata; +	return container_of(hose, struct ar71xx_pci_controller, pci_ctrl); +} + +static int ar71xx_pci_check_error(struct ar71xx_pci_controller *apc, int quiet) +{ +	void __iomem *base = apc->cfg_base; +	u32 pci_err; +	u32 ahb_err; + +	pci_err = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR) & 3; +	if (pci_err) { +		if (!quiet) { +			u32 addr; + +			addr = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR_ADDR); +			pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", +				"PCI", pci_err, addr); +		} + +		/* clear PCI error status */ +		__raw_writel(pci_err, base + AR71XX_PCI_REG_PCI_ERR); +	} + +	ahb_err = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR) & 1; +	if (ahb_err) { +		if (!quiet) { +			u32 addr; + +			addr = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR_ADDR); +			pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", +				"AHB", ahb_err, addr); +		} + +		/* clear AHB error status */ +		__raw_writel(ahb_err, base + AR71XX_PCI_REG_AHB_ERR); +	} + +	return !!(ahb_err | pci_err); +} + +static inline void ar71xx_pci_local_write(struct ar71xx_pci_controller *apc, +					  int where, int size, u32 value) +{ +	void __iomem *base = apc->cfg_base; +	u32 ad_cbe; + +	value = value << (8 * (where & 3)); + +	ad_cbe = AR71XX_PCI_CRP_CMD_WRITE | (where & ~3); +	ad_cbe |= ar71xx_pci_get_ble(where, size, 1); + +	__raw_writel(ad_cbe, base + AR71XX_PCI_REG_CRP_AD_CBE); +	__raw_writel(value, base + AR71XX_PCI_REG_CRP_WRDATA); +} + +static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, +					 unsigned int devfn, +					 int where, int size, u32 cmd) +{ +	struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); +	void __iomem *base = apc->cfg_base; +	u32 addr; + +	addr = ar71xx_pci_bus_addr(bus, devfn, where); + +	__raw_writel(addr, base + AR71XX_PCI_REG_CFG_AD); +	__raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0), +		     base + AR71XX_PCI_REG_CFG_CBE); + +	return ar71xx_pci_check_error(apc, 1); +} + +static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, +				  int where, int size, u32 *value) +{ +	struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); +	void __iomem *base = apc->cfg_base; +	unsigned long flags; +	u32 data; +	int err; +	int ret; + +	ret = PCIBIOS_SUCCESSFUL; +	data = ~0; + +	spin_lock_irqsave(&apc->lock, flags); + +	err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, +				     AR71XX_PCI_CFG_CMD_READ); +	if (err) +		ret = PCIBIOS_DEVICE_NOT_FOUND; +	else +		data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); + +	spin_unlock_irqrestore(&apc->lock, flags); + +	*value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; + +	return ret; +} + +static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, +				   int where, int size, u32 value) +{ +	struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); +	void __iomem *base = apc->cfg_base; +	unsigned long flags; +	int err; +	int ret; + +	value = value << (8 * (where & 3)); +	ret = PCIBIOS_SUCCESSFUL; + +	spin_lock_irqsave(&apc->lock, flags); + +	err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, +				     AR71XX_PCI_CFG_CMD_WRITE); +	if (err) +		ret = PCIBIOS_DEVICE_NOT_FOUND; +	else +		__raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); + +	spin_unlock_irqrestore(&apc->lock, flags); + +	return ret; +} + +static struct pci_ops ar71xx_pci_ops = { +	.read	= ar71xx_pci_read_config, +	.write	= ar71xx_pci_write_config, +}; + +static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) +{ +	struct ar71xx_pci_controller *apc; +	void __iomem *base = ath79_reset_base; +	u32 pending; + +	apc = irq_get_handler_data(irq); + +	pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) & +		  __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); + +	if (pending & AR71XX_PCI_INT_DEV0) +		generic_handle_irq(apc->irq_base + 0); + +	else if (pending & AR71XX_PCI_INT_DEV1) +		generic_handle_irq(apc->irq_base + 1); + +	else if (pending & AR71XX_PCI_INT_DEV2) +		generic_handle_irq(apc->irq_base + 2); + +	else if (pending & AR71XX_PCI_INT_CORE) +		generic_handle_irq(apc->irq_base + 4); + +	else +		spurious_interrupt(); +} + +static void ar71xx_pci_irq_unmask(struct irq_data *d) +{ +	struct ar71xx_pci_controller *apc; +	unsigned int irq; +	void __iomem *base = ath79_reset_base; +	u32 t; + +	apc = irq_data_get_irq_chip_data(d); +	irq = d->irq - apc->irq_base; + +	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); +	__raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); + +	/* flush write */ +	__raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); +} + +static void ar71xx_pci_irq_mask(struct irq_data *d) +{ +	struct ar71xx_pci_controller *apc; +	unsigned int irq; +	void __iomem *base = ath79_reset_base; +	u32 t; + +	apc = irq_data_get_irq_chip_data(d); +	irq = d->irq - apc->irq_base; + +	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); +	__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); + +	/* flush write */ +	__raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); +} + +static struct irq_chip ar71xx_pci_irq_chip = { +	.name		= "AR71XX PCI", +	.irq_mask	= ar71xx_pci_irq_mask, +	.irq_unmask	= ar71xx_pci_irq_unmask, +	.irq_mask_ack	= ar71xx_pci_irq_mask, +}; + +static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) +{ +	void __iomem *base = ath79_reset_base; +	int i; + +	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE); +	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS); + +	BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT); + +	apc->irq_base = ATH79_PCI_IRQ_BASE; +	for (i = apc->irq_base; +	     i < apc->irq_base + AR71XX_PCI_IRQ_COUNT; i++) { +		irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, +					 handle_level_irq); +		irq_set_chip_data(i, apc); +	} + +	irq_set_handler_data(apc->irq, apc); +	irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); +} + +static void ar71xx_pci_reset(void) +{ +	void __iomem *ddr_base = ath79_ddr_base; + +	ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); +	mdelay(100); + +	ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); +	mdelay(100); + +	__raw_writel(AR71XX_PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0); +	__raw_writel(AR71XX_PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1); +	__raw_writel(AR71XX_PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2); +	__raw_writel(AR71XX_PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3); +	__raw_writel(AR71XX_PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4); +	__raw_writel(AR71XX_PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5); +	__raw_writel(AR71XX_PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6); +	__raw_writel(AR71XX_PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7); + +	mdelay(100); +} + +static int ar71xx_pci_probe(struct platform_device *pdev) +{ +	struct ar71xx_pci_controller *apc; +	struct resource *res; +	u32 t; + +	apc = devm_kzalloc(&pdev->dev, sizeof(struct ar71xx_pci_controller), +			   GFP_KERNEL); +	if (!apc) +		return -ENOMEM; + +	spin_lock_init(&apc->lock); + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); +	apc->cfg_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(apc->cfg_base)) +		return PTR_ERR(apc->cfg_base); + +	apc->irq = platform_get_irq(pdev, 0); +	if (apc->irq < 0) +		return -EINVAL; + +	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); +	if (!res) +		return -EINVAL; + +	apc->io_res.parent = res; +	apc->io_res.name = "PCI IO space"; +	apc->io_res.start = res->start; +	apc->io_res.end = res->end; +	apc->io_res.flags = IORESOURCE_IO; + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base"); +	if (!res) +		return -EINVAL; + +	apc->mem_res.parent = res; +	apc->mem_res.name = "PCI memory space"; +	apc->mem_res.start = res->start; +	apc->mem_res.end = res->end; +	apc->mem_res.flags = IORESOURCE_MEM; + +	ar71xx_pci_reset(); + +	/* setup COMMAND register */ +	t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE +	  | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; +	ar71xx_pci_local_write(apc, PCI_COMMAND, 4, t); + +	/* clear bus errors */ +	ar71xx_pci_check_error(apc, 1); + +	ar71xx_pci_irq_init(apc); + +	apc->pci_ctrl.pci_ops = &ar71xx_pci_ops; +	apc->pci_ctrl.mem_resource = &apc->mem_res; +	apc->pci_ctrl.io_resource = &apc->io_res; + +	register_pci_controller(&apc->pci_ctrl); + +	return 0; +} + +static struct platform_driver ar71xx_pci_driver = { +	.probe = ar71xx_pci_probe, +	.driver = { +		.name = "ar71xx-pci", +		.owner = THIS_MODULE, +	}, +}; + +static int __init ar71xx_pci_init(void) +{ +	return platform_driver_register(&ar71xx_pci_driver); +} + +postcore_initcall(ar71xx_pci_init); diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c new file mode 100644 index 00000000000..785b2659b51 --- /dev/null +++ b/arch/mips/pci/pci-ar724x.c @@ -0,0 +1,435 @@ +/* + *  Atheros AR724X PCI host controller driver + * + *  Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com> + *  Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + */ + +#include <linux/spinlock.h> +#include <linux/irq.h> +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <asm/mach-ath79/ath79.h> +#include <asm/mach-ath79/ar71xx_regs.h> + +#define AR724X_PCI_REG_RESET		0x18 +#define AR724X_PCI_REG_INT_STATUS	0x4c +#define AR724X_PCI_REG_INT_MASK		0x50 + +#define AR724X_PCI_RESET_LINK_UP	BIT(0) + +#define AR724X_PCI_INT_DEV0		BIT(14) + +#define AR724X_PCI_IRQ_COUNT		1 + +#define AR7240_BAR0_WAR_VALUE	0xffff + +#define AR724X_PCI_CMD_INIT	(PCI_COMMAND_MEMORY |		\ +				 PCI_COMMAND_MASTER |		\ +				 PCI_COMMAND_INVALIDATE |	\ +				 PCI_COMMAND_PARITY |		\ +				 PCI_COMMAND_SERR |		\ +				 PCI_COMMAND_FAST_BACK) + +struct ar724x_pci_controller { +	void __iomem *devcfg_base; +	void __iomem *ctrl_base; +	void __iomem *crp_base; + +	int irq; +	int irq_base; + +	bool link_up; +	bool bar0_is_cached; +	u32  bar0_value; + +	spinlock_t lock; + +	struct pci_controller pci_controller; +	struct resource io_res; +	struct resource mem_res; +}; + +static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc) +{ +	u32 reset; + +	reset = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_RESET); +	return reset & AR724X_PCI_RESET_LINK_UP; +} + +static inline struct ar724x_pci_controller * +pci_bus_to_ar724x_controller(struct pci_bus *bus) +{ +	struct pci_controller *hose; + +	hose = (struct pci_controller *) bus->sysdata; +	return container_of(hose, struct ar724x_pci_controller, pci_controller); +} + +static int ar724x_pci_local_write(struct ar724x_pci_controller *apc, +				  int where, int size, u32 value) +{ +	unsigned long flags; +	void __iomem *base; +	u32 data; +	int s; + +	WARN_ON(where & (size - 1)); + +	if (!apc->link_up) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	base = apc->crp_base; + +	spin_lock_irqsave(&apc->lock, flags); +	data = __raw_readl(base + (where & ~3)); + +	switch (size) { +	case 1: +		s = ((where & 3) * 8); +		data &= ~(0xff << s); +		data |= ((value & 0xff) << s); +		break; +	case 2: +		s = ((where & 2) * 8); +		data &= ~(0xffff << s); +		data |= ((value & 0xffff) << s); +		break; +	case 4: +		data = value; +		break; +	default: +		spin_unlock_irqrestore(&apc->lock, flags); +		return PCIBIOS_BAD_REGISTER_NUMBER; +	} + +	__raw_writel(data, base + (where & ~3)); +	/* flush write */ +	__raw_readl(base + (where & ~3)); +	spin_unlock_irqrestore(&apc->lock, flags); + +	return PCIBIOS_SUCCESSFUL; +} + +static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, +			    int size, uint32_t *value) +{ +	struct ar724x_pci_controller *apc; +	unsigned long flags; +	void __iomem *base; +	u32 data; + +	apc = pci_bus_to_ar724x_controller(bus); +	if (!apc->link_up) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	if (devfn) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	base = apc->devcfg_base; + +	spin_lock_irqsave(&apc->lock, flags); +	data = __raw_readl(base + (where & ~3)); + +	switch (size) { +	case 1: +		if (where & 1) +			data >>= 8; +		if (where & 2) +			data >>= 16; +		data &= 0xff; +		break; +	case 2: +		if (where & 2) +			data >>= 16; +		data &= 0xffff; +		break; +	case 4: +		break; +	default: +		spin_unlock_irqrestore(&apc->lock, flags); + +		return PCIBIOS_BAD_REGISTER_NUMBER; +	} + +	spin_unlock_irqrestore(&apc->lock, flags); + +	if (where == PCI_BASE_ADDRESS_0 && size == 4 && +	    apc->bar0_is_cached) { +		/* use the cached value */ +		*value = apc->bar0_value; +	} else { +		*value = data; +	} + +	return PCIBIOS_SUCCESSFUL; +} + +static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, +			     int size, uint32_t value) +{ +	struct ar724x_pci_controller *apc; +	unsigned long flags; +	void __iomem *base; +	u32 data; +	int s; + +	apc = pci_bus_to_ar724x_controller(bus); +	if (!apc->link_up) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	if (devfn) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && size == 4) { +		if (value != 0xffffffff) { +			/* +			 * WAR for a hw issue. If the BAR0 register of the +			 * device is set to the proper base address, the +			 * memory space of the device is not accessible. +			 * +			 * Cache the intended value so it can be read back, +			 * and write a SoC specific constant value to the +			 * BAR0 register in order to make the device memory +			 * accessible. +			 */ +			apc->bar0_is_cached = true; +			apc->bar0_value = value; + +			value = AR7240_BAR0_WAR_VALUE; +		} else { +			apc->bar0_is_cached = false; +		} +	} + +	base = apc->devcfg_base; + +	spin_lock_irqsave(&apc->lock, flags); +	data = __raw_readl(base + (where & ~3)); + +	switch (size) { +	case 1: +		s = ((where & 3) * 8); +		data &= ~(0xff << s); +		data |= ((value & 0xff) << s); +		break; +	case 2: +		s = ((where & 2) * 8); +		data &= ~(0xffff << s); +		data |= ((value & 0xffff) << s); +		break; +	case 4: +		data = value; +		break; +	default: +		spin_unlock_irqrestore(&apc->lock, flags); + +		return PCIBIOS_BAD_REGISTER_NUMBER; +	} + +	__raw_writel(data, base + (where & ~3)); +	/* flush write */ +	__raw_readl(base + (where & ~3)); +	spin_unlock_irqrestore(&apc->lock, flags); + +	return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ar724x_pci_ops = { +	.read	= ar724x_pci_read, +	.write	= ar724x_pci_write, +}; + +static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) +{ +	struct ar724x_pci_controller *apc; +	void __iomem *base; +	u32 pending; + +	apc = irq_get_handler_data(irq); +	base = apc->ctrl_base; + +	pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & +		  __raw_readl(base + AR724X_PCI_REG_INT_MASK); + +	if (pending & AR724X_PCI_INT_DEV0) +		generic_handle_irq(apc->irq_base + 0); + +	else +		spurious_interrupt(); +} + +static void ar724x_pci_irq_unmask(struct irq_data *d) +{ +	struct ar724x_pci_controller *apc; +	void __iomem *base; +	int offset; +	u32 t; + +	apc = irq_data_get_irq_chip_data(d); +	base = apc->ctrl_base; +	offset = apc->irq_base - d->irq; + +	switch (offset) { +	case 0: +		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); +		__raw_writel(t | AR724X_PCI_INT_DEV0, +			     base + AR724X_PCI_REG_INT_MASK); +		/* flush write */ +		__raw_readl(base + AR724X_PCI_REG_INT_MASK); +	} +} + +static void ar724x_pci_irq_mask(struct irq_data *d) +{ +	struct ar724x_pci_controller *apc; +	void __iomem *base; +	int offset; +	u32 t; + +	apc = irq_data_get_irq_chip_data(d); +	base = apc->ctrl_base; +	offset = apc->irq_base - d->irq; + +	switch (offset) { +	case 0: +		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); +		__raw_writel(t & ~AR724X_PCI_INT_DEV0, +			     base + AR724X_PCI_REG_INT_MASK); + +		/* flush write */ +		__raw_readl(base + AR724X_PCI_REG_INT_MASK); + +		t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS); +		__raw_writel(t | AR724X_PCI_INT_DEV0, +			     base + AR724X_PCI_REG_INT_STATUS); + +		/* flush write */ +		__raw_readl(base + AR724X_PCI_REG_INT_STATUS); +	} +} + +static struct irq_chip ar724x_pci_irq_chip = { +	.name		= "AR724X PCI ", +	.irq_mask	= ar724x_pci_irq_mask, +	.irq_unmask	= ar724x_pci_irq_unmask, +	.irq_mask_ack	= ar724x_pci_irq_mask, +}; + +static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc, +				int id) +{ +	void __iomem *base; +	int i; + +	base = apc->ctrl_base; + +	__raw_writel(0, base + AR724X_PCI_REG_INT_MASK); +	__raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); + +	apc->irq_base = ATH79_PCI_IRQ_BASE + (id * AR724X_PCI_IRQ_COUNT); + +	for (i = apc->irq_base; +	     i < apc->irq_base + AR724X_PCI_IRQ_COUNT; i++) { +		irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, +					 handle_level_irq); +		irq_set_chip_data(i, apc); +	} + +	irq_set_handler_data(apc->irq, apc); +	irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); +} + +static int ar724x_pci_probe(struct platform_device *pdev) +{ +	struct ar724x_pci_controller *apc; +	struct resource *res; +	int id; + +	id = pdev->id; +	if (id == -1) +		id = 0; + +	apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller), +			    GFP_KERNEL); +	if (!apc) +		return -ENOMEM; + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base"); +	apc->ctrl_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(apc->ctrl_base)) +		return PTR_ERR(apc->ctrl_base); + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); +	apc->devcfg_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(apc->devcfg_base)) +		return PTR_ERR(apc->devcfg_base); + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "crp_base"); +	apc->crp_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(apc->crp_base)) +		return PTR_ERR(apc->crp_base); + +	apc->irq = platform_get_irq(pdev, 0); +	if (apc->irq < 0) +		return -EINVAL; + +	spin_lock_init(&apc->lock); + +	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); +	if (!res) +		return -EINVAL; + +	apc->io_res.parent = res; +	apc->io_res.name = "PCI IO space"; +	apc->io_res.start = res->start; +	apc->io_res.end = res->end; +	apc->io_res.flags = IORESOURCE_IO; + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base"); +	if (!res) +		return -EINVAL; + +	apc->mem_res.parent = res; +	apc->mem_res.name = "PCI memory space"; +	apc->mem_res.start = res->start; +	apc->mem_res.end = res->end; +	apc->mem_res.flags = IORESOURCE_MEM; + +	apc->pci_controller.pci_ops = &ar724x_pci_ops; +	apc->pci_controller.io_resource = &apc->io_res; +	apc->pci_controller.mem_resource = &apc->mem_res; + +	apc->link_up = ar724x_pci_check_link(apc); +	if (!apc->link_up) +		dev_warn(&pdev->dev, "PCIe link is down\n"); + +	ar724x_pci_irq_init(apc, id); + +	ar724x_pci_local_write(apc, PCI_COMMAND, 4, AR724X_PCI_CMD_INIT); + +	register_pci_controller(&apc->pci_controller); + +	return 0; +} + +static struct platform_driver ar724x_pci_driver = { +	.probe = ar724x_pci_probe, +	.driver = { +		.name = "ar724x-pci", +		.owner = THIS_MODULE, +	}, +}; + +static int __init ar724x_pci_init(void) +{ +	return platform_driver_register(&ar724x_pci_driver); +} + +postcore_initcall(ar724x_pci_init); diff --git a/arch/mips/pci/pci-bcm1480.c b/arch/mips/pci/pci-bcm1480.c index 6f5e24c6ae6..5ec2a7bae02 100644 --- a/arch/mips/pci/pci-bcm1480.c +++ b/arch/mips/pci/pci-bcm1480.c @@ -39,6 +39,7 @@  #include <linux/mm.h>  #include <linux/console.h>  #include <linux/tty.h> +#include <linux/vt.h>  #include <asm/sibyte/bcm1480_regs.h>  #include <asm/sibyte/bcm1480_scd.h> @@ -54,8 +55,8 @@  static void *cfg_space; -#define PCI_BUS_ENABLED	1 -#define PCI_DEVICE_MODE	2 +#define PCI_BUS_ENABLED 1 +#define PCI_DEVICE_MODE 2  static int bcm1480_bus_status; @@ -194,7 +195,7 @@ struct pci_controller bcm1480_controller = {  	.pci_ops	= &bcm1480_pci_ops,  	.mem_resource	= &bcm1480_mem_resource,  	.io_resource	= &bcm1480_io_resource, -	.io_offset      = A_BCM1480_PHYS_PCI_IO_MATCH_BYTES, +	.io_offset	= A_BCM1480_PHYS_PCI_IO_MATCH_BYTES,  }; @@ -204,13 +205,13 @@ static int __init bcm1480_pcibios_init(void)  	uint64_t reg;  	/* CFE will assign PCI resources */ -	pci_probe_only = 1; +	pci_set_flags(PCI_PROBE_ONLY);  	/* Avoid ISA compat ranges.  */  	PCIBIOS_MIN_IO = 0x00008000UL;  	PCIBIOS_MIN_MEM = 0x01000000UL; -	/* Set I/O resource limits. - unlimited for now to accomodate HT */ +	/* Set I/O resource limits. - unlimited for now to accommodate HT */  	ioport_resource.end = 0xffffffffUL;  	iomem_resource.end = 0xffffffffUL; @@ -227,7 +228,7 @@ static int __init bcm1480_pcibios_init(void)  					     PCI_COMMAND));  		if (!(cmdreg & PCI_COMMAND_MASTER)) {  			printk -			    ("PCI: Skipping PCI probe.  Bus is not initialized.\n"); +			    ("PCI: Skipping PCI probe.	Bus is not initialized.\n");  			iounmap(cfg_space);  			return 1; /* XXX */  		} @@ -257,7 +258,9 @@ static int __init bcm1480_pcibios_init(void)  	register_pci_controller(&bcm1480_controller);  #ifdef CONFIG_VGA_CONSOLE -	take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1); +	console_lock(); +	do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1); +	console_unlock();  #endif  	return 0;  } diff --git a/arch/mips/pci/pci-bcm1480ht.c b/arch/mips/pci/pci-bcm1480ht.c index 50cc6e9e824..1263c5e7dbe 100644 --- a/arch/mips/pci/pci-bcm1480ht.c +++ b/arch/mips/pci/pci-bcm1480ht.c @@ -53,8 +53,8 @@  static void *ht_cfg_space; -#define PCI_BUS_ENABLED	1 -#define PCI_DEVICE_MODE	2 +#define PCI_BUS_ENABLED 1 +#define PCI_DEVICE_MODE 2  static int bcm1480ht_bus_status; @@ -191,7 +191,7 @@ struct pci_controller bcm1480ht_controller = {  	.io_resource	= &bcm1480ht_io_resource,  	.index		= 1,  	.get_busno	= bcm1480ht_pcibios_get_busno, -	.io_offset      = A_BCM1480_PHYS_HT_IO_MATCH_BYTES, +	.io_offset	= A_BCM1480_PHYS_HT_IO_MATCH_BYTES,  };  static int __init bcm1480ht_pcibios_init(void) diff --git a/arch/mips/pci/pci-bcm47xx.c b/arch/mips/pci/pci-bcm47xx.c index 455f8e50a00..76f16eaed0a 100644 --- a/arch/mips/pci/pci-bcm47xx.c +++ b/arch/mips/pci/pci-bcm47xx.c @@ -25,13 +25,16 @@  #include <linux/types.h>  #include <linux/pci.h>  #include <linux/ssb/ssb.h> +#include <linux/bcma/bcma.h> +#include <bcm47xx.h>  int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  {  	return 0;  } -int pcibios_plat_dev_init(struct pci_dev *dev) +#ifdef CONFIG_BCM47XX_SSB +static int bcm47xx_pcibios_plat_dev_init_ssb(struct pci_dev *dev)  {  	int res;  	u8 slot, pin; @@ -57,3 +60,45 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  	dev->irq = res;  	return 0;  } +#endif + +#ifdef CONFIG_BCM47XX_BCMA +static int bcm47xx_pcibios_plat_dev_init_bcma(struct pci_dev *dev) +{ +	int res; + +	res = bcma_core_pci_plat_dev_init(dev); +	if (res < 0) { +		printk(KERN_ALERT "PCI: Failed to init device %s\n", +		       pci_name(dev)); +		return res; +	} + +	res = bcma_core_pci_pcibios_map_irq(dev); + +	/* IRQ-0 and IRQ-1 are software interrupts. */ +	if (res < 2) { +		printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n", +		       pci_name(dev)); +		return res; +	} + +	dev->irq = res; +	return 0; +} +#endif + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +#ifdef CONFIG_BCM47XX_SSB +	if (bcm47xx_bus_type ==	 BCM47XX_BUS_TYPE_SSB) +		return bcm47xx_pcibios_plat_dev_init_ssb(dev); +	else +#endif +#ifdef CONFIG_BCM47XX_BCMA +	if  (bcm47xx_bus_type ==  BCM47XX_BUS_TYPE_BCMA) +		return bcm47xx_pcibios_plat_dev_init_bcma(dev); +	else +#endif +		return 0; +} diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index 82e0fde1dba..151d9b5870b 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -10,8 +10,12 @@  #include <linux/pci.h>  #include <linux/kernel.h>  #include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h>  #include <asm/bootinfo.h> +#include <bcm63xx_reset.h> +  #include "pci-bcm63xx.h"  /* @@ -21,21 +25,21 @@  int bcm63xx_pci_enabled;  static struct resource bcm_pci_mem_resource = { -	.name   = "bcm63xx PCI memory space", -	.start  = BCM_PCI_MEM_BASE_PA, -	.end    = BCM_PCI_MEM_END_PA, -	.flags  = IORESOURCE_MEM +	.name	= "bcm63xx PCI memory space", +	.start	= BCM_PCI_MEM_BASE_PA, +	.end	= BCM_PCI_MEM_END_PA, +	.flags	= IORESOURCE_MEM  };  static struct resource bcm_pci_io_resource = { -	.name   = "bcm63xx PCI IO space", -	.start  = BCM_PCI_IO_BASE_PA, +	.name	= "bcm63xx PCI IO space", +	.start	= BCM_PCI_IO_BASE_PA,  #ifdef CONFIG_CARDBUS -	.end    = BCM_PCI_IO_HALF_PA, +	.end	= BCM_PCI_IO_HALF_PA,  #else -	.end    = BCM_PCI_IO_END_PA, +	.end	= BCM_PCI_IO_END_PA,  #endif -	.flags  = IORESOURCE_IO +	.flags	= IORESOURCE_IO  };  struct pci_controller bcm63xx_controller = { @@ -51,17 +55,17 @@ struct pci_controller bcm63xx_controller = {   */  #ifdef CONFIG_CARDBUS  static struct resource bcm_cb_mem_resource = { -	.name   = "bcm63xx Cardbus memory space", -	.start  = BCM_CB_MEM_BASE_PA, -	.end    = BCM_CB_MEM_END_PA, -	.flags  = IORESOURCE_MEM +	.name	= "bcm63xx Cardbus memory space", +	.start	= BCM_CB_MEM_BASE_PA, +	.end	= BCM_CB_MEM_END_PA, +	.flags	= IORESOURCE_MEM  };  static struct resource bcm_cb_io_resource = { -	.name   = "bcm63xx Cardbus IO space", -	.start  = BCM_PCI_IO_HALF_PA + 1, -	.end    = BCM_PCI_IO_END_PA, -	.flags  = IORESOURCE_IO +	.name	= "bcm63xx Cardbus IO space", +	.start	= BCM_PCI_IO_HALF_PA + 1, +	.end	= BCM_PCI_IO_END_PA, +	.flags	= IORESOURCE_IO  };  struct pci_controller bcm63xx_cb_controller = { @@ -71,6 +75,26 @@ struct pci_controller bcm63xx_cb_controller = {  };  #endif +static struct resource bcm_pcie_mem_resource = { +	.name	= "bcm63xx PCIe memory space", +	.start	= BCM_PCIE_MEM_BASE_PA, +	.end	= BCM_PCIE_MEM_END_PA, +	.flags	= IORESOURCE_MEM, +}; + +static struct resource bcm_pcie_io_resource = { +	.name	= "bcm63xx PCIe IO space", +	.start	= 0, +	.end	= 0, +	.flags	= 0, +}; + +struct pci_controller bcm63xx_pcie_controller = { +	.pci_ops	= &bcm63xx_pcie_ops, +	.io_resource	= &bcm_pcie_io_resource, +	.mem_resource	= &bcm_pcie_mem_resource, +}; +  static u32 bcm63xx_int_cfg_readl(u32 reg)  {  	u32 tmp; @@ -87,30 +111,113 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg)  	u32 tmp;  	tmp = reg & MPI_PCICFGCTL_CFGADDR_MASK; -	tmp |=  MPI_PCICFGCTL_WRITEEN_MASK; +	tmp |=	MPI_PCICFGCTL_WRITEEN_MASK;  	bcm_mpi_writel(tmp, MPI_PCICFGCTL_REG);  	bcm_mpi_writel(val, MPI_PCICFGDATA_REG);  }  void __iomem *pci_iospace_start; -static int __init bcm63xx_pci_init(void) +static void __init bcm63xx_reset_pcie(void)  { -	unsigned int mem_size;  	u32 val; +	u32 reg; -	if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358()) -		return -ENODEV; +	/* enable SERDES */ +	if (BCMCPU_IS_6328()) +		reg = MISC_SERDES_CTRL_6328_REG; +	else +		reg = MISC_SERDES_CTRL_6362_REG; -	if (!bcm63xx_pci_enabled) +	val = bcm_misc_readl(reg); +	val |= SERDES_PCIE_EN | SERDES_PCIE_EXD_EN; +	bcm_misc_writel(val, reg); + +	/* reset the PCIe core */ +	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 1); +	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_EXT, 1); +	mdelay(10); + +	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE, 0); +	mdelay(10); + +	bcm63xx_core_set_reset(BCM63XX_RESET_PCIE_EXT, 0); +	mdelay(200); +} + +static struct clk *pcie_clk; + +static int __init bcm63xx_register_pcie(void) +{ +	u32 val; + +	/* enable clock */ +	pcie_clk = clk_get(NULL, "pcie"); +	if (IS_ERR_OR_NULL(pcie_clk))  		return -ENODEV; +	clk_prepare_enable(pcie_clk); + +	bcm63xx_reset_pcie(); + +	/* configure the PCIe bridge */ +	val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG); +	val |= OPT1_RD_BE_OPT_EN; +	val |= OPT1_RD_REPLY_BE_FIX_EN; +	val |= OPT1_PCIE_BRIDGE_HOLE_DET_EN; +	val |= OPT1_L1_INT_STATUS_MASK_POL; +	bcm_pcie_writel(val, PCIE_BRIDGE_OPT1_REG); + +	/* setup the interrupts */ +	val = bcm_pcie_readl(PCIE_BRIDGE_RC_INT_MASK_REG); +	val |= PCIE_RC_INT_A | PCIE_RC_INT_B | PCIE_RC_INT_C | PCIE_RC_INT_D; +	bcm_pcie_writel(val, PCIE_BRIDGE_RC_INT_MASK_REG); + +	val = bcm_pcie_readl(PCIE_BRIDGE_OPT2_REG); +	/* enable credit checking and error checking */ +	val |= OPT2_TX_CREDIT_CHK_EN; +	val |= OPT2_UBUS_UR_DECODE_DIS; + +	/* set device bus/func for the pcie device */ +	val |= (PCIE_BUS_DEVICE << OPT2_CFG_TYPE1_BUS_NO_SHIFT); +	val |= OPT2_CFG_TYPE1_BD_SEL; +	bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG); + +	/* setup class code as bridge */ +	val = bcm_pcie_readl(PCIE_IDVAL3_REG); +	val &= ~IDVAL3_CLASS_CODE_MASK; +	val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT); +	bcm_pcie_writel(val, PCIE_IDVAL3_REG); + +	/* disable bar1 size */ +	val = bcm_pcie_readl(PCIE_CONFIG2_REG); +	val &= ~CONFIG2_BAR1_SIZE_MASK; +	bcm_pcie_writel(val, PCIE_CONFIG2_REG); + +	/* set bar0 to little endian */ +	val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT; +	val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT; +	val |= BASEMASK_REMAP_EN; +	bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG); + +	val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT; +	bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG); + +	register_pci_controller(&bcm63xx_pcie_controller); + +	return 0; +} + +static int __init bcm63xx_register_pci(void) +{ +	unsigned int mem_size; +	u32 val;  	/*  	 * configuration  access are  done through  IO space,  remap 4  	 * first bytes to access it from CPU.  	 *  	 * this means that  no io access from CPU  should happen while -	 * we do a configuration cycle,  but there's no way we can add +	 * we do a configuration cycle,	 but there's no way we can add  	 * a spinlock for each io access, so this is currently kind of  	 * broken on SMP.  	 */ @@ -143,9 +250,9 @@ static int __init bcm63xx_pci_init(void)  	bcm_mpi_writel(0, MPI_L2PMEMREMAP2_REG);  #endif -	/* setup local bus  to PCI access (IO memory),  we have only 1 -	 * IO window  for both PCI  and cardbus, but it  cannot handle -	 * both  at the  same time,  assume standard  PCI for  now, if +	/* setup local bus  to PCI access (IO memory),	we have only 1 +	 * IO window  for both PCI  and cardbus, but it	 cannot handle +	 * both	 at the	 same time,  assume standard  PCI for  now, if  	 * cardbus card has  IO zone, PCI fixup will  change window to  	 * cardbus */  	val = BCM_PCI_IO_BASE_PA & MPI_L2P_BASE_MASK; @@ -159,7 +266,7 @@ static int __init bcm63xx_pci_init(void)  	/* setup PCI to local bus access, used by PCI device to target  	 * local RAM while bus mastering */  	bcm63xx_int_cfg_writel(0, PCI_BASE_ADDRESS_3); -	if (BCMCPU_IS_6358()) +	if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6368())  		val = MPI_SP0_REMAP_ENABLE_MASK;  	else  		val = 0; @@ -183,7 +290,7 @@ static int __init bcm63xx_pci_init(void)  		bcm_mpi_writel(0, MPI_SP1_RANGE_REG);  	} -	/* change  host bridge  retry  counter to  infinite number  of +	/* change  host bridge	retry  counter to  infinite number  of  	 * retry,  needed for  some broadcom  wifi cards  with Silicon  	 * Backplane bus where access to srom seems very slow  */  	val = bcm63xx_int_cfg_readl(BCMPCI_REG_TIMERS); @@ -221,4 +328,24 @@ static int __init bcm63xx_pci_init(void)  	return 0;  } + +static int __init bcm63xx_pci_init(void) +{ +	if (!bcm63xx_pci_enabled) +		return -ENODEV; + +	switch (bcm63xx_get_cpu_id()) { +	case BCM6328_CPU_ID: +	case BCM6362_CPU_ID: +		return bcm63xx_register_pcie(); +	case BCM3368_CPU_ID: +	case BCM6348_CPU_ID: +	case BCM6358_CPU_ID: +	case BCM6368_CPU_ID: +		return bcm63xx_register_pci(); +	default: +		return -ENODEV; +	} +} +  arch_initcall(bcm63xx_pci_init); diff --git a/arch/mips/pci/pci-bcm63xx.h b/arch/mips/pci/pci-bcm63xx.h index a6e594ef3d6..ffab4da7bd0 100644 --- a/arch/mips/pci/pci-bcm63xx.h +++ b/arch/mips/pci/pci-bcm63xx.h @@ -7,17 +7,22 @@  #include <bcm63xx_dev_pci.h>  /* - * Cardbus shares  the PCI bus, but has  no IDSEL, so a  special id is + * Cardbus shares  the PCI bus, but has	 no IDSEL, so a	 special id is   * reserved for it.  If you have a standard PCI device at this id, you   * need to change the following definition.   */  #define CARDBUS_PCI_IDSEL	0x8 + +#define PCIE_BUS_BRIDGE		0 +#define PCIE_BUS_DEVICE		1 +  /*   * defined in ops-bcm63xx.c   */  extern struct pci_ops bcm63xx_pci_ops;  extern struct pci_ops bcm63xx_cb_ops; +extern struct pci_ops bcm63xx_pcie_ops;  /*   * defined in pci-bcm63xx.c diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c index a0e726eb039..0f09eafa5e3 100644 --- a/arch/mips/pci/pci-ip27.c +++ b/arch/mips/pci/pci-ip27.c @@ -7,8 +7,8 @@   * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)   * Copyright (C) 1999, 2000 Silicon Graphics, Inc.   */ -#include <linux/init.h>  #include <linux/kernel.h> +#include <linux/export.h>  #include <linux/pci.h>  #include <linux/smp.h>  #include <asm/sn/arch.h> @@ -29,7 +29,7 @@  /*   * XXX: No kmalloc available when we do our crosstalk scan, - * 	we should try to move it later in the boot process. + *	we should try to move it later in the boot process.   */  static struct bridge_controller bridges[MAX_PCI_BUSSES]; @@ -41,7 +41,7 @@ int irq_to_slot[MAX_PCI_BUSSES * MAX_DEVICES_PER_PCIBUS];  extern struct pci_ops bridge_pci_ops; -int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid) +int bridge_probe(nasid_t nasid, int widget_id, int masterwid)  {  	unsigned long offset = NODE_OFFSET(nasid);  	struct bridge_controller *bc; @@ -49,7 +49,7 @@ int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid)  	bridge_t *bridge;  	int slot; -	pci_probe_only = 1; +	pci_set_flags(PCI_PROBE_ONLY);  	printk("a bridge\n"); @@ -102,7 +102,7 @@ int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid)  	 * swap pio's to pci mem and io space (big windows)  	 */  	bridge->b_wid_control |= BRIDGE_CTRL_IO_SWAP | -	                         BRIDGE_CTRL_MEM_SWAP; +				 BRIDGE_CTRL_MEM_SWAP;  #ifdef CONFIG_PAGE_SIZE_4KB  	bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE;  #else /* 16kB or larger */ @@ -122,7 +122,7 @@ int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid)  		bridge->b_device[slot].reg |= BRIDGE_DEV_SWAP_DIR;  		bc->pci_int[slot] = -1;  	} -	bridge->b_wid_tflush;     /* wait until Bridge PIO complete */ +	bridge->b_wid_tflush;	  /* wait until Bridge PIO complete */  	bc->base = bridge; @@ -142,7 +142,7 @@ int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid)   * A given PCI device, in general, should be able to intr any of the cpus   * on any one of the hubs connected to its xbow.   */ -int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  {  	return 0;  } @@ -183,7 +183,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  }  /* - * Device might live on a subordinate PCI bus.  XXX Walk up the chain of buses + * Device might live on a subordinate PCI bus.	XXX Walk up the chain of buses   * to find the slot number in sense of the bridge device register.   * XXX This also means multiple devices might rely on conflicting bridge   * settings. @@ -211,11 +211,12 @@ static inline void pci_enable_swapping(struct pci_dev *dev)  	bridge->b_widget.w_tflush;	/* Flush */  } -static void __init pci_fixup_ioc3(struct pci_dev *d) +static void pci_fixup_ioc3(struct pci_dev *d)  {  	pci_disable_swapping(d);  } +#ifdef CONFIG_NUMA  int pcibus_to_node(struct pci_bus *bus)  {  	struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); @@ -223,6 +224,7 @@ int pcibus_to_node(struct pci_bus *bus)  	return bc->nasid;  }  EXPORT_SYMBOL(pcibus_to_node); +#endif /* CONFIG_NUMA */  DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,  	pci_fixup_ioc3); diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c index 532b561b444..b1e061f7fdc 100644 --- a/arch/mips/pci/pci-ip32.c +++ b/arch/mips/pci/pci-ip32.c @@ -18,9 +18,9 @@  /*   * Handle errors from the bridge.  This includes master and target aborts, - * various command and address errors, and the interrupt test.  This gets - * registered on the bridge error irq.  It's conceivable that some of these - * conditions warrant a panic.  Anybody care to say which ones? + * various command and address errors, and the interrupt test.	This gets + * registered on the bridge error irq.	It's conceivable that some of these + * conditions warrant a panic.	Anybody care to say which ones?   */  static irqreturn_t macepci_error(int irq, void *dev)  { diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c new file mode 100644 index 00000000000..cb1ef998406 --- /dev/null +++ b/arch/mips/pci/pci-lantiq.c @@ -0,0 +1,263 @@ +/* + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + * + *  Copyright (C) 2010 John Crispin <blogic@openwrt.org> + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> + +#include <asm/pci.h> +#include <asm/gpio.h> +#include <asm/addrspace.h> + +#include <lantiq_soc.h> +#include <lantiq_irq.h> + +#include "pci-lantiq.h" + +#define PCI_CR_FCI_ADDR_MAP0		0x00C0 +#define PCI_CR_FCI_ADDR_MAP1		0x00C4 +#define PCI_CR_FCI_ADDR_MAP2		0x00C8 +#define PCI_CR_FCI_ADDR_MAP3		0x00CC +#define PCI_CR_FCI_ADDR_MAP4		0x00D0 +#define PCI_CR_FCI_ADDR_MAP5		0x00D4 +#define PCI_CR_FCI_ADDR_MAP6		0x00D8 +#define PCI_CR_FCI_ADDR_MAP7		0x00DC +#define PCI_CR_CLK_CTRL			0x0000 +#define PCI_CR_PCI_MOD			0x0030 +#define PCI_CR_PC_ARB			0x0080 +#define PCI_CR_FCI_ADDR_MAP11hg		0x00E4 +#define PCI_CR_BAR11MASK		0x0044 +#define PCI_CR_BAR12MASK		0x0048 +#define PCI_CR_BAR13MASK		0x004C +#define PCI_CS_BASE_ADDR1		0x0010 +#define PCI_CR_PCI_ADDR_MAP11		0x0064 +#define PCI_CR_FCI_BURST_LENGTH		0x00E8 +#define PCI_CR_PCI_EOI			0x002C +#define PCI_CS_STS_CMD			0x0004 + +#define PCI_MASTER0_REQ_MASK_2BITS	8 +#define PCI_MASTER1_REQ_MASK_2BITS	10 +#define PCI_MASTER2_REQ_MASK_2BITS	12 +#define INTERNAL_ARB_ENABLE_BIT		0 + +#define LTQ_CGU_IFCCR		0x0018 +#define LTQ_CGU_PCICR		0x0034 + +#define ltq_pci_w32(x, y)	ltq_w32((x), ltq_pci_membase + (y)) +#define ltq_pci_r32(x)		ltq_r32(ltq_pci_membase + (x)) + +#define ltq_pci_cfg_w32(x, y)	ltq_w32((x), ltq_pci_mapped_cfg + (y)) +#define ltq_pci_cfg_r32(x)	ltq_r32(ltq_pci_mapped_cfg + (x)) + +__iomem void *ltq_pci_mapped_cfg; +static __iomem void *ltq_pci_membase; + +static int reset_gpio; +static struct clk *clk_pci, *clk_external; +static struct resource pci_io_resource; +static struct resource pci_mem_resource; +static struct pci_ops pci_ops = { +	.read	= ltq_pci_read_config_dword, +	.write	= ltq_pci_write_config_dword +}; + +static struct pci_controller pci_controller = { +	.pci_ops	= &pci_ops, +	.mem_resource	= &pci_mem_resource, +	.mem_offset	= 0x00000000UL, +	.io_resource	= &pci_io_resource, +	.io_offset	= 0x00000000UL, +}; + +static inline u32 ltq_calc_bar11mask(void) +{ +	u32 mem, bar11mask; + +	/* BAR11MASK value depends on available memory on system. */ +	mem = get_num_physpages() * PAGE_SIZE; +	bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8; + +	return bar11mask; +} + +static int ltq_pci_startup(struct platform_device *pdev) +{ +	struct device_node *node = pdev->dev.of_node; +	const __be32 *req_mask, *bus_clk; +	u32 temp_buffer; + +	/* get our clocks */ +	clk_pci = clk_get(&pdev->dev, NULL); +	if (IS_ERR(clk_pci)) { +		dev_err(&pdev->dev, "failed to get pci clock\n"); +		return PTR_ERR(clk_pci); +	} + +	clk_external = clk_get(&pdev->dev, "external"); +	if (IS_ERR(clk_external)) { +		clk_put(clk_pci); +		dev_err(&pdev->dev, "failed to get external pci clock\n"); +		return PTR_ERR(clk_external); +	} + +	/* read the bus speed that we want */ +	bus_clk = of_get_property(node, "lantiq,bus-clock", NULL); +	if (bus_clk) +		clk_set_rate(clk_pci, *bus_clk); + +	/* and enable the clocks */ +	clk_enable(clk_pci); +	if (of_find_property(node, "lantiq,external-clock", NULL)) +		clk_enable(clk_external); +	else +		clk_disable(clk_external); + +	/* setup reset gpio used by pci */ +	reset_gpio = of_get_named_gpio(node, "gpio-reset", 0); +	if (gpio_is_valid(reset_gpio)) { +		int ret = devm_gpio_request(&pdev->dev, +						reset_gpio, "pci-reset"); +		if (ret) { +			dev_err(&pdev->dev, +				"failed to request gpio %d\n", reset_gpio); +			return ret; +		} +		gpio_direction_output(reset_gpio, 1); +	} + +	/* enable auto-switching between PCI and EBU */ +	ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); + +	/* busy, i.e. configuration is not done, PCI access has to be retried */ +	ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD); +	wmb(); +	/* BUS Master/IO/MEM access */ +	ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD); + +	/* enable external 2 PCI masters */ +	temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); +	/* setup the request mask */ +	req_mask = of_get_property(node, "req-mask", NULL); +	if (req_mask) +		temp_buffer &= ~((*req_mask & 0xf) << 16); +	else +		temp_buffer &= ~0xf0000; +	/* enable internal arbiter */ +	temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); +	/* enable internal PCI master reqest */ +	temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS)); + +	/* enable EBU request */ +	temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS)); + +	/* enable all external masters request */ +	temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS)); +	ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB); +	wmb(); + +	/* setup BAR memory regions */ +	ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0); +	ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1); +	ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2); +	ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3); +	ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4); +	ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5); +	ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6); +	ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7); +	ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg); +	ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK); +	ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11); +	ltq_pci_w32(0, PCI_CS_BASE_ADDR1); +	/* both TX and RX endian swap are enabled */ +	ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI); +	wmb(); +	ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000, +		PCI_CR_BAR12MASK); +	ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000, +		PCI_CR_BAR13MASK); +	/*use 8 dw burst length */ +	ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH); +	ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD); +	wmb(); + +	/* setup irq line */ +	ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON); +	ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); + +	/* toggle reset pin */ +	if (gpio_is_valid(reset_gpio)) { +		__gpio_set_value(reset_gpio, 0); +		wmb(); +		mdelay(1); +		__gpio_set_value(reset_gpio, 1); +	} +	return 0; +} + +static int ltq_pci_probe(struct platform_device *pdev) +{ +	struct resource *res_cfg, *res_bridge; + +	pci_clear_flags(PCI_PROBE_ONLY); + +	res_cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	res_bridge = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	if (!res_cfg || !res_bridge) { +		dev_err(&pdev->dev, "missing memory reources\n"); +		return -EINVAL; +	} + +	ltq_pci_membase = devm_ioremap_resource(&pdev->dev, res_bridge); +	if (IS_ERR(ltq_pci_membase)) +		return PTR_ERR(ltq_pci_membase); + +	ltq_pci_mapped_cfg = devm_ioremap_resource(&pdev->dev, res_cfg); +	if (IS_ERR(ltq_pci_mapped_cfg)) +		return PTR_ERR(ltq_pci_mapped_cfg); + +	ltq_pci_startup(pdev); + +	pci_load_of_ranges(&pci_controller, pdev->dev.of_node); +	register_pci_controller(&pci_controller); +	return 0; +} + +static const struct of_device_id ltq_pci_match[] = { +	{ .compatible = "lantiq,pci-xway" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, ltq_pci_match); + +static struct platform_driver ltq_pci_driver = { +	.probe = ltq_pci_probe, +	.driver = { +		.name = "pci-xway", +		.owner = THIS_MODULE, +		.of_match_table = ltq_pci_match, +	}, +}; + +int __init pcibios_init(void) +{ +	int ret = platform_driver_register(<q_pci_driver); +	if (ret) +		pr_info("pci-xway: Error registering platform driver!"); +	return ret; +} + +arch_initcall(pcibios_init); diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h new file mode 100644 index 00000000000..66bf6cd6be3 --- /dev/null +++ b/arch/mips/pci/pci-lantiq.h @@ -0,0 +1,18 @@ +/* + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + * + *  Copyright (C) 2010 John Crispin <blogic@openwrt.org> + */ + +#ifndef _LTQ_PCI_H__ +#define _LTQ_PCI_H__ + +extern __iomem void *ltq_pci_mapped_cfg; +extern int ltq_pci_read_config_dword(struct pci_bus *bus, +	unsigned int devfn, int where, int size, u32 *val); +extern int ltq_pci_write_config_dword(struct pci_bus *bus, +	unsigned int devfn, int where, int size, u32 val); + +#endif diff --git a/arch/mips/pci/pci-lasat.c b/arch/mips/pci/pci-lasat.c index a98e543a514..40d2797d2bc 100644 --- a/arch/mips/pci/pci-lasat.c +++ b/arch/mips/pci/pci-lasat.c @@ -51,15 +51,15 @@ static int __init lasat_pci_setup(void)  arch_initcall(lasat_pci_setup); -#define LASAT_IRQ_ETH1   (LASAT_IRQ_BASE + 0) -#define LASAT_IRQ_ETH0   (LASAT_IRQ_BASE + 1) -#define LASAT_IRQ_HDC    (LASAT_IRQ_BASE + 2) -#define LASAT_IRQ_COMP   (LASAT_IRQ_BASE + 3) -#define LASAT_IRQ_HDLC   (LASAT_IRQ_BASE + 4) -#define LASAT_IRQ_PCIA   (LASAT_IRQ_BASE + 5) -#define LASAT_IRQ_PCIB   (LASAT_IRQ_BASE + 6) -#define LASAT_IRQ_PCIC   (LASAT_IRQ_BASE + 7) -#define LASAT_IRQ_PCID   (LASAT_IRQ_BASE + 8) +#define LASAT_IRQ_ETH1	 (LASAT_IRQ_BASE + 0) +#define LASAT_IRQ_ETH0	 (LASAT_IRQ_BASE + 1) +#define LASAT_IRQ_HDC	 (LASAT_IRQ_BASE + 2) +#define LASAT_IRQ_COMP	 (LASAT_IRQ_BASE + 3) +#define LASAT_IRQ_HDLC	 (LASAT_IRQ_BASE + 4) +#define LASAT_IRQ_PCIA	 (LASAT_IRQ_BASE + 5) +#define LASAT_IRQ_PCIB	 (LASAT_IRQ_BASE + 6) +#define LASAT_IRQ_PCIC	 (LASAT_IRQ_BASE + 7) +#define LASAT_IRQ_PCID	 (LASAT_IRQ_BASE + 8)  int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  { @@ -69,13 +69,13 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)  	case 3:  		return LASAT_IRQ_PCIA + (((slot-1) + (pin-1)) % 4);  	case 4: -		return LASAT_IRQ_ETH1;   /* Ethernet 1 (LAN 2) */ +		return LASAT_IRQ_ETH1;	 /* Ethernet 1 (LAN 2) */  	case 5: -		return LASAT_IRQ_ETH0;   /* Ethernet 0 (LAN 1) */ +		return LASAT_IRQ_ETH0;	 /* Ethernet 0 (LAN 1) */  	case 6: -		return LASAT_IRQ_HDC;    /* IDE controller */ +		return LASAT_IRQ_HDC;	 /* IDE controller */  	default: -		return 0xff;            /* Illegal */ +		return 0xff;		/* Illegal */  	}  	return -1; diff --git a/arch/mips/pci/pci-malta.c b/arch/mips/pci/pci-malta.c new file mode 100644 index 00000000000..cfbbc3e3e91 --- /dev/null +++ b/arch/mips/pci/pci-malta.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 1999, 2000, 2004, 2005	 MIPS Technologies, Inc. + *	All rights reserved. + *	Authors: Carsten Langgaard <carstenl@mips.com> + *		 Maciej W. Rozycki <macro@mips.com> + * + * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) + * + *  This program is free software; you can distribute it and/or modify it + *  under the terms of the GNU General Public License (Version 2) as + *  published by the Free Software Foundation. + * + *  This program is distributed in the hope it will be useful, but WITHOUT + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License + *  for more details. + * + *  You should have received a copy of the GNU General Public License along + *  with this program; if not, write to the Free Software Foundation, Inc., + *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * MIPS boards specific PCI support. + */ +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/gt64120.h> +#include <asm/mips-cm.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/bonito64.h> +#include <asm/mips-boards/msc01_pci.h> + +static struct resource bonito64_mem_resource = { +	.name	= "Bonito PCI MEM", +	.flags	= IORESOURCE_MEM, +}; + +static struct resource bonito64_io_resource = { +	.name	= "Bonito PCI I/O", +	.start	= 0x00000000UL, +	.end	= 0x000fffffUL, +	.flags	= IORESOURCE_IO, +}; + +static struct resource gt64120_mem_resource = { +	.name	= "GT-64120 PCI MEM", +	.flags	= IORESOURCE_MEM, +}; + +static struct resource gt64120_io_resource = { +	.name	= "GT-64120 PCI I/O", +	.flags	= IORESOURCE_IO, +}; + +static struct resource msc_mem_resource = { +	.name	= "MSC PCI MEM", +	.flags	= IORESOURCE_MEM, +}; + +static struct resource msc_io_resource = { +	.name	= "MSC PCI I/O", +	.flags	= IORESOURCE_IO, +}; + +extern struct pci_ops bonito64_pci_ops; +extern struct pci_ops gt64xxx_pci0_ops; +extern struct pci_ops msc_pci_ops; + +static struct pci_controller bonito64_controller = { +	.pci_ops	= &bonito64_pci_ops, +	.io_resource	= &bonito64_io_resource, +	.mem_resource	= &bonito64_mem_resource, +	.io_offset	= 0x00000000UL, +}; + +static struct pci_controller gt64120_controller = { +	.pci_ops	= >64xxx_pci0_ops, +	.io_resource	= >64120_io_resource, +	.mem_resource	= >64120_mem_resource, +}; + +static struct pci_controller msc_controller = { +	.pci_ops	= &msc_pci_ops, +	.io_resource	= &msc_io_resource, +	.mem_resource	= &msc_mem_resource, +}; + +void __init mips_pcibios_init(void) +{ +	struct pci_controller *controller; +	resource_size_t start, end, map, start1, end1, map1, map2, map3, mask; + +	switch (mips_revision_sconid) { +	case MIPS_REVISION_SCON_GT64120: +		/* +		 * Due to a bug in the Galileo system controller, we need +		 * to setup the PCI BAR for the Galileo internal registers. +		 * This should be done in the bios/bootprom and will be +		 * fixed in a later revision of YAMON (the MIPS boards +		 * boot prom). +		 */ +		GT_WRITE(GT_PCI0_CFGADDR_OFS, +			 (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ +			 (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */ +			 (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/ +			 ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/ +			 GT_PCI0_CFGADDR_CONFIGEN_BIT); + +		/* Perform the write */ +		GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); + +		/* Set up resource ranges from the controller's registers.  */ +		start = GT_READ(GT_PCI0M0LD_OFS); +		end = GT_READ(GT_PCI0M0HD_OFS); +		map = GT_READ(GT_PCI0M0REMAP_OFS); +		end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); +		start1 = GT_READ(GT_PCI0M1LD_OFS); +		end1 = GT_READ(GT_PCI0M1HD_OFS); +		map1 = GT_READ(GT_PCI0M1REMAP_OFS); +		end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK); +		/* Cannot support multiple windows, use the wider.  */ +		if (end1 - start1 > end - start) { +			start = start1; +			end = end1; +			map = map1; +		} +		mask = ~(start ^ end); +		/* We don't support remapping with a discontiguous mask.  */ +		BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && +		       mask != ~((mask & -mask) - 1)); +		gt64120_mem_resource.start = start; +		gt64120_mem_resource.end = end; +		gt64120_controller.mem_offset = (start & mask) - (map & mask); +		/* Addresses are 36-bit, so do shifts in the destinations.  */ +		gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF; +		gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF; +		gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; +		gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF; + +		start = GT_READ(GT_PCI0IOLD_OFS); +		end = GT_READ(GT_PCI0IOHD_OFS); +		map = GT_READ(GT_PCI0IOREMAP_OFS); +		end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); +		mask = ~(start ^ end); +		/* We don't support remapping with a discontiguous mask.  */ +		BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && +		       mask != ~((mask & -mask) - 1)); +		gt64120_io_resource.start = map & mask; +		gt64120_io_resource.end = (map & mask) | ~mask; +		gt64120_controller.io_offset = 0; +		/* Addresses are 36-bit, so do shifts in the destinations.  */ +		gt64120_io_resource.start <<= GT_PCI_DCRM_SHF; +		gt64120_io_resource.end <<= GT_PCI_DCRM_SHF; +		gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; + +		controller = >64120_controller; +		break; + +	case MIPS_REVISION_SCON_BONITO: +		/* Set up resource ranges from the controller's registers.  */ +		map = BONITO_PCIMAP; +		map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >> +		       BONITO_PCIMAP_PCIMAP_LO0_SHIFT; +		map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >> +		       BONITO_PCIMAP_PCIMAP_LO1_SHIFT; +		map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >> +		       BONITO_PCIMAP_PCIMAP_LO2_SHIFT; +		/* Combine as many adjacent windows as possible.  */ +		map = map1; +		start = BONITO_PCILO0_BASE; +		end = 1; +		if (map3 == map2 + 1) { +			map = map2; +			start = BONITO_PCILO1_BASE; +			end++; +		} +		if (map2 == map1 + 1) { +			map = map1; +			start = BONITO_PCILO0_BASE; +			end++; +		} +		bonito64_mem_resource.start = start; +		bonito64_mem_resource.end = start + +					    BONITO_PCIMAP_WINBASE(end) - 1; +		bonito64_controller.mem_offset = start - +						 BONITO_PCIMAP_WINBASE(map); + +		controller = &bonito64_controller; +		break; + +	case MIPS_REVISION_SCON_SOCIT: +	case MIPS_REVISION_SCON_ROCIT: +	case MIPS_REVISION_SCON_SOCITSC: +	case MIPS_REVISION_SCON_SOCITSCP: +		/* Set up resource ranges from the controller's registers.  */ +		MSC_READ(MSC01_PCI_SC2PMBASL, start); +		MSC_READ(MSC01_PCI_SC2PMMSKL, mask); +		MSC_READ(MSC01_PCI_SC2PMMAPL, map); +		msc_mem_resource.start = start & mask; +		msc_mem_resource.end = (start & mask) | ~mask; +		msc_controller.mem_offset = (start & mask) - (map & mask); +		if (mips_cm_numiocu()) { +			write_gcr_reg0_base(start); +			write_gcr_reg0_mask(mask | +					    CM_GCR_REGn_MASK_CMTGT_IOCU0); +		} +		MSC_READ(MSC01_PCI_SC2PIOBASL, start); +		MSC_READ(MSC01_PCI_SC2PIOMSKL, mask); +		MSC_READ(MSC01_PCI_SC2PIOMAPL, map); +		msc_io_resource.start = map & mask; +		msc_io_resource.end = (map & mask) | ~mask; +		msc_controller.io_offset = 0; +		ioport_resource.end = ~mask; +		if (mips_cm_numiocu()) { +			write_gcr_reg1_base(start); +			write_gcr_reg1_mask(mask | +					    CM_GCR_REGn_MASK_CMTGT_IOCU0); +		} +		/* If ranges overlap I/O takes precedence.  */ +		start = start & mask; +		end = start | ~mask; +		if ((start >= msc_mem_resource.start && +		     start <= msc_mem_resource.end) || +		    (end >= msc_mem_resource.start && +		     end <= msc_mem_resource.end)) { +			/* Use the larger space.  */ +			start = max(start, msc_mem_resource.start); +			end = min(end, msc_mem_resource.end); +			if (start - msc_mem_resource.start >= +			    msc_mem_resource.end - end) +				msc_mem_resource.end = start - 1; +			else +				msc_mem_resource.start = end + 1; +		} + +		controller = &msc_controller; +		break; +	default: +		return; +	} + +	/* PIIX4 ACPI starts at 0x1000 */ +	if (controller->io_resource->start < 0x00001000UL) +		controller->io_resource->start = 0x00001000UL; + +	iomem_resource.end &= 0xfffffffffULL;			/* 64 GB */ +	ioport_resource.end = controller->io_resource->end; + +	controller->io_map_base = mips_io_port_base; + +	register_pci_controller(controller); +} diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c index 2d74fc9ae3b..59cccd95688 100644 --- a/arch/mips/pci/pci-octeon.c +++ b/arch/mips/pci/pci-octeon.c @@ -11,6 +11,7 @@  #include <linux/interrupt.h>  #include <linux/time.h>  #include <linux/delay.h> +#include <linux/platform_device.h>  #include <linux/swiotlb.h>  #include <asm/time.h> @@ -29,8 +30,8 @@   * addresses. Use PCI endian swapping 1 so no address swapping is   * necessary. The Linux io routines will endian swap the data.   */ -#define OCTEON_PCI_IOSPACE_BASE     0x80011a0400000000ull -#define OCTEON_PCI_IOSPACE_SIZE     (1ull<<32) +#define OCTEON_PCI_IOSPACE_BASE	    0x80011a0400000000ull +#define OCTEON_PCI_IOSPACE_SIZE	    (1ull<<32)  /* Octeon't PCI controller uses did=3, subdid=3 for PCI memory. */  #define OCTEON_PCI_MEMSPACE_OFFSET  (0x00011b0000000000ull) @@ -58,7 +59,7 @@ union octeon_pci_address {  	} s;  }; -int __initdata (*octeon_pcibios_map_irq)(const struct pci_dev *dev, +int __initconst (*octeon_pcibios_map_irq)(const struct pci_dev *dev,  					 u8 slot, u8 pin);  enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID; @@ -67,10 +68,10 @@ enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID;   *   * @dev:    The Linux PCI device structure for the device to map   * @slot:   The slot number for this device on __BUS 0__. Linux - *               enumerates through all the bridges and figures out the - *               slot on Bus 0 where this device eventually hooks to. + *		 enumerates through all the bridges and figures out the + *		 slot on Bus 0 where this device eventually hooks to.   * @pin:    The PCI interrupt pin read from the device, then swizzled - *               as it goes through each bridge. + *		 as it goes through each bridge.   * Returns Interrupt number for the device   */  int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) @@ -99,7 +100,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  	 */  	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 64 / 4);  	/* Set latency timers for all devices */ -	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 48); +	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);  	/* Enable reporting System errors and parity errors on all devices */  	/* Enable parity checking and error reporting */ @@ -109,7 +110,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  	if (dev->subordinate) {  		/* Set latency timers on sub bridges */ -		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 48); +		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 64);  		/* More bridge error detection */  		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);  		config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR; @@ -117,20 +118,11 @@ int pcibios_plat_dev_init(struct pci_dev *dev)  	}  	/* Enable the PCIe normal error reporting */ -	pos = pci_find_capability(dev, PCI_CAP_ID_EXP); -	if (pos) { -		/* Update Device Control */ -		pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config); -		/* Correctable Error Reporting */ -		config |= PCI_EXP_DEVCTL_CERE; -		/* Non-Fatal Error Reporting */ -		config |= PCI_EXP_DEVCTL_NFERE; -		/* Fatal Error Reporting */ -		config |= PCI_EXP_DEVCTL_FERE; -		/* Unsupported Request */ -		config |= PCI_EXP_DEVCTL_URRE; -		pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config); -	} +	config = PCI_EXP_DEVCTL_CERE; /* Correctable Error Reporting */ +	config |= PCI_EXP_DEVCTL_NFERE; /* Non-Fatal Error Reporting */ +	config |= PCI_EXP_DEVCTL_FERE;	/* Fatal Error Reporting */ +	config |= PCI_EXP_DEVCTL_URRE;	/* Unsupported Request */ +	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, config);  	/* Find the Advanced Error Reporting capability */  	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); @@ -234,10 +226,10 @@ const char *octeon_get_pci_interrupts(void)   *   * @dev:    The Linux PCI device structure for the device to map   * @slot:   The slot number for this device on __BUS 0__. Linux - *               enumerates through all the bridges and figures out the - *               slot on Bus 0 where this device eventually hooks to. + *		 enumerates through all the bridges and figures out the + *		 slot on Bus 0 where this device eventually hooks to.   * @pin:    The PCI interrupt pin read from the device, then swizzled - *               as it goes through each bridge. + *		 as it goes through each bridge.   * Returns Interrupt number for the device   */  int __init octeon_pci_pcibios_map_irq(const struct pci_dev *dev, @@ -412,8 +404,8 @@ static void octeon_pci_initialize(void)  		ctl_status_2.s.bb1_siz = 1;  /* BAR1 is 2GB */  		ctl_status_2.s.bb_ca = 1;    /* Don't use L2 with big bars */  		ctl_status_2.s.bb_es = 1;    /* Big bar in byte swap mode */ -		ctl_status_2.s.bb1 = 1;      /* BAR1 is big */ -		ctl_status_2.s.bb0 = 1;      /* BAR0 is big */ +		ctl_status_2.s.bb1 = 1;	     /* BAR1 is big */ +		ctl_status_2.s.bb0 = 1;	     /* BAR0 is big */  	}  	octeon_npi_write32(CVMX_NPI_PCI_CTL_STATUS_2, ctl_status_2.u32); @@ -441,7 +433,7 @@ static void octeon_pci_initialize(void)  	/*  	 * TDOMC must be set to one in PCI mode. TDOMC should be set to 4 -	 * in PCI-X mode to allow four oustanding splits. Otherwise, +	 * in PCI-X mode to allow four outstanding splits. Otherwise,  	 * should not change from its reset value. Don't write PCI_CFG19  	 * in PCI mode (0x82000001 reset value), write it to 0x82000004  	 * after PCI-X mode is known. MRBCI,MDWE,MDRE -> must be zero. @@ -454,7 +446,7 @@ static void octeon_pci_initialize(void)  		 * count. [1..31] and 0=32.  NOTE: If the user  		 * programs these bits beyond the Designed Maximum  		 * outstanding count, then the designed maximum table -		 * depth will be used instead.  No additional +		 * depth will be used instead.	No additional  		 * Deferred/Split transactions will be accepted if  		 * this outstanding maximum count is  		 * reached. Furthermore, no additional deferred/split @@ -464,7 +456,7 @@ static void octeon_pci_initialize(void)  		cfg19.s.tdomc = 4;  		/*  		 * Master Deferred Read Request Outstanding Max Count -		 * (PCI only).  CR4C[26:24] Max SAC cycles MAX DAC +		 * (PCI only).	CR4C[26:24] Max SAC cycles MAX DAC  		 * cycles 000 8 4 001 1 0 010 2 1 011 3 1 100 4 2 101  		 * 5 2 110 6 3 111 7 3 For example, if these bits are  		 * programmed to 100, the core can support 2 DAC @@ -515,7 +507,7 @@ static void octeon_pci_initialize(void)  #endif	/* USE_OCTEON_INTERNAL_ARBITER */  	/* -	 * Preferrably written to 1 to set MLTD. [RDSATI,TRTAE, +	 * Preferably written to 1 to set MLTD. [RDSATI,TRTAE,  	 * TWTAE,TMAE,DPPMR -> must be zero. TILT -> must not be set to  	 * 1..7.  	 */ @@ -558,7 +550,7 @@ static void octeon_pci_initialize(void)  	/*  	 * Affects PCI performance when OCTEON services reads to its -	 * BAR1/BAR2. Refer to Section 10.6.1.  The recommended values are +	 * BAR1/BAR2. Refer to Section 10.6.1.	The recommended values are  	 * 0x22, 0x33, and 0x33 for PCI_READ_CMD_6, PCI_READ_CMD_C, and  	 * PCI_READ_CMD_E, respectively. Unfortunately due to errata DDR-700,  	 * these values need to be changed so they won't possibly prefetch off @@ -594,15 +586,16 @@ static int __init octeon_pci_setup(void)  	else  		octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_BIG; -	/* PCI I/O and PCI MEM values */ -	set_io_port_base(OCTEON_PCI_IOSPACE_BASE); -	ioport_resource.start = 0; -	ioport_resource.end = OCTEON_PCI_IOSPACE_SIZE - 1;  	if (!octeon_is_pci_host()) {  		pr_notice("Not in host mode, PCI Controller not initialized\n");  		return 0;  	} +	/* PCI I/O and PCI MEM values */ +	set_io_port_base(OCTEON_PCI_IOSPACE_BASE); +	ioport_resource.start = 0; +	ioport_resource.end = OCTEON_PCI_IOSPACE_SIZE - 1; +  	pr_notice("%s Octeon big bar support\n",  		  (octeon_dma_bar_type ==  		  OCTEON_DMA_BAR_TYPE_BIG) ? "Enabling" : "Disabling"); @@ -713,6 +706,10 @@ static int __init octeon_pci_setup(void)  	 */  	cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, -1); +	if (IS_ERR(platform_device_register_simple("octeon_pci_edac", +						   -1, NULL, 0))) +		pr_err("Registation of co_pci_edac failed!\n"); +  	octeon_pci_dma_init();  	return 0; diff --git a/arch/mips/pci/pci-rc32434.c b/arch/mips/pci/pci-rc32434.c index f31218e17d3..7f6ce6d734c 100644 --- a/arch/mips/pci/pci-rc32434.c +++ b/arch/mips/pci/pci-rc32434.c @@ -33,7 +33,7 @@  #include <asm/mach-rc32434/rc32434.h>  #include <asm/mach-rc32434/pci.h> -#define PCI_ACCESS_READ  0 +#define PCI_ACCESS_READ	 0  #define PCI_ACCESS_WRITE 1  /* define an unsigned array for the PCI registers */ @@ -53,7 +53,6 @@ static struct resource rc32434_res_pci_mem1 = {  	.start = 0x50000000,  	.end = 0x5FFFFFFF,  	.flags = IORESOURCE_MEM, -	.parent = &rc32434_res_pci_mem1,  	.sibling = NULL,  	.child = &rc32434_res_pci_mem2  }; @@ -82,11 +81,11 @@ extern struct pci_ops rc32434_pci_ops;  #define PCI_MEM2_START	(PCI_ADDR_START + CPUTOPCI_MEM_WIN)  #define PCI_MEM2_END	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN)  - 1)  #define PCI_IO1_START	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN)) -#define PCI_IO1_END 							\ +#define PCI_IO1_END							\  	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN - 1)  #define PCI_IO2_START							\  	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN) -#define PCI_IO2_END 							\ +#define PCI_IO2_END							\  	(PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + (2 * CPUTOPCI_IO_WIN) - 1)  struct pci_controller rc32434_controller2; @@ -215,7 +214,7 @@ static int __init rc32434_pci_init(void)  	rc32434_pcibridge_init();  	io_map_base = ioremap(rc32434_res_pci_io1.start, -		rc32434_res_pci_io1.end - rc32434_res_pci_io1.start + 1); +			      resource_size(&rc32434_res_pci_io1));  	if (!io_map_base)  		return -ENOMEM; diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c new file mode 100644 index 00000000000..72919aeef42 --- /dev/null +++ b/arch/mips/pci/pci-rt3883.c @@ -0,0 +1,611 @@ +/* + *  Ralink RT3662/RT3883 SoC PCI support + * + *  Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> + * + *  Parts of this file are based on Ralink's 2.6.21 BSP + * + *  This program is free software; you can redistribute it and/or modify it + *  under the terms of the GNU General Public License version 2 as published + *  by the Free Software Foundation. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_pci.h> +#include <linux/platform_device.h> + +#include <asm/mach-ralink/rt3883.h> +#include <asm/mach-ralink/ralink_regs.h> + +#define RT3883_MEMORY_BASE		0x00000000 +#define RT3883_MEMORY_SIZE		0x02000000 + +#define RT3883_PCI_REG_PCICFG		0x00 +#define   RT3883_PCICFG_P2P_BR_DEVNUM_M 0xf +#define   RT3883_PCICFG_P2P_BR_DEVNUM_S 16 +#define   RT3883_PCICFG_PCIRST		BIT(1) +#define RT3883_PCI_REG_PCIRAW		0x04 +#define RT3883_PCI_REG_PCIINT		0x08 +#define RT3883_PCI_REG_PCIENA		0x0c + +#define RT3883_PCI_REG_CFGADDR		0x20 +#define RT3883_PCI_REG_CFGDATA		0x24 +#define RT3883_PCI_REG_MEMBASE		0x28 +#define RT3883_PCI_REG_IOBASE		0x2c +#define RT3883_PCI_REG_ARBCTL		0x80 + +#define RT3883_PCI_REG_BASE(_x)		(0x1000 + (_x) * 0x1000) +#define RT3883_PCI_REG_BAR0SETUP(_x)	(RT3883_PCI_REG_BASE((_x)) + 0x10) +#define RT3883_PCI_REG_IMBASEBAR0(_x)	(RT3883_PCI_REG_BASE((_x)) + 0x18) +#define RT3883_PCI_REG_ID(_x)		(RT3883_PCI_REG_BASE((_x)) + 0x30) +#define RT3883_PCI_REG_CLASS(_x)	(RT3883_PCI_REG_BASE((_x)) + 0x34) +#define RT3883_PCI_REG_SUBID(_x)	(RT3883_PCI_REG_BASE((_x)) + 0x38) +#define RT3883_PCI_REG_STATUS(_x)	(RT3883_PCI_REG_BASE((_x)) + 0x50) + +#define RT3883_PCI_MODE_NONE	0 +#define RT3883_PCI_MODE_PCI	BIT(0) +#define RT3883_PCI_MODE_PCIE	BIT(1) +#define RT3883_PCI_MODE_BOTH	(RT3883_PCI_MODE_PCI | RT3883_PCI_MODE_PCIE) + +#define RT3883_PCI_IRQ_COUNT	32 + +#define RT3883_P2P_BR_DEVNUM	1 + +struct rt3883_pci_controller { +	void __iomem *base; +	spinlock_t lock; + +	struct device_node *intc_of_node; +	struct irq_domain *irq_domain; + +	struct pci_controller pci_controller; +	struct resource io_res; +	struct resource mem_res; + +	bool pcie_ready; +}; + +static inline struct rt3883_pci_controller * +pci_bus_to_rt3883_controller(struct pci_bus *bus) +{ +	struct pci_controller *hose; + +	hose = (struct pci_controller *) bus->sysdata; +	return container_of(hose, struct rt3883_pci_controller, pci_controller); +} + +static inline u32 rt3883_pci_r32(struct rt3883_pci_controller *rpc, +				 unsigned reg) +{ +	return ioread32(rpc->base + reg); +} + +static inline void rt3883_pci_w32(struct rt3883_pci_controller *rpc, +				  u32 val, unsigned reg) +{ +	iowrite32(val, rpc->base + reg); +} + +static inline u32 rt3883_pci_get_cfgaddr(unsigned int bus, unsigned int slot, +					 unsigned int func, unsigned int where) +{ +	return (bus << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | +	       0x80000000; +} + +static u32 rt3883_pci_read_cfg32(struct rt3883_pci_controller *rpc, +			       unsigned bus, unsigned slot, +			       unsigned func, unsigned reg) +{ +	unsigned long flags; +	u32 address; +	u32 ret; + +	address = rt3883_pci_get_cfgaddr(bus, slot, func, reg); + +	spin_lock_irqsave(&rpc->lock, flags); +	rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); +	ret = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); +	spin_unlock_irqrestore(&rpc->lock, flags); + +	return ret; +} + +static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc, +				 unsigned bus, unsigned slot, +				 unsigned func, unsigned reg, u32 val) +{ +	unsigned long flags; +	u32 address; + +	address = rt3883_pci_get_cfgaddr(bus, slot, func, reg); + +	spin_lock_irqsave(&rpc->lock, flags); +	rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); +	rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA); +	spin_unlock_irqrestore(&rpc->lock, flags); +} + +static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) +{ +	struct rt3883_pci_controller *rpc; +	u32 pending; + +	rpc = irq_get_handler_data(irq); + +	pending = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIINT) & +		  rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); + +	if (!pending) { +		spurious_interrupt(); +		return; +	} + +	while (pending) { +		unsigned bit = __ffs(pending); + +		irq = irq_find_mapping(rpc->irq_domain, bit); +		generic_handle_irq(irq); + +		pending &= ~BIT(bit); +	} +} + +static void rt3883_pci_irq_unmask(struct irq_data *d) +{ +	struct rt3883_pci_controller *rpc; +	u32 t; + +	rpc = irq_data_get_irq_chip_data(d); + +	t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); +	rt3883_pci_w32(rpc, t | BIT(d->hwirq), RT3883_PCI_REG_PCIENA); +	/* flush write */ +	rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); +} + +static void rt3883_pci_irq_mask(struct irq_data *d) +{ +	struct rt3883_pci_controller *rpc; +	u32 t; + +	rpc = irq_data_get_irq_chip_data(d); + +	t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); +	rt3883_pci_w32(rpc, t & ~BIT(d->hwirq), RT3883_PCI_REG_PCIENA); +	/* flush write */ +	rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); +} + +static struct irq_chip rt3883_pci_irq_chip = { +	.name		= "RT3883 PCI", +	.irq_mask	= rt3883_pci_irq_mask, +	.irq_unmask	= rt3883_pci_irq_unmask, +	.irq_mask_ack	= rt3883_pci_irq_mask, +}; + +static int rt3883_pci_irq_map(struct irq_domain *d, unsigned int irq, +			      irq_hw_number_t hw) +{ +	irq_set_chip_and_handler(irq, &rt3883_pci_irq_chip, handle_level_irq); +	irq_set_chip_data(irq, d->host_data); + +	return 0; +} + +static const struct irq_domain_ops rt3883_pci_irq_domain_ops = { +	.map = rt3883_pci_irq_map, +	.xlate = irq_domain_xlate_onecell, +}; + +static int rt3883_pci_irq_init(struct device *dev, +			       struct rt3883_pci_controller *rpc) +{ +	int irq; + +	irq = irq_of_parse_and_map(rpc->intc_of_node, 0); +	if (irq == 0) { +		dev_err(dev, "%s has no IRQ", +			of_node_full_name(rpc->intc_of_node)); +		return -EINVAL; +	} + +	/* disable all interrupts */ +	rt3883_pci_w32(rpc, 0, RT3883_PCI_REG_PCIENA); + +	rpc->irq_domain = +		irq_domain_add_linear(rpc->intc_of_node, RT3883_PCI_IRQ_COUNT, +				      &rt3883_pci_irq_domain_ops, +				      rpc); +	if (!rpc->irq_domain) { +		dev_err(dev, "unable to add IRQ domain\n"); +		return -ENODEV; +	} + +	irq_set_handler_data(irq, rpc); +	irq_set_chained_handler(irq, rt3883_pci_irq_handler); + +	return 0; +} + +static int rt3883_pci_config_read(struct pci_bus *bus, unsigned int devfn, +				  int where, int size, u32 *val) +{ +	struct rt3883_pci_controller *rpc; +	unsigned long flags; +	u32 address; +	u32 data; + +	rpc = pci_bus_to_rt3883_controller(bus); + +	if (!rpc->pcie_ready && bus->number == 1) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), +					 PCI_FUNC(devfn), where); + +	spin_lock_irqsave(&rpc->lock, flags); +	rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); +	data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); +	spin_unlock_irqrestore(&rpc->lock, flags); + +	switch (size) { +	case 1: +		*val = (data >> ((where & 3) << 3)) & 0xff; +		break; +	case 2: +		*val = (data >> ((where & 3) << 3)) & 0xffff; +		break; +	case 4: +		*val = data; +		break; +	} + +	return PCIBIOS_SUCCESSFUL; +} + +static int rt3883_pci_config_write(struct pci_bus *bus, unsigned int devfn, +				   int where, int size, u32 val) +{ +	struct rt3883_pci_controller *rpc; +	unsigned long flags; +	u32 address; +	u32 data; + +	rpc = pci_bus_to_rt3883_controller(bus); + +	if (!rpc->pcie_ready && bus->number == 1) +		return PCIBIOS_DEVICE_NOT_FOUND; + +	address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), +					 PCI_FUNC(devfn), where); + +	spin_lock_irqsave(&rpc->lock, flags); +	rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); +	data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); + +	switch (size) { +	case 1: +		data = (data & ~(0xff << ((where & 3) << 3))) | +		       (val << ((where & 3) << 3)); +		break; +	case 2: +		data = (data & ~(0xffff << ((where & 3) << 3))) | +		       (val << ((where & 3) << 3)); +		break; +	case 4: +		data = val; +		break; +	} + +	rt3883_pci_w32(rpc, data, RT3883_PCI_REG_CFGDATA); +	spin_unlock_irqrestore(&rpc->lock, flags); + +	return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops rt3883_pci_ops = { +	.read	= rt3883_pci_config_read, +	.write	= rt3883_pci_config_write, +}; + +static void rt3883_pci_preinit(struct rt3883_pci_controller *rpc, unsigned mode) +{ +	u32 syscfg1; +	u32 rstctrl; +	u32 clkcfg1; +	u32 t; + +	rstctrl = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); +	syscfg1 = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1); +	clkcfg1 = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1); + +	if (mode & RT3883_PCI_MODE_PCIE) { +		rstctrl |= RT3883_RSTCTRL_PCIE; +		rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL); + +		/* setup PCI PAD drive mode */ +		syscfg1 &= ~(0x30); +		syscfg1 |= (2 << 4); +		rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1); + +		t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0); +		t &= ~BIT(31); +		rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0); + +		t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1); +		t &= 0x80ffffff; +		rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1); + +		t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1); +		t |= 0xa << 24; +		rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1); + +		t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0); +		t |= BIT(31); +		rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0); + +		msleep(50); + +		rstctrl &= ~RT3883_RSTCTRL_PCIE; +		rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL); +	} + +	syscfg1 |= (RT3883_SYSCFG1_PCIE_RC_MODE | RT3883_SYSCFG1_PCI_HOST_MODE); + +	clkcfg1 &= ~(RT3883_CLKCFG1_PCI_CLK_EN | RT3883_CLKCFG1_PCIE_CLK_EN); + +	if (mode & RT3883_PCI_MODE_PCI) { +		clkcfg1 |= RT3883_CLKCFG1_PCI_CLK_EN; +		rstctrl &= ~RT3883_RSTCTRL_PCI; +	} + +	if (mode & RT3883_PCI_MODE_PCIE) { +		clkcfg1 |= RT3883_CLKCFG1_PCIE_CLK_EN; +		rstctrl &= ~RT3883_RSTCTRL_PCIE; +	} + +	rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1); +	rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL); +	rt_sysc_w32(clkcfg1, RT3883_SYSC_REG_CLKCFG1); + +	msleep(500); + +	/* +	 * setup the device number of the P2P bridge +	 * and de-assert the reset line +	 */ +	t = (RT3883_P2P_BR_DEVNUM << RT3883_PCICFG_P2P_BR_DEVNUM_S); +	rt3883_pci_w32(rpc, t, RT3883_PCI_REG_PCICFG); + +	/* flush write */ +	rt3883_pci_r32(rpc, RT3883_PCI_REG_PCICFG); +	msleep(500); + +	if (mode & RT3883_PCI_MODE_PCIE) { +		msleep(500); + +		t = rt3883_pci_r32(rpc, RT3883_PCI_REG_STATUS(1)); + +		rpc->pcie_ready = t & BIT(0); + +		if (!rpc->pcie_ready) { +			/* reset the PCIe block */ +			t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); +			t |= RT3883_RSTCTRL_PCIE; +			rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); +			t &= ~RT3883_RSTCTRL_PCIE; +			rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); + +			/* turn off PCIe clock */ +			t = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1); +			t &= ~RT3883_CLKCFG1_PCIE_CLK_EN; +			rt_sysc_w32(t, RT3883_SYSC_REG_CLKCFG1); + +			t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0); +			t &= ~0xf000c080; +			rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0); +		} +	} + +	/* enable PCI arbiter */ +	rt3883_pci_w32(rpc, 0x79, RT3883_PCI_REG_ARBCTL); +} + +static int rt3883_pci_probe(struct platform_device *pdev) +{ +	struct rt3883_pci_controller *rpc; +	struct device *dev = &pdev->dev; +	struct device_node *np = dev->of_node; +	struct resource *res; +	struct device_node *child; +	u32 val; +	int err; +	int mode; + +	rpc = devm_kzalloc(dev, sizeof(*rpc), GFP_KERNEL); +	if (!rpc) +		return -ENOMEM; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	rpc->base = devm_ioremap_resource(dev, res); +	if (IS_ERR(rpc->base)) +		return PTR_ERR(rpc->base); + +	/* find the interrupt controller child node */ +	for_each_child_of_node(np, child) { +		if (of_get_property(child, "interrupt-controller", NULL) && +		    of_node_get(child)) { +			rpc->intc_of_node = child; +			break; +		} +	} + +	if (!rpc->intc_of_node) { +		dev_err(dev, "%s has no %s child node", +			of_node_full_name(rpc->intc_of_node), +			"interrupt controller"); +		return -EINVAL; +	} + +	/* find the PCI host bridge child node */ +	for_each_child_of_node(np, child) { +		if (child->type && +		    of_node_cmp(child->type, "pci") == 0 && +		    of_node_get(child)) { +			rpc->pci_controller.of_node = child; +			break; +		} +	} + +	if (!rpc->pci_controller.of_node) { +		dev_err(dev, "%s has no %s child node", +			of_node_full_name(rpc->intc_of_node), +			"PCI host bridge"); +		err = -EINVAL; +		goto err_put_intc_node; +	} + +	mode = RT3883_PCI_MODE_NONE; +	for_each_available_child_of_node(rpc->pci_controller.of_node, child) { +		int devfn; + +		if (!child->type || +		    of_node_cmp(child->type, "pci") != 0) +			continue; + +		devfn = of_pci_get_devfn(child); +		if (devfn < 0) +			continue; + +		switch (PCI_SLOT(devfn)) { +		case 1: +			mode |= RT3883_PCI_MODE_PCIE; +			break; + +		case 17: +		case 18: +			mode |= RT3883_PCI_MODE_PCI; +			break; +		} +	} + +	if (mode == RT3883_PCI_MODE_NONE) { +		dev_err(dev, "unable to determine PCI mode\n"); +		err = -EINVAL; +		goto err_put_hb_node; +	} + +	dev_info(dev, "mode:%s%s\n", +		 (mode & RT3883_PCI_MODE_PCI) ? " PCI" : "", +		 (mode & RT3883_PCI_MODE_PCIE) ? " PCIe" : ""); + +	rt3883_pci_preinit(rpc, mode); + +	rpc->pci_controller.pci_ops = &rt3883_pci_ops; +	rpc->pci_controller.io_resource = &rpc->io_res; +	rpc->pci_controller.mem_resource = &rpc->mem_res; + +	/* Load PCI I/O and memory resources from DT */ +	pci_load_of_ranges(&rpc->pci_controller, +			   rpc->pci_controller.of_node); + +	rt3883_pci_w32(rpc, rpc->mem_res.start, RT3883_PCI_REG_MEMBASE); +	rt3883_pci_w32(rpc, rpc->io_res.start, RT3883_PCI_REG_IOBASE); + +	ioport_resource.start = rpc->io_res.start; +	ioport_resource.end = rpc->io_res.end; + +	/* PCI */ +	rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(0)); +	rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(0)); +	rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(0)); +	rt3883_pci_w32(rpc, 0x00800001, RT3883_PCI_REG_CLASS(0)); +	rt3883_pci_w32(rpc, 0x28801814, RT3883_PCI_REG_SUBID(0)); + +	/* PCIe */ +	rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(1)); +	rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(1)); +	rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(1)); +	rt3883_pci_w32(rpc, 0x06040001, RT3883_PCI_REG_CLASS(1)); +	rt3883_pci_w32(rpc, 0x28801814, RT3883_PCI_REG_SUBID(1)); + +	err = rt3883_pci_irq_init(dev, rpc); +	if (err) +		goto err_put_hb_node; + +	/* PCIe */ +	val = rt3883_pci_read_cfg32(rpc, 0, 0x01, 0, PCI_COMMAND); +	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; +	rt3883_pci_write_cfg32(rpc, 0, 0x01, 0, PCI_COMMAND, val); + +	/* PCI */ +	val = rt3883_pci_read_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND); +	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; +	rt3883_pci_write_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND, val); + +	if (mode == RT3883_PCI_MODE_PCIE) { +		rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(0)); +		rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(1)); + +		rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0, +				       PCI_BASE_ADDRESS_0, +				       RT3883_MEMORY_BASE); +		/* flush write */ +		rt3883_pci_read_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0, +				      PCI_BASE_ADDRESS_0); +	} else { +		rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0, +				       PCI_IO_BASE, 0x00000101); +	} + +	register_pci_controller(&rpc->pci_controller); + +	return 0; + +err_put_hb_node: +	of_node_put(rpc->pci_controller.of_node); +err_put_intc_node: +	of_node_put(rpc->intc_of_node); +	return err; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	return of_irq_parse_and_map_pci(dev, slot, pin); +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	return 0; +} + +static const struct of_device_id rt3883_pci_ids[] = { +	{ .compatible = "ralink,rt3883-pci" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, rt3883_pci_ids); + +static struct platform_driver rt3883_pci_driver = { +	.probe = rt3883_pci_probe, +	.driver = { +		.name = "rt3883-pci", +		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(rt3883_pci_ids), +	}, +}; + +static int __init rt3883_pci_init(void) +{ +	return platform_driver_register(&rt3883_pci_driver); +} + +postcore_initcall(rt3883_pci_init); diff --git a/arch/mips/pci/pci-sb1250.c b/arch/mips/pci/pci-sb1250.c index 1711e8e101b..fc634aeda4a 100644 --- a/arch/mips/pci/pci-sb1250.c +++ b/arch/mips/pci/pci-sb1250.c @@ -55,9 +55,9 @@  static void *cfg_space; -#define PCI_BUS_ENABLED	1 -#define LDT_BUS_ENABLED	2 -#define PCI_DEVICE_MODE	4 +#define PCI_BUS_ENABLED 1 +#define LDT_BUS_ENABLED 2 +#define PCI_DEVICE_MODE 4  static int sb1250_bus_status; @@ -213,7 +213,7 @@ static int __init sb1250_pcibios_init(void)  	uint64_t reg;  	/* CFE will assign PCI resources */ -	pci_probe_only = 1; +	pci_set_flags(PCI_PROBE_ONLY);  	/* Avoid ISA compat ranges.  */  	PCIBIOS_MIN_IO = 0x00008000UL; @@ -239,7 +239,7 @@ static int __init sb1250_pcibios_init(void)  			       PCI_COMMAND));  		if (!(cmdreg & PCI_COMMAND_MASTER)) {  			printk -			    ("PCI: Skipping PCI probe.  Bus is not initialized.\n"); +			    ("PCI: Skipping PCI probe.	Bus is not initialized.\n");  			iounmap(cfg_space);  			return 0;  		} @@ -283,7 +283,9 @@ static int __init sb1250_pcibios_init(void)  	register_pci_controller(&sb1250_controller);  #ifdef CONFIG_VGA_CONSOLE -	take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1); +	console_lock(); +	do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1); +	console_unlock();  #endif  	return 0;  } diff --git a/arch/mips/pci/pci-tx4927.c b/arch/mips/pci/pci-tx4927.c index a5807406a7f..a032ae0a533 100644 --- a/arch/mips/pci/pci-tx4927.c +++ b/arch/mips/pci/pci-tx4927.c @@ -85,7 +85,7 @@ void __init tx4927_setup_pcierr_irq(void)  {  	if (request_irq(TXX9_IRQ_BASE + TX4927_IR_PCIERR,  			tx4927_pcierr_interrupt, -			IRQF_DISABLED, "PCI error", +			0, "PCI error",  			(void *)TX4927_PCIC_REG))  		printk(KERN_WARNING "Failed to request irq for PCIERR\n");  } diff --git a/arch/mips/pci/pci-tx4938.c b/arch/mips/pci/pci-tx4938.c index 20e45f30b2e..141bba56248 100644 --- a/arch/mips/pci/pci-tx4938.c +++ b/arch/mips/pci/pci-tx4938.c @@ -136,7 +136,7 @@ void __init tx4938_setup_pcierr_irq(void)  {  	if (request_irq(TXX9_IRQ_BASE + TX4938_IR_PCIERR,  			tx4927_pcierr_interrupt, -			IRQF_DISABLED, "PCI error", +			0, "PCI error",  			(void *)TX4927_PCIC_REG))  		printk(KERN_WARNING "Failed to request irq for PCIERR\n");  } diff --git a/arch/mips/pci/pci-tx4939.c b/arch/mips/pci/pci-tx4939.c index 9ef840693ba..c10fbf2a19d 100644 --- a/arch/mips/pci/pci-tx4939.c +++ b/arch/mips/pci/pci-tx4939.c @@ -101,7 +101,7 @@ void __init tx4939_setup_pcierr_irq(void)  {  	if (request_irq(TXX9_IRQ_BASE + TX4939_IR_PCIERR,  			tx4927_pcierr_interrupt, -			IRQF_DISABLED, "PCI error", +			0, "PCI error",  			(void *)TX4939_PCIC_REG))  		pr_warning("Failed to request irq for PCIERR\n");  } diff --git a/arch/mips/pci/pci-virtio-guest.c b/arch/mips/pci/pci-virtio-guest.c new file mode 100644 index 00000000000..40a078bc461 --- /dev/null +++ b/arch/mips/pci/pci-virtio-guest.c @@ -0,0 +1,131 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License.  See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2013 Cavium, Inc. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> + +#include <uapi/asm/bitfield.h> +#include <asm/byteorder.h> +#include <asm/io.h> + +#define PCI_CONFIG_ADDRESS	0xcf8 +#define PCI_CONFIG_DATA		0xcfc + +union pci_config_address { +	struct { +		__BITFIELD_FIELD(unsigned enable_bit	  : 1,	/* 31       */ +		__BITFIELD_FIELD(unsigned reserved	  : 7,	/* 30 .. 24 */ +		__BITFIELD_FIELD(unsigned bus_number	  : 8,	/* 23 .. 16 */ +		__BITFIELD_FIELD(unsigned devfn_number	  : 8,	/* 15 .. 8  */ +		__BITFIELD_FIELD(unsigned register_number : 8,	/* 7  .. 0  */ +		))))); +	}; +	u32 w; +}; + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	return 0; +} + +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	return ((pin + slot) % 4)+ MIPS_IRQ_PCIA; +} + +static void pci_virtio_guest_write_config_addr(struct pci_bus *bus, +					unsigned int devfn, int reg) +{ +	union pci_config_address pca = { .w = 0 }; + +	pca.register_number = reg; +	pca.devfn_number = devfn; +	pca.bus_number = bus->number; +	pca.enable_bit = 1; + +	outl(pca.w, PCI_CONFIG_ADDRESS); +} + +static int pci_virtio_guest_write_config(struct pci_bus *bus, +		unsigned int devfn, int reg, int size, u32 val) +{ +	pci_virtio_guest_write_config_addr(bus, devfn, reg); + +	switch (size) { +	case 1: +		outb(val, PCI_CONFIG_DATA + (reg & 3)); +		break; +	case 2: +		outw(val, PCI_CONFIG_DATA + (reg & 2)); +		break; +	case 4: +		outl(val, PCI_CONFIG_DATA); +		break; +	} + +	return PCIBIOS_SUCCESSFUL; +} + +static int pci_virtio_guest_read_config(struct pci_bus *bus, unsigned int devfn, +					int reg, int size, u32 *val) +{ +	pci_virtio_guest_write_config_addr(bus, devfn, reg); + +	switch (size) { +	case 1: +		*val = inb(PCI_CONFIG_DATA + (reg & 3)); +		break; +	case 2: +		*val = inw(PCI_CONFIG_DATA + (reg & 2)); +		break; +	case 4: +		*val = inl(PCI_CONFIG_DATA); +		break; +	} +	return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_virtio_guest_ops = { +	.read  = pci_virtio_guest_read_config, +	.write = pci_virtio_guest_write_config, +}; + +static struct resource pci_virtio_guest_mem_resource = { +	.name = "Virtio MEM", +	.flags = IORESOURCE_MEM, +	.start	= 0x10000000, +	.end	= 0x1dffffff +}; + +static struct resource pci_virtio_guest_io_resource = { +	.name = "Virtio IO", +	.flags = IORESOURCE_IO, +	.start	= 0, +	.end	= 0xffff +}; + +static struct pci_controller pci_virtio_guest_controller = { +	.pci_ops = &pci_virtio_guest_ops, +	.mem_resource = &pci_virtio_guest_mem_resource, +	.io_resource = &pci_virtio_guest_io_resource, +}; + +static int __init pci_virtio_guest_setup(void) +{ +	pr_err("pci_virtio_guest_setup\n"); + +	/* Virtio comes pre-assigned */ +	pci_set_flags(PCI_PROBE_ONLY); + +	pci_virtio_guest_controller.io_map_base = mips_io_port_base; +	register_pci_controller(&pci_virtio_guest_controller); +	return 0; +} +arch_initcall(pci_virtio_guest_setup); diff --git a/arch/mips/pci/pci-vr41xx.c b/arch/mips/pci/pci-vr41xx.c index 56525711f8b..157c7715b7c 100644 --- a/arch/mips/pci/pci-vr41xx.c +++ b/arch/mips/pci/pci-vr41xx.c @@ -69,17 +69,17 @@ static struct pci_target_address_window pci_target_window1 = {  };  static struct resource pci_mem_resource = { -	.name   = "PCI Memory resources", -	.start  = PCI_MEM_RESOURCE_START, -	.end    = PCI_MEM_RESOURCE_END, -	.flags  = IORESOURCE_MEM, +	.name	= "PCI Memory resources", +	.start	= PCI_MEM_RESOURCE_START, +	.end	= PCI_MEM_RESOURCE_END, +	.flags	= IORESOURCE_MEM,  };  static struct resource pci_io_resource = { -	.name   = "PCI I/O resources", -	.start  = PCI_IO_RESOURCE_START, -	.end    = PCI_IO_RESOURCE_END, -	.flags  = IORESOURCE_IO, +	.name	= "PCI I/O resources", +	.start	= PCI_IO_RESOURCE_START, +	.end	= PCI_IO_RESOURCE_END, +	.flags	= IORESOURCE_IO,  };  static struct pci_controller_unit_setup vr41xx_pci_controller_unit_setup = { @@ -97,7 +97,7 @@ static struct pci_controller_unit_setup vr41xx_pci_controller_unit_setup = {  };  static struct pci_controller vr41xx_pci_controller = { -	.pci_ops        = &vr41xx_pci_ops, +	.pci_ops	= &vr41xx_pci_ops,  	.mem_resource	= &pci_mem_resource,  	.io_resource	= &pci_io_resource,  }; @@ -148,7 +148,7 @@ static int __init vr41xx_pciu_init(void)  	else if ((vtclock / 2) < pci_clock_max)  		pciu_write(PCICLKSELREG, HALF_VTCLOCK);  	else if (current_cpu_data.processor_id >= PRID_VR4131_REV2_1 && -	         (vtclock / 3) < pci_clock_max) +		 (vtclock / 3) < pci_clock_max)  		pciu_write(PCICLKSELREG, ONE_THIRD_VTCLOCK);  	else if ((vtclock / 4) < pci_clock_max)  		pciu_write(PCICLKSELREG, QUARTER_VTCLOCK); @@ -281,7 +281,7 @@ static int __init vr41xx_pciu_init(void)  	pciu_write(PCIAPCNTREG, val);  	pciu_write(COMMANDREG, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | -	                       PCI_COMMAND_MASTER | PCI_COMMAND_PARITY | +			       PCI_COMMAND_MASTER | PCI_COMMAND_PARITY |  			       PCI_COMMAND_SERR);  	/* Clear bus error */ @@ -305,7 +305,7 @@ static int __init vr41xx_pciu_init(void)  		struct resource *res = vr41xx_pci_controller.io_resource;  		master = setup->master_io;  		io_map_base = ioremap(master->bus_base_address, -				      res->end - res->start + 1); +				      resource_size(res));  		if (!io_map_base)  			return -EBUSY; diff --git a/arch/mips/pci/pci-vr41xx.h b/arch/mips/pci/pci-vr41xx.h index 6b1ae2eb1c0..e6b4a1b969f 100644 --- a/arch/mips/pci/pci-vr41xx.h +++ b/arch/mips/pci/pci-vr41xx.h @@ -1,7 +1,7 @@  /*   *  pci-vr41xx.h, Include file for PCI Control Unit of the NEC VR4100 series.   * - *  Copyright (C) 2002  MontaVista Software Inc. + *  Copyright (C) 2002	MontaVista Software Inc.   *    Author: Yoichi Yuasa <source@mvista.com>   *  Copyright (C) 2004-2005  Yoichi Yuasa <yuasa@linux-mips.org>   * diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c new file mode 100644 index 00000000000..7babf01600c --- /dev/null +++ b/arch/mips/pci/pci-xlp.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2003-2012 Broadcom Corporation + * All Rights Reserved + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the Broadcom + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in + *    the documentation and/or other materials provided with the + *    distribution. + * + * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/msi.h> +#include <linux/mm.h> +#include <linux/irq.h> +#include <linux/irqdesc.h> +#include <linux/console.h> + +#include <asm/io.h> + +#include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> +#include <asm/netlogic/mips-extns.h> + +#include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> +#include <asm/netlogic/xlp-hal/pic.h> +#include <asm/netlogic/xlp-hal/pcibus.h> +#include <asm/netlogic/xlp-hal/bridge.h> + +static void *pci_config_base; + +#define pci_cfg_addr(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off)) + +/* PCI ops */ +static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, +	int where) +{ +	u32 data; +	u32 *cfgaddr; + +	where &= ~3; +	if (cpu_is_xlp9xx()) { +		/* be very careful on SoC buses */ +		if (bus->number == 0) { +			/* Scan only existing nodes - uboot bug? */ +			if (PCI_SLOT(devfn) != 0 || +					   !nlm_node_present(PCI_FUNC(devfn))) +				return 0xffffffff; +		} else if (bus->parent->number == 0) {	/* SoC bus */ +			if (PCI_SLOT(devfn) == 0)	/* b.0.0 hangs */ +				return 0xffffffff; +			if (devfn == 44)		/* b.5.4 hangs */ +				return 0xffffffff; +		} +	} else if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) { +		return 0xffffffff; +	} +	cfgaddr = (u32 *)(pci_config_base + +			pci_cfg_addr(bus->number, devfn, where)); +	data = *cfgaddr; +	return data; +} + +static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn, +	int where, u32 data) +{ +	u32 *cfgaddr; + +	cfgaddr = (u32 *)(pci_config_base + +			pci_cfg_addr(bus->number, devfn, where & ~3)); +	*cfgaddr = data; +} + +static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn, +	int where, int size, u32 *val) +{ +	u32 data; + +	if ((size == 2) && (where & 1)) +		return PCIBIOS_BAD_REGISTER_NUMBER; +	else if ((size == 4) && (where & 3)) +		return PCIBIOS_BAD_REGISTER_NUMBER; + +	data = pci_cfg_read_32bit(bus, devfn, where); + +	if (size == 1) +		*val = (data >> ((where & 3) << 3)) & 0xff; +	else if (size == 2) +		*val = (data >> ((where & 3) << 3)) & 0xffff; +	else +		*val = data; + +	return PCIBIOS_SUCCESSFUL; +} + + +static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn, +		int where, int size, u32 val) +{ +	u32 data; + +	if ((size == 2) && (where & 1)) +		return PCIBIOS_BAD_REGISTER_NUMBER; +	else if ((size == 4) && (where & 3)) +		return PCIBIOS_BAD_REGISTER_NUMBER; + +	data = pci_cfg_read_32bit(bus, devfn, where); + +	if (size == 1) +		data = (data & ~(0xff << ((where & 3) << 3))) | +			(val << ((where & 3) << 3)); +	else if (size == 2) +		data = (data & ~(0xffff << ((where & 3) << 3))) | +			(val << ((where & 3) << 3)); +	else +		data = val; + +	pci_cfg_write_32bit(bus, devfn, where, data); + +	return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops nlm_pci_ops = { +	.read  = nlm_pcibios_read, +	.write = nlm_pcibios_write +}; + +static struct resource nlm_pci_mem_resource = { +	.name		= "XLP PCI MEM", +	.start		= 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */ +	.end		= 0xdfffffffUL, +	.flags		= IORESOURCE_MEM, +}; + +static struct resource nlm_pci_io_resource = { +	.name		= "XLP IO MEM", +	.start		= 0x14000000UL, /* 64MB PCI IO @ 0x1000_0000 */ +	.end		= 0x17ffffffUL, +	.flags		= IORESOURCE_IO, +}; + +struct pci_controller nlm_pci_controller = { +	.index		= 0, +	.pci_ops	= &nlm_pci_ops, +	.mem_resource	= &nlm_pci_mem_resource, +	.mem_offset	= 0x00000000UL, +	.io_resource	= &nlm_pci_io_resource, +	.io_offset	= 0x00000000UL, +}; + +struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) +{ +	struct pci_bus *bus, *p; + +	bus = dev->bus; + +	if (cpu_is_xlp9xx()) { +		/* find bus with grand parent number == 0 */ +		for (p = bus->parent; p && p->parent && p->parent->number != 0; +				p = p->parent) +			bus = p; +		return (p && p->parent) ? bus->self : NULL; +	} else { +		/* Find the bridge on bus 0 */ +		for (p = bus->parent; p && p->number != 0; p = p->parent) +			bus = p; + +		return p ? bus->self : NULL; +	} +} + +int xlp_socdev_to_node(const struct pci_dev *lnkdev) +{ +	if (cpu_is_xlp9xx()) +		return PCI_FUNC(lnkdev->bus->self->devfn); +	else +		return PCI_SLOT(lnkdev->devfn) / 8; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	struct pci_dev *lnkdev; +	int lnkfunc, node; + +	/* +	 * For XLP PCIe, there is an IRQ per Link, find out which +	 * link the device is on to assign interrupts +	*/ +	lnkdev = xlp_get_pcie_link(dev); +	if (lnkdev == NULL) +		return 0; + +	lnkfunc = PCI_FUNC(lnkdev->devfn); +	node = xlp_socdev_to_node(lnkdev); + +	return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc)); +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	return 0; +} + +/* + * If big-endian, enable hardware byteswap on the PCIe bridges. + * This will make both the SoC and PCIe devices behave consistently with + * readl/writel. + */ +#ifdef __BIG_ENDIAN +static void xlp_config_pci_bswap(int node, int link) +{ +	uint64_t nbubase, lnkbase; +	u32 reg; + +	nbubase = nlm_get_bridge_regbase(node); +	lnkbase = nlm_get_pcie_base(node, link); + +	/* +	 *  Enable byte swap in hardware. Program each link's PCIe SWAP regions +	 * from the link's address ranges. +	 */ +	if (cpu_is_xlp9xx()) { +		reg = nlm_read_bridge_reg(nbubase, +				BRIDGE_9XX_PCIEMEM_BASE0 + link); +		nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg); + +		reg = nlm_read_bridge_reg(nbubase, +				BRIDGE_9XX_PCIEMEM_LIMIT0 + link); +		nlm_write_pci_reg(lnkbase, +				PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff); + +		reg = nlm_read_bridge_reg(nbubase, +				BRIDGE_9XX_PCIEIO_BASE0 + link); +		nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_IO_BASE, reg); + +		reg = nlm_read_bridge_reg(nbubase, +				BRIDGE_9XX_PCIEIO_LIMIT0 + link); +		nlm_write_pci_reg(lnkbase, +				PCIE_9XX_BYTE_SWAP_IO_LIM, reg | 0xfff); +	} else { +		reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); +		nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); + +		reg = nlm_read_bridge_reg(nbubase, +					BRIDGE_PCIEMEM_LIMIT0 + link); +		nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); + +		reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); +		nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); + +		reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); +		nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); +	} +} +#else +/* Swap configuration not needed in little-endian mode */ +static inline void xlp_config_pci_bswap(int node, int link) {} +#endif /* __BIG_ENDIAN */ + +static int __init pcibios_init(void) +{ +	uint64_t pciebase; +	int link, n; +	u32 reg; + +	/* Firmware assigns PCI resources */ +	pci_set_flags(PCI_PROBE_ONLY); +	pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20); + +	/* Extend IO port for memory mapped io */ +	ioport_resource.start =	 0; +	ioport_resource.end   = ~0; + +	for (n = 0; n < NLM_NR_NODES; n++) { +		if (!nlm_node_present(n)) +			continue; + +		for (link = 0; link < PCIE_NLINKS; link++) { +			pciebase = nlm_get_pcie_base(n, link); +			if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) +				continue; +			xlp_config_pci_bswap(n, link); +			xlp_init_node_msi_irqs(n, link); + +			/* put in intpin and irq - u-boot does not */ +			reg = nlm_read_pci_reg(pciebase, 0xf); +			reg &= ~0x1ffu; +			reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link); +			nlm_write_pci_reg(pciebase, 0xf, reg); +			pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); +		} +	} + +	set_io_port_base(CKSEG1); +	nlm_pci_controller.io_map_base = CKSEG1; + +	register_pci_controller(&nlm_pci_controller); +	pr_info("XLP PCIe Controller %pR%pR.\n", &nlm_pci_io_resource, +		&nlm_pci_mem_resource); + +	return 0; +} +arch_initcall(pcibios_init); diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c new file mode 100644 index 00000000000..0dde80332d3 --- /dev/null +++ b/arch/mips/pci/pci-xlr.c @@ -0,0 +1,368 @@ +/* + * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights + * reserved. + * + * This software is available to you under a choice of one of two + * licenses.  You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the NetLogic + * license below: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in + *    the documentation and/or other materials provided with the + *    distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/msi.h> +#include <linux/mm.h> +#include <linux/irq.h> +#include <linux/irqdesc.h> +#include <linux/console.h> +#include <linux/pci_regs.h> + +#include <asm/io.h> + +#include <asm/netlogic/interrupt.h> +#include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> + +#include <asm/netlogic/xlr/msidef.h> +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> +#include <asm/netlogic/xlr/xlr.h> + +static void *pci_config_base; + +#define pci_cfg_addr(bus, devfn, off) (((bus) << 16) | ((devfn) << 8) | (off)) + +/* PCI ops */ +static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, +	int where) +{ +	u32 data; +	u32 *cfgaddr; + +	cfgaddr = (u32 *)(pci_config_base + +			pci_cfg_addr(bus->number, devfn, where & ~3)); +	data = *cfgaddr; +	return cpu_to_le32(data); +} + +static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn, +	int where, u32 data) +{ +	u32 *cfgaddr; + +	cfgaddr = (u32 *)(pci_config_base + +			pci_cfg_addr(bus->number, devfn, where & ~3)); +	*cfgaddr = cpu_to_le32(data); +} + +static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn, +	int where, int size, u32 *val) +{ +	u32 data; + +	if ((size == 2) && (where & 1)) +		return PCIBIOS_BAD_REGISTER_NUMBER; +	else if ((size == 4) && (where & 3)) +		return PCIBIOS_BAD_REGISTER_NUMBER; + +	data = pci_cfg_read_32bit(bus, devfn, where); + +	if (size == 1) +		*val = (data >> ((where & 3) << 3)) & 0xff; +	else if (size == 2) +		*val = (data >> ((where & 3) << 3)) & 0xffff; +	else +		*val = data; + +	return PCIBIOS_SUCCESSFUL; +} + + +static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn, +		int where, int size, u32 val) +{ +	u32 data; + +	if ((size == 2) && (where & 1)) +		return PCIBIOS_BAD_REGISTER_NUMBER; +	else if ((size == 4) && (where & 3)) +		return PCIBIOS_BAD_REGISTER_NUMBER; + +	data = pci_cfg_read_32bit(bus, devfn, where); + +	if (size == 1) +		data = (data & ~(0xff << ((where & 3) << 3))) | +			(val << ((where & 3) << 3)); +	else if (size == 2) +		data = (data & ~(0xffff << ((where & 3) << 3))) | +			(val << ((where & 3) << 3)); +	else +		data = val; + +	pci_cfg_write_32bit(bus, devfn, where, data); + +	return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops nlm_pci_ops = { +	.read  = nlm_pcibios_read, +	.write = nlm_pcibios_write +}; + +static struct resource nlm_pci_mem_resource = { +	.name		= "XLR PCI MEM", +	.start		= 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */ +	.end		= 0xdfffffffUL, +	.flags		= IORESOURCE_MEM, +}; + +static struct resource nlm_pci_io_resource = { +	.name		= "XLR IO MEM", +	.start		= 0x10000000UL, /* 16MB PCI IO @ 0x1000_0000 */ +	.end		= 0x100fffffUL, +	.flags		= IORESOURCE_IO, +}; + +struct pci_controller nlm_pci_controller = { +	.index		= 0, +	.pci_ops	= &nlm_pci_ops, +	.mem_resource	= &nlm_pci_mem_resource, +	.mem_offset	= 0x00000000UL, +	.io_resource	= &nlm_pci_io_resource, +	.io_offset	= 0x00000000UL, +}; + +/* + * The top level PCIe links on the XLS PCIe controller appear as + * bridges. Given a device, this function finds which link it is + * on. + */ +static struct pci_dev *xls_get_pcie_link(const struct pci_dev *dev) +{ +	struct pci_bus *bus, *p; + +	/* Find the bridge on bus 0 */ +	bus = dev->bus; +	for (p = bus->parent; p && p->number != 0; p = p->parent) +		bus = p; + +	return p ? bus->self : NULL; +} + +static int nlm_pci_link_to_irq(int link) +{ +	switch	(link) { +	case 0: +		return PIC_PCIE_LINK0_IRQ; +	case 1: +		return PIC_PCIE_LINK1_IRQ; +	case 2: +		if (nlm_chip_is_xls_b()) +			return PIC_PCIE_XLSB0_LINK2_IRQ; +		else +			return PIC_PCIE_LINK2_IRQ; +	case 3: +		if (nlm_chip_is_xls_b()) +			return PIC_PCIE_XLSB0_LINK3_IRQ; +		else +			return PIC_PCIE_LINK3_IRQ; +	} +	WARN(1, "Unexpected link %d\n", link); +	return 0; +} + +static int get_irq_vector(const struct pci_dev *dev) +{ +	struct pci_dev *lnk; +	int link; + +	if (!nlm_chip_is_xls()) +		return	PIC_PCIX_IRQ;	/* for XLR just one IRQ */ + +	lnk = xls_get_pcie_link(dev); +	if (lnk == NULL) +		return 0; + +	link = PCI_SLOT(lnk->devfn); +	return nlm_pci_link_to_irq(link); +} + +#ifdef CONFIG_PCI_MSI +void arch_teardown_msi_irq(unsigned int irq) +{ +} + +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) +{ +	struct msi_msg msg; +	struct pci_dev *lnk; +	int irq, ret; +	u16 val; + +	/* MSI not supported on XLR */ +	if (!nlm_chip_is_xls()) +		return 1; + +	/* +	 * Enable MSI on the XLS PCIe controller bridge which was disabled +	 * at enumeration, the bridge MSI capability is at 0x50 +	 */ +	lnk = xls_get_pcie_link(dev); +	if (lnk == NULL) +		return 1; + +	pci_read_config_word(lnk, 0x50 + PCI_MSI_FLAGS, &val); +	if ((val & PCI_MSI_FLAGS_ENABLE) == 0) { +		val |= PCI_MSI_FLAGS_ENABLE; +		pci_write_config_word(lnk, 0x50 + PCI_MSI_FLAGS, val); +	} + +	irq = get_irq_vector(dev); +	if (irq <= 0) +		return 1; + +	msg.address_hi = MSI_ADDR_BASE_HI; +	msg.address_lo = MSI_ADDR_BASE_LO   | +		MSI_ADDR_DEST_MODE_PHYSICAL | +		MSI_ADDR_REDIRECTION_CPU; + +	msg.data = MSI_DATA_TRIGGER_EDGE | +		MSI_DATA_LEVEL_ASSERT	 | +		MSI_DATA_DELIVERY_FIXED; + +	ret = irq_set_msi_desc(irq, desc); +	if (ret < 0) +		return ret; + +	write_msi_msg(irq, &msg); +	return 0; +} +#endif + +/* Extra ACK needed for XLR on chip PCI controller */ +static void xlr_pci_ack(struct irq_data *d) +{ +	uint64_t pcibase = nlm_mmio_base(NETLOGIC_IO_PCIX_OFFSET); + +	nlm_read_reg(pcibase, (0x140 >> 2)); +} + +/* Extra ACK needed for XLS on chip PCIe controller */ +static void xls_pcie_ack(struct irq_data *d) +{ +	uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + +	switch (d->irq) { +	case PIC_PCIE_LINK0_IRQ: +		nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK1_IRQ: +		nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK2_IRQ: +		nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK3_IRQ: +		nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); +		break; +	} +} + +/* For XLS B silicon, the 3,4 PCI interrupts are different */ +static void xls_pcie_ack_b(struct irq_data *d) +{ +	uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET); + +	switch (d->irq) { +	case PIC_PCIE_LINK0_IRQ: +		nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_LINK1_IRQ: +		nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_XLSB0_LINK2_IRQ: +		nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff); +		break; +	case PIC_PCIE_XLSB0_LINK3_IRQ: +		nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff); +		break; +	} +} + +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ +	return get_irq_vector(dev); +} + +/* Do platform specific device initialization at pci_enable_device() time */ +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	return 0; +} + +static int __init pcibios_init(void) +{ +	void (*extra_ack)(struct irq_data *); +	int link, irq; + +	/* PSB assigns PCI resources */ +	pci_set_flags(PCI_PROBE_ONLY); +	pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20); + +	/* Extend IO port for memory mapped io */ +	ioport_resource.start =	 0; +	ioport_resource.end   = ~0; + +	set_io_port_base(CKSEG1); +	nlm_pci_controller.io_map_base = CKSEG1; + +	pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n"); +	register_pci_controller(&nlm_pci_controller); + +	/* +	 * For PCI interrupts, we need to ack the PCI controller too, overload +	 * irq handler data to do this +	 */ +	if (!nlm_chip_is_xls()) { +		/* XLR PCI controller ACK */ +		nlm_set_pic_extra_ack(0, PIC_PCIX_IRQ, xlr_pci_ack); +	} else { +		if  (nlm_chip_is_xls_b()) +			extra_ack = xls_pcie_ack_b; +		else +			extra_ack = xls_pcie_ack; +		for (link = 0; link < 4; link++) { +			irq = nlm_pci_link_to_irq(link); +			nlm_set_pic_extra_ack(0, irq, extra_ack); +		} +	} +	return 0; +} + +arch_initcall(pcibios_init); diff --git a/arch/mips/pci/pci-yosemite.c b/arch/mips/pci/pci-yosemite.c deleted file mode 100644 index cf5e1a25cb7..00000000000 --- a/arch/mips/pci/pci-yosemite.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License.  See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <asm/titan_dep.h> - -extern struct pci_ops titan_pci_ops; - -static struct resource py_mem_resource = { -	.start	= 0xe0000000UL, -	.end	= 0xe3ffffffUL, -	.name	= "Titan PCI MEM", -	.flags	= IORESOURCE_MEM -}; - -/* - * PMON really reserves 16MB of I/O port space but that's stupid, nothing - * needs that much since allocations are limited to 256 bytes per device - * anyway.  So we just claim 64kB here. - */ -#define TITAN_IO_SIZE	0x0000ffffUL -#define TITAN_IO_BASE	0xe8000000UL - -static struct resource py_io_resource = { -	.start	= 0x00001000UL, -	.end	= TITAN_IO_SIZE - 1, -	.name	= "Titan IO MEM", -	.flags	= IORESOURCE_IO, -}; - -static struct pci_controller py_controller = { -	.pci_ops	= &titan_pci_ops, -	.mem_resource	= &py_mem_resource, -	.mem_offset	= 0x00000000UL, -	.io_resource	= &py_io_resource, -	.io_offset	= 0x00000000UL -}; - -static char ioremap_failed[] __initdata = "Could not ioremap I/O port range"; - -static int __init pmc_yosemite_setup(void) -{ -	unsigned long io_v_base; - -	io_v_base = (unsigned long) ioremap(TITAN_IO_BASE, TITAN_IO_SIZE); -	if (!io_v_base) -		panic(ioremap_failed); - -	set_io_port_base(io_v_base); -	py_controller.io_map_base = io_v_base; -	TITAN_WRITE(RM9000x2_OCD_LKM7, TITAN_READ(RM9000x2_OCD_LKM7) | 1); - -	ioport_resource.end = TITAN_IO_SIZE - 1; - -	register_pci_controller(&py_controller); - -	return 0; -} - -arch_initcall(pmc_yosemite_setup); diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index 38bc28005b4..1bf60b12737 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -1,29 +1,29 @@  /* - * 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 + * 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.   * - * Copyright (C) 2003, 04 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2003, 04, 11 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2011 Wind River Systems, + *   written by Ralf Baechle (ralf@linux-mips.org)   */ +#include <linux/bug.h>  #include <linux/kernel.h>  #include <linux/mm.h>  #include <linux/bootmem.h> +#include <linux/export.h>  #include <linux/init.h>  #include <linux/types.h>  #include <linux/pci.h> +#include <linux/of_address.h> + +#include <asm/cpu-info.h>  /* - * Indicate whether we respect the PCI setup left by the firmware. - * - * Make this long-lived  so that we know when shutting down - * whether we probed only or not. + * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource + * assignments.   */ -int pci_probe_only; - -#define PCI_ASSIGN_ALL_BUSSES	1 - -unsigned int pci_probe = PCI_ASSIGN_ALL_BUSSES;  /*   * The PCI controller list. @@ -76,25 +76,33 @@ pcibios_align_resource(void *data, const struct resource *res,  	return start;  } -static void __devinit pcibios_scanbus(struct pci_controller *hose) +static void pcibios_scanbus(struct pci_controller *hose)  {  	static int next_busno;  	static int need_domain_info; +	LIST_HEAD(resources);  	struct pci_bus *bus;  	if (!hose->iommu)  		PCI_DMA_BUS_IS_PHYS = 1; -	if (hose->get_busno && pci_probe_only) +	if (hose->get_busno && pci_has_flag(PCI_PROBE_ONLY))  		next_busno = (*hose->get_busno)(); -	bus = pci_scan_bus(next_busno, hose->pci_ops, hose); +	pci_add_resource_offset(&resources, +				hose->mem_resource, hose->mem_offset); +	pci_add_resource_offset(&resources, hose->io_resource, hose->io_offset); +	bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose, +				&resources); +	if (!bus) +		pci_free_resource_list(&resources); +  	hose->bus = bus;  	need_domain_info = need_domain_info || hose->index;  	hose->need_domain_info = need_domain_info;  	if (bus) { -		next_busno = bus->subordinate + 1; +		next_busno = bus->busn_res.end + 1;  		/* Don't allow 8-bit bus number overflow inside the hose -  		   reserve some space for bridges. */  		if (next_busno > 224) { @@ -102,21 +110,76 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)  			need_domain_info = 1;  		} -		if (!pci_probe_only) { +		if (!pci_has_flag(PCI_PROBE_ONLY)) {  			pci_bus_size_bridges(bus);  			pci_bus_assign_resources(bus); -			pci_enable_bridges(bus);  		}  	}  } +#ifdef CONFIG_OF +void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node) +{ +	struct of_pci_range range; +	struct of_pci_range_parser parser; + +	pr_info("PCI host bridge %s ranges:\n", node->full_name); +	hose->of_node = node; + +	if (of_pci_range_parser_init(&parser, node)) +		return; + +	for_each_of_pci_range(&parser, &range) { +		struct resource *res = NULL; + +		switch (range.flags & IORESOURCE_TYPE_BITS) { +		case IORESOURCE_IO: +			pr_info("  IO 0x%016llx..0x%016llx\n", +				range.cpu_addr, +				range.cpu_addr + range.size - 1); +			hose->io_map_base = +				(unsigned long)ioremap(range.cpu_addr, +						       range.size); +			res = hose->io_resource; +			break; +		case IORESOURCE_MEM: +			pr_info(" MEM 0x%016llx..0x%016llx\n", +				range.cpu_addr, +				range.cpu_addr + range.size - 1); +			res = hose->mem_resource; +			break; +		} +		if (res != NULL) +			of_pci_range_to_resource(&range, node, res); +	} +} + +struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) +{ +	struct pci_controller *hose = bus->sysdata; + +	return of_node_get(hose->of_node); +} +#endif +  static DEFINE_MUTEX(pci_scan_mutex); -void __devinit register_pci_controller(struct pci_controller *hose) +void register_pci_controller(struct pci_controller *hose)  { -	if (request_resource(&iomem_resource, hose->mem_resource) < 0) +	struct resource *parent; + +	parent = hose->mem_resource->parent; +	if (!parent) +		parent = &iomem_resource; + +	if (request_resource(parent, hose->mem_resource) < 0)  		goto out; -	if (request_resource(&ioport_resource, hose->io_resource) < 0) { + +	parent = hose->io_resource->parent; +	if (!parent) +		parent = &ioport_resource; + +	if (request_resource(parent, hose->io_resource) < 0) {  		release_resource(hose->mem_resource);  		goto out;  	} @@ -125,7 +188,7 @@ void __devinit register_pci_controller(struct pci_controller *hose)  	hose_tail = &hose->next;  	/* -	 * Do not panic here but later - this might hapen before console init. +	 * Do not panic here but later - this might happen before console init.  	 */  	if (!hose->io_map_base) {  		printk(KERN_WARNING @@ -149,10 +212,32 @@ out:  	       "Skipping PCI bus scan due to resource conflict\n");  } +static void __init pcibios_set_cache_line_size(void) +{ +	struct cpuinfo_mips *c = ¤t_cpu_data; +	unsigned int lsize; + +	/* +	 * Set PCI cacheline size to that of the highest level in the +	 * cache hierarchy. +	 */ +	lsize = c->dcache.linesz; +	lsize = c->scache.linesz ? : lsize; +	lsize = c->tcache.linesz ? : lsize; + +	BUG_ON(!lsize); + +	pci_dfl_cache_line_size = lsize >> 2; + +	pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize); +} +  static int __init pcibios_init(void)  {  	struct pci_controller *hose; +	pcibios_set_cache_line_size(); +  	/* Scan all of the recorded PCI controllers.  */  	for (hose = hose_head; hose; hose = hose->next)  		pcibios_scanbus(hose); @@ -204,30 +289,9 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask)  	return 0;  } -/* - *  If we set up a device for bus mastering, we need to check the latency - *  timer as certain crappy BIOSes forget to set it properly. - */ -static unsigned int pcibios_max_latency = 255; - -void pcibios_set_master(struct pci_dev *dev) -{ -	u8 lat; -	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); -	if (lat < 16) -		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; -	else if (lat > pcibios_max_latency) -		lat = pcibios_max_latency; -	else -		return; -	printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", -	       pci_name(dev), lat); -	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} -  unsigned int pcibios_assign_all_busses(void)  { -	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; +	return 1;  }  int pcibios_enable_device(struct pci_dev *dev, int mask) @@ -240,95 +304,18 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)  	return pcibios_plat_dev_init(dev);  } -static void pcibios_fixup_device_resources(struct pci_dev *dev, -	struct pci_bus *bus) +void pcibios_fixup_bus(struct pci_bus *bus)  { -	/* Update device resources.  */ -	struct pci_controller *hose = (struct pci_controller *)bus->sysdata; -	unsigned long offset = 0; -	int i; - -	for (i = 0; i < PCI_NUM_RESOURCES; i++) { -		if (!dev->resource[i].start) -			continue; -		if (dev->resource[i].flags & IORESOURCE_IO) -			offset = hose->io_offset; -		else if (dev->resource[i].flags & IORESOURCE_MEM) -			offset = hose->mem_offset; - -		dev->resource[i].start += offset; -		dev->resource[i].end += offset; -	} -} - -void __devinit pcibios_fixup_bus(struct pci_bus *bus) -{ -	/* Propagate hose info into the subordinate devices.  */ - -	struct pci_controller *hose = bus->sysdata; -	struct list_head *ln;  	struct pci_dev *dev = bus->self; -	if (!dev) { -		bus->resource[0] = hose->io_resource; -		bus->resource[1] = hose->mem_resource; -	} else if (pci_probe_only && -		   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { +	if (pci_has_flag(PCI_PROBE_ONLY) && dev && +	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {  		pci_read_bridge_bases(bus); -		pcibios_fixup_device_resources(dev, bus);  	} - -	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { -		dev = pci_dev_b(ln); - -		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) -			pcibios_fixup_device_resources(dev, bus); -	} -} - -void __init -pcibios_update_irq(struct pci_dev *dev, int irq) -{ -	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); -} - -void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, -			 struct resource *res) -{ -	struct pci_controller *hose = (struct pci_controller *)dev->sysdata; -	unsigned long offset = 0; - -	if (res->flags & IORESOURCE_IO) -		offset = hose->io_offset; -	else if (res->flags & IORESOURCE_MEM) -		offset = hose->mem_offset; - -	region->start = res->start - offset; -	region->end = res->end - offset; -} - -void __devinit -pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, -			struct pci_bus_region *region) -{ -	struct pci_controller *hose = (struct pci_controller *)dev->sysdata; -	unsigned long offset = 0; - -	if (res->flags & IORESOURCE_IO) -		offset = hose->io_offset; -	else if (res->flags & IORESOURCE_MEM) -		offset = hose->mem_offset; - -	res->start = region->start + offset; -	res->end = region->end + offset;  } -#ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pcibios_resource_to_bus); -EXPORT_SYMBOL(pcibios_bus_to_resource);  EXPORT_SYMBOL(PCIBIOS_MIN_IO);  EXPORT_SYMBOL(PCIBIOS_MIN_MEM); -#endif  int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,  			enum pci_mmap_state mmap_state, int write_combine) @@ -354,9 +341,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,  		vma->vm_end - vma->vm_start, vma->vm_page_prot);  } -char * (*pcibios_plat_setup)(char *str) __devinitdata; +char * (*pcibios_plat_setup)(char *str) __initdata; -char *__devinit pcibios_setup(char *str) +char *__init pcibios_setup(char *str)  {  	if (pcibios_plat_setup)  		return pcibios_plat_setup(str); diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index 385f035b24e..5e36c33e554 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -3,7 +3,7 @@   * License.  See the file "COPYING" in the main directory of this archive   * for more details.   * - * Copyright (C) 2007, 2008 Cavium Networks + * Copyright (C) 2007, 2008, 2009, 2010, 2011 Cavium Networks   */  #include <linux/kernel.h>  #include <linux/init.h> @@ -11,22 +11,39 @@  #include <linux/interrupt.h>  #include <linux/time.h>  #include <linux/delay.h> +#include <linux/module.h>  #include <asm/octeon/octeon.h>  #include <asm/octeon/cvmx-npei-defs.h>  #include <asm/octeon/cvmx-pciercx-defs.h>  #include <asm/octeon/cvmx-pescx-defs.h>  #include <asm/octeon/cvmx-pexp-defs.h> +#include <asm/octeon/cvmx-pemx-defs.h> +#include <asm/octeon/cvmx-dpi-defs.h> +#include <asm/octeon/cvmx-sli-defs.h> +#include <asm/octeon/cvmx-sriox-defs.h>  #include <asm/octeon/cvmx-helper-errata.h>  #include <asm/octeon/pci-octeon.h> +#define MRRS_CN5XXX 0 /* 128 byte Max Read Request Size */ +#define MPS_CN5XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */ +#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */ +#define MPS_CN6XXX  0 /* 128 byte Max Packet Size (Limit of most PCs) */ + +/* Module parameter to disable PCI probing */ +static int pcie_disable; +module_param(pcie_disable, int, S_IRUGO); + +static int enable_pcie_14459_war; +static int enable_pcie_bus_num_war[2]; +  union cvmx_pcie_address {  	uint64_t u64;  	struct {  		uint64_t upper:2;	/* Normally 2 for XKPHYS */  		uint64_t reserved_49_61:13;	/* Must be zero */  		uint64_t io:1;	/* 1 for IO space access */ -		uint64_t did:5;	/* PCIe DID = 3 */ +		uint64_t did:5; /* PCIe DID = 3 */  		uint64_t subdid:3;	/* PCIe SubDID = 1 */  		uint64_t reserved_36_39:4;	/* Must be zero */  		uint64_t es:2;	/* Endian swap = 1 */ @@ -57,7 +74,7 @@ union cvmx_pcie_address {  		uint64_t upper:2;	/* Normally 2 for XKPHYS */  		uint64_t reserved_49_61:13;	/* Must be zero */  		uint64_t io:1;	/* 1 for IO space access */ -		uint64_t did:5;	/* PCIe DID = 3 */ +		uint64_t did:5; /* PCIe DID = 3 */  		uint64_t subdid:3;	/* PCIe SubDID = 2 */  		uint64_t reserved_36_39:4;	/* Must be zero */  		uint64_t es:2;	/* Endian swap = 1 */ @@ -68,13 +85,15 @@ union cvmx_pcie_address {  		uint64_t upper:2;	/* Normally 2 for XKPHYS */  		uint64_t reserved_49_61:13;	/* Must be zero */  		uint64_t io:1;	/* 1 for IO space access */ -		uint64_t did:5;	/* PCIe DID = 3 */ +		uint64_t did:5; /* PCIe DID = 3 */  		uint64_t subdid:3;	/* PCIe SubDID = 3-6 */  		uint64_t reserved_36_39:4;	/* Must be zero */  		uint64_t address:36;	/* PCIe Mem address */  	} mem;  }; +static int cvmx_pcie_rc_initialize(int pcie_port); +  #include <dma-coherence.h>  /** @@ -147,37 +166,54 @@ static inline uint64_t cvmx_pcie_get_mem_size(int pcie_port)   * Read a PCIe config space register indirectly. This is used for   * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.   * - * @pcie_port:  PCIe port to read from + * @pcie_port:	PCIe port to read from   * @cfg_offset: Address to read   *   * Returns Value read   */  static uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset)  { -	union cvmx_pescx_cfg_rd pescx_cfg_rd; -	pescx_cfg_rd.u64 = 0; -	pescx_cfg_rd.s.addr = cfg_offset; -	cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); -	pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); -	return pescx_cfg_rd.s.data; +	if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { +		union cvmx_pescx_cfg_rd pescx_cfg_rd; +		pescx_cfg_rd.u64 = 0; +		pescx_cfg_rd.s.addr = cfg_offset; +		cvmx_write_csr(CVMX_PESCX_CFG_RD(pcie_port), pescx_cfg_rd.u64); +		pescx_cfg_rd.u64 = cvmx_read_csr(CVMX_PESCX_CFG_RD(pcie_port)); +		return pescx_cfg_rd.s.data; +	} else { +		union cvmx_pemx_cfg_rd pemx_cfg_rd; +		pemx_cfg_rd.u64 = 0; +		pemx_cfg_rd.s.addr = cfg_offset; +		cvmx_write_csr(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64); +		pemx_cfg_rd.u64 = cvmx_read_csr(CVMX_PEMX_CFG_RD(pcie_port)); +		return pemx_cfg_rd.s.data; +	}  }  /**   * Write a PCIe config space register indirectly. This is used for   * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.   * - * @pcie_port:  PCIe port to write to + * @pcie_port:	PCIe port to write to   * @cfg_offset: Address to write - * @val:        Value to write + * @val:	Value to write   */  static void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset,  				 uint32_t val)  { -	union cvmx_pescx_cfg_wr pescx_cfg_wr; -	pescx_cfg_wr.u64 = 0; -	pescx_cfg_wr.s.addr = cfg_offset; -	pescx_cfg_wr.s.data = val; -	cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); +	if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { +		union cvmx_pescx_cfg_wr pescx_cfg_wr; +		pescx_cfg_wr.u64 = 0; +		pescx_cfg_wr.s.addr = cfg_offset; +		pescx_cfg_wr.s.data = val; +		cvmx_write_csr(CVMX_PESCX_CFG_WR(pcie_port), pescx_cfg_wr.u64); +	} else { +		union cvmx_pemx_cfg_wr pemx_cfg_wr; +		pemx_cfg_wr.u64 = 0; +		pemx_cfg_wr.s.addr = cfg_offset; +		pemx_cfg_wr.s.data = val; +		cvmx_write_csr(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64); +	}  }  /** @@ -186,7 +222,7 @@ static void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset,   * @pcie_port: PCIe port to access   * @bus:       Sub bus   * @dev:       Device ID - * @fn:        Device sub function + * @fn:	       Device sub function   * @reg:       Register to access   *   * Returns 64bit Octeon IO address @@ -223,7 +259,7 @@ static inline uint64_t __cvmx_pcie_build_config_addr(int pcie_port, int bus,   * @pcie_port: PCIe port the device is on   * @bus:       Sub bus   * @dev:       Device ID - * @fn:        Device sub function + * @fn:	       Device sub function   * @reg:       Register to access   *   * Returns Result of the read @@ -245,7 +281,7 @@ static uint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev,   * @pcie_port: PCIe port the device is on   * @bus:       Sub bus   * @dev:       Device ID - * @fn:        Device sub function + * @fn:	       Device sub function   * @reg:       Register to access   *   * Returns Result of the read @@ -267,7 +303,7 @@ static uint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev,   * @pcie_port: PCIe port the device is on   * @bus:       Sub bus   * @dev:       Device ID - * @fn:        Device sub function + * @fn:	       Device sub function   * @reg:       Register to access   *   * Returns Result of the read @@ -289,7 +325,7 @@ static uint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev,   * @pcie_port: PCIe port the device is on   * @bus:       Sub bus   * @dev:       Device ID - * @fn:        Device sub function + * @fn:	       Device sub function   * @reg:       Register to access   * @val:       Value to write   */ @@ -308,7 +344,7 @@ static void cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn,   * @pcie_port: PCIe port the device is on   * @bus:       Sub bus   * @dev:       Device ID - * @fn:        Device sub function + * @fn:	       Device sub function   * @reg:       Register to access   * @val:       Value to write   */ @@ -327,7 +363,7 @@ static void cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn,   * @pcie_port: PCIe port the device is on   * @bus:       Sub bus   * @dev:       Device ID - * @fn:        Device sub function + * @fn:	       Device sub function   * @reg:       Register to access   * @val:       Value to write   */ @@ -348,7 +384,6 @@ static void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn,  static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)  {  	union cvmx_pciercx_cfg030 pciercx_cfg030; -	union cvmx_npei_ctl_status2 npei_ctl_status2;  	union cvmx_pciercx_cfg070 pciercx_cfg070;  	union cvmx_pciercx_cfg001 pciercx_cfg001;  	union cvmx_pciercx_cfg032 pciercx_cfg032; @@ -365,21 +400,21 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)  	/* Max Read Request Size (PCIE*_CFG030[MRRS]) */  	/* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */  	/* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */ -	pciercx_cfg030.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); -	/* -	 * Max payload size = 128 bytes for best Octeon DMA -	 * performance. -	 */ -	pciercx_cfg030.s.mps = 0; + +	pciercx_cfg030.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG030(pcie_port)); +	if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { +		pciercx_cfg030.s.mps = MPS_CN5XXX; +		pciercx_cfg030.s.mrrs = MRRS_CN5XXX; +	} else { +		pciercx_cfg030.s.mps = MPS_CN6XXX; +		pciercx_cfg030.s.mrrs = MRRS_CN6XXX; +	}  	/* -	 * Max read request size = 128 bytes for best Octeon DMA -	 * performance. +	 * Enable relaxed order processing. This will allow devices to +	 * affect read response ordering.  	 */ -	pciercx_cfg030.s.mrrs = 0; -	/* Enable relaxed ordering. */  	pciercx_cfg030.s.ro_en = 1; -	/* Enable no snoop. */ +	/* Enable no snoop processing. Not used by Octeon */  	pciercx_cfg030.s.ns_en = 1;  	/* Correctable error reporting enable. */  	pciercx_cfg030.s.ce_en = 1; @@ -389,50 +424,67 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)  	pciercx_cfg030.s.fe_en = 1;  	/* Unsupported request reporting enable. */  	pciercx_cfg030.s.ur_en = 1; -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), -			     pciercx_cfg030.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG030(pcie_port), pciercx_cfg030.u32); -	/* -	 * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match -	 * PCIE*_CFG030[MPS] -	 * -	 * Max Read Request Size (NPEI_CTL_STATUS2[MRRS]) must not -	 * exceed PCIE*_CFG030[MRRS]. -	 */ -	npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); -	/* Max payload size = 128 bytes for best Octeon DMA performance */ -	npei_ctl_status2.s.mps = 0; -	/* Max read request size = 128 bytes for best Octeon DMA performance */ -	npei_ctl_status2.s.mrrs = 0; -	if (pcie_port) -		npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ -	else -		npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ -	cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); + +	if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { +		union cvmx_npei_ctl_status2 npei_ctl_status2; +		/* +		 * Max Payload Size (NPEI_CTL_STATUS2[MPS]) must match +		 * PCIE*_CFG030[MPS].  Max Read Request Size +		 * (NPEI_CTL_STATUS2[MRRS]) must not exceed +		 * PCIE*_CFG030[MRRS] +		 */ +		npei_ctl_status2.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS2); +		/* Max payload size = 128 bytes for best Octeon DMA performance */ +		npei_ctl_status2.s.mps = MPS_CN5XXX; +		/* Max read request size = 128 bytes for best Octeon DMA performance */ +		npei_ctl_status2.s.mrrs = MRRS_CN5XXX; +		if (pcie_port) +			npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */ +		else +			npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */ + +		cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); +	} else { +		/* +		 * Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match +		 * PCIE*_CFG030[MPS].  Max Read Request Size +		 * (DPI_SLI_PRTX_CFG[MRRS]) must not exceed +		 * PCIE*_CFG030[MRRS]. +		 */ +		union cvmx_dpi_sli_prtx_cfg prt_cfg; +		union cvmx_sli_s2m_portx_ctl sli_s2m_portx_ctl; +		prt_cfg.u64 = cvmx_read_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port)); +		prt_cfg.s.mps = MPS_CN6XXX; +		prt_cfg.s.mrrs = MRRS_CN6XXX; +		/* Max outstanding load request. */ +		prt_cfg.s.molr = 32; +		cvmx_write_csr(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64); + +		sli_s2m_portx_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port)); +		sli_s2m_portx_ctl.s.mrrs = MRRS_CN6XXX; +		cvmx_write_csr(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64); +	}  	/* ECRC Generation (PCIE*_CFG070[GE,CE]) */ -	pciercx_cfg070.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port)); +	pciercx_cfg070.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG070(pcie_port));  	pciercx_cfg070.s.ge = 1;	/* ECRC generation enable. */  	pciercx_cfg070.s.ce = 1;	/* ECRC check enable. */ -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), -			     pciercx_cfg070.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32);  	/* -	 * Access Enables (PCIE*_CFG001[MSAE,ME]) ME and MSAE should -	 * always be set. -	 * -	 * Interrupt Disable (PCIE*_CFG001[I_DIS]) System Error -	 * Message Enable (PCIE*_CFG001[SEE]) +	 * Access Enables (PCIE*_CFG001[MSAE,ME]) +	 * ME and MSAE should always be set. +	 * Interrupt Disable (PCIE*_CFG001[I_DIS]) +	 * System Error Message Enable (PCIE*_CFG001[SEE])  	 */ -	pciercx_cfg001.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port)); +	pciercx_cfg001.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG001(pcie_port));  	pciercx_cfg001.s.msae = 1;	/* Memory space enable. */  	pciercx_cfg001.s.me = 1;	/* Bus master enable. */  	pciercx_cfg001.s.i_dis = 1;	/* INTx assertion disable. */  	pciercx_cfg001.s.see = 1;	/* SERR# enable */ -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), -			pciercx_cfg001.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32);  	/* Advanced Error Recovery Message Enables */  	/* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */ @@ -440,14 +492,11 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)  	/* Use CVMX_PCIERCX_CFG067 hardware default */  	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0); -	/* Active State Power Management (PCIE*_CFG032[ASLPC]) */ -	pciercx_cfg032.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); -	pciercx_cfg032.s.aslpc = 0;	/* Active state Link PM control. */ -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), -			     pciercx_cfg032.u32); -	/* Entrance Latencies (PCIE*_CFG451[L0EL,L1EL]) */ +	/* Active State Power Management (PCIE*_CFG032[ASLPC]) */ +	pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); +	pciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */ +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32);  	/*  	 * Link Width Mode (PCIERCn_CFG452[LME]) - Set during @@ -462,8 +511,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)  	pciercx_cfg006.s.pbnum = 1;  	pciercx_cfg006.s.sbnum = 1;  	pciercx_cfg006.s.subbnum = 1; -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), -			     pciercx_cfg006.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32); +  	/*  	 * Memory-mapped I/O BAR (PCIERCn_CFG008) @@ -473,8 +522,8 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)  	pciercx_cfg008.u32 = 0;  	pciercx_cfg008.s.mb_addr = 0x100;  	pciercx_cfg008.s.ml_addr = 0; -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), -			     pciercx_cfg008.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32); +  	/*  	 * Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) @@ -482,72 +531,51 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)  	 * PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] <  	 * PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE]  	 */ -	pciercx_cfg009.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); -	pciercx_cfg010.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); -	pciercx_cfg011.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port)); +	pciercx_cfg009.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG009(pcie_port)); +	pciercx_cfg010.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG010(pcie_port)); +	pciercx_cfg011.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG011(pcie_port));  	pciercx_cfg009.s.lmem_base = 0x100;  	pciercx_cfg009.s.lmem_limit = 0;  	pciercx_cfg010.s.umem_base = 0x100;  	pciercx_cfg011.s.umem_limit = 0; -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), -			     pciercx_cfg009.u32); -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), -			     pciercx_cfg010.u32); -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), -			     pciercx_cfg011.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32);  	/*  	 * System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE])  	 * PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) -	 */ -	pciercx_cfg035.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); -	/* System error on correctable error enable. */ -	pciercx_cfg035.s.secee = 1; -	/* System error on fatal error enable. */ -	pciercx_cfg035.s.sefee = 1; -	/* System error on non-fatal error enable. */ -	pciercx_cfg035.s.senfee = 1; -	/* PME interrupt enable. */ -	pciercx_cfg035.s.pmeie = 1; -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), -			     pciercx_cfg035.u32); +	*/ +	pciercx_cfg035.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG035(pcie_port)); +	pciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */ +	pciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */ +	pciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */ +	pciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */ +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32);  	/*  	 * Advanced Error Recovery Interrupt Enables  	 * (PCIERCn_CFG075[CERE,NFERE,FERE])  	 */ -	pciercx_cfg075.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); -	/* Correctable error reporting enable. */ -	pciercx_cfg075.s.cere = 1; -	/* Non-fatal error reporting enable. */ -	pciercx_cfg075.s.nfere = 1; -	/* Fatal error reporting enable. */ -	pciercx_cfg075.s.fere = 1; -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), -			     pciercx_cfg075.u32); +	pciercx_cfg075.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG075(pcie_port)); +	pciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */ +	pciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */ +	pciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */ +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32); -	/* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], +	/* +	 * HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN],  	 * PCIERCn_CFG034[DLLS_EN,CCINT_EN])  	 */ -	pciercx_cfg034.u32 = -		cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); -	/* Hot-plug interrupt enable. */ -	pciercx_cfg034.s.hpint_en = 1; -	/* Data Link Layer state changed enable */ -	pciercx_cfg034.s.dlls_en = 1; -	/* Command completed interrupt enable. */ -	pciercx_cfg034.s.ccint_en = 1; -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), -			     pciercx_cfg034.u32); +	pciercx_cfg034.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG034(pcie_port)); +	pciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */ +	pciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */ +	pciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */ +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32);  }  /** - * Initialize a host mode PCIe link. This function takes a PCIe + * Initialize a host mode PCIe gen 1 link. This function takes a PCIe   * port from reset to a link up state. Software can then begin   * configuring the rest of the link.   * @@ -555,7 +583,7 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)   *   * Returns Zero on success   */ -static int __cvmx_pcie_rc_initialize_link(int pcie_port) +static int __cvmx_pcie_rc_initialize_link_gen1(int pcie_port)  {  	uint64_t start_cycle;  	union cvmx_pescx_ctl_status pescx_ctl_status; @@ -564,18 +592,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)  	union cvmx_pciercx_cfg448 pciercx_cfg448;  	/* Set the lane width */ -	pciercx_cfg452.u32 = -	    cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port)); +	pciercx_cfg452.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG452(pcie_port));  	pescx_ctl_status.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS(pcie_port)); -	if (pescx_ctl_status.s.qlm_cfg == 0) { +	if (pescx_ctl_status.s.qlm_cfg == 0)  		/* We're in 8 lane (56XX) or 4 lane (54XX) mode */  		pciercx_cfg452.s.lme = 0xf; -	} else { +	else  		/* We're in 4 lane (56XX) or 2 lane (52XX) mode */  		pciercx_cfg452.s.lme = 0x7; -	} -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), -			     pciercx_cfg452.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), pciercx_cfg452.u32);  	/*  	 * CN52XX pass 1.x has an errata where length mismatches on UR @@ -584,19 +609,15 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)  	 */  	if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {  		union cvmx_pciercx_cfg455 pciercx_cfg455; -		pciercx_cfg455.u32 = -		    cvmx_pcie_cfgx_read(pcie_port, -					CVMX_PCIERCX_CFG455(pcie_port)); +		pciercx_cfg455.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG455(pcie_port));  		pciercx_cfg455.s.m_cpl_len_err = 1; -		cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), -				     pciercx_cfg455.u32); +		cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG455(pcie_port), pciercx_cfg455.u32);  	}  	/* Lane swap needs to be manually enabled for CN52XX */  	if (OCTEON_IS_MODEL(OCTEON_CN52XX) && (pcie_port == 1)) {  		pescx_ctl_status.s.lane_swp = 1; -		cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), -			       pescx_ctl_status.u64); +		cvmx_write_csr(CVMX_PESCX_CTL_STATUS(pcie_port), pescx_ctl_status.u64);  	}  	/* Bring up the link */ @@ -612,24 +633,18 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)  		__cvmx_helper_errata_qlm_disable_2nd_order_cdr(0);  	/* Wait for the link to come up */ -	cvmx_dprintf("PCIe: Waiting for port %d link\n", pcie_port);  	start_cycle = cvmx_get_cycle();  	do { -		if (cvmx_get_cycle() - start_cycle > -		    2 * cvmx_sysinfo_get()->cpu_clock_hz) { -			cvmx_dprintf("PCIe: Port %d link timeout\n", -				     pcie_port); +		if (cvmx_get_cycle() - start_cycle > 2 * octeon_get_clock_rate()) { +			cvmx_dprintf("PCIe: Port %d link timeout\n", pcie_port);  			return -1;  		}  		cvmx_wait(10000); -		pciercx_cfg032.u32 = -		    cvmx_pcie_cfgx_read(pcie_port, -					CVMX_PCIERCX_CFG032(pcie_port)); +		pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));  	} while (pciercx_cfg032.s.dlla == 0); -	/* Display the link status */ -	cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, -		     pciercx_cfg032.s.nlw); +	/* Clear all pending errors */ +	cvmx_write_csr(CVMX_PEXP_NPEI_INT_SUM, cvmx_read_csr(CVMX_PEXP_NPEI_INT_SUM));  	/*  	 * Update the Replay Time Limit. Empirically, some PCIe @@ -639,8 +654,7 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)  	 * our actual 256 byte MPS. The numbers below are directly  	 * from the PCIe spec table 3-4.  	 */ -	pciercx_cfg448.u32 = -	    cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); +	pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));  	switch (pciercx_cfg032.s.nlw) {  	case 1:		/* 1 lane */  		pciercx_cfg448.s.rtl = 1677; @@ -655,21 +669,28 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)  		pciercx_cfg448.s.rtl = 258;  		break;  	} -	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), -			     pciercx_cfg448.u32); +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);  	return 0;  } +static void __cvmx_increment_ba(union cvmx_sli_mem_access_subidx *pmas) +{ +	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) +		pmas->cn68xx.ba++; +	else +		pmas->cn63xx.ba++; +} +  /** - * Initialize a PCIe port for use in host(RC) mode. It doesn't + * Initialize a PCIe gen 1 port for use in host(RC) mode. It doesn't   * enumerate the bus.   *   * @pcie_port: PCIe port to initialize   *   * Returns Zero on success   */ -static int cvmx_pcie_rc_initialize(int pcie_port) +static int __cvmx_pcie_rc_initialize_gen1(int pcie_port)  {  	int i;  	int base; @@ -682,16 +703,17 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  	union cvmx_npei_mem_access_subidx mem_access_subid;  	union cvmx_npei_dbg_data npei_dbg_data;  	union cvmx_pescx_ctl_status2 pescx_ctl_status2; +	union cvmx_pciercx_cfg032 pciercx_cfg032;  	union cvmx_npei_bar1_indexx bar1_index; +retry:  	/*  	 * Make sure we aren't trying to setup a target mode interface  	 * in host mode.  	 */  	npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS);  	if ((pcie_port == 0) && !npei_ctl_status.s.host_mode) { -		cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called " -			     "on port0, but port0 is not in host mode\n"); +		cvmx_dprintf("PCIe: Port %d in endpoint mode\n", pcie_port);  		return -1;  	} @@ -702,9 +724,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  	if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {  		npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA);  		if ((pcie_port == 1) && npei_dbg_data.cn52xx.qlm0_link_width) { -			cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() " -				     "called on port1, but port1 is " -				     "disabled\n"); +			cvmx_dprintf("PCIe: ERROR: cvmx_pcie_rc_initialize() called on port1, but port1 is disabled\n");  			return -1;  		}  	} @@ -733,7 +753,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  		 * the board. As a workaround for this bug, we bring  		 * both PCIe ports out of reset at the same time  		 * instead of on separate calls. So for port 0, we -		 * bring both out of reset and do nothing on port 1. +		 * bring both out of reset and do nothing on port 1  		 */  		if (pcie_port == 0) {  			ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); @@ -746,13 +766,10 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  			if (ciu_soft_prst.s.soft_prst == 0) {  				/* Reset the ports */  				ciu_soft_prst.s.soft_prst = 1; -				cvmx_write_csr(CVMX_CIU_SOFT_PRST, -					       ciu_soft_prst.u64); -				ciu_soft_prst.u64 = -				    cvmx_read_csr(CVMX_CIU_SOFT_PRST1); +				cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); +				ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1);  				ciu_soft_prst.s.soft_prst = 1; -				cvmx_write_csr(CVMX_CIU_SOFT_PRST1, -					       ciu_soft_prst.u64); +				cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);  				/* Wait until pcie resets the ports. */  				udelay(2000);  			} @@ -782,11 +799,9 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  			/* Reset the port */  			ciu_soft_prst.s.soft_prst = 1;  			if (pcie_port) -				cvmx_write_csr(CVMX_CIU_SOFT_PRST1, -					       ciu_soft_prst.u64); +				cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64);  			else -				cvmx_write_csr(CVMX_CIU_SOFT_PRST, -					       ciu_soft_prst.u64); +				cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64);  			/* Wait until pcie resets the ports. */  			udelay(2000);  		} @@ -808,25 +823,21 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  	 */  	cvmx_wait(400000); -	/* PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of CN56XX and -	   CN52XX, so we only probe it on newer chips */ -	if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) -	    && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { +	/* +	 * PESCX_BIST_STATUS2[PCLK_RUN] was missing on pass 1 of +	 * CN56XX and CN52XX, so we only probe it on newer chips +	 */ +	if (!OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {  		/* Clear PCLK_RUN so we can check if the clock is running */ -		pescx_ctl_status2.u64 = -		    cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); +		pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));  		pescx_ctl_status2.s.pclk_run = 1; -		cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), -			       pescx_ctl_status2.u64); -		/* -		 * Now that we cleared PCLK_RUN, wait for it to be set -		 * again telling us the clock is running. +		cvmx_write_csr(CVMX_PESCX_CTL_STATUS2(pcie_port), pescx_ctl_status2.u64); +		/* Now that we cleared PCLK_RUN, wait for it to be set +		 * again telling us the clock is running  		 */  		if (CVMX_WAIT_FOR_FIELD64(CVMX_PESCX_CTL_STATUS2(pcie_port), -					  union cvmx_pescx_ctl_status2, -					  pclk_run, ==, 1, 10000)) { -			cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", -				     pcie_port); +					  union cvmx_pescx_ctl_status2, pclk_run, ==, 1, 10000)) { +			cvmx_dprintf("PCIe: Port %d isn't clocked, skipping.\n", pcie_port);  			return -1;  		}  	} @@ -836,30 +847,26 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  	 * the board probably hasn't wired the clocks up and the  	 * interface should be skipped.  	 */ -	pescx_ctl_status2.u64 = -	    cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port)); +	pescx_ctl_status2.u64 = cvmx_read_csr(CVMX_PESCX_CTL_STATUS2(pcie_port));  	if (pescx_ctl_status2.s.pcierst) { -		cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", -			     pcie_port); +		cvmx_dprintf("PCIe: Port %d stuck in reset, skipping.\n", pcie_port);  		return -1;  	}  	/* -	 * Check BIST2 status. If any bits are set skip this interface. This -	 * is an attempt to catch PCIE-813 on pass 1 parts. +	 * Check BIST2 status. If any bits are set skip this +	 * interface. This is an attempt to catch PCIE-813 on pass 1 +	 * parts.  	 */ -	pescx_bist_status2.u64 = -	    cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port)); +	pescx_bist_status2.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS2(pcie_port));  	if (pescx_bist_status2.u64) { -		cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this " -			     "port isn't hooked up, skipping.\n", +		cvmx_dprintf("PCIe: Port %d BIST2 failed. Most likely this port isn't hooked up, skipping.\n",  			     pcie_port);  		return -1;  	}  	/* Check BIST status */ -	pescx_bist_status.u64 = -	    cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port)); +	pescx_bist_status.u64 = cvmx_read_csr(CVMX_PESCX_BIST_STATUS(pcie_port));  	if (pescx_bist_status.u64)  		cvmx_dprintf("PCIe: BIST FAILED for port %d (0x%016llx)\n",  			     pcie_port, CAST64(pescx_bist_status.u64)); @@ -868,50 +875,37 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  	__cvmx_pcie_rc_initialize_config_space(pcie_port);  	/* Bring the link up */ -	if (__cvmx_pcie_rc_initialize_link(pcie_port)) { -		cvmx_dprintf -		    ("PCIe: ERROR: cvmx_pcie_rc_initialize_link() failed\n"); +	if (__cvmx_pcie_rc_initialize_link_gen1(pcie_port)) { +		cvmx_dprintf("PCIe: Failed to initialize port %d, probably the slot is empty\n", +			     pcie_port);  		return -1;  	}  	/* Store merge control (NPEI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */  	npei_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL); -	/* Allow 16 words to combine */ -	npei_mem_access_ctl.s.max_word = 0; -	/* Wait up to 127 cycles for more data */ -	npei_mem_access_ctl.s.timer = 127; +	npei_mem_access_ctl.s.max_word = 0;	/* Allow 16 words to combine */ +	npei_mem_access_ctl.s.timer = 127;	/* Wait up to 127 cycles for more data */  	cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_CTL, npei_mem_access_ctl.u64);  	/* Setup Mem access SubDIDs */  	mem_access_subid.u64 = 0; -	/* Port the request is sent to. */ -	mem_access_subid.s.port = pcie_port; -	/* Due to an errata on pass 1 chips, no merging is allowed. */ -	mem_access_subid.s.nmerge = 1; -	/* Endian-swap for Reads. */ -	mem_access_subid.s.esr = 1; -	/* Endian-swap for Writes. */ -	mem_access_subid.s.esw = 1; -	/* No Snoop for Reads. */ -	mem_access_subid.s.nsr = 1; -	/* No Snoop for Writes. */ -	mem_access_subid.s.nsw = 1; -	/* Disable Relaxed Ordering for Reads. */ -	mem_access_subid.s.ror = 0; -	/* Disable Relaxed Ordering for Writes. */ -	mem_access_subid.s.row = 0; -	/* PCIe Adddress Bits <63:34>. */ -	mem_access_subid.s.ba = 0; +	mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ +	mem_access_subid.s.nmerge = 1;	/* Due to an errata on pass 1 chips, no merging is allowed. */ +	mem_access_subid.s.esr = 1;	/* Endian-swap for Reads. */ +	mem_access_subid.s.esw = 1;	/* Endian-swap for Writes. */ +	mem_access_subid.s.nsr = 0;	/* Enable Snooping for Reads. Octeon doesn't care, but devices might want this more conservative setting */ +	mem_access_subid.s.nsw = 0;	/* Enable Snoop for Writes. */ +	mem_access_subid.s.ror = 0;	/* Disable Relaxed Ordering for Reads. */ +	mem_access_subid.s.row = 0;	/* Disable Relaxed Ordering for Writes. */ +	mem_access_subid.s.ba = 0;	/* PCIe Adddress Bits <63:34>. */  	/*  	 * Setup mem access 12-15 for port 0, 16-19 for port 1,  	 * supplying 36 bits of address space.  	 */  	for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { -		cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), -			       mem_access_subid.u64); -		/* Set each SUBID to extend the addressable range */ -		mem_access_subid.s.ba += 1; +		cvmx_write_csr(CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); +		mem_access_subid.s.ba += 1; /* Set each SUBID to extend the addressable range */  	}  	/* @@ -927,12 +921,12 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  	/* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */  	cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0); -	/* BAR1 follows BAR2 with a gap. */ +	/* BAR1 follows BAR2 with a gap so it has the same address as for gen2. */  	cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);  	bar1_index.u32 = 0;  	bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22); -	bar1_index.s.ca = 1;       /* Not Cached */ +	bar1_index.s.ca = 1;	   /* Not Cached */  	bar1_index.s.end_swp = 1;  /* Endian Swap mode */  	bar1_index.s.addr_v = 1;   /* Valid entry */ @@ -992,22 +986,482 @@ static int cvmx_pcie_rc_initialize(int pcie_port)  		npei_ctl_port.s.waitl_com = 0;  		cvmx_write_csr(CVMX_PEXP_NPEI_CTL_PORT0, npei_ctl_port.u64);  	} + +	/* +	 * Both pass 1 and pass 2 of CN52XX and CN56XX have an errata +	 * that causes TLP ordering to not be preserved after multiple +	 * PCIe port resets. This code detects this fault and corrects +	 * it by aligning the TLP counters properly. Another link +	 * reset is then performed. See PCIE-13340 +	 */ +	if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS2_X) || +	    OCTEON_IS_MODEL(OCTEON_CN52XX_PASS2_X) || +	    OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) || +	    OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { +		union cvmx_npei_dbg_data dbg_data; +		int old_in_fif_p_count; +		int in_fif_p_count; +		int out_p_count; +		int in_p_offset = (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X) || OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) ? 4 : 1; +		int i; + +		/* +		 * Choose a write address of 1MB. It should be +		 * harmless as all bars haven't been setup. +		 */ +		uint64_t write_address = (cvmx_pcie_get_mem_base_address(pcie_port) + 0x100000) | (1ull<<63); + +		/* +		 * Make sure at least in_p_offset have been executed before we try and +		 * read in_fif_p_count +		 */ +		i = in_p_offset; +		while (i--) { +			cvmx_write64_uint32(write_address, 0); +			cvmx_wait(10000); +		} + +		/* +		 * Read the IN_FIF_P_COUNT from the debug +		 * select. IN_FIF_P_COUNT can be unstable sometimes so +		 * read it twice with a write between the reads.  This +		 * way we can tell the value is good as it will +		 * increment by one due to the write +		 */ +		cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd7fc : 0xcffc); +		cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); +		do { +			dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); +			old_in_fif_p_count = dbg_data.s.data & 0xff; +			cvmx_write64_uint32(write_address, 0); +			cvmx_wait(10000); +			dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); +			in_fif_p_count = dbg_data.s.data & 0xff; +		} while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff)); + +		/* Update in_fif_p_count for it's offset with respect to out_p_count */ +		in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff; + +		/* Read the OUT_P_COUNT from the debug select */ +		cvmx_write_csr(CVMX_PEXP_NPEI_DBG_SELECT, (pcie_port) ? 0xd00f : 0xc80f); +		cvmx_read_csr(CVMX_PEXP_NPEI_DBG_SELECT); +		dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); +		out_p_count = (dbg_data.s.data>>1) & 0xff; + +		/* Check that the two counters are aligned */ +		if (out_p_count != in_fif_p_count) { +			cvmx_dprintf("PCIe: Port %d aligning TLP counters as workaround to maintain ordering\n", pcie_port); +			while (in_fif_p_count != 0) { +				cvmx_write64_uint32(write_address, 0); +				cvmx_wait(10000); +				in_fif_p_count = (in_fif_p_count + 1) & 0xff; +			} +			/* +			 * The EBH5200 board swapped the PCIe reset +			 * lines on the board. This means we must +			 * bring both links down and up, which will +			 * cause the PCIe0 to need alignment +			 * again. Lots of messages will be displayed, +			 * but everything should work +			 */ +			if ((cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBH5200) && +				(pcie_port == 1)) +				cvmx_pcie_rc_initialize(0); +			/* Rety bringing this port up */ +			goto retry; +		} +	} + +	/* Display the link status */ +	pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); +	cvmx_dprintf("PCIe: Port %d link active, %d lanes\n", pcie_port, pciercx_cfg032.s.nlw); +  	return 0;  } +/** +  * Initialize a host mode PCIe gen 2 link. This function takes a PCIe + * port from reset to a link up state. Software can then begin + * configuring the rest of the link. + * + * @pcie_port: PCIe port to initialize + * + * Return Zero on success. + */ +static int __cvmx_pcie_rc_initialize_link_gen2(int pcie_port) +{ +	uint64_t start_cycle; +	union cvmx_pemx_ctl_status pem_ctl_status; +	union cvmx_pciercx_cfg032 pciercx_cfg032; +	union cvmx_pciercx_cfg448 pciercx_cfg448; -/* Above was cvmx-pcie.c, below original pcie.c */ +	/* Bring up the link */ +	pem_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); +	pem_ctl_status.s.lnk_enb = 1; +	cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64); + +	/* Wait for the link to come up */ +	start_cycle = cvmx_get_cycle(); +	do { +		if (cvmx_get_cycle() - start_cycle >  octeon_get_clock_rate()) +			return -1; +		cvmx_wait(10000); +		pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); +	} while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1)); + +	/* +	 * Update the Replay Time Limit. Empirically, some PCIe +	 * devices take a little longer to respond than expected under +	 * load. As a workaround for this we configure the Replay Time +	 * Limit to the value expected for a 512 byte MPS instead of +	 * our actual 256 byte MPS. The numbers below are directly +	 * from the PCIe spec table 3-4 +	 */ +	pciercx_cfg448.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG448(pcie_port)); +	switch (pciercx_cfg032.s.nlw) { +	case 1: /* 1 lane */ +		pciercx_cfg448.s.rtl = 1677; +		break; +	case 2: /* 2 lanes */ +		pciercx_cfg448.s.rtl = 867; +		break; +	case 4: /* 4 lanes */ +		pciercx_cfg448.s.rtl = 462; +		break; +	case 8: /* 8 lanes */ +		pciercx_cfg448.s.rtl = 258; +		break; +	} +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32); + +	return 0; +} + + +/** + * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate + * the bus. + * + * @pcie_port: PCIe port to initialize + * + * Returns Zero on success. + */ +static int __cvmx_pcie_rc_initialize_gen2(int pcie_port) +{ +	int i; +	union cvmx_ciu_soft_prst ciu_soft_prst; +	union cvmx_mio_rst_ctlx mio_rst_ctl; +	union cvmx_pemx_bar_ctl pemx_bar_ctl; +	union cvmx_pemx_ctl_status pemx_ctl_status; +	union cvmx_pemx_bist_status pemx_bist_status; +	union cvmx_pemx_bist_status2 pemx_bist_status2; +	union cvmx_pciercx_cfg032 pciercx_cfg032; +	union cvmx_pciercx_cfg515 pciercx_cfg515; +	union cvmx_sli_ctl_portx sli_ctl_portx; +	union cvmx_sli_mem_access_ctl sli_mem_access_ctl; +	union cvmx_sli_mem_access_subidx mem_access_subid; +	union cvmx_sriox_status_reg sriox_status_reg; +	union cvmx_pemx_bar1_indexx bar1_index; + +	if (octeon_has_feature(OCTEON_FEATURE_SRIO)) { +		/* Make sure this interface isn't SRIO */ +		if (OCTEON_IS_MODEL(OCTEON_CN66XX)) { +			/* +			 * The CN66XX requires reading the +			 * MIO_QLMX_CFG register to figure out the +			 * port type. +			 */ +			union cvmx_mio_qlmx_cfg qlmx_cfg; +			qlmx_cfg.u64 = cvmx_read_csr(CVMX_MIO_QLMX_CFG(pcie_port)); + +			if (qlmx_cfg.s.qlm_spd == 15) { +				pr_notice("PCIe: Port %d is disabled, skipping.\n", pcie_port); +				return -1; +			} + +			switch (qlmx_cfg.s.qlm_spd) { +			case 0x1: /* SRIO 1x4 short */ +			case 0x3: /* SRIO 1x4 long */ +			case 0x4: /* SRIO 2x2 short */ +			case 0x6: /* SRIO 2x2 long */ +				pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); +				return -1; +			case 0x9: /* SGMII */ +				pr_notice("PCIe: Port %d is SGMII, skipping.\n", pcie_port); +				return -1; +			case 0xb: /* XAUI */ +				pr_notice("PCIe: Port %d is XAUI, skipping.\n", pcie_port); +				return -1; +			case 0x0: /* PCIE gen2 */ +			case 0x8: /* PCIE gen2 (alias) */ +			case 0x2: /* PCIE gen1 */ +			case 0xa: /* PCIE gen1 (alias) */ +				break; +			default: +				pr_notice("PCIe: Port %d is unknown, skipping.\n", pcie_port); +				return -1; +			} +		} else { +			sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(pcie_port)); +			if (sriox_status_reg.s.srio) { +				pr_notice("PCIe: Port %d is SRIO, skipping.\n", pcie_port); +				return -1; +			} +		} +	} + +#if 0 +    /* This code is so that the PCIe analyzer is able to see 63XX traffic */ +	pr_notice("PCIE : init for pcie analyzer.\n"); +	cvmx_helper_qlm_jtag_init(); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); +	cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); +	cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); +	cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 85); +	cvmx_helper_qlm_jtag_shift(pcie_port, 1, 1); +	cvmx_helper_qlm_jtag_shift_zeros(pcie_port, 300-86); +	cvmx_helper_qlm_jtag_update(pcie_port); +#endif + +	/* Make sure we aren't trying to setup a target mode interface in host mode */ +	mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(pcie_port)); +	if (!mio_rst_ctl.s.host_mode) { +		pr_notice("PCIe: Port %d in endpoint mode.\n", pcie_port); +		return -1; +	} + +	/* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be programmed */ +	if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) { +		if (pcie_port) { +			union cvmx_ciu_qlm1 ciu_qlm; +			ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM1); +			ciu_qlm.s.txbypass = 1; +			ciu_qlm.s.txdeemph = 5; +			ciu_qlm.s.txmargin = 0x17; +			cvmx_write_csr(CVMX_CIU_QLM1, ciu_qlm.u64); +		} else { +			union cvmx_ciu_qlm0 ciu_qlm; +			ciu_qlm.u64 = cvmx_read_csr(CVMX_CIU_QLM0); +			ciu_qlm.s.txbypass = 1; +			ciu_qlm.s.txdeemph = 5; +			ciu_qlm.s.txmargin = 0x17; +			cvmx_write_csr(CVMX_CIU_QLM0, ciu_qlm.u64); +		} +	} +	/* Bring the PCIe out of reset */ +	if (pcie_port) +		ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); +	else +		ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); +	/* +	 * After a chip reset the PCIe will also be in reset. If it +	 * isn't, most likely someone is trying to init it again +	 * without a proper PCIe reset +	 */ +	if (ciu_soft_prst.s.soft_prst == 0) { +		/* Reset the port */ +		ciu_soft_prst.s.soft_prst = 1; +		if (pcie_port) +			cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); +		else +			cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); +		/* Wait until pcie resets the ports. */ +		udelay(2000); +	} +	if (pcie_port) { +		ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST1); +		ciu_soft_prst.s.soft_prst = 0; +		cvmx_write_csr(CVMX_CIU_SOFT_PRST1, ciu_soft_prst.u64); +	} else { +		ciu_soft_prst.u64 = cvmx_read_csr(CVMX_CIU_SOFT_PRST); +		ciu_soft_prst.s.soft_prst = 0; +		cvmx_write_csr(CVMX_CIU_SOFT_PRST, ciu_soft_prst.u64); +	} + +	/* Wait for PCIe reset to complete */ +	udelay(1000); + +	/* +	 * Check and make sure PCIe came out of reset. If it doesn't +	 * the board probably hasn't wired the clocks up and the +	 * interface should be skipped. +	 */ +	if (CVMX_WAIT_FOR_FIELD64(CVMX_MIO_RST_CTLX(pcie_port), union cvmx_mio_rst_ctlx, rst_done, ==, 1, 10000)) { +		pr_notice("PCIe: Port %d stuck in reset, skipping.\n", pcie_port); +		return -1; +	} + +	/* Check BIST status */ +	pemx_bist_status.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS(pcie_port)); +	if (pemx_bist_status.u64) +		pr_notice("PCIe: BIST FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status.u64)); +	pemx_bist_status2.u64 = cvmx_read_csr(CVMX_PEMX_BIST_STATUS2(pcie_port)); +	/* Errata PCIE-14766 may cause the lower 6 bits to be randomly set on CN63XXp1 */ +	if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) +		pemx_bist_status2.u64 &= ~0x3full; +	if (pemx_bist_status2.u64) +		pr_notice("PCIe: BIST2 FAILED for port %d (0x%016llx)\n", pcie_port, CAST64(pemx_bist_status2.u64)); + +	/* Initialize the config space CSRs */ +	__cvmx_pcie_rc_initialize_config_space(pcie_port); + +	/* Enable gen2 speed selection */ +	pciercx_cfg515.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG515(pcie_port)); +	pciercx_cfg515.s.dsc = 1; +	cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32); + +	/* Bring the link up */ +	if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { +		/* +		 * Some gen1 devices don't handle the gen 2 training +		 * correctly. Disable gen2 and try again with only +		 * gen1 +		 */ +		union cvmx_pciercx_cfg031 pciercx_cfg031; +		pciercx_cfg031.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG031(pcie_port)); +		pciercx_cfg031.s.mls = 1; +		cvmx_pcie_cfgx_write(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32); +		if (__cvmx_pcie_rc_initialize_link_gen2(pcie_port)) { +			pr_notice("PCIe: Link timeout on port %d, probably the slot is empty\n", pcie_port); +			return -1; +		} +	} + +	/* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */ +	sli_mem_access_ctl.u64 = cvmx_read_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL); +	sli_mem_access_ctl.s.max_word = 0;	/* Allow 16 words to combine */ +	sli_mem_access_ctl.s.timer = 127;	/* Wait up to 127 cycles for more data */ +	cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64); + +	/* Setup Mem access SubDIDs */ +	mem_access_subid.u64 = 0; +	mem_access_subid.s.port = pcie_port; /* Port the request is sent to. */ +	mem_access_subid.s.nmerge = 0;	/* Allow merging as it works on CN6XXX. */ +	mem_access_subid.s.esr = 1;	/* Endian-swap for Reads. */ +	mem_access_subid.s.esw = 1;	/* Endian-swap for Writes. */ +	mem_access_subid.s.wtype = 0;	/* "No snoop" and "Relaxed ordering" are not set */ +	mem_access_subid.s.rtype = 0;	/* "No snoop" and "Relaxed ordering" are not set */ +	/* PCIe Adddress Bits <63:34>. */ +	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) +		mem_access_subid.cn68xx.ba = 0; +	else +		mem_access_subid.cn63xx.ba = 0; + +	/* +	 * Setup mem access 12-15 for port 0, 16-19 for port 1, +	 * supplying 36 bits of address space. +	 */ +	for (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) { +		cvmx_write_csr(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64); +		/* Set each SUBID to extend the addressable range */ +		__cvmx_increment_ba(&mem_access_subid); +	} + +	/* +	 * Disable the peer to peer forwarding register. This must be +	 * setup by the OS after it enumerates the bus and assigns +	 * addresses to the PCIe busses. +	 */ +	for (i = 0; i < 4; i++) { +		cvmx_write_csr(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1); +		cvmx_write_csr(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1); +	} + +	/* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ +	cvmx_write_csr(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0); + +	/* +	 * Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take +	 * precedence where they overlap. It also overlaps with the +	 * device addresses, so make sure the peer to peer forwarding +	 * is set right. +	 */ +	cvmx_write_csr(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0); + +	/* +	 * Setup BAR2 attributes +	 * Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) +	 * - PTLP_RO,CTLP_RO should normally be set (except for debug). +	 * - WAIT_COM=0 will likely work for all applications. +	 * Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) +	 */ +	pemx_bar_ctl.u64 = cvmx_read_csr(CVMX_PEMX_BAR_CTL(pcie_port)); +	pemx_bar_ctl.s.bar1_siz = 3;  /* 256MB BAR1*/ +	pemx_bar_ctl.s.bar2_enb = 1; +	pemx_bar_ctl.s.bar2_esx = 1; +	pemx_bar_ctl.s.bar2_cax = 0; +	cvmx_write_csr(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64); +	sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port)); +	sli_ctl_portx.s.ptlp_ro = 1; +	sli_ctl_portx.s.ctlp_ro = 1; +	sli_ctl_portx.s.wait_com = 0; +	sli_ctl_portx.s.waitl_com = 0; +	cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64); + +	/* BAR1 follows BAR2 */ +	cvmx_write_csr(CVMX_PEMX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE); + +	bar1_index.u64 = 0; +	bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22); +	bar1_index.s.ca = 1;	   /* Not Cached */ +	bar1_index.s.end_swp = 1;  /* Endian Swap mode */ +	bar1_index.s.addr_v = 1;   /* Valid entry */ + +	for (i = 0; i < 16; i++) { +		cvmx_write_csr(CVMX_PEMX_BAR1_INDEXX(i, pcie_port), bar1_index.u64); +		/* 256MB / 16 >> 22 == 4 */ +		bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22); +	} + +	/* +	 * Allow config retries for 250ms. Count is based off the 5Ghz +	 * SERDES clock. +	 */ +	pemx_ctl_status.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(pcie_port)); +	pemx_ctl_status.s.cfg_rtry = 250 * 5000000 / 0x10000; +	cvmx_write_csr(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64); +	/* Display the link status */ +	pciercx_cfg032.u32 = cvmx_pcie_cfgx_read(pcie_port, CVMX_PCIERCX_CFG032(pcie_port)); +	pr_notice("PCIe: Port %d link active, %d lanes, speed gen%d\n", pcie_port, pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls); + +	return 0; +} + +/** + * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus. + * + * @pcie_port: PCIe port to initialize + * + * Returns Zero on success + */ +static int cvmx_pcie_rc_initialize(int pcie_port) +{ +	int result; +	if (octeon_has_feature(OCTEON_FEATURE_NPEI)) +		result = __cvmx_pcie_rc_initialize_gen1(pcie_port); +	else +		result = __cvmx_pcie_rc_initialize_gen2(pcie_port); +	return result; +} + +/* Above was cvmx-pcie.c, below original pcie.c */  /**   * Map a PCI device to the appropriate interrupt line   *   * @dev:    The Linux PCI device structure for the device to map   * @slot:   The slot number for this device on __BUS 0__. Linux - *               enumerates through all the bridges and figures out the - *               slot on Bus 0 where this device eventually hooks to. + *		 enumerates through all the bridges and figures out the + *		 slot on Bus 0 where this device eventually hooks to.   * @pin:    The PCI interrupt pin read from the device, then swizzled - *               as it goes through each bridge. + *		 as it goes through each bridge.   * Returns Interrupt number for the device   */  int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev, @@ -1027,11 +1481,12 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,  		 */  		while (dev->bus && dev->bus->parent)  			dev = to_pci_dev(dev->bus->bridge); -		/* If the root bus is number 0 and the PEX 8114 is the +		/* +		 * If the root bus is number 0 and the PEX 8114 is the  		 * root, assume we are behind the miswired bus. We  		 * need to correct the swizzle level by two. Yuck.  		 */ -		if ((dev->bus->number == 0) && +		if ((dev->bus->number == 1) &&  		    (dev->vendor == 0x10b5) && (dev->device == 0x8114)) {  			/*  			 * The pin field is one based, not zero. We @@ -1048,39 +1503,73 @@ int __init octeon_pcie_pcibios_map_irq(const struct pci_dev *dev,  	return pin - 1 + OCTEON_IRQ_PCI_INT0;  } -/** +static	void set_cfg_read_retry(u32 retry_cnt) +{ +	union cvmx_pemx_ctl_status pemx_ctl; +	pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); +	pemx_ctl.s.cfg_rtry = retry_cnt; +	cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); +} + + +static u32 disable_cfg_read_retry(void) +{ +	u32 retry_cnt; + +	union cvmx_pemx_ctl_status pemx_ctl; +	pemx_ctl.u64 = cvmx_read_csr(CVMX_PEMX_CTL_STATUS(1)); +	retry_cnt =  pemx_ctl.s.cfg_rtry; +	pemx_ctl.s.cfg_rtry = 0; +	cvmx_write_csr(CVMX_PEMX_CTL_STATUS(1), pemx_ctl.u64); +	return retry_cnt; +} + +static int is_cfg_retry(void) +{ +	union cvmx_pemx_int_sum pemx_int_sum; +	pemx_int_sum.u64 = cvmx_read_csr(CVMX_PEMX_INT_SUM(1)); +	if (pemx_int_sum.s.crs_dr) +		return 1; +	return 0; +} + +/*   * Read a value from configuration space   * - * @bus: - * @devfn: - * @reg: - * @size: - * @val: - * Returns   */ -static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus, -					  unsigned int devfn, int reg, int size, -					  u32 *val) +static int octeon_pcie_read_config(unsigned int pcie_port, struct pci_bus *bus, +				   unsigned int devfn, int reg, int size, +				   u32 *val)  {  	union octeon_cvmemctl cvmmemctl;  	union octeon_cvmemctl cvmmemctl_save;  	int bus_number = bus->number; +	int cfg_retry = 0; +	int retry_cnt = 0; +	int max_retry_cnt = 10; +	u32 cfg_retry_cnt = 0; +	cvmmemctl_save.u64 = 0; +	BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war));  	/*  	 * For the top level bus make sure our hardware bus number -	 * matches the software one. +	 * matches the software one  	 */  	if (bus->parent == NULL) { -		union cvmx_pciercx_cfg006 pciercx_cfg006; -		pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, -			CVMX_PCIERCX_CFG006(pcie_port)); -		if (pciercx_cfg006.s.pbnum != bus_number) { -			pciercx_cfg006.s.pbnum = bus_number; -			pciercx_cfg006.s.sbnum = bus_number; -			pciercx_cfg006.s.subbnum = bus_number; -			cvmx_pcie_cfgx_write(pcie_port, -				CVMX_PCIERCX_CFG006(pcie_port), -				pciercx_cfg006.u32); +		if (enable_pcie_bus_num_war[pcie_port]) +			bus_number = 0; +		else { +			union cvmx_pciercx_cfg006 pciercx_cfg006; +			pciercx_cfg006.u32 = cvmx_pcie_cfgx_read(pcie_port, +					     CVMX_PCIERCX_CFG006(pcie_port)); +			if (pciercx_cfg006.s.pbnum != bus_number) { +				pciercx_cfg006.s.pbnum = bus_number; +				pciercx_cfg006.s.sbnum = bus_number; +				pciercx_cfg006.s.subbnum = bus_number; +				cvmx_pcie_cfgx_write(pcie_port, +					    CVMX_PCIERCX_CFG006(pcie_port), +					    pciercx_cfg006.u32); +			}  		}  	} @@ -1116,29 +1605,52 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,  		 */  #if 1  		/* Use this option if you aren't using either slot */ -		if (bus_number == 1) +		if (bus_number == 2)  			return PCIBIOS_FUNC_NOT_SUPPORTED;  #elif 0  		/*  		 * Use this option if you are using the first slot but  		 * not the second.  		 */ -		if ((bus_number == 1) && (devfn >> 3 != 2)) +		if ((bus_number == 2) && (devfn >> 3 != 2))  			return PCIBIOS_FUNC_NOT_SUPPORTED;  #elif 0  		/*  		 * Use this option if you are using the second slot  		 * but not the first.  		 */ -		if ((bus_number == 1) && (devfn >> 3 != 3)) +		if ((bus_number == 2) && (devfn >> 3 != 3))  			return PCIBIOS_FUNC_NOT_SUPPORTED;  #elif 0  		/* Use this opion if you are using both slots */ -		if ((bus_number == 1) && +		if ((bus_number == 2) &&  		    !((devfn == (2 << 3)) || (devfn == (3 << 3))))  			return PCIBIOS_FUNC_NOT_SUPPORTED;  #endif +		/* The following #if gives a more complicated example. This is +		   the required checks for running a Nitrox CN16XX-NHBX in the +		   slot of the EBH5600. This card has a PLX PCIe bridge with +		   four Nitrox PLX parts behind it */ +#if 0 +		/* PLX bridge with 4 ports */ +		if ((bus_number == 4) && +		    !((devfn >> 3 >= 1) && (devfn >> 3 <= 4))) +			return PCIBIOS_FUNC_NOT_SUPPORTED; +		/* Nitrox behind PLX 1 */ +		if ((bus_number == 5) && (devfn >> 3 != 0)) +			return PCIBIOS_FUNC_NOT_SUPPORTED; +		/* Nitrox behind PLX 2 */ +		if ((bus_number == 6) && (devfn >> 3 != 0)) +			return PCIBIOS_FUNC_NOT_SUPPORTED; +		/* Nitrox behind PLX 3 */ +		if ((bus_number == 7) && (devfn >> 3 != 0)) +			return PCIBIOS_FUNC_NOT_SUPPORTED; +		/* Nitrox behind PLX 4 */ +		if ((bus_number == 8) && (devfn >> 3 != 0)) +			return PCIBIOS_FUNC_NOT_SUPPORTED; +#endif +  		/*  		 * Shorten the DID timeout so bus errors for PCIe  		 * config reads from non existent devices happen @@ -1152,26 +1664,48 @@ static inline int octeon_pcie_read_config(int pcie_port, struct pci_bus *bus,  		__write_64bit_c0_register($11, 7, cvmmemctl.u64);  	} -	switch (size) { -	case 4: -		*val = cvmx_pcie_config_read32(pcie_port, bus_number, -					       devfn >> 3, devfn & 0x7, reg); +	if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) +		cfg_retry_cnt = disable_cfg_read_retry(); + +	pr_debug("pcie_cfg_rd port=%d b=%d devfn=0x%03x reg=0x%03x" +		 " size=%d ", pcie_port, bus_number, devfn, reg, size); +	do { +		switch (size) { +		case 4: +			*val = cvmx_pcie_config_read32(pcie_port, bus_number, +				devfn >> 3, devfn & 0x7, reg);  		break; -	case 2: -		*val = cvmx_pcie_config_read16(pcie_port, bus_number, -					       devfn >> 3, devfn & 0x7, reg); +		case 2: +			*val = cvmx_pcie_config_read16(pcie_port, bus_number, +				devfn >> 3, devfn & 0x7, reg);  		break; -	case 1: -		*val = cvmx_pcie_config_read8(pcie_port, bus_number, devfn >> 3, -					      devfn & 0x7, reg); +		case 1: +			*val = cvmx_pcie_config_read8(pcie_port, bus_number, +				devfn >> 3, devfn & 0x7, reg);  		break; -	default: -		return PCIBIOS_FUNC_NOT_SUPPORTED; -	} +		default: +			if (OCTEON_IS_MODEL(OCTEON_CN63XX)) +				set_cfg_read_retry(cfg_retry_cnt); +			return PCIBIOS_FUNC_NOT_SUPPORTED; +		} +		if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && +			(enable_pcie_14459_war)) { +			cfg_retry = is_cfg_retry(); +			retry_cnt++; +			if (retry_cnt > max_retry_cnt) { +				pr_err(" pcie cfg_read retries failed. retry_cnt=%d\n", +				       retry_cnt); +				cfg_retry = 0; +			} +		} +	} while (cfg_retry); +	if ((OCTEON_IS_MODEL(OCTEON_CN63XX)) && (enable_pcie_14459_war)) +		set_cfg_read_retry(cfg_retry_cnt); +	pr_debug("val=%08x  : tries=%02d\n", *val, retry_cnt);  	if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1) ||  	    OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_1)) -		__write_64bit_c0_register($11, 7, cvmmemctl_save.u64); +		write_c0_cvmmemctl(cvmmemctl_save.u64);  	return PCIBIOS_SUCCESSFUL;  } @@ -1187,42 +1721,56 @@ static int octeon_pcie1_read_config(struct pci_bus *bus, unsigned int devfn,  	return octeon_pcie_read_config(1, bus, devfn, reg, size, val);  } +static int octeon_dummy_read_config(struct pci_bus *bus, unsigned int devfn, +				    int reg, int size, u32 *val) +{ +	return PCIBIOS_FUNC_NOT_SUPPORTED; +} - -/** +/*   * Write a value to PCI configuration space - * - * @bus: - * @devfn: - * @reg: - * @size: - * @val: - * Returns   */ -static inline int octeon_pcie_write_config(int pcie_port, struct pci_bus *bus, -					   unsigned int devfn, int reg, -					   int size, u32 val) +static int octeon_pcie_write_config(unsigned int pcie_port, struct pci_bus *bus, +				    unsigned int devfn, int reg, +				    int size, u32 val)  {  	int bus_number = bus->number; +	BUG_ON(pcie_port >= ARRAY_SIZE(enable_pcie_bus_num_war)); + +	if ((bus->parent == NULL) && (enable_pcie_bus_num_war[pcie_port])) +		bus_number = 0; + +	pr_debug("pcie_cfg_wr port=%d b=%d devfn=0x%03x" +		 " reg=0x%03x size=%d val=%08x\n", pcie_port, bus_number, devfn, +		 reg, size, val); + +  	switch (size) {  	case 4:  		cvmx_pcie_config_write32(pcie_port, bus_number, devfn >> 3,  					 devfn & 0x7, reg, val); -		return PCIBIOS_SUCCESSFUL; +		break;  	case 2:  		cvmx_pcie_config_write16(pcie_port, bus_number, devfn >> 3,  					 devfn & 0x7, reg, val); -		return PCIBIOS_SUCCESSFUL; +		break;  	case 1:  		cvmx_pcie_config_write8(pcie_port, bus_number, devfn >> 3,  					devfn & 0x7, reg, val); -		return PCIBIOS_SUCCESSFUL; +		break; +	default: +		return PCIBIOS_FUNC_NOT_SUPPORTED;  	}  #if PCI_CONFIG_SPACE_DELAY +	/* +	 * Delay on writes so that devices have time to come up. Some +	 * bridges need this to allow time for the secondary busses to +	 * work +	 */  	udelay(PCI_CONFIG_SPACE_DELAY);  #endif -	return PCIBIOS_FUNC_NOT_SUPPORTED; +	return PCIBIOS_SUCCESSFUL;  }  static int octeon_pcie0_write_config(struct pci_bus *bus, unsigned int devfn, @@ -1237,6 +1785,12 @@ static int octeon_pcie1_write_config(struct pci_bus *bus, unsigned int devfn,  	return octeon_pcie_write_config(1, bus, devfn, reg, size, val);  } +static int octeon_dummy_write_config(struct pci_bus *bus, unsigned int devfn, +				     int reg, int size, u32 val) +{ +	return PCIBIOS_FUNC_NOT_SUPPORTED; +} +  static struct pci_ops octeon_pcie0_ops = {  	octeon_pcie0_read_config,  	octeon_pcie0_write_config, @@ -1279,6 +1833,35 @@ static struct pci_controller octeon_pcie1_controller = {  	.io_resource = &octeon_pcie1_io_resource,  }; +static struct pci_ops octeon_dummy_ops = { +	octeon_dummy_read_config, +	octeon_dummy_write_config, +}; + +static struct resource octeon_dummy_mem_resource = { +	.name = "Virtual PCIe MEM", +	.flags = IORESOURCE_MEM, +}; + +static struct resource octeon_dummy_io_resource = { +	.name = "Virtual PCIe IO", +	.flags = IORESOURCE_IO, +}; + +static struct pci_controller octeon_dummy_controller = { +	.pci_ops = &octeon_dummy_ops, +	.mem_resource = &octeon_dummy_mem_resource, +	.io_resource = &octeon_dummy_io_resource, +}; + +static int device_needs_bus_num_war(uint32_t deviceid) +{ +#define IDT_VENDOR_ID 0x111d + +	if ((deviceid  & 0xffff) == IDT_VENDOR_ID) +		return 1; +	return 0; +}  /**   * Initialize the Octeon PCIe controllers @@ -1287,19 +1870,27 @@ static struct pci_controller octeon_pcie1_controller = {   */  static int __init octeon_pcie_setup(void)  { -	union cvmx_npei_ctl_status npei_ctl_status;  	int result; +	int host_mode; +	int srio_war15205 = 0, port; +	union cvmx_sli_ctl_portx sli_ctl_portx; +	union cvmx_sriox_status_reg sriox_status_reg;  	/* These chips don't have PCIe */  	if (!octeon_has_feature(OCTEON_FEATURE_PCIE))  		return 0; +	/* No PCIe simulation */ +	if (octeon_is_simulation()) +		return 0; + +	/* Disable PCI if instructed on the command line */ +	if (pcie_disable) +		return 0; +  	/* Point pcibios_map_irq() to the PCIe version of it */  	octeon_pcibios_map_irq = octeon_pcie_pcibios_map_irq; -	/* Use the PCIe based DMA mappings */ -	octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE; -  	/*  	 * PCIe I/O range. It is based on port 0 but includes up until  	 * port 1's end. @@ -1310,11 +1901,43 @@ static int __init octeon_pcie_setup(void)  		cvmx_pcie_get_io_base_address(1) -  		cvmx_pcie_get_io_base_address(0) + cvmx_pcie_get_io_size(1) - 1; -	npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); -	if (npei_ctl_status.s.host_mode) { +	/* +	 * Create a dummy PCIe controller to swallow up bus 0. IDT bridges +	 * don't work if the primary bus number is zero. Here we add a fake +	 * PCIe controller that the kernel will give bus 0. This allows +	 * us to not change the normal kernel bus enumeration +	 */ +	octeon_dummy_controller.io_map_base = -1; +	octeon_dummy_controller.mem_resource->start = (1ull<<48); +	octeon_dummy_controller.mem_resource->end = (1ull<<48); +	register_pci_controller(&octeon_dummy_controller); + +	if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { +		union cvmx_npei_ctl_status npei_ctl_status; +		npei_ctl_status.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_CTL_STATUS); +		host_mode = npei_ctl_status.s.host_mode; +		octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE; +	} else { +		union cvmx_mio_rst_ctlx mio_rst_ctl; +		mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(0)); +		host_mode = mio_rst_ctl.s.host_mode; +		octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_PCIE2; +	} + +	if (host_mode) {  		pr_notice("PCIe: Initializing port 0\n"); +		/* CN63XX pass 1_x/2.0 errata PCIe-15205 */ +		if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || +			OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { +			sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(0)); +			if (sriox_status_reg.s.srio) { +				srio_war15205 += 1;	 /* Port is SRIO */ +				port = 0; +			} +		}  		result = cvmx_pcie_rc_initialize(0);  		if (result == 0) { +			uint32_t device0;  			/* Memory offsets are physical addresses */  			octeon_pcie0_controller.mem_offset =  				cvmx_pcie_get_mem_base_address(0); @@ -1343,60 +1966,134 @@ static int __init octeon_pcie_setup(void)  			octeon_pcie0_controller.io_resource->start = 4 << 10;  			octeon_pcie0_controller.io_resource->end =  				cvmx_pcie_get_io_size(0) - 1; +			msleep(100); /* Some devices need extra time */  			register_pci_controller(&octeon_pcie0_controller); +			device0 = cvmx_pcie_config_read32(0, 0, 0, 0, 0); +			enable_pcie_bus_num_war[0] = +				device_needs_bus_num_war(device0);  		}  	} else {  		pr_notice("PCIe: Port 0 in endpoint mode, skipping.\n"); +		/* CN63XX pass 1_x/2.0 errata PCIe-15205 */ +		if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || +			OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { +			srio_war15205 += 1; +			port = 0; +		}  	} -	/* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ -	if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { -		union cvmx_npei_dbg_data npei_dbg_data; -		npei_dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); -		if (npei_dbg_data.cn52xx.qlm0_link_width) -			return 0; +	if (octeon_has_feature(OCTEON_FEATURE_NPEI)) { +		host_mode = 1; +		/* Skip the 2nd port on CN52XX if port 0 is in 4 lane mode */ +		if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { +			union cvmx_npei_dbg_data dbg_data; +			dbg_data.u64 = cvmx_read_csr(CVMX_PEXP_NPEI_DBG_DATA); +			if (dbg_data.cn52xx.qlm0_link_width) +				host_mode = 0; +		} +	} else { +		union cvmx_mio_rst_ctlx mio_rst_ctl; +		mio_rst_ctl.u64 = cvmx_read_csr(CVMX_MIO_RST_CTLX(1)); +		host_mode = mio_rst_ctl.s.host_mode;  	} -	pr_notice("PCIe: Initializing port 1\n"); -	result = cvmx_pcie_rc_initialize(1); -	if (result == 0) { -		/* Memory offsets are physical addresses */ -		octeon_pcie1_controller.mem_offset = -			cvmx_pcie_get_mem_base_address(1); -		/* IO offsets are Mips virtual addresses */ -		octeon_pcie1_controller.io_map_base = -			CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(1)); -		octeon_pcie1_controller.io_offset = -			cvmx_pcie_get_io_base_address(1) - -			cvmx_pcie_get_io_base_address(0); -		/* -		 * To keep things similar to PCI, we start device -		 * addresses at the same place as PCI uisng big bar -		 * support. This normally translates to 4GB-256MB, -		 * which is the same as most x86 PCs. -		 */ -		octeon_pcie1_controller.mem_resource->start = -			cvmx_pcie_get_mem_base_address(1) + (4ul << 30) - -			(OCTEON_PCI_BAR1_HOLE_SIZE << 20); -		octeon_pcie1_controller.mem_resource->end = -			cvmx_pcie_get_mem_base_address(1) + -			cvmx_pcie_get_mem_size(1) - 1; -		/* -		 * Ports must be above 16KB for the ISA bus filtering -		 * in the PCI-X to PCI bridge. -		 */ -		octeon_pcie1_controller.io_resource->start = -			cvmx_pcie_get_io_base_address(1) - -			cvmx_pcie_get_io_base_address(0); -		octeon_pcie1_controller.io_resource->end = -			octeon_pcie1_controller.io_resource->start + -			cvmx_pcie_get_io_size(1) - 1; -		register_pci_controller(&octeon_pcie1_controller); +	if (host_mode) { +		pr_notice("PCIe: Initializing port 1\n"); +		/* CN63XX pass 1_x/2.0 errata PCIe-15205 */ +		if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || +			OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { +			sriox_status_reg.u64 = cvmx_read_csr(CVMX_SRIOX_STATUS_REG(1)); +			if (sriox_status_reg.s.srio) { +				srio_war15205 += 1;	 /* Port is SRIO */ +				port = 1; +			} +		} +		result = cvmx_pcie_rc_initialize(1); +		if (result == 0) { +			uint32_t device0; +			/* Memory offsets are physical addresses */ +			octeon_pcie1_controller.mem_offset = +				cvmx_pcie_get_mem_base_address(1); +			/* +			 * To calculate the address for accessing the 2nd PCIe device, +			 * either 'io_map_base' (pci_iomap()), or 'mips_io_port_base' +			 * (ioport_map()) value is added to +			 * pci_resource_start(dev,bar)). The 'mips_io_port_base' is set +			 * only once based on first PCIe. Also changing 'io_map_base' +			 * based on first slot's value so that both the routines will +			 * work properly. +			 */ +			octeon_pcie1_controller.io_map_base = +				CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(0)); +			/* IO offsets are Mips virtual addresses */ +			octeon_pcie1_controller.io_offset = +				cvmx_pcie_get_io_base_address(1) - +				cvmx_pcie_get_io_base_address(0); +			/* +			 * To keep things similar to PCI, we start device +			 * addresses at the same place as PCI uisng big bar +			 * support. This normally translates to 4GB-256MB, +			 * which is the same as most x86 PCs. +			 */ +			octeon_pcie1_controller.mem_resource->start = +				cvmx_pcie_get_mem_base_address(1) + (4ul << 30) - +				(OCTEON_PCI_BAR1_HOLE_SIZE << 20); +			octeon_pcie1_controller.mem_resource->end = +				cvmx_pcie_get_mem_base_address(1) + +				cvmx_pcie_get_mem_size(1) - 1; +			/* +			 * Ports must be above 16KB for the ISA bus filtering +			 * in the PCI-X to PCI bridge. +			 */ +			octeon_pcie1_controller.io_resource->start = +				cvmx_pcie_get_io_base_address(1) - +				cvmx_pcie_get_io_base_address(0); +			octeon_pcie1_controller.io_resource->end = +				octeon_pcie1_controller.io_resource->start + +				cvmx_pcie_get_io_size(1) - 1; +			msleep(100); /* Some devices need extra time */ +			register_pci_controller(&octeon_pcie1_controller); +			device0 = cvmx_pcie_config_read32(1, 0, 0, 0, 0); +			enable_pcie_bus_num_war[1] = +				device_needs_bus_num_war(device0); +		} +	} else { +		pr_notice("PCIe: Port 1 not in root complex mode, skipping.\n"); +		/* CN63XX pass 1_x/2.0 errata PCIe-15205  */ +		if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || +			OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { +			srio_war15205 += 1; +			port = 1; +		} +	} + +	/* +	 * CN63XX pass 1_x/2.0 errata PCIe-15205 requires setting all +	 * of SRIO MACs SLI_CTL_PORT*[INT*_MAP] to similar value and +	 * all of PCIe Macs SLI_CTL_PORT*[INT*_MAP] to different value +	 * from the previous set values +	 */ +	if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) || +		OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_0)) { +		if (srio_war15205 == 1) { +			sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(port)); +			sli_ctl_portx.s.inta_map = 1; +			sli_ctl_portx.s.intb_map = 1; +			sli_ctl_portx.s.intc_map = 1; +			sli_ctl_portx.s.intd_map = 1; +			cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(port), sli_ctl_portx.u64); + +			sli_ctl_portx.u64 = cvmx_read_csr(CVMX_PEXP_SLI_CTL_PORTX(!port)); +			sli_ctl_portx.s.inta_map = 0; +			sli_ctl_portx.s.intb_map = 0; +			sli_ctl_portx.s.intc_map = 0; +			sli_ctl_portx.s.intd_map = 0; +			cvmx_write_csr(CVMX_PEXP_SLI_CTL_PORTX(!port), sli_ctl_portx.u64); +		}  	}  	octeon_pci_dma_init();  	return 0;  } -  arch_initcall(octeon_pcie_setup);  | 
