diff options
Diffstat (limited to 'arch/powerpc/platforms')
132 files changed, 2512 insertions, 10655 deletions
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index fcf6bf2ceee..2e4e64abfab 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -23,6 +23,7 @@ config BLUESTONE  	default n  	select PPC44x_SIMPLE  	select APM821xx +	select PPC4xx_PCI_EXPRESS  	select IBM_EMAC_RGMII  	help  	  This option enables support for the APM APM821xx Evaluation board. diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c index 3f6229b5dee..583e67fee37 100644 --- a/arch/powerpc/platforms/44x/currituck.c +++ b/arch/powerpc/platforms/44x/currituck.c @@ -83,7 +83,7 @@ static void __init ppc47x_init_irq(void)  		 * device-tree, just pass 0 to all arguments  		 */  		struct mpic *mpic = -			mpic_alloc(np, 0, 0, 0, 0, " MPIC     "); +			mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");  		BUG_ON(mpic == NULL);  		mpic_init(mpic);  		ppc_md.get_irq = mpic_get_irq; diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index 5b8cdbb82f8..a28a8629727 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -71,8 +71,7 @@ static void __init iss4xx_init_irq(void)  		/* The MPIC driver will get everything it needs from the  		 * device-tree, just pass 0 to all arguments  		 */ -		struct mpic *mpic = mpic_alloc(np, 0, 0, 0, 0, -					       " MPIC     "); +		struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");  		BUG_ON(mpic == NULL);  		mpic_init(mpic);  		ppc_md.get_irq = mpic_get_irq; diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index 8d220276341..3ffb915446e 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c @@ -52,7 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe);  static char *board[] __initdata = {  	"amcc,arches",  	"amcc,bamboo", -	"amcc,bluestone", +	"apm,bluestone",  	"amcc,glacier",  	"ibm,ebony",  	"amcc,eiger", diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 9f09319352c..ca3a062ed1b 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -21,7 +21,7 @@  #include <asm/prom.h>  static struct device_node *cpld_pic_node; -static struct irq_host *cpld_pic_host; +static struct irq_domain *cpld_pic_host;  /*   * Bits to ignore in the misc_status register @@ -123,13 +123,13 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)  }  static int -cpld_pic_host_match(struct irq_host *h, struct device_node *node) +cpld_pic_host_match(struct irq_domain *h, struct device_node *node)  {  	return cpld_pic_node == node;  }  static int -cpld_pic_host_map(struct irq_host *h, unsigned int virq, +cpld_pic_host_map(struct irq_domain *h, unsigned int virq,  			     irq_hw_number_t hw)  {  	irq_set_status_flags(virq, IRQ_LEVEL); @@ -137,8 +137,7 @@ cpld_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct -irq_host_ops cpld_pic_host_ops = { +static const struct irq_domain_ops cpld_pic_host_ops = {  	.match = cpld_pic_host_match,  	.map = cpld_pic_host_map,  }; @@ -191,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void)  	cpld_pic_node = of_node_get(np); -	cpld_pic_host = -	    irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); +	cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL);  	if (!cpld_pic_host) {  		printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");  		goto end; diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 96f85e5e0cd..17d91b7da31 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -45,7 +45,7 @@ static struct of_device_id mpc5200_gpio_ids[] __initdata = {  struct media5200_irq {  	void __iomem *regs;  	spinlock_t lock; -	struct irq_host *irqhost; +	struct irq_domain *irqhost;  };  struct media5200_irq media5200_irq; @@ -112,7 +112,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)  	raw_spin_unlock(&desc->lock);  } -static int media5200_irq_map(struct irq_host *h, unsigned int virq, +static int media5200_irq_map(struct irq_domain *h, unsigned int virq,  			     irq_hw_number_t hw)  {  	pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw); @@ -122,7 +122,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, +static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops media5200_irq_ops = { +static const struct irq_domain_ops media5200_irq_ops = {  	.map = media5200_irq_map,  	.xlate = media5200_irq_xlate,  }; @@ -173,15 +173,12 @@ static void __init media5200_init_irq(void)  	spin_lock_init(&media5200_irq.lock); -	media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_HOST_MAP_LINEAR, -					       MEDIA5200_NUM_IRQS, -					       &media5200_irq_ops, -1); +	media5200_irq.irqhost = irq_domain_add_linear(fpga_np, +			MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq);  	if (!media5200_irq.irqhost)  		goto out;  	pr_debug("%s: allocated irqhost\n", __func__); -	media5200_irq.irqhost->host_data = &media5200_irq; -  	irq_set_handler_data(cascade_virq, &media5200_irq);  	irq_set_chained_handler(cascade_virq, media5200_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index 846b789fb19..c0aa04068d6 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void)  /* list of the supported boards */  static const char *board[] __initdata = { +	"anonymous,a4m072",  	"anon,charon",  	"intercontrol,digsy-mtc",  	"manroland,mucmc52", diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 369fd5457a3..d7e94f49532 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -98,13 +98,11 @@ struct mpc52xx_gpio_wkup __iomem *wkup_gpio;   *					of the localplus bus to the of_platform   *					bus.   */ -void __init -mpc52xx_declare_of_platform_devices(void) +void __init mpc52xx_declare_of_platform_devices(void)  { -	/* Find every child of the SOC node and add it to of_platform */ -	if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL)) -		printk(KERN_ERR __FILE__ ": " -			"Error while probing of_platform bus\n"); +	/* Find all the 'platform' devices and register them. */ +	if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL)) +		pr_err(__FILE__ ": Error while populating devices from DT\n");  }  /* diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index f94f06e5276..028470b9588 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -81,7 +81,7 @@ MODULE_LICENSE("GPL");   * @regs: virtual address of GPT registers   * @lock: spinlock to coordinate between different functions.   * @gc: gpio_chip instance structure; used when GPIO is enabled - * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported + * @irqhost: Pointer to irq_domain instance; used when IRQ mode is supported   * @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates   *   if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates   *   if the timer is actively used as wdt which blocks gpt functions @@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv {  	struct device *dev;  	struct mpc52xx_gpt __iomem *regs;  	spinlock_t lock; -	struct irq_host *irqhost; +	struct irq_domain *irqhost;  	u32 ipb_freq;  	u8 wdt_mode; @@ -204,7 +204,7 @@ void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)  	}  } -static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_gpt_irq_map(struct irq_domain *h, unsigned int virq,  			       irq_hw_number_t hw)  {  	struct mpc52xx_gpt_priv *gpt = h->host_data; @@ -216,7 +216,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_gpt_irq_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops mpc52xx_gpt_irq_ops = { +static const struct irq_domain_ops mpc52xx_gpt_irq_ops = {  	.map = mpc52xx_gpt_irq_map,  	.xlate = mpc52xx_gpt_irq_xlate,  }; @@ -252,14 +252,12 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)  	if (!cascade_virq)  		return; -	gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1, -				      &mpc52xx_gpt_irq_ops, -1); +	gpt->irqhost = irq_domain_add_linear(node, 1, &mpc52xx_gpt_irq_ops, gpt);  	if (!gpt->irqhost) { -		dev_err(gpt->dev, "irq_alloc_host() failed\n"); +		dev_err(gpt->dev, "irq_domain_add_linear() failed\n");  		return;  	} -	gpt->irqhost->host_data = gpt;  	irq_set_handler_data(cascade_virq, gpt);  	irq_set_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1a9a4957057..8520b58a5e9 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -132,7 +132,7 @@ static struct of_device_id mpc52xx_sdma_ids[] __initdata = {  static struct mpc52xx_intr __iomem *intr;  static struct mpc52xx_sdma __iomem *sdma; -static struct irq_host *mpc52xx_irqhost = NULL; +static struct irq_domain *mpc52xx_irqhost = NULL;  static unsigned char mpc52xx_map_senses[4] = {  	IRQ_TYPE_LEVEL_HIGH, @@ -301,7 +301,7 @@ static int mpc52xx_is_extirq(int l1, int l2)  /**   * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property   */ -static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -335,7 +335,7 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,  /**   * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure   */ -static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,  			       irq_hw_number_t irq)  {  	int l1irq; @@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops mpc52xx_irqhost_ops = { +static const struct irq_domain_ops mpc52xx_irqhost_ops = {  	.xlate = mpc52xx_irqhost_xlate,  	.map = mpc52xx_irqhost_map,  }; @@ -444,9 +444,9 @@ void __init mpc52xx_init_irq(void)  	 * As last step, add an irq host to translate the real  	 * hw irq information provided by the ofw to linux virq  	 */ -	mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, +	mpc52xx_irqhost = irq_domain_add_linear(picnode,  	                                 MPC52xx_IRQ_HIGHTESTHWIRQ, -	                                 &mpc52xx_irqhost_ops, -1); +	                                 &mpc52xx_irqhost_ops, NULL);  	if (!mpc52xx_irqhost)  		panic(__FILE__ ": Cannot allocate the IRQ host\n"); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 8ccf9ed62fe..328d221fd1c 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -29,7 +29,7 @@ static DEFINE_RAW_SPINLOCK(pci_pic_lock);  struct pq2ads_pci_pic {  	struct device_node *node; -	struct irq_host *host; +	struct irq_domain *host;  	struct {  		u32 stat; @@ -103,7 +103,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc)  	}  } -static int pci_pic_host_map(struct irq_host *h, unsigned int virq, +static int pci_pic_host_map(struct irq_domain *h, unsigned int virq,  			    irq_hw_number_t hw)  {  	irq_set_status_flags(virq, IRQ_LEVEL); @@ -112,14 +112,14 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops pci_pic_host_ops = { +static const struct irq_domain_ops pci_pic_host_ops = {  	.map = pci_pic_host_map,  };  int __init pq2ads_pci_init_irq(void)  {  	struct pq2ads_pci_pic *priv; -	struct irq_host *host; +	struct irq_domain *host;  	struct device_node *np;  	int ret = -ENODEV;  	int irq; @@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void)  	out_be32(&priv->regs->mask, ~0);  	mb(); -	host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS, -	                      &pci_pic_host_ops, NUM_IRQS); +	host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv);  	if (!host) {  		ret = -ENOMEM;  		goto out_unmap_regs;  	} -	host->host_data = priv; -  	priv->host = host; -	host->host_data = priv;  	irq_set_handler_data(irq, priv);  	irq_set_chained_handler(irq, pq2ads_pci_irq_demux); diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index d7946be298b..f000d81c4e3 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -6,6 +6,7 @@ menuconfig FSL_SOC_BOOKE  	select MPIC  	select PPC_PCI_CHOICE  	select FSL_PCI if PCI +	select SERIAL_8250_EXTENDED if SERIAL_8250  	select SERIAL_8250_SHARE_IRQ if SERIAL_8250  	default y @@ -13,6 +14,15 @@ if FSL_SOC_BOOKE  if PPC32 +config FSL_85XX_CACHE_SRAM +	bool +	select PPC_LIB_RHEAP +	help +	  When selected, this option enables cache-sram support +	  for memory allocation on P1/P2 QorIQ platforms. +	  cache-sram-size and cache-sram-offset kernel boot +	  parameters should be passed when this option is enabled. +  config MPC8540_ADS  	bool "Freescale MPC8540 ADS"  	select DEFAULT_UIMAGE @@ -30,6 +40,7 @@ config MPC85xx_CDS  	bool "Freescale MPC85xx CDS"  	select DEFAULT_UIMAGE  	select PPC_I8259 +	select HAS_RAPIDIO  	help  	  This option enables support for the MPC85xx CDS board @@ -80,7 +91,6 @@ config P1010_RDB  config P1022_DS  	bool "Freescale P1022 DS"  	select DEFAULT_UIMAGE -	select PHYS_64BIT	# The DTS has 36-bit addresses  	select SWIOTLB  	help  	  This option enables support for the Freescale P1022DS reference board. @@ -171,6 +181,21 @@ config SBC8560  	help  	  This option enables support for the Wind River SBC8560 board +config GE_IMP3A +	bool "GE Intelligent Platforms IMP3A" +	select DEFAULT_UIMAGE +	select SWIOTLB +	select MMIO_NVRAM +	select GENERIC_GPIO +	select ARCH_REQUIRE_GPIOLIB +	select GE_FPGA +	help +	  This option enables support for the GE Intelligent Platforms IMP3A +	  board. + +	  This board is a 3U CompactPCI Single Board Computer with a Freescale +	  P2020 processor. +  config P2041_RDB  	bool "Freescale P2041 RDB"  	select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 9cb2d4320dc..2125d4ca068 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_SBC8548)     += sbc8548.o  obj-$(CONFIG_SOCRATES)    += socrates.o socrates_fpga_pic.o  obj-$(CONFIG_KSI8560)	  += ksi8560.o  obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o +obj-$(CONFIG_GE_IMP3A)	  += ge_imp3a.o diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c index 07e3e6c4737..df69e99e511 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/arch/powerpc/platforms/85xx/corenet_ds.c @@ -36,8 +36,8 @@  void __init corenet_ds_pic_init(void)  {  	struct mpic *mpic; -	unsigned int flags = MPIC_BIG_ENDIAN | -				MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU; +	unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU | +		MPIC_NO_RESET;  	if (ppc_md.get_irq == mpic_get_coreint_irq)  		flags |= MPIC_ENABLE_COREINT; diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c new file mode 100644 index 00000000000..d50056f424f --- /dev/null +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -0,0 +1,246 @@ +/* + * GE IMP3A Board Setup + * + * Author Martyn Welch <martyn.welch@ge.com> + * + * Copyright 2010 GE Intelligent Platforms Embedded Systems, Inc. + * + * 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. + * + * Based on: mpc85xx_ds.c (MPC85xx DS Board Setup) + * Copyright 2007 Freescale Semiconductor Inc. + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/interrupt.h> +#include <linux/of_platform.h> +#include <linux/memblock.h> + +#include <asm/system.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <mm/mmu_decl.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/mpic.h> +#include <asm/swiotlb.h> +#include <asm/nvram.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> +#include "smp.h" + +#include "mpc85xx.h" +#include <sysdev/ge/ge_pic.h> + +void __iomem *imp3a_regs; + +void __init ge_imp3a_pic_init(void) +{ +	struct mpic *mpic; +	struct device_node *np; +	struct device_node *cascade_node = NULL; +	unsigned long root = of_get_flat_dt_root(); + +	if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { +		mpic = mpic_alloc(NULL, 0, +			MPIC_NO_RESET | +			MPIC_BIG_ENDIAN | +			MPIC_SINGLE_DEST_CPU, +			0, 256, " OpenPIC  "); +	} else { +		mpic = mpic_alloc(NULL, 0, +			  MPIC_BIG_ENDIAN | +			  MPIC_SINGLE_DEST_CPU, +			0, 256, " OpenPIC  "); +	} + +	BUG_ON(mpic == NULL); +	mpic_init(mpic); +	/* +	 * There is a simple interrupt handler in the main FPGA, this needs +	 * to be cascaded into the MPIC +	 */ +	for_each_node_by_type(np, "interrupt-controller") +		if (of_device_is_compatible(np, "gef,fpga-pic-1.00")) { +			cascade_node = np; +			break; +		} + +	if (cascade_node == NULL) { +		printk(KERN_WARNING "IMP3A: No FPGA PIC\n"); +		return; +	} + +	gef_pic_init(cascade_node); +	of_node_put(cascade_node); +} + +#ifdef CONFIG_PCI +static int primary_phb_addr; +#endif	/* CONFIG_PCI */ + +/* + * Setup the architecture + */ +static void __init ge_imp3a_setup_arch(void) +{ +	struct device_node *regs; +#ifdef CONFIG_PCI +	struct device_node *np; +	struct pci_controller *hose; +#endif +	dma_addr_t max = 0xffffffff; + +	if (ppc_md.progress) +		ppc_md.progress("ge_imp3a_setup_arch()", 0); + +#ifdef CONFIG_PCI +	for_each_node_by_type(np, "pci") { +		if (of_device_is_compatible(np, "fsl,mpc8540-pci") || +		    of_device_is_compatible(np, "fsl,mpc8548-pcie") || +		    of_device_is_compatible(np, "fsl,p2020-pcie")) { +			struct resource rsrc; +			of_address_to_resource(np, 0, &rsrc); +			if ((rsrc.start & 0xfffff) == primary_phb_addr) +				fsl_add_bridge(np, 1); +			else +				fsl_add_bridge(np, 0); + +			hose = pci_find_hose_for_OF_device(np); +			max = min(max, hose->dma_window_base_cur + +					hose->dma_window_size); +		} +	} +#endif + +	mpc85xx_smp_init(); + +#ifdef CONFIG_SWIOTLB +	if (memblock_end_of_DRAM() > max) { +		ppc_swiotlb_enable = 1; +		set_pci_dma_ops(&swiotlb_dma_ops); +		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; +	} +#endif + +	/* Remap basic board registers */ +	regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs"); +	if (regs) { +		imp3a_regs = of_iomap(regs, 0); +		if (imp3a_regs == NULL) +			printk(KERN_WARNING "Unable to map board registers\n"); +		of_node_put(regs); +	} + +#if defined(CONFIG_MMIO_NVRAM) +	mmio_nvram_init(); +#endif + +	printk(KERN_INFO "GE Intelligent Platforms IMP3A 3U cPCI SBC\n"); +} + +/* Return the PCB revision */ +static unsigned int ge_imp3a_get_pcb_rev(void) +{ +	unsigned int reg; + +	reg = ioread16(imp3a_regs); +	return (reg >> 8) & 0xff; +} + +/* Return the board (software) revision */ +static unsigned int ge_imp3a_get_board_rev(void) +{ +	unsigned int reg; + +	reg = ioread16(imp3a_regs + 0x2); +	return reg & 0xff; +} + +/* Return the FPGA revision */ +static unsigned int ge_imp3a_get_fpga_rev(void) +{ +	unsigned int reg; + +	reg = ioread16(imp3a_regs + 0x2); +	return (reg >> 8) & 0xff; +} + +/* Return compactPCI Geographical Address */ +static unsigned int ge_imp3a_get_cpci_geo_addr(void) +{ +	unsigned int reg; + +	reg = ioread16(imp3a_regs + 0x6); +	return (reg & 0x0f00) >> 8; +} + +/* Return compactPCI System Controller Status */ +static unsigned int ge_imp3a_get_cpci_is_syscon(void) +{ +	unsigned int reg; + +	reg = ioread16(imp3a_regs + 0x6); +	return reg & (1 << 12); +} + +static void ge_imp3a_show_cpuinfo(struct seq_file *m) +{ +	seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n"); + +	seq_printf(m, "Revision\t: %u%c\n", ge_imp3a_get_pcb_rev(), +		('A' + ge_imp3a_get_board_rev() - 1)); + +	seq_printf(m, "FPGA Revision\t: %u\n", ge_imp3a_get_fpga_rev()); + +	seq_printf(m, "cPCI geo. addr\t: %u\n", ge_imp3a_get_cpci_geo_addr()); + +	seq_printf(m, "cPCI syscon\t: %s\n", +		ge_imp3a_get_cpci_is_syscon() ? "yes" : "no"); +} + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init ge_imp3a_probe(void) +{ +	unsigned long root = of_get_flat_dt_root(); + +	if (of_flat_dt_is_compatible(root, "ge,IMP3A")) { +#ifdef CONFIG_PCI +		primary_phb_addr = 0x9000; +#endif +		return 1; +	} + +	return 0; +} + +machine_device_initcall(ge_imp3a, mpc85xx_common_publish_devices); + +machine_arch_initcall(ge_imp3a, swiotlb_setup_bus_notifier); + +define_machine(ge_imp3a) { +	.name			= "GE_IMP3A", +	.probe			= ge_imp3a_probe, +	.setup_arch		= ge_imp3a_setup_arch, +	.init_IRQ		= ge_imp3a_pic_init, +	.show_cpuinfo		= ge_imp3a_show_cpuinfo, +#ifdef CONFIG_PCI +	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +#endif +	.get_irq		= mpic_get_irq, +	.restart		= fsl_rstcr_restart, +	.calibrate_decr		= generic_calibrate_decr, +	.progress		= udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index 20f75d7819c..60120e55da4 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c @@ -57,8 +57,7 @@ static void machine_restart(char *cmd)  static void __init ksi8560_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index cf266826682..f58872688d8 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -36,9 +36,7 @@  void __init mpc8536_ds_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			  MPIC_WANTS_RESET | -			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 3bebb5173bf..d19f675cb36 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -50,8 +50,7 @@ static int mpc85xx_exclude_device(struct pci_controller *hose,  static void __init mpc85xx_ads_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 40f03da616a..ab5f0bf1945 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -3,7 +3,7 @@   *   * Maintained by Kumar Gala (see MAINTAINERS for contact information)   * - * Copyright 2005 Freescale Semiconductor Inc. + * Copyright 2005, 2011-2012 Freescale Semiconductor Inc.   *   * 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 @@ -48,17 +48,24 @@  #include "mpc85xx.h" -/* CADMUS info */ -/* xxx - galak, move into device tree */ -#define CADMUS_BASE (0xf8004000) -#define CADMUS_SIZE (256) -#define CM_VER	(0) -#define CM_CSR	(1) -#define CM_RST	(2) - +/* + * The CDS board contains an FPGA/CPLD called "Cadmus", which collects + * various logic and performs system control functions. + * Here is the FPGA/CPLD register map. + */ +struct cadmus_reg { +	u8 cm_ver;		/* Board version */ +	u8 cm_csr;		/* General control/status */ +	u8 cm_rst;		/* Reset control */ +	u8 cm_hsclk;	/* High speed clock */ +	u8 cm_hsxclk;	/* High speed clock extended */ +	u8 cm_led;		/* LED data */ +	u8 cm_pci;		/* PCI control/status */ +	u8 cm_dma;		/* DMA control */ +	u8 res[248];	/* Total 256 bytes */ +}; -static int cds_pci_slot = 2; -static volatile u8 *cadmus; +static struct cadmus_reg *cadmus;  #ifdef CONFIG_PCI @@ -158,6 +165,33 @@ DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge);  DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge);  DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge); +#define PCI_DEVICE_ID_IDT_TSI310	0x01a7 + +/* + * Fix Tsi310 PCI-X bridge resource. + * Force the bridge to open a window from 0x0000-0x1fff in PCI I/O space. + * This allows legacy I/O(i8259, etc) on the VIA southbridge to be accessed. + */ +void mpc85xx_cds_fixup_bus(struct pci_bus *bus) +{ +	struct pci_dev *dev = bus->self; +	struct resource *res = bus->resource[0]; + +	if (dev != NULL && +	    dev->vendor == PCI_VENDOR_ID_IBM && +	    dev->device == PCI_DEVICE_ID_IDT_TSI310) { +		if (res) { +			res->start = 0; +			res->end   = 0x1fff; +			res->flags = IORESOURCE_IO; +			pr_info("mpc85xx_cds: PCI bridge resource fixup applied\n"); +			pr_info("mpc85xx_cds: %pR\n", res); +		} +	} + +	fsl_pcibios_fixup_bus(bus); +} +  #ifdef CONFIG_PPC_I8259  static void mpc85xx_8259_cascade_handler(unsigned int irq,  					 struct irq_desc *desc) @@ -188,8 +222,7 @@ static struct irqaction mpc85xxcds_8259_irqaction = {  static void __init mpc85xx_cds_pic_init(void)  {  	struct mpic *mpic; -	mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +	mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); @@ -249,20 +282,30 @@ machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach);   */  static void __init mpc85xx_cds_setup_arch(void)  { -#ifdef CONFIG_PCI  	struct device_node *np; -#endif +	int cds_pci_slot;  	if (ppc_md.progress)  		ppc_md.progress("mpc85xx_cds_setup_arch()", 0); -	cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); -	cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; +	np = of_find_compatible_node(NULL, NULL, "fsl,mpc8548cds-fpga"); +	if (!np) { +		pr_err("Could not find FPGA node.\n"); +		return; +	} + +	cadmus = of_iomap(np, 0); +	of_node_put(np); +	if (!cadmus) { +		pr_err("Fail to map FPGA area.\n"); +		return; +	}  	if (ppc_md.progress) {  		char buf[40]; +		cds_pci_slot = ((in_8(&cadmus->cm_csr) >> 6) & 0x3) + 1;  		snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n", -				cadmus[CM_VER], cds_pci_slot); +				in_8(&cadmus->cm_ver), cds_pci_slot);  		ppc_md.progress(buf, 0);  	} @@ -292,7 +335,8 @@ static void mpc85xx_cds_show_cpuinfo(struct seq_file *m)  	svid = mfspr(SPRN_SVR);  	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); -	seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]); +	seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", +			in_8(&cadmus->cm_ver));  	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);  	seq_printf(m, "SVR\t\t: 0x%x\n", svid); @@ -323,7 +367,7 @@ define_machine(mpc85xx_cds) {  	.get_irq	= mpic_get_irq,  #ifdef CONFIG_PCI  	.restart	= mpc85xx_cds_restart, -	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +	.pcibios_fixup_bus	= mpc85xx_cds_fixup_bus,  #else  	.restart	= fsl_rstcr_restart,  #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index eefbb91e1d6..6e23e3e34bd 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -72,13 +72,13 @@ void __init mpc85xx_ds_pic_init(void)  	if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {  		mpic = mpic_alloc(NULL, 0, -			MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | +			MPIC_NO_RESET | +			MPIC_BIG_ENDIAN |  			MPIC_SINGLE_DEST_CPU,  			0, 256, " OpenPIC  ");  	} else {  		mpic = mpic_alloc(NULL, 0, -			  MPIC_WANTS_RESET | -			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | +			  MPIC_BIG_ENDIAN |  			  MPIC_SINGLE_DEST_CPU,  			0, 256, " OpenPIC  ");  	} diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 1d15a0cd2c8..f33662b46b8 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,6 @@  /* - * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved. + * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc. + * All rights reserved.   *   * Author: Andy Fleming <afleming@freescale.com>   * @@ -51,6 +52,7 @@  #include <asm/qe_ic.h>  #include <asm/mpic.h>  #include <asm/swiotlb.h> +#include <asm/fsl_guts.h>  #include "smp.h"  #include "mpc85xx.h" @@ -268,34 +270,27 @@ static void __init mpc85xx_mds_qe_init(void)  	mpc85xx_mds_reset_ucc_phys();  	if (machine_is(p1021_mds)) { -#define MPC85xx_PMUXCR_OFFSET           0x60 -#define MPC85xx_PMUXCR_QE0              0x00008000 -#define MPC85xx_PMUXCR_QE3              0x00001000 -#define MPC85xx_PMUXCR_QE9              0x00000040 -#define MPC85xx_PMUXCR_QE12             0x00000008 -		static __be32 __iomem *pmuxcr; -		np = of_find_node_by_name(NULL, "global-utilities"); +		struct ccsr_guts_85xx __iomem *guts; +		np = of_find_node_by_name(NULL, "global-utilities");  		if (np) { -			pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET; - -			if (!pmuxcr) -				printk(KERN_EMERG "Error: Alternate function" -					" signal multiplex control register not" -					" mapped!\n"); -			else +			guts = of_iomap(np, 0); +			if (!guts) +				pr_err("mpc85xx-rdb: could not map global utilities register\n"); +			else{  			/* P1021 has pins muxed for QE and other functions. To  			 * enable QE UEC mode, we need to set bit QE0 for UCC1  			 * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9  			 * and QE12 for QE MII management signals in PMUXCR  			 * register.  			 */ -				setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 | -						  MPC85xx_PMUXCR_QE3 | -						  MPC85xx_PMUXCR_QE9 | -						  MPC85xx_PMUXCR_QE12); - +				setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | +						  MPC85xx_PMUXCR_QE(3) | +						  MPC85xx_PMUXCR_QE(9) | +						  MPC85xx_PMUXCR_QE(12)); +				iounmap(guts); +			}  			of_node_put(np);  		} @@ -434,9 +429,8 @@ machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier);  static void __init mpc85xx_mds_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | -			MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | +			MPIC_SINGLE_DEST_CPU,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index ccf520e890b..db214cd4c82 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -1,7 +1,7 @@  /*   * MPC85xx RDB Board Setup   * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009,2012 Freescale Semiconductor Inc.   *   * 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 @@ -26,6 +26,9 @@  #include <asm/prom.h>  #include <asm/udbg.h>  #include <asm/mpic.h> +#include <asm/qe.h> +#include <asm/qe_ic.h> +#include <asm/fsl_guts.h>  #include <sysdev/fsl_soc.h>  #include <sysdev/fsl_pci.h> @@ -47,21 +50,36 @@ void __init mpc85xx_rdb_pic_init(void)  	struct mpic *mpic;  	unsigned long root = of_get_flat_dt_root(); +#ifdef CONFIG_QUICC_ENGINE +	struct device_node *np; +#endif +  	if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) { -		mpic = mpic_alloc(NULL, 0, -			MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | +		mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET | +			MPIC_BIG_ENDIAN |  			MPIC_SINGLE_DEST_CPU,  			0, 256, " OpenPIC  ");  	} else {  		mpic = mpic_alloc(NULL, 0, -		  MPIC_WANTS_RESET | -		  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | +		  MPIC_BIG_ENDIAN |  		  MPIC_SINGLE_DEST_CPU,  		  0, 256, " OpenPIC  ");  	}  	BUG_ON(mpic == NULL);  	mpic_init(mpic); + +#ifdef CONFIG_QUICC_ENGINE +	np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); +	if (np) { +		qe_ic_init(np, 0, qe_ic_cascade_low_mpic, +				qe_ic_cascade_high_mpic); +		of_node_put(np); + +	} else +		pr_err("%s: Could not find qe-ic node\n", __func__); +#endif +  }  /* @@ -69,7 +87,7 @@ void __init mpc85xx_rdb_pic_init(void)   */  static void __init mpc85xx_rdb_setup_arch(void)  { -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE)  	struct device_node *np;  #endif @@ -85,11 +103,73 @@ static void __init mpc85xx_rdb_setup_arch(void)  #endif  	mpc85xx_smp_init(); + +#ifdef CONFIG_QUICC_ENGINE +	np = of_find_compatible_node(NULL, NULL, "fsl,qe"); +	if (!np) { +		pr_err("%s: Could not find Quicc Engine node\n", __func__); +		goto qe_fail; +	} + +	qe_reset(); +	of_node_put(np); + +	np = of_find_node_by_name(NULL, "par_io"); +	if (np) { +		struct device_node *ucc; + +		par_io_init(np); +		of_node_put(np); + +		for_each_node_by_name(ucc, "ucc") +			par_io_of_config(ucc); + +	} +#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) +	if (machine_is(p1025_rdb)) { + +		struct ccsr_guts_85xx __iomem *guts; + +		np = of_find_node_by_name(NULL, "global-utilities"); +		if (np) { +			guts = of_iomap(np, 0); +			if (!guts) { + +				pr_err("mpc85xx-rdb: could not map global utilities register\n"); + +			} else { +			/* P1025 has pins muxed for QE and other functions. To +			* enable QE UEC mode, we need to set bit QE0 for UCC1 +			* in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 +			* and QE12 for QE MII management singals in PMUXCR +			* register. +			*/ +				setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | +						MPC85xx_PMUXCR_QE(3) | +						MPC85xx_PMUXCR_QE(9) | +						MPC85xx_PMUXCR_QE(12)); +				iounmap(guts); +			} +			of_node_put(np); +		} + +	} +#endif + +qe_fail: +#endif	/* CONFIG_QUICC_ENGINE */ +  	printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n");  }  machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices); +machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices);  machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices); +machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices); +machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices);  /*   * Called very early, device-tree isn't unflattened @@ -112,6 +192,52 @@ static int __init p1020_rdb_probe(void)  	return 0;  } +static int __init p1020_rdb_pc_probe(void) +{ +	unsigned long root = of_get_flat_dt_root(); + +	return of_flat_dt_is_compatible(root, "fsl,P1020RDB-PC"); +} + +static int __init p1021_rdb_pc_probe(void) +{ +	unsigned long root = of_get_flat_dt_root(); + +	if (of_flat_dt_is_compatible(root, "fsl,P1021RDB-PC")) +		return 1; +	return 0; +} + +static int __init p2020_rdb_pc_probe(void) +{ +	unsigned long root = of_get_flat_dt_root(); + +	if (of_flat_dt_is_compatible(root, "fsl,P2020RDB-PC")) +		return 1; +	return 0; +} + +static int __init p1025_rdb_probe(void) +{ +	unsigned long root = of_get_flat_dt_root(); + +	return of_flat_dt_is_compatible(root, "fsl,P1025RDB"); +} + +static int __init p1020_mbg_pc_probe(void) +{ +	unsigned long root = of_get_flat_dt_root(); + +	return of_flat_dt_is_compatible(root, "fsl,P1020MBG-PC"); +} + +static int __init p1020_utm_pc_probe(void) +{ +	unsigned long root = of_get_flat_dt_root(); + +	return of_flat_dt_is_compatible(root, "fsl,P1020UTM-PC"); +} +  define_machine(p2020_rdb) {  	.name			= "P2020 RDB",  	.probe			= p2020_rdb_probe, @@ -139,3 +265,87 @@ define_machine(p1020_rdb) {  	.calibrate_decr		= generic_calibrate_decr,  	.progress		= udbg_progress,  }; + +define_machine(p1021_rdb_pc) { +	.name			= "P1021 RDB-PC", +	.probe			= p1021_rdb_pc_probe, +	.setup_arch		= mpc85xx_rdb_setup_arch, +	.init_IRQ		= mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI +	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +#endif +	.get_irq		= mpic_get_irq, +	.restart		= fsl_rstcr_restart, +	.calibrate_decr		= generic_calibrate_decr, +	.progress		= udbg_progress, +}; + +define_machine(p2020_rdb_pc) { +	.name			= "P2020RDB-PC", +	.probe			= p2020_rdb_pc_probe, +	.setup_arch		= mpc85xx_rdb_setup_arch, +	.init_IRQ		= mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI +	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +#endif +	.get_irq		= mpic_get_irq, +	.restart		= fsl_rstcr_restart, +	.calibrate_decr		= generic_calibrate_decr, +	.progress		= udbg_progress, +}; + +define_machine(p1025_rdb) { +	.name			= "P1025 RDB", +	.probe			= p1025_rdb_probe, +	.setup_arch		= mpc85xx_rdb_setup_arch, +	.init_IRQ		= mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI +	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +#endif +	.get_irq		= mpic_get_irq, +	.restart		= fsl_rstcr_restart, +	.calibrate_decr		= generic_calibrate_decr, +	.progress		= udbg_progress, +}; + +define_machine(p1020_mbg_pc) { +	.name			= "P1020 MBG-PC", +	.probe			= p1020_mbg_pc_probe, +	.setup_arch		= mpc85xx_rdb_setup_arch, +	.init_IRQ		= mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI +	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +#endif +	.get_irq		= mpic_get_irq, +	.restart		= fsl_rstcr_restart, +	.calibrate_decr		= generic_calibrate_decr, +	.progress		= udbg_progress, +}; + +define_machine(p1020_utm_pc) { +	.name			= "P1020 UTM-PC", +	.probe			= p1020_utm_pc_probe, +	.setup_arch		= mpc85xx_rdb_setup_arch, +	.init_IRQ		= mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI +	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +#endif +	.get_irq		= mpic_get_irq, +	.restart		= fsl_rstcr_restart, +	.calibrate_decr		= generic_calibrate_decr, +	.progress		= udbg_progress, +}; + +define_machine(p1020_rdb_pc) { +	.name			= "P1020RDB-PC", +	.probe			= p1020_rdb_pc_probe, +	.setup_arch		= mpc85xx_rdb_setup_arch, +	.init_IRQ		= mpc85xx_rdb_pic_init, +#ifdef CONFIG_PCI +	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus, +#endif +	.get_irq		= mpic_get_irq, +	.restart		= fsl_rstcr_restart, +	.calibrate_decr		= generic_calibrate_decr, +	.progress		= udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index 538bc3f57e9..d8bd6563d9c 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -32,9 +32,8 @@  void __init p1010_rdb_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -	  MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | -	  MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | +	  MPIC_SINGLE_DEST_CPU,  	  0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index bb3d84f4046..0fe88e39945 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -25,6 +25,7 @@  #include <sysdev/fsl_soc.h>  #include <sysdev/fsl_pci.h> +#include <asm/udbg.h>  #include <asm/fsl_guts.h>  #include "smp.h" @@ -32,6 +33,10 @@  #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) +#define PMUXCR_ELBCDIU_MASK	0xc0000000 +#define PMUXCR_ELBCDIU_NOR16	0x80000000 +#define PMUXCR_ELBCDIU_DIU	0x40000000 +  /*   * Board-specific initialization of the DIU.  This code should probably be   * executed when the DIU is opened, rather than in arch code, but the DIU @@ -49,11 +54,22 @@  #define CLKDVDR_PXCLK_MASK	0x00FF0000  /* Some ngPIXIS register definitions */ +#define PX_CTL		3 +#define PX_BRDCFG0	8 +#define PX_BRDCFG1	9 + +#define PX_BRDCFG0_ELBC_SPI_MASK	0xc0 +#define PX_BRDCFG0_ELBC_SPI_ELBC	0x00 +#define PX_BRDCFG0_ELBC_SPI_NULL	0xc0 +#define PX_BRDCFG0_ELBC_DIU		0x02 +  #define PX_BRDCFG1_DVIEN	0x80  #define PX_BRDCFG1_DFPEN	0x40  #define PX_BRDCFG1_BACKLIGHT	0x20  #define PX_BRDCFG1_DDCEN	0x10 +#define PX_CTL_ALTACC		0x80 +  /*   * DIU Area Descriptor   * @@ -132,44 +148,117 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port,   */  static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)  { -	struct device_node *np; -	void __iomem *pixis; -	u8 __iomem *brdcfg1; +	struct device_node *guts_node; +	struct device_node *indirect_node = NULL; +	struct ccsr_guts_85xx __iomem *guts; +	u8 __iomem *lbc_lcs0_ba = NULL; +	u8 __iomem *lbc_lcs1_ba = NULL; +	u8 b; -	np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); -	if (!np) -		/* older device trees used "fsl,p1022ds-pixis" */ -		np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis"); -	if (!np) { -		pr_err("p1022ds: missing ngPIXIS node\n"); +	/* Map the global utilities registers. */ +	guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); +	if (!guts_node) { +		pr_err("p1022ds: missing global utilties device node\n");  		return;  	} -	pixis = of_iomap(np, 0); -	if (!pixis) { -		pr_err("p1022ds: could not map ngPIXIS registers\n"); -		return; +	guts = of_iomap(guts_node, 0); +	if (!guts) { +		pr_err("p1022ds: could not map global utilties device\n"); +		goto exit;  	} -	brdcfg1 = pixis + 9;	/* BRDCFG1 is at offset 9 in the ngPIXIS */ + +	indirect_node = of_find_compatible_node(NULL, NULL, +					     "fsl,p1022ds-indirect-pixis"); +	if (!indirect_node) { +		pr_err("p1022ds: missing pixis indirect mode node\n"); +		goto exit; +	} + +	lbc_lcs0_ba = of_iomap(indirect_node, 0); +	if (!lbc_lcs0_ba) { +		pr_err("p1022ds: could not map localbus chip select 0\n"); +		goto exit; +	} + +	lbc_lcs1_ba = of_iomap(indirect_node, 1); +	if (!lbc_lcs1_ba) { +		pr_err("p1022ds: could not map localbus chip select 1\n"); +		goto exit; +	} + +	/* Make sure we're in indirect mode first. */ +	if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != +	    PMUXCR_ELBCDIU_DIU) { +		struct device_node *pixis_node; +		void __iomem *pixis; + +		pixis_node = +			of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); +		if (!pixis_node) { +			pr_err("p1022ds: missing pixis node\n"); +			goto exit; +		} + +		pixis = of_iomap(pixis_node, 0); +		of_node_put(pixis_node); +		if (!pixis) { +			pr_err("p1022ds: could not map pixis registers\n"); +			goto exit; +		} + +		/* Enable indirect PIXIS mode.  */ +		setbits8(pixis + PX_CTL, PX_CTL_ALTACC); +		iounmap(pixis); + +		/* Switch the board mux to the DIU */ +		out_8(lbc_lcs0_ba, PX_BRDCFG0);	/* BRDCFG0 */ +		b = in_8(lbc_lcs1_ba); +		b |= PX_BRDCFG0_ELBC_DIU; +		out_8(lbc_lcs1_ba, b); + +		/* Set the chip mux to DIU mode. */ +		clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, +				PMUXCR_ELBCDIU_DIU); +		in_be32(&guts->pmuxcr); +	} +  	switch (port) {  	case FSL_DIU_PORT_DVI: -		printk(KERN_INFO "%s:%u\n", __func__, __LINE__);  		/* Enable the DVI port, disable the DFP and the backlight */ -		clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT, -			     PX_BRDCFG1_DVIEN); +		out_8(lbc_lcs0_ba, PX_BRDCFG1); +		b = in_8(lbc_lcs1_ba); +		b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); +		b |= PX_BRDCFG1_DVIEN; +		out_8(lbc_lcs1_ba, b);  		break;  	case FSL_DIU_PORT_LVDS: -		printk(KERN_INFO "%s:%u\n", __func__, __LINE__); +		/* +		 * LVDS also needs backlight enabled, otherwise the display +		 * will be blank. +		 */  		/* Enable the DFP port, disable the DVI and the backlight */ -		clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT, -			     PX_BRDCFG1_DFPEN); +		out_8(lbc_lcs0_ba, PX_BRDCFG1); +		b = in_8(lbc_lcs1_ba); +		b &= ~PX_BRDCFG1_DVIEN; +		b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; +		out_8(lbc_lcs1_ba, b);  		break;  	default:  		pr_err("p1022ds: unsupported monitor port %i\n", port);  	} -	iounmap(pixis); +exit: +	if (lbc_lcs1_ba) +		iounmap(lbc_lcs1_ba); +	if (lbc_lcs0_ba) +		iounmap(lbc_lcs0_ba); +	if (guts) +		iounmap(guts); + +	of_node_put(indirect_node); +	of_node_put(guts_node);  }  /** @@ -241,15 +330,56 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port)  void __init p1022_ds_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -		MPIC_WANTS_RESET | -		MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |  		MPIC_SINGLE_DEST_CPU,  		0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic);  } +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + +/* + * Disables a node in the device tree. + * + * This function is called before kmalloc() is available, so the 'new' object + * should be allocated in the global area.  The easiest way is to do that is + * to allocate one static local variable for each call to this function. + */ +static void __init disable_one_node(struct device_node *np, struct property *new) +{ +	struct property *old; + +	old = of_find_property(np, new->name, NULL); +	if (old) +		prom_update_property(np, new, old); +	else +		prom_add_property(np, new); +} + +/* TRUE if there is a "video=fslfb" command-line parameter. */ +static bool fslfb; + +/* + * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to + * true if we find it. + * + * We need to use early_param() instead of __setup() because the normal + * __setup() gets called to late.  However, early_param() gets called very + * early, before the device tree is unflattened, so all we can do now is set a + * global variable.  Later on, p1022_ds_setup_arch() will use that variable + * to determine if we need to update the device tree. + */ +static int __init early_video_setup(char *options) +{ +	fslfb = (strncmp(options, "fslfb:", 6) == 0); + +	return 0; +} +early_param("video", early_video_setup); + +#endif +  /*   * Setup the architecture   */ @@ -287,6 +417,34 @@ static void __init p1022_ds_setup_arch(void)  	diu_ops.set_monitor_port	= p1022ds_set_monitor_port;  	diu_ops.set_pixel_clock		= p1022ds_set_pixel_clock;  	diu_ops.valid_monitor_port	= p1022ds_valid_monitor_port; + +	/* +	 * Disable the NOR flash node if there is video=fslfb... command-line +	 * parameter.  When the DIU is active, NOR flash is unavailable, so we +	 * have to disable the node before the MTD driver loads. +	 */ +	if (fslfb) { +		struct device_node *np = +			of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); + +		if (np) { +			np = of_find_compatible_node(np, NULL, "cfi-flash"); +			if (np) { +				static struct property nor_status = { +					.name = "status", +					.value = "disabled", +					.length = sizeof("disabled"), +				}; + +				pr_info("p1022ds: disabling %s node", +					np->full_name); +				disable_one_node(np, &nor_status); +				of_node_put(np); +			} +		} + +	} +  #endif  	mpc85xx_smp_init(); diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c index d951e7027bb..6b07398e436 100644 --- a/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/arch/powerpc/platforms/85xx/p1023_rds.c @@ -93,9 +93,8 @@ machine_device_initcall(p1023_rds, mpc85xx_common_publish_devices);  static void __init mpc85xx_rds_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -		MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | -		MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | +		MPIC_SINGLE_DEST_CPU,  		0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index 184a5078461..1677b8a2267 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c @@ -54,8 +54,7 @@ static int sbc_rev;  static void __init sbc8548_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index 940752e9305..3c3bbcc2756 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c @@ -41,8 +41,7 @@  static void __init sbc8560_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index 18f635906b2..b7191921775 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c @@ -48,8 +48,7 @@ static void __init socrates_pic_init(void)  {  	struct device_node *np; -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index 12cb9bb2cc6..3bbbf748948 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -51,7 +51,7 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {  static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);  static void __iomem *socrates_fpga_pic_iobase; -static struct irq_host *socrates_fpga_pic_irq_host; +static struct irq_domain *socrates_fpga_pic_irq_host;  static unsigned int socrates_fpga_irqs[3];  static inline uint32_t socrates_fpga_pic_read(int reg) @@ -227,7 +227,7 @@ static struct irq_chip socrates_fpga_pic_chip = {  	.irq_set_type	= socrates_fpga_pic_set_type,  }; -static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, +static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,  		irq_hw_number_t hwirq)  {  	/* All interrupts are LEVEL sensitive */ @@ -238,7 +238,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int socrates_fpga_pic_host_xlate(struct irq_host *h, +static int socrates_fpga_pic_host_xlate(struct irq_domain *h,  		struct device_node *ct,	const u32 *intspec, unsigned int intsize,  		irq_hw_number_t *out_hwirq, unsigned int *out_flags)  { @@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_host *h,  	return 0;  } -static struct irq_host_ops socrates_fpga_pic_host_ops = { +static const struct irq_domain_ops socrates_fpga_pic_host_ops = {  	.map    = socrates_fpga_pic_host_map,  	.xlate  = socrates_fpga_pic_host_xlate,  }; @@ -279,10 +279,9 @@ void socrates_fpga_pic_init(struct device_node *pic)  	unsigned long flags;  	int i; -	/* Setup an irq_host structure */ -	socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR, -			SOCRATES_FPGA_NUM_IRQS,	&socrates_fpga_pic_host_ops, -			SOCRATES_FPGA_NUM_IRQS); +	/* Setup an irq_domain structure */ +	socrates_fpga_pic_irq_host = irq_domain_add_linear(pic, +		    SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);  	if (socrates_fpga_pic_irq_host == NULL) {  		pr_err("FPGA PIC: Unable to allocate host\n");  		return; diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index e9e5234b4e7..27ca3a7b04a 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -48,8 +48,7 @@  static void __init stx_gp3_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index bf7c89fb75b..d7504cefe01 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -47,7 +47,7 @@  static void __init tqm85xx_pic_init(void)  {  	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, +			MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 3a69f8b77de..503c21596c6 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -43,9 +43,7 @@  void __init xes_mpc85xx_pic_init(void)  { -	struct mpic *mpic = mpic_alloc(NULL, 0, -			  MPIC_WANTS_RESET | -			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,  			0, 256, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	mpic_init(mpic); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 8d6599d54ea..7a6279e3821 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -39,6 +39,7 @@ config GEF_PPC9A  	select MMIO_NVRAM  	select GENERIC_GPIO  	select ARCH_REQUIRE_GPIOLIB +	select GE_FPGA  	help  	  This option enables support for the GE PPC9A. @@ -48,6 +49,7 @@ config GEF_SBC310  	select MMIO_NVRAM  	select GENERIC_GPIO  	select ARCH_REQUIRE_GPIOLIB +	select GE_FPGA  	help  	  This option enables support for the GE SBC310. @@ -57,6 +59,7 @@ config GEF_SBC610  	select MMIO_NVRAM  	select GENERIC_GPIO  	select ARCH_REQUIRE_GPIOLIB +	select GE_FPGA  	select HAS_RAPIDIO  	help  	  This option enables support for the GE SBC610. diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 4b0d7b1aa00..ede815d6489 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_SMP)		+= mpc86xx_smp.o  obj-$(CONFIG_MPC8641_HPCN)	+= mpc86xx_hpcn.o  obj-$(CONFIG_SBC8641D)		+= sbc8641d.o  obj-$(CONFIG_MPC8610_HPCD)	+= mpc8610_hpcd.o -gef-gpio-$(CONFIG_GPIOLIB)	+= gef_gpio.o -obj-$(CONFIG_GEF_SBC610)	+= gef_sbc610.o gef_pic.o $(gef-gpio-y) -obj-$(CONFIG_GEF_SBC310)	+= gef_sbc310.o gef_pic.o $(gef-gpio-y) -obj-$(CONFIG_GEF_PPC9A)		+= gef_ppc9a.o gef_pic.o $(gef-gpio-y) +obj-$(CONFIG_GEF_SBC610)	+= gef_sbc610.o +obj-$(CONFIG_GEF_SBC310)	+= gef_sbc310.o +obj-$(CONFIG_GEF_PPC9A)		+= gef_ppc9a.o diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c deleted file mode 100644 index 2a703365e66..00000000000 --- a/arch/powerpc/platforms/86xx/gef_gpio.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Driver for GE FPGA based GPIO - * - * Author: Martyn Welch <martyn.welch@ge.com> - * - * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2.  This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -/* TODO - * - * Configuration of output modes (totem-pole/open-drain) - * Interrupt configuration - interrupts are always generated the FPGA relies on - * 	the I/O interrupt controllers mask to stop them propergating - */ - -#include <linux/kernel.h> -#include <linux/compiler.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_platform.h> -#include <linux/of_gpio.h> -#include <linux/gpio.h> -#include <linux/slab.h> -#include <linux/module.h> - -#define GEF_GPIO_DIRECT		0x00 -#define GEF_GPIO_IN		0x04 -#define GEF_GPIO_OUT		0x08 -#define GEF_GPIO_TRIG		0x0C -#define GEF_GPIO_POLAR_A	0x10 -#define GEF_GPIO_POLAR_B	0x14 -#define GEF_GPIO_INT_STAT	0x18 -#define GEF_GPIO_OVERRUN	0x1C -#define GEF_GPIO_MODE		0x20 - -static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) -{ -	unsigned int data; - -	data = ioread32be(reg); -	/* value: 0=low; 1=high */ -	if (value & 0x1) -		data = data | (0x1 << offset); -	else -		data = data & ~(0x1 << offset); - -	iowrite32be(data, reg); -} - - -static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ -	unsigned int data; -	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - -	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); -	data = data | (0x1 << offset); -	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - -	return 0; -} - -static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) -{ -	unsigned int data; -	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - -	/* Set direction before switching to input */ -	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); - -	data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); -	data = data & ~(0x1 << offset); -	iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); - -	return 0; -} - -static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) -{ -	unsigned int data; -	int state = 0; -	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - -	data = ioread32be(mmchip->regs + GEF_GPIO_IN); -	state = (int)((data >> offset) & 0x1); - -	return state; -} - -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ -	struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - -	_gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); -} - -static int __init gef_gpio_init(void) -{ -	struct device_node *np; -	int retval; -	struct of_mm_gpio_chip *gef_gpio_chip; - -	for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { - -		pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - -		/* Allocate chip structure */ -		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); -		if (!gef_gpio_chip) { -			pr_err("%s: Unable to allocate structure\n", -				np->full_name); -			continue; -		} - -		/* Setup pointers to chip functions */ -		gef_gpio_chip->gc.of_gpio_n_cells = 2; -		gef_gpio_chip->gc.ngpio = 19; -		gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; -		gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; -		gef_gpio_chip->gc.get = gef_gpio_get; -		gef_gpio_chip->gc.set = gef_gpio_set; - -		/* This function adds a memory mapped GPIO chip */ -		retval = of_mm_gpiochip_add(np, gef_gpio_chip); -		if (retval) { -			kfree(gef_gpio_chip); -			pr_err("%s: Unable to add GPIO\n", np->full_name); -		} -	} - -	for_each_compatible_node(np, NULL, "gef,sbc310-gpio") { - -		pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - -		/* Allocate chip structure */ -		gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); -		if (!gef_gpio_chip) { -			pr_err("%s: Unable to allocate structure\n", -				np->full_name); -			continue; -		} - -		/* Setup pointers to chip functions */ -		gef_gpio_chip->gc.of_gpio_n_cells = 2; -		gef_gpio_chip->gc.ngpio = 6; -		gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; -		gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; -		gef_gpio_chip->gc.get = gef_gpio_get; -		gef_gpio_chip->gc.set = gef_gpio_set; - -		/* This function adds a memory mapped GPIO chip */ -		retval = of_mm_gpiochip_add(np, gef_gpio_chip); -		if (retval) { -			kfree(gef_gpio_chip); -			pr_err("%s: Unable to add GPIO\n", np->full_name); -		} -	} - -	return 0; -}; -arch_initcall(gef_gpio_init); - -MODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); -MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); -MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c deleted file mode 100644 index 94594e58594..00000000000 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Interrupt handling for GE FPGA based PIC - * - * Author: Martyn Welch <martyn.welch@ge.com> - * - * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2.  This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/irq.h> - -#include "gef_pic.h" - -#define DEBUG -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0) -#else -#define DBG(fmt...) do { } while (0) -#endif - -#define GEF_PIC_NUM_IRQS	32 - -/* Interrupt Controller Interface Registers */ -#define GEF_PIC_INTR_STATUS	0x0000 - -#define GEF_PIC_INTR_MASK(cpu)	(0x0010 + (0x4 * cpu)) -#define GEF_PIC_CPU0_INTR_MASK	GEF_PIC_INTR_MASK(0) -#define GEF_PIC_CPU1_INTR_MASK	GEF_PIC_INTR_MASK(1) - -#define GEF_PIC_MCP_MASK(cpu)	(0x0018 + (0x4 * cpu)) -#define GEF_PIC_CPU0_MCP_MASK	GEF_PIC_MCP_MASK(0) -#define GEF_PIC_CPU1_MCP_MASK	GEF_PIC_MCP_MASK(1) - - -static DEFINE_RAW_SPINLOCK(gef_pic_lock); - -static void __iomem *gef_pic_irq_reg_base; -static struct irq_host *gef_pic_irq_host; -static int gef_pic_cascade_irq; - -/* - * Interrupt Controller Handling - * - * The interrupt controller handles interrupts for most on board interrupts, - * apart from PCI interrupts. For example on SBC610: - * - * 17:31 RO Reserved - * 16    RO PCI Express Doorbell 3 Status - * 15    RO PCI Express Doorbell 2 Status - * 14    RO PCI Express Doorbell 1 Status - * 13    RO PCI Express Doorbell 0 Status - * 12    RO Real Time Clock Interrupt Status - * 11    RO Temperature Interrupt Status - * 10    RO Temperature Critical Interrupt Status - * 9     RO Ethernet PHY1 Interrupt Status - * 8     RO Ethernet PHY3 Interrupt Status - * 7     RO PEX8548 Interrupt Status - * 6     RO Reserved - * 5     RO Watchdog 0 Interrupt Status - * 4     RO Watchdog 1 Interrupt Status - * 3     RO AXIS Message FIFO A Interrupt Status - * 2     RO AXIS Message FIFO B Interrupt Status - * 1     RO AXIS Message FIFO C Interrupt Status - * 0     RO AXIS Message FIFO D Interrupt Status - * - * Interrupts can be forwarded to one of two output lines. Nothing - * clever is done, so if the masks are incorrectly set, a single input - * interrupt could generate interrupts on both output lines! - * - * The dual lines are there to allow the chained interrupts to be easily - * passed into two different cores. We currently do not use this functionality - * in this driver. - * - * Controller can also be configured to generate Machine checks (MCP), again on - * two lines, to be attached to two different cores. It is suggested that these - * should be masked out. - */ - -void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) -{ -	struct irq_chip *chip = irq_desc_get_chip(desc); -	unsigned int cascade_irq; - -	/* -	 * See if we actually have an interrupt, call generic handling code if -	 * we do. -	 */ -	cascade_irq = gef_pic_get_irq(); - -	if (cascade_irq != NO_IRQ) -		generic_handle_irq(cascade_irq); - -	chip->irq_eoi(&desc->irq_data); -} - -static void gef_pic_mask(struct irq_data *d) -{ -	unsigned long flags; -	unsigned int hwirq = irqd_to_hwirq(d); -	u32 mask; - -	raw_spin_lock_irqsave(&gef_pic_lock, flags); -	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); -	mask &= ~(1 << hwirq); -	out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); -	raw_spin_unlock_irqrestore(&gef_pic_lock, flags); -} - -static void gef_pic_mask_ack(struct irq_data *d) -{ -	/* Don't think we actually have to do anything to ack an interrupt, -	 * we just need to clear down the devices interrupt and it will go away -	 */ -	gef_pic_mask(d); -} - -static void gef_pic_unmask(struct irq_data *d) -{ -	unsigned long flags; -	unsigned int hwirq = irqd_to_hwirq(d); -	u32 mask; - -	raw_spin_lock_irqsave(&gef_pic_lock, flags); -	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); -	mask |= (1 << hwirq); -	out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); -	raw_spin_unlock_irqrestore(&gef_pic_lock, flags); -} - -static struct irq_chip gef_pic_chip = { -	.name		= "gefp", -	.irq_mask	= gef_pic_mask, -	.irq_mask_ack	= gef_pic_mask_ack, -	.irq_unmask	= gef_pic_unmask, -}; - - -/* When an interrupt is being configured, this call allows some flexibilty - * in deciding which irq_chip structure is used - */ -static int gef_pic_host_map(struct irq_host *h, unsigned int virq, -			  irq_hw_number_t hwirq) -{ -	/* All interrupts are LEVEL sensitive */ -	irq_set_status_flags(virq, IRQ_LEVEL); -	irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); - -	return 0; -} - -static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, -			    const u32 *intspec, unsigned int intsize, -			    irq_hw_number_t *out_hwirq, unsigned int *out_flags) -{ - -	*out_hwirq = intspec[0]; -	if (intsize > 1) -		*out_flags = intspec[1]; -	else -		*out_flags = IRQ_TYPE_LEVEL_HIGH; - -	return 0; -} - -static struct irq_host_ops gef_pic_host_ops = { -	.map	= gef_pic_host_map, -	.xlate	= gef_pic_host_xlate, -}; - - -/* - * Initialisation of PIC, this should be called in BSP - */ -void __init gef_pic_init(struct device_node *np) -{ -	unsigned long flags; - -	/* Map the devices registers into memory */ -	gef_pic_irq_reg_base = of_iomap(np, 0); - -	raw_spin_lock_irqsave(&gef_pic_lock, flags); - -	/* Initialise everything as masked. */ -	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0); -	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0); - -	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0); -	out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0); - -	raw_spin_unlock_irqrestore(&gef_pic_lock, flags); - -	/* Map controller */ -	gef_pic_cascade_irq = irq_of_parse_and_map(np, 0); -	if (gef_pic_cascade_irq == NO_IRQ) { -		printk(KERN_ERR "SBC610: failed to map cascade interrupt"); -		return; -	} - -	/* Setup an irq_host structure */ -	gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, -					  GEF_PIC_NUM_IRQS, -					  &gef_pic_host_ops, NO_IRQ); -	if (gef_pic_irq_host == NULL) -		return; - -	/* Chain with parent controller */ -	irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade); -} - -/* - * This is called when we receive an interrupt with apparently comes from this - * chip - check, returning the highest interrupt generated or return NO_IRQ - */ -unsigned int gef_pic_get_irq(void) -{ -	u32 cause, mask, active; -	unsigned int virq = NO_IRQ; -	int hwirq; - -	cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS); - -	mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); - -	active = cause & mask; - -	if (active) { -		for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) { -			if (active & (0x1 << hwirq)) -				break; -		} -		virq = irq_linear_revmap(gef_pic_irq_host, -			(irq_hw_number_t)hwirq); -	} - -	return virq; -} - diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h deleted file mode 100644 index 6149916da3f..00000000000 --- a/arch/powerpc/platforms/86xx/gef_pic.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __GEF_PIC_H__ -#define __GEF_PIC_H__ - -#include <linux/init.h> - -void gef_pic_cascade(unsigned int, struct irq_desc *); -unsigned int gef_pic_get_irq(void); -void gef_pic_init(struct device_node *); - -#endif /* __GEF_PIC_H__ */ - diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 60ce07e3910..ed58b6cfd60 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -37,9 +37,9 @@  #include <sysdev/fsl_pci.h>  #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h>  #include "mpc86xx.h" -#include "gef_pic.h"  #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 3ecee25bf3e..710db69bd52 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -37,9 +37,9 @@  #include <sysdev/fsl_pci.h>  #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h>  #include "mpc86xx.h" -#include "gef_pic.h"  #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 5090d608d9e..4a13d2f4ac2 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -37,9 +37,9 @@  #include <sysdev/fsl_pci.h>  #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h>  #include "mpc86xx.h" -#include "gef_pic.h"  #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c index 52bbfa03153..22cc3571ae1 100644 --- a/arch/powerpc/platforms/86xx/pic.c +++ b/arch/powerpc/platforms/86xx/pic.c @@ -37,9 +37,8 @@ void __init mpc86xx_init_irq(void)  	int cascade_irq;  #endif -	struct mpic *mpic = mpic_alloc(NULL, 0, -			MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | -			MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, +	struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | +			MPIC_SINGLE_DEST_CPU,  			0, 256, " MPIC     ");  	BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index ee56a9ea6a7..1fb0b3cddeb 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -26,6 +26,7 @@ config MPC86XADS  config MPC885ADS  	bool "MPC885ADS"  	select CPM1 +	select OF_DYNAMIC  	help  	  Freescale Semiconductor MPC885 Application Development System (ADS).  	  Also known as DUET. diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 0cfb46d54b8..a35ca44ade6 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -2,7 +2,6 @@ menu "Platform support"  source "arch/powerpc/platforms/powernv/Kconfig"  source "arch/powerpc/platforms/pseries/Kconfig" -source "arch/powerpc/platforms/iseries/Kconfig"  source "arch/powerpc/platforms/chrp/Kconfig"  source "arch/powerpc/platforms/512x/Kconfig"  source "arch/powerpc/platforms/52xx/Kconfig" @@ -87,6 +86,14 @@ config MPIC_WEIRD  	bool  	default n +config MPIC_MSGR +	bool "MPIC message register support" +	depends on MPIC +	default n +	help +	  Enables support for the MPIC message registers.  These +	  registers are used for inter-processor communication. +  config PPC_I8259  	bool  	default n @@ -138,7 +145,7 @@ config MPIC_BROKEN_REGREAD  	  of the register contents in software.  config IBMVIO -	depends on PPC_PSERIES || PPC_ISERIES +	depends on PPC_PSERIES  	bool  	default y diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 2635a22bade..879b4a44849 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_FSL_SOC_BOOKE)	+= 85xx/  obj-$(CONFIG_PPC_86xx)		+= 86xx/  obj-$(CONFIG_PPC_POWERNV)	+= powernv/  obj-$(CONFIG_PPC_PSERIES)	+= pseries/ -obj-$(CONFIG_PPC_ISERIES)	+= iseries/  obj-$(CONFIG_PPC_MAPLE)		+= maple/  obj-$(CONFIG_PPC_PASEMI)	+= pasemi/  obj-$(CONFIG_PPC_CELL)		+= cell/ diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 40a6e34793b..db360fc4cf0 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -67,7 +67,7 @@  struct axon_msic { -	struct irq_host *irq_host; +	struct irq_domain *irq_domain;  	__le32 *fifo_virt;  	dma_addr_t fifo_phys;  	dcr_host_t dcr_host; @@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)  static struct axon_msic *find_msi_translator(struct pci_dev *dev)  { -	struct irq_host *irq_host; +	struct irq_domain *irq_domain;  	struct device_node *dn, *tmp;  	const phandle *ph;  	struct axon_msic *msic = NULL; @@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)  		goto out_error;  	} -	irq_host = irq_find_host(dn); -	if (!irq_host) { -		dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n", +	irq_domain = irq_find_host(dn); +	if (!irq_domain) { +		dev_dbg(&dev->dev, "axon_msi: no irq_domain found for node %s\n",  			dn->full_name);  		goto out_error;  	} -	msic = irq_host->host_data; +	msic = irq_domain->host_data;  out_error:  	of_node_put(dn); @@ -280,7 +280,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)  	BUILD_BUG_ON(NR_IRQS > 65536);  	list_for_each_entry(entry, &dev->msi_list, list) { -		virq = irq_create_direct_mapping(msic->irq_host); +		virq = irq_create_direct_mapping(msic->irq_domain);  		if (virq == NO_IRQ) {  			dev_warn(&dev->dev,  				 "axon_msi: virq allocation failed!\n"); @@ -318,7 +318,7 @@ static struct irq_chip msic_irq_chip = {  	.name		= "AXON-MSI",  }; -static int msic_host_map(struct irq_host *h, unsigned int virq, +static int msic_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	irq_set_chip_data(virq, h->host_data); @@ -327,7 +327,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops msic_host_ops = { +static const struct irq_domain_ops msic_host_ops = {  	.map	= msic_host_map,  }; @@ -337,7 +337,7 @@ static void axon_msi_shutdown(struct platform_device *device)  	u32 tmp;  	pr_devel("axon_msi: disabling %s\n", -		  msic->irq_host->of_node->full_name); +		  msic->irq_domain->of_node->full_name);  	tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);  	tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;  	msic_dcr_write(msic, MSIC_CTRL_REG, tmp); @@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device)  	}  	memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES); -	msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP, -					NR_IRQS, &msic_host_ops, 0); -	if (!msic->irq_host) { -		printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", +	msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic); +	if (!msic->irq_domain) { +		printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n",  		       dn->full_name);  		goto out_free_fifo;  	} -	msic->irq_host->host_data = msic; -  	irq_set_handler_data(virq, msic);  	irq_set_chained_handler(virq, axon_msi_cascade);  	pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq); diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c index 2516c1cf846..943c9d39aa1 100644 --- a/arch/powerpc/platforms/cell/beat_htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c @@ -95,7 +95,6 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group,  	unsigned long lpar_rc;  	u64 hpte_v, hpte_r, slot; -	/* same as iseries */  	if (vflags & HPTE_V_SECONDARY)  		return -1; @@ -319,7 +318,6 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group,  	unsigned long lpar_rc;  	u64 hpte_v, hpte_r, slot; -	/* same as iseries */  	if (vflags & HPTE_V_SECONDARY)  		return -1; diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 55015e1f693..e5c3a2c6090 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -34,7 +34,7 @@ static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock);  static uint64_t	beatic_irq_mask_enable[(MAX_IRQS+255)/64];  static uint64_t	beatic_irq_mask_ack[(MAX_IRQS+255)/64]; -static struct irq_host *beatic_host; +static struct irq_domain *beatic_host;  /*   * In this implementation, "virq" == "IRQ plug number", @@ -122,7 +122,7 @@ static struct irq_chip beatic_pic = {   *   * Note that the number (virq) is already assigned at upper layer.   */ -static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) +static void beatic_pic_host_unmap(struct irq_domain *h, unsigned int virq)  {  	beat_destruct_irq_plug(virq);  } @@ -133,7 +133,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)   *   * Note that the number (virq) is already assigned at upper layer.   */ -static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, +static int beatic_pic_host_map(struct irq_domain *h, unsigned int virq,  			       irq_hw_number_t hw)  {  	int64_t	err; @@ -154,7 +154,7 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,   * Called from irq_create_of_mapping() only.   * Note: We have only 1 entry to translate.   */ -static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int beatic_pic_host_xlate(struct irq_domain *h, struct device_node *ct,  				 const u32 *intspec, unsigned int intsize,  				 irq_hw_number_t *out_hwirq,  				 unsigned int *out_flags) @@ -166,13 +166,13 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) +static int beatic_pic_host_match(struct irq_domain *h, struct device_node *np)  {  	/* Match all */  	return 1;  } -static struct irq_host_ops beatic_pic_host_ops = { +static const struct irq_domain_ops beatic_pic_host_ops = {  	.map = beatic_pic_host_map,  	.unmap = beatic_pic_host_unmap,  	.xlate = beatic_pic_host_xlate, @@ -239,9 +239,7 @@ void __init beatic_init_IRQ(void)  	ppc_md.get_irq = beatic_get_irq;  	/* Allocate an irq host */ -	beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, -				     &beatic_pic_host_ops, -					 0); +	beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL);  	BUG_ON(beatic_host == NULL);  	irq_set_default_host(beatic_host);  } diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 96a433dd2d6..2d42f3bb66d 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -56,7 +56,7 @@ struct iic {  static DEFINE_PER_CPU(struct iic, cpu_iic);  #define IIC_NODE_COUNT	2 -static struct irq_host *iic_host; +static struct irq_domain *iic_host;  /* Convert between "pending" bits and hw irq number */  static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) @@ -186,7 +186,7 @@ void iic_message_pass(int cpu, int msg)  	out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4);  } -struct irq_host *iic_get_irq_host(int node) +struct irq_domain *iic_get_irq_host(int node)  {  	return iic_host;  } @@ -222,13 +222,13 @@ void iic_request_IPIs(void)  #endif /* CONFIG_SMP */ -static int iic_host_match(struct irq_host *h, struct device_node *node) +static int iic_host_match(struct irq_domain *h, struct device_node *node)  {  	return of_device_is_compatible(node,  				    "IBM,CBEA-Internal-Interrupt-Controller");  } -static int iic_host_map(struct irq_host *h, unsigned int virq, +static int iic_host_map(struct irq_domain *h, unsigned int virq,  			irq_hw_number_t hw)  {  	switch (hw & IIC_IRQ_TYPE_MASK) { @@ -245,7 +245,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int iic_host_xlate(struct irq_host *h, struct device_node *ct, +static int iic_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops iic_host_ops = { +static const struct irq_domain_ops iic_host_ops = {  	.match = iic_host_match,  	.map = iic_host_map,  	.xlate = iic_host_xlate, @@ -378,8 +378,8 @@ static int __init setup_iic(void)  void __init iic_init_IRQ(void)  {  	/* Setup an irq host data structure */ -	iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, -				  &iic_host_ops, IIC_IRQ_INVALID); +	iic_host = irq_domain_add_linear(NULL, IIC_SOURCE_COUNT, &iic_host_ops, +					 NULL);  	BUG_ON(iic_host == NULL);  	irq_set_default_host(iic_host); diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 62002a7edfe..fa3e294fd34 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -197,7 +197,8 @@ static void __init mpic_init_IRQ(void)  		/* The MPIC driver will get everything it needs from the  		 * device-tree, just pass 0 to all arguments  		 */ -		mpic = mpic_alloc(dn, 0, MPIC_SECONDARY, 0, 0, " MPIC     "); +		mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET, +				0, 0, " MPIC     ");  		if (mpic == NULL)  			continue;  		mpic_init(mpic); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 442c28c00f8..d8b7cc8a66c 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -62,7 +62,7 @@ enum {  #define SPIDER_IRQ_INVALID	63  struct spider_pic { -	struct irq_host		*host; +	struct irq_domain		*host;  	void __iomem		*regs;  	unsigned int		node_id;  }; @@ -168,7 +168,7 @@ static struct irq_chip spider_pic = {  	.irq_set_type = spider_set_irq_type,  }; -static int spider_host_map(struct irq_host *h, unsigned int virq, +static int spider_host_map(struct irq_domain *h, unsigned int virq,  			irq_hw_number_t hw)  {  	irq_set_chip_data(virq, h->host_data); @@ -180,7 +180,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int spider_host_xlate(struct irq_host *h, struct device_node *ct, +static int spider_host_xlate(struct irq_domain *h, struct device_node *ct,  			   const u32 *intspec, unsigned int intsize,  			   irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct,  	return 0;  } -static struct irq_host_ops spider_host_ops = { +static const struct irq_domain_ops spider_host_ops = {  	.map = spider_host_map,  	.xlate = spider_host_xlate,  }; @@ -299,12 +299,10 @@ static void __init spider_init_one(struct device_node *of_node, int chip,  		panic("spider_pic: can't map registers !");  	/* Allocate a host */ -	pic->host = irq_alloc_host(of_node, IRQ_HOST_MAP_LINEAR, -				   SPIDER_SRC_COUNT, &spider_host_ops, -				   SPIDER_IRQ_INVALID); +	pic->host = irq_domain_add_linear(of_node, SPIDER_SRC_COUNT, +					  &spider_host_ops, pic);  	if (pic->host == NULL)  		panic("spider_pic: can't allocate irq host !"); -	pic->host->host_data = pic;  	/* Go through all sources and disable them */  	for (i = 0; i < SPIDER_SRC_COUNT; i++) { diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d4a094ca96f..1d75c92ea8f 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -646,6 +646,7 @@ long spufs_create(struct path *path, struct dentry *dentry,  out:  	mutex_unlock(&path->dentry->d_inode->i_mutex); +	dput(dentry);  	return ret;  } @@ -757,9 +758,9 @@ spufs_create_root(struct super_block *sb, void *data)  		goto out_iput;  	ret = -ENOMEM; -	sb->s_root = d_alloc_root(inode); +	sb->s_root = d_make_root(inode);  	if (!sb->s_root) -		goto out_iput; +		goto out;  	return 0;  out_iput: @@ -828,19 +829,19 @@ static int __init spufs_init(void)  	ret = spu_sched_init();  	if (ret)  		goto out_cache; -	ret = register_filesystem(&spufs_type); +	ret = register_spu_syscalls(&spufs_calls);  	if (ret)  		goto out_sched; -	ret = register_spu_syscalls(&spufs_calls); +	ret = register_filesystem(&spufs_type);  	if (ret) -		goto out_fs; +		goto out_syscalls;  	spufs_init_isolated_loader();  	return 0; -out_fs: -	unregister_filesystem(&spufs_type); +out_syscalls: +	unregister_spu_syscalls(&spufs_calls);  out_sched:  	spu_sched_exit();  out_cache: diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 8591bb62d7f..5665dcc382c 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -70,8 +70,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,  	ret = PTR_ERR(dentry);  	if (!IS_ERR(dentry)) {  		ret = spufs_create(&path, dentry, flags, mode, neighbor); -		mutex_unlock(&path.dentry->d_inode->i_mutex); -		dput(dentry);  		path_put(&path);  	} diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index f1f17bb2c33..c665d7de6c9 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -435,7 +435,8 @@ static void __init chrp_find_openpic(void)  	if (len > 1)  		isu_size = iranges[3]; -	chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC    "); +	chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET, +			isu_size, 0, " MPIC    ");  	if (chrp_mpic == NULL) {  		printk(KERN_ERR "Failed to allocate MPIC structure\n");  		goto bail; diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index f61a2dd96b9..53d6eee0196 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -96,9 +96,9 @@ static struct irq_chip flipper_pic = {   *   */ -static struct irq_host *flipper_irq_host; +static struct irq_domain *flipper_irq_host; -static int flipper_pic_map(struct irq_host *h, unsigned int virq, +static int flipper_pic_map(struct irq_domain *h, unsigned int virq,  			   irq_hw_number_t hwirq)  {  	irq_set_chip_data(virq, h->host_data); @@ -107,13 +107,13 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int flipper_pic_match(struct irq_host *h, struct device_node *np) +static int flipper_pic_match(struct irq_domain *h, struct device_node *np)  {  	return 1;  } -static struct irq_host_ops flipper_irq_host_ops = { +static const struct irq_domain_ops flipper_irq_domain_ops = {  	.map = flipper_pic_map,  	.match = flipper_pic_match,  }; @@ -130,10 +130,10 @@ static void __flipper_quiesce(void __iomem *io_base)  	out_be32(io_base + FLIPPER_ICR, 0xffffffff);  } -struct irq_host * __init flipper_pic_init(struct device_node *np) +struct irq_domain * __init flipper_pic_init(struct device_node *np)  {  	struct device_node *pi; -	struct irq_host *irq_host = NULL; +	struct irq_domain *irq_domain = NULL;  	struct resource res;  	void __iomem *io_base;  	int retval; @@ -159,17 +159,15 @@ struct irq_host * __init flipper_pic_init(struct device_node *np)  	__flipper_quiesce(io_base); -	irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS, -				  &flipper_irq_host_ops, -1); -	if (!irq_host) { -		pr_err("failed to allocate irq_host\n"); +	irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS, +				  &flipper_irq_domain_ops, io_base); +	if (!irq_domain) { +		pr_err("failed to allocate irq_domain\n");  		return NULL;  	} -	irq_host->host_data = io_base; -  out: -	return irq_host; +	return irq_domain;  }  unsigned int flipper_pic_get_irq(void) diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index e4919170c6b..3006b5117ec 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -89,9 +89,9 @@ static struct irq_chip hlwd_pic = {   *   */ -static struct irq_host *hlwd_irq_host; +static struct irq_domain *hlwd_irq_host; -static int hlwd_pic_map(struct irq_host *h, unsigned int virq, +static int hlwd_pic_map(struct irq_domain *h, unsigned int virq,  			   irq_hw_number_t hwirq)  {  	irq_set_chip_data(virq, h->host_data); @@ -100,11 +100,11 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static struct irq_host_ops hlwd_irq_host_ops = { +static const struct irq_domain_ops hlwd_irq_domain_ops = {  	.map = hlwd_pic_map,  }; -static unsigned int __hlwd_pic_get_irq(struct irq_host *h) +static unsigned int __hlwd_pic_get_irq(struct irq_domain *h)  {  	void __iomem *io_base = h->host_data;  	int irq; @@ -123,14 +123,14 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,  				      struct irq_desc *desc)  {  	struct irq_chip *chip = irq_desc_get_chip(desc); -	struct irq_host *irq_host = irq_get_handler_data(cascade_virq); +	struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq);  	unsigned int virq;  	raw_spin_lock(&desc->lock);  	chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */  	raw_spin_unlock(&desc->lock); -	virq = __hlwd_pic_get_irq(irq_host); +	virq = __hlwd_pic_get_irq(irq_domain);  	if (virq != NO_IRQ)  		generic_handle_irq(virq);  	else @@ -155,9 +155,9 @@ static void __hlwd_quiesce(void __iomem *io_base)  	out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff);  } -struct irq_host *hlwd_pic_init(struct device_node *np) +struct irq_domain *hlwd_pic_init(struct device_node *np)  { -	struct irq_host *irq_host; +	struct irq_domain *irq_domain;  	struct resource res;  	void __iomem *io_base;  	int retval; @@ -177,15 +177,14 @@ struct irq_host *hlwd_pic_init(struct device_node *np)  	__hlwd_quiesce(io_base); -	irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, HLWD_NR_IRQS, -				  &hlwd_irq_host_ops, -1); -	if (!irq_host) { -		pr_err("failed to allocate irq_host\n"); +	irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS, +					   &hlwd_irq_domain_ops, io_base); +	if (!irq_domain) { +		pr_err("failed to allocate irq_domain\n");  		return NULL;  	} -	irq_host->host_data = io_base; -	return irq_host; +	return irq_domain;  }  unsigned int hlwd_pic_get_irq(void) @@ -200,7 +199,7 @@ unsigned int hlwd_pic_get_irq(void)  void hlwd_pic_probe(void)  { -	struct irq_host *host; +	struct irq_domain *host;  	struct device_node *np;  	const u32 *interrupts;  	int cascade_virq; diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 9cfcf20c056..ab51b21b4bd 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -154,11 +154,9 @@ static void __init holly_init_IRQ(void)  	struct device_node *cascade_node = NULL;  #endif -	mpic = mpic_alloc(NULL, 0, -			MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | +	mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |  			MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, -			24, -			NR_IRQS-4, /* num_sources used */ +			24, 0,  			"Tsi108_PIC");  	BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index bcfad92c9ce..455e7c08742 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -82,8 +82,7 @@ static void __init linkstation_init_IRQ(void)  {  	struct mpic *mpic; -	mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, -			4, 32, " EPIC     "); +	mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC     ");  	BUG_ON(mpic == NULL);  	/* PCI IRQs */ diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index f3350d786f5..74ccce36bae 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -108,11 +108,9 @@ static void __init mpc7448_hpc2_init_IRQ(void)  	struct device_node *cascade_node = NULL;  #endif -	mpic = mpic_alloc(NULL, 0, -			MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | +	mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |  			MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, -			24, -			NR_IRQS-4, /* num_sources used */ +			24, 0,  			"Tsi108_PIC");  	BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index afa63883496..e0ed3c71d69 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -84,8 +84,7 @@ static void __init storcenter_init_IRQ(void)  {  	struct mpic *mpic; -	mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, -			16, 32, " OpenPIC  "); +	mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC  ");  	BUG_ON(mpic == NULL);  	/* diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig deleted file mode 100644 index b57cda3a081..00000000000 --- a/arch/powerpc/platforms/iseries/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -config PPC_ISERIES -	bool "IBM Legacy iSeries" -	depends on PPC64 && PPC_BOOK3S -	select PPC_SMP_MUXED_IPI -	select PPC_INDIRECT_PIO -	select PPC_INDIRECT_MMIO -	select PPC_PCI_CHOICE if EXPERT - -menu "iSeries device drivers" -	depends on PPC_ISERIES - -config VIODASD -	tristate "iSeries Virtual I/O disk support" -	depends on BLOCK -	select VIOPATH -	help -	  If you are running on an iSeries system and you want to use -	  virtual disks created and managed by OS/400, say Y. - -config VIOCD -	tristate "iSeries Virtual I/O CD support" -	depends on BLOCK -	select VIOPATH -	help -	  If you are running Linux on an IBM iSeries system and you want to -	  read a CD drive owned by OS/400, say Y here. - -config VIOTAPE -	tristate "iSeries Virtual Tape Support" -	select VIOPATH -	help -	  If you are running Linux on an iSeries system and you want Linux -	  to read and/or write a tape drive owned by OS/400, say Y here. - -endmenu - -config VIOPATH -	bool diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile deleted file mode 100644 index a7602b11ed9..00000000000 --- a/arch/powerpc/platforms/iseries/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -ccflags-y	:= -mno-minimal-toc - -obj-y += exception.o -obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \ -	hvcall.o proc.o htab.o iommu.o misc.o irq.o -obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_VIOPATH) += viopath.o vio.o -obj-$(CONFIG_MODULES) += ksyms.o diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h deleted file mode 100644 index 8d95fe4b554..00000000000 --- a/arch/powerpc/platforms/iseries/call_hpt.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _PLATFORMS_ISERIES_CALL_HPT_H -#define _PLATFORMS_ISERIES_CALL_HPT_H - -/* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> -#include <asm/mmu.h> - -#define HvCallHptGetHptAddress		HvCallHpt +  0 -#define HvCallHptGetHptPages		HvCallHpt +  1 -#define HvCallHptSetPp			HvCallHpt +  5 -#define HvCallHptSetSwBits		HvCallHpt +  6 -#define HvCallHptUpdate			HvCallHpt +  7 -#define HvCallHptInvalidateNoSyncICache	HvCallHpt +  8 -#define HvCallHptGet			HvCallHpt + 11 -#define HvCallHptFindNextValid		HvCallHpt + 12 -#define HvCallHptFindValid		HvCallHpt + 13 -#define HvCallHptAddValidate		HvCallHpt + 16 -#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18 - - -static inline u64 HvCallHpt_getHptAddress(void) -{ -	return HvCall0(HvCallHptGetHptAddress); -} - -static inline u64 HvCallHpt_getHptPages(void) -{ -	return HvCall0(HvCallHptGetHptPages); -} - -static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) -{ -	HvCall2(HvCallHptSetPp, hpteIndex, value); -} - -static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff) -{ -	HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff); -} - -static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) -{ -	HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); -} - -static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, -		u8 bitsoff) -{ -	u64 compressedStatus; - -	compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet, -			hpteIndex, bitson, bitsoff, 1); -	HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); -	return compressedStatus; -} - -static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn) -{ -	return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); -} - -static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex, -		u8 bitson, u8 bitsoff) -{ -	return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, -			bitson, bitsoff); -} - -static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex) -{ -	HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); -} - -static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, -					 struct hash_pte *hpte) -{ -	HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); -} - -#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */ diff --git a/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h deleted file mode 100644 index dbdf69850ed..00000000000 --- a/arch/powerpc/platforms/iseries/call_pci.h +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Provides the Hypervisor PCI calls for iSeries Linux Parition. - * Copyright (C) 2001  <Wayne G Holm> <IBM Corporation> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, - * Boston, MA  02111-1307  USA - * - * Change Activity: - *   Created, Jan 9, 2001 - */ - -#ifndef _PLATFORMS_ISERIES_CALL_PCI_H -#define _PLATFORMS_ISERIES_CALL_PCI_H - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -/* - * DSA == Direct Select Address - * this struct must be 64 bits in total - */ -struct HvCallPci_DsaAddr { -	u16		busNumber;		/* PHB index? */ -	u8		subBusNumber;		/* PCI bus number? */ -	u8		deviceId;		/* device and function? */ -	u8		barNumber; -	u8		reserved[3]; -}; - -union HvDsaMap { -	u64	DsaAddr; -	struct HvCallPci_DsaAddr Dsa; -}; - -struct HvCallPci_LoadReturn { -	u64		rc; -	u64		value; -}; - -enum HvCallPci_DeviceType { -	HvCallPci_NodeDevice	= 1, -	HvCallPci_SpDevice	= 2, -	HvCallPci_IopDevice     = 3, -	HvCallPci_BridgeDevice	= 4, -	HvCallPci_MultiFunctionDevice = 5, -	HvCallPci_IoaDevice	= 6 -}; - - -struct HvCallPci_DeviceInfo { -	u32	deviceType;		/* See DeviceType enum for values */ -}; - -struct HvCallPci_BusUnitInfo { -	u32	sizeReturned;		/* length of data returned */ -	u32	deviceType;		/* see DeviceType enum for values */ -}; - -struct HvCallPci_BridgeInfo { -	struct HvCallPci_BusUnitInfo busUnitInfo;  /* Generic bus unit info */ -	u8		subBusNumber;	/* Bus number of secondary bus */ -	u8		maxAgents;	/* Max idsels on secondary bus */ -        u8              maxSubBusNumber; /* Max Sub Bus */ -	u8		logicalSlotNumber; /* Logical Slot Number for IOA */ -}; - - -/* - * Maximum BusUnitInfo buffer size.  Provided for clients so - * they can allocate a buffer big enough for any type of bus - * unit.  Increase as needed. - */ -enum {HvCallPci_MaxBusUnitInfoSize = 128}; - -struct HvCallPci_BarParms { -	u64		vaddr; -	u64		raddr; -	u64		size; -	u64		protectStart; -	u64		protectEnd; -	u64		relocationOffset; -	u64		pciAddress; -	u64		reserved[3]; -}; - -enum HvCallPci_VpdType { -	HvCallPci_BusVpd	= 1, -	HvCallPci_BusAdapterVpd	= 2 -}; - -#define HvCallPciConfigLoad8		HvCallPci + 0 -#define HvCallPciConfigLoad16		HvCallPci + 1 -#define HvCallPciConfigLoad32		HvCallPci + 2 -#define HvCallPciConfigStore8		HvCallPci + 3 -#define HvCallPciConfigStore16		HvCallPci + 4 -#define HvCallPciConfigStore32		HvCallPci + 5 -#define HvCallPciEoi			HvCallPci + 16 -#define HvCallPciGetBarParms		HvCallPci + 18 -#define HvCallPciMaskFisr		HvCallPci + 20 -#define HvCallPciUnmaskFisr		HvCallPci + 21 -#define HvCallPciSetSlotReset		HvCallPci + 25 -#define HvCallPciGetDeviceInfo		HvCallPci + 27 -#define HvCallPciGetCardVpd		HvCallPci + 28 -#define HvCallPciBarLoad8		HvCallPci + 40 -#define HvCallPciBarLoad16		HvCallPci + 41 -#define HvCallPciBarLoad32		HvCallPci + 42 -#define HvCallPciBarLoad64		HvCallPci + 43 -#define HvCallPciBarStore8		HvCallPci + 44 -#define HvCallPciBarStore16		HvCallPci + 45 -#define HvCallPciBarStore32		HvCallPci + 46 -#define HvCallPciBarStore64		HvCallPci + 47 -#define HvCallPciMaskInterrupts		HvCallPci + 48 -#define HvCallPciUnmaskInterrupts	HvCallPci + 49 -#define HvCallPciGetBusUnitInfo		HvCallPci + 50 - -static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, -		u8 deviceId, u32 offset, u16 *value) -{ -	struct HvCallPci_DsaAddr dsa; -	struct HvCallPci_LoadReturn retVal; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumber; -	dsa.subBusNumber = subBusNumber; -	dsa.deviceId = deviceId; - -	HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0); - -	*value = retVal.value; - -	return retVal.rc; -} - -static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, -		u8 deviceId, u32 offset, u32 *value) -{ -	struct HvCallPci_DsaAddr dsa; -	struct HvCallPci_LoadReturn retVal; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumber; -	dsa.subBusNumber = subBusNumber; -	dsa.deviceId = deviceId; - -	HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0); - -	*value = retVal.value; - -	return retVal.rc; -} - -static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, -		u8 deviceId, u32 offset, u8 value) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumber; -	dsa.subBusNumber = subBusNumber; -	dsa.deviceId = deviceId; - -	return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0); -} - -static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, -		u8 deviceIdParm) -{ -	struct HvCallPci_DsaAddr dsa; -	struct HvCallPci_LoadReturn retVal; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceIdParm; - -	HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa); - -	return retVal.rc; -} - -static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, -		u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceIdParm; -	dsa.barNumber = barNumberParm; - -	return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms); -} - -static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, -		u8 deviceIdParm, u64 fisrMask) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceIdParm; - -	return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask); -} - -static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, -		u8 deviceIdParm, u64 fisrMask) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceIdParm; - -	return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask); -} - -static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, -		u8 deviceNumberParm, u64 parms, u32 sizeofParms) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceNumberParm << 4; - -	return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms); -} - -static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, -		u8 deviceIdParm, u64 interruptMask) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceIdParm; - -	return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask); -} - -static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, -		u8 deviceIdParm, u64 interruptMask) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceIdParm; - -	return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask); -} - -static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, -		u8 deviceIdParm, u64 parms, u32 sizeofParms) -{ -	struct HvCallPci_DsaAddr dsa; - -	*((u64*)&dsa) = 0; - -	dsa.busNumber = busNumberParm; -	dsa.subBusNumber = subBusParm; -	dsa.deviceId = deviceIdParm; - -	return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, -			sizeofParms); -} - -static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, -		u16 sizeParm) -{ -	u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, -			sizeParm, HvCallPci_BusVpd); -	if (xRc == -1) -		return -1; -	else -		return xRc & 0xFFFF; -} - -#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */ diff --git a/arch/powerpc/platforms/iseries/call_sm.h b/arch/powerpc/platforms/iseries/call_sm.h deleted file mode 100644 index c7e251619f4..00000000000 --- a/arch/powerpc/platforms/iseries/call_sm.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _ISERIES_CALL_SM_H -#define _ISERIES_CALL_SM_H - -/* - * This file contains the "hypervisor call" interface which is used to - * drive the hypervisor from the OS. - */ - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -#define HvCallSmGet64BitsOfAccessMap	HvCallSm  + 11 - -static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, -		u64 indexIntoBitMap) -{ -	return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap); -} - -#endif /* _ISERIES_CALL_SM_H */ diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c deleted file mode 100644 index f0491cc2890..00000000000 --- a/arch/powerpc/platforms/iseries/dt.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - *    Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation - *    Copyright (C) 2000-2004, IBM Corporation - * - *    Description: - *      This file contains all the routines to build a flattened device - *      tree for a legacy iSeries machine. - * - *      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. - */ - -#undef DEBUG - -#include <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/pci_regs.h> -#include <linux/pci_ids.h> -#include <linux/threads.h> -#include <linux/bitops.h> -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/if_ether.h>	/* ETH_ALEN */ - -#include <asm/machdep.h> -#include <asm/prom.h> -#include <asm/lppaca.h> -#include <asm/cputable.h> -#include <asm/abs_addr.h> -#include <asm/system.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/udbg.h> - -#include "processor_vpd.h" -#include "call_hpt.h" -#include "call_pci.h" -#include "pci.h" -#include "it_exp_vpd_panel.h" -#include "naca.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* - * These are created by the linker script at the start and end - * of the section containing all the strings marked with the DS macro. - */ -extern char __dt_strings_start[]; -extern char __dt_strings_end[]; - -#define DS(s)	({	\ -	static const char __s[] __attribute__((section(".dt_strings"))) = s; \ -	__s;		\ -}) - -struct iseries_flat_dt { -	struct boot_param_header header; -	u64 reserve_map[2]; -}; - -static void * __initdata dt_data; - -/* - * Putting these strings here keeps them out of the .dt_strings section - * that we capture for the strings blob of the flattened device tree. - */ -static char __initdata device_type_cpu[] = "cpu"; -static char __initdata device_type_memory[] = "memory"; -static char __initdata device_type_serial[] = "serial"; -static char __initdata device_type_network[] = "network"; -static char __initdata device_type_pci[] = "pci"; -static char __initdata device_type_vdevice[] = "vdevice"; -static char __initdata device_type_vscsi[] = "vscsi"; - - -/* EBCDIC to ASCII conversion routines */ - -static unsigned char __init e2a(unsigned char x) -{ -	switch (x) { -	case 0x81 ... 0x89: -		return x - 0x81 + 'a'; -	case 0x91 ... 0x99: -		return x - 0x91 + 'j'; -	case 0xA2 ... 0xA9: -		return x - 0xA2 + 's'; -	case 0xC1 ... 0xC9: -		return x - 0xC1 + 'A'; -	case 0xD1 ... 0xD9: -		return x - 0xD1 + 'J'; -	case 0xE2 ... 0xE9: -		return x - 0xE2 + 'S'; -	case 0xF0 ... 0xF9: -		return x - 0xF0 + '0'; -	} -	return ' '; -} - -static unsigned char * __init strne2a(unsigned char *dest, -		const unsigned char *src, size_t n) -{ -	int i; - -	n = strnlen(src, n); - -	for (i = 0; i < n; i++) -		dest[i] = e2a(src[i]); - -	return dest; -} - -static struct iseries_flat_dt * __init dt_init(void) -{ -	struct iseries_flat_dt *dt; -	unsigned long str_len; - -	str_len = __dt_strings_end - __dt_strings_start; -	dt = (struct iseries_flat_dt *)ALIGN(klimit, 8); -	dt->header.off_mem_rsvmap = -		offsetof(struct iseries_flat_dt, reserve_map); -	dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8); -	dt->header.off_dt_struct = dt->header.off_dt_strings -		+ ALIGN(str_len, 8); -	dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct); -	dt->header.dt_strings_size = str_len; - -	/* There is no notion of hardware cpu id on iSeries */ -	dt->header.boot_cpuid_phys = smp_processor_id(); - -	memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start, -			str_len); - -	dt->header.magic = OF_DT_HEADER; -	dt->header.version = 0x10; -	dt->header.last_comp_version = 0x10; - -	dt->reserve_map[0] = 0; -	dt->reserve_map[1] = 0; - -	return dt; -} - -static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value) -{ -	*((u32 *)dt_data) = value; -	dt_data += sizeof(u32); -} - -#ifdef notyet -static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value) -{ -	*((u64 *)dt_data) = value; -	dt_data += sizeof(u64); -} -#endif - -static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data, -		int len) -{ -	memcpy(dt_data, data, len); -	dt_data += ALIGN(len, 4); -} - -static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name) -{ -	dt_push_u32(dt, OF_DT_BEGIN_NODE); -	dt_push_bytes(dt, name, strlen(name) + 1); -} - -#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) - -static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name, -		const void *data, int len) -{ -	unsigned long offset; - -	dt_push_u32(dt, OF_DT_PROP); - -	/* Length of the data */ -	dt_push_u32(dt, len); - -	offset = name - __dt_strings_start; - -	/* The offset of the properties name in the string blob. */ -	dt_push_u32(dt, (u32)offset); - -	/* The actual data. */ -	dt_push_bytes(dt, data, len); -} -#define dt_prop(dt, name, data, len)	__dt_prop((dt), DS(name), (data), (len)) - -#define dt_prop_str(dt, name, data)	\ -	dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */ - -static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name, -		u32 data) -{ -	__dt_prop(dt, name, &data, sizeof(u32)); -} -#define dt_prop_u32(dt, name, data)	__dt_prop_u32((dt), DS(name), (data)) - -static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt, -		const char *name, u64 data) -{ -	__dt_prop(dt, name, &data, sizeof(u64)); -} -#define dt_prop_u64(dt, name, data)	__dt_prop_u64((dt), DS(name), (data)) - -#define dt_prop_u64_list(dt, name, data, n)	\ -	dt_prop((dt), name, (data), sizeof(u64) * (n)) - -#define dt_prop_u32_list(dt, name, data, n)	\ -	dt_prop((dt), name, (data), sizeof(u32) * (n)) - -#define dt_prop_empty(dt, name)		dt_prop((dt), name, NULL, 0) - -static void __init dt_cpus(struct iseries_flat_dt *dt) -{ -	unsigned char buf[32]; -	unsigned char *p; -	unsigned int i, index; -	struct IoHriProcessorVpd *d; -	u32 pft_size[2]; - -	/* yuck */ -	snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name); -	p = strchr(buf, ' '); -	if (!p) p = buf + strlen(buf); - -	dt_start_node(dt, "cpus"); -	dt_prop_u32(dt, "#address-cells", 1); -	dt_prop_u32(dt, "#size-cells", 0); - -	pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA  */ -	pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE); - -	for (i = 0; i < NR_LPPACAS; i++) { -		if (lppaca[i].dyn_proc_status >= 2) -			continue; - -		snprintf(p, 32 - (p - buf), "@%d", i); -		dt_start_node(dt, buf); - -		dt_prop_str(dt, "device_type", device_type_cpu); - -		index = lppaca[i].dyn_hv_phys_proc_index; -		d = &xIoHriProcessorVpd[index]; - -		dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); -		dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize); - -		dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024); -		dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize); - -		/* magic conversions to Hz copied from old code */ -		dt_prop_u32(dt, "clock-frequency", -			((1UL << 34) * 1000000) / d->xProcFreq); -		dt_prop_u32(dt, "timebase-frequency", -			((1UL << 32) * 1000000) / d->xTimeBaseFreq); - -		dt_prop_u32(dt, "reg", i); - -		dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2); - -		dt_end_node(dt); -	} - -	dt_end_node(dt); -} - -static void __init dt_model(struct iseries_flat_dt *dt) -{ -	char buf[16] = "IBM,"; - -	/* N.B. lparcfg.c knows about the "IBM," prefixes ... */ -	/* "IBM," + mfgId[2:3] + systemSerial[1:5] */ -	strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2); -	strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5); -	buf[11] = '\0'; -	dt_prop_str(dt, "system-id", buf); - -	/* "IBM," + machineType[0:4] */ -	strne2a(buf + 4, xItExtVpdPanel.machineType, 4); -	buf[8] = '\0'; -	dt_prop_str(dt, "model", buf); - -	dt_prop_str(dt, "compatible", "IBM,iSeries"); -	dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex()); -} - -static void __init dt_initrd(struct iseries_flat_dt *dt) -{ -#ifdef CONFIG_BLK_DEV_INITRD -	if (naca.xRamDisk) { -		dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk); -		dt_prop_u64(dt, "linux,initrd-end", -			(u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE); -	} -#endif -} - -static void __init dt_do_vdevice(struct iseries_flat_dt *dt, -		const char *name, u32 reg, int unit, -		const char *type, const char *compat, int end) -{ -	char buf[32]; - -	snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0)); -	dt_start_node(dt, buf); -	dt_prop_str(dt, "device_type", type); -	if (compat) -		dt_prop_str(dt, "compatible", compat); -	dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0)); -	if (unit >= 0) -		dt_prop_u32(dt, "linux,unit_address", unit); -	if (end) -		dt_end_node(dt); -} - -static void __init dt_vdevices(struct iseries_flat_dt *dt) -{ -	u32 reg = 0; -	HvLpIndexMap vlan_map; -	int i; - -	dt_start_node(dt, "vdevice"); -	dt_prop_str(dt, "device_type", device_type_vdevice); -	dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice"); -	dt_prop_u32(dt, "#address-cells", 1); -	dt_prop_u32(dt, "#size-cells", 0); - -	dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, -			"IBM,iSeries-vty", 1); -	reg++; - -	dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi, -			"IBM,v-scsi", 1); -	reg++; - -	vlan_map = HvLpConfig_getVirtualLanIndexMap(); -	for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { -		unsigned char mac_addr[ETH_ALEN]; - -		if ((vlan_map & (0x8000 >> i)) == 0) -			continue; -		dt_do_vdevice(dt, "l-lan", reg, i, device_type_network, -				"IBM,iSeries-l-lan", 0); -		mac_addr[0] = 0x02; -		mac_addr[1] = 0x01; -		mac_addr[2] = 0xff; -		mac_addr[3] = i; -		mac_addr[4] = 0xff; -		mac_addr[5] = HvLpConfig_getLpIndex_outline(); -		dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN); -		dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN); -		dt_prop_u32(dt, "max-frame-size", 9000); -		dt_prop_u32(dt, "address-bits", 48); - -		dt_end_node(dt); -	} - -	dt_end_node(dt); -} - -struct pci_class_name { -	u16 code; -	const char *name; -	const char *type; -}; - -static struct pci_class_name __initdata pci_class_name[] = { -	{ PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network }, -}; - -static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code) -{ -	struct pci_class_name *cp; - -	for (cp = pci_class_name; -			cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++) -		if (cp->code == class_code) -			return cp; -	return NULL; -} - -/* - * This assumes that the node slot is always on the primary bus! - */ -static void __init scan_bridge_slot(struct iseries_flat_dt *dt, -		HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info) -{ -	HvSubBusNumber sub_bus = bridge_info->subBusNumber; -	u16 vendor_id; -	u16 device_id; -	u32 class_id; -	int err; -	char buf[32]; -	u32 reg[5]; -	int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus); -	int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus); -	HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function); -	u8 devfn; -	struct pci_class_name *cp; - -	/* -	 * Connect all functions of any device found. -	 */ -	for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) { -		for (function = 0; function < 8; function++) { -			HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel, -					function); -			err = HvCallXm_connectBusUnit(bus, sub_bus, -					agent_id, 0); -			if (err) { -				if (err != 0x302) -					DBG("connectBusUnit(%x, %x, %x) %x\n", -						bus, sub_bus, agent_id, err); -				continue; -			} - -			err = HvCallPci_configLoad16(bus, sub_bus, agent_id, -					PCI_VENDOR_ID, &vendor_id); -			if (err) { -				DBG("ReadVendor(%x, %x, %x) %x\n", -					bus, sub_bus, agent_id, err); -				continue; -			} -			err = HvCallPci_configLoad16(bus, sub_bus, agent_id, -					PCI_DEVICE_ID, &device_id); -			if (err) { -				DBG("ReadDevice(%x, %x, %x) %x\n", -					bus, sub_bus, agent_id, err); -				continue; -			} -			err = HvCallPci_configLoad32(bus, sub_bus, agent_id, -					PCI_CLASS_REVISION , &class_id); -			if (err) { -				DBG("ReadClass(%x, %x, %x) %x\n", -					bus, sub_bus, agent_id, err); -				continue; -			} - -			devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel), -					function); -			cp = dt_find_pci_class_name(class_id >> 16); -			if (cp && cp->name) -				strncpy(buf, cp->name, sizeof(buf) - 1); -			else -				snprintf(buf, sizeof(buf), "pci%x,%x", -						vendor_id, device_id); -			buf[sizeof(buf) - 1] = '\0'; -			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), -					"@%x", PCI_SLOT(devfn)); -			buf[sizeof(buf) - 1] = '\0'; -			if (function != 0) -				snprintf(buf + strlen(buf), -					sizeof(buf) - strlen(buf), -					",%x", function); -			dt_start_node(dt, buf); -			reg[0] = (bus << 16) | (devfn << 8); -			reg[1] = 0; -			reg[2] = 0; -			reg[3] = 0; -			reg[4] = 0; -			dt_prop_u32_list(dt, "reg", reg, 5); -			if (cp && (cp->type || cp->name)) -				dt_prop_str(dt, "device_type", -					cp->type ? cp->type : cp->name); -			dt_prop_u32(dt, "vendor-id", vendor_id); -			dt_prop_u32(dt, "device-id", device_id); -			dt_prop_u32(dt, "class-code", class_id >> 8); -			dt_prop_u32(dt, "revision-id", class_id & 0xff); -			dt_prop_u32(dt, "linux,subbus", sub_bus); -			dt_prop_u32(dt, "linux,agent-id", agent_id); -			dt_prop_u32(dt, "linux,logical-slot-number", -					bridge_info->logicalSlotNumber); -			dt_end_node(dt); - -		} -	} -} - -static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus, -		HvSubBusNumber sub_bus, int id_sel) -{ -	struct HvCallPci_BridgeInfo bridge_info; -	HvAgentId agent_id; -	int function; -	int ret; - -	/* Note: hvSubBus and irq is always be 0 at this level! */ -	for (function = 0; function < 8; ++function) { -		agent_id = ISERIES_PCI_AGENTID(id_sel, function); -		ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0); -		if (ret != 0) { -			if (ret != 0xb) -				DBG("connectBusUnit(%x, %x, %x) %x\n", -						bus, sub_bus, agent_id, ret); -			continue; -		} -		DBG("found device at bus %d idsel %d func %d (AgentId %x)\n", -				bus, id_sel, function, agent_id); -		ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id, -				iseries_hv_addr(&bridge_info), -				sizeof(struct HvCallPci_BridgeInfo)); -		if (ret != 0) -			continue; -		DBG("bridge info: type %x subbus %x " -			"maxAgents %x maxsubbus %x logslot %x\n", -			bridge_info.busUnitInfo.deviceType, -			bridge_info.subBusNumber, -			bridge_info.maxAgents, -			bridge_info.maxSubBusNumber, -			bridge_info.logicalSlotNumber); -		if (bridge_info.busUnitInfo.deviceType == -				HvCallPci_BridgeDevice) -			scan_bridge_slot(dt, bus, &bridge_info); -		else -			DBG("PCI: Invalid Bridge Configuration(0x%02X)", -				bridge_info.busUnitInfo.deviceType); -	} -} - -static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus) -{ -	struct HvCallPci_DeviceInfo dev_info; -	const HvSubBusNumber sub_bus = 0;	/* EADs is always 0. */ -	int err; -	int id_sel; -	const int max_agents = 8; - -	/* -	 * Probe for EADs Bridges -	 */ -	for (id_sel = 1; id_sel < max_agents; ++id_sel) { -		err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel, -				iseries_hv_addr(&dev_info), -				sizeof(struct HvCallPci_DeviceInfo)); -		if (err) { -			if (err != 0x302) -				DBG("getDeviceInfo(%x, %x, %x) %x\n", -						bus, sub_bus, id_sel, err); -			continue; -		} -		if (dev_info.deviceType != HvCallPci_NodeDevice) { -			DBG("PCI: Invalid System Configuration" -					"(0x%02X) for bus 0x%02x id 0x%02x.\n", -					dev_info.deviceType, bus, id_sel); -			continue; -		} -		scan_bridge(dt, bus, sub_bus, id_sel); -	} -} - -static void __init dt_pci_devices(struct iseries_flat_dt *dt) -{ -	HvBusNumber bus; -	char buf[32]; -	u32 buses[2]; -	int phb_num = 0; - -	/* Check all possible buses. */ -	for (bus = 0; bus < 256; bus++) { -		int err = HvCallXm_testBus(bus); - -		if (err) { -			/* -			 * Check for Unexpected Return code, a clue that -			 * something has gone wrong. -			 */ -			if (err != 0x0301) -				DBG("Unexpected Return on Probe(0x%02X) " -						"0x%04X\n", bus, err); -			continue; -		} -		DBG("bus %d appears to exist\n", bus); -		snprintf(buf, 32, "pci@%d", phb_num); -		dt_start_node(dt, buf); -		dt_prop_str(dt, "device_type", device_type_pci); -		dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB"); -		dt_prop_u32(dt, "#address-cells", 3); -		dt_prop_u32(dt, "#size-cells", 2); -		buses[0] = buses[1] = bus; -		dt_prop_u32_list(dt, "bus-range", buses, 2); -		scan_phb(dt, bus); -		dt_end_node(dt); -		phb_num++; -	} -} - -static void dt_finish(struct iseries_flat_dt *dt) -{ -	dt_push_u32(dt, OF_DT_END); -	dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt; -	klimit = ALIGN((unsigned long)dt_data, 8); -} - -void * __init build_flat_dt(unsigned long phys_mem_size) -{ -	struct iseries_flat_dt *iseries_dt; -	u64 tmp[2]; - -	iseries_dt = dt_init(); - -	dt_start_node(iseries_dt, ""); - -	dt_prop_u32(iseries_dt, "#address-cells", 2); -	dt_prop_u32(iseries_dt, "#size-cells", 2); -	dt_model(iseries_dt); - -	/* /memory */ -	dt_start_node(iseries_dt, "memory@0"); -	dt_prop_str(iseries_dt, "device_type", device_type_memory); -	tmp[0] = 0; -	tmp[1] = phys_mem_size; -	dt_prop_u64_list(iseries_dt, "reg", tmp, 2); -	dt_end_node(iseries_dt); - -	/* /chosen */ -	dt_start_node(iseries_dt, "chosen"); -	dt_prop_str(iseries_dt, "bootargs", cmd_line); -	dt_initrd(iseries_dt); -	dt_end_node(iseries_dt); - -	dt_cpus(iseries_dt); - -	dt_vdevices(iseries_dt); -	dt_pci_devices(iseries_dt); - -	dt_end_node(iseries_dt); - -	dt_finish(iseries_dt); - -	return iseries_dt; -} diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S deleted file mode 100644 index f519ee17ff7..00000000000 --- a/arch/powerpc/platforms/iseries/exception.S +++ /dev/null @@ -1,311 +0,0 @@ -/* - *  Low level routines for legacy iSeries support. - * - *  Extracted from head_64.S - * - *  PowerPC version - *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - *  Adapted for Power Macintosh by Paul Mackerras. - *  Low-level exception handlers and MMU support - *  rewritten by Paul Mackerras. - *    Copyright (C) 1996 Paul Mackerras. - * - *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and - *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com - * - *  This file contains the low-level support and setup for the - *  PowerPC-64 platform, including trap and interrupt dispatch. - * - *  This program is free software; you can redistribute it and/or - *  modify it under the terms of the GNU General Public License - *  as published by the Free Software Foundation; either version - *  2 of the License, or (at your option) any later version. - */ - -#include <asm/reg.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/thread_info.h> -#include <asm/ptrace.h> -#include <asm/cputable.h> -#include <asm/mmu.h> - -#include "exception.h" - -	.text - -	.globl system_reset_iSeries -system_reset_iSeries: -	bl	.relative_toc -	mfspr	r13,SPRN_SPRG3		/* Get alpaca address */ -	LOAD_REG_ADDR(r23, alpaca) -	li	r0,ALPACA_SIZE -	sub	r23,r13,r23 -	divdu	r24,r23,r0		/* r24 has cpu number */ -	cmpwi	0,r24,0			/* Are we processor 0? */ -	bne	1f -	LOAD_REG_ADDR(r13, boot_paca) -	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */ -	mfmsr	r23 -	ori	r23,r23,MSR_RI -	mtmsrd	r23			/* RI on */ -	b	.__start_initialization_iSeries	/* Start up the first processor */ -1:	mfspr	r4,SPRN_CTRLF -	li	r5,CTRL_RUNLATCH	/* Turn off the run light */ -	andc	r4,r4,r5 -	mtspr	SPRN_CTRLT,r4 - -/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ -/* In the UP case we'll yield() later, and we will not access the paca anyway */ -#ifdef CONFIG_SMP -iSeries_secondary_wait_paca: -	HMT_LOW -	LOAD_REG_ADDR(r23, __secondary_hold_spinloop) -	ld	r23,0(r23) - -	cmpdi	0,r23,0 -	bne	2f			/* go on when the master is ready */ - -	/* Keep poking the Hypervisor until we're released */ -	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ -	lis	r3,0x8002 -	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */ -	li	r0,-1			/* r0=-1 indicates a Hypervisor call */ -	sc				/* Invoke the hypervisor via a system call */ -	b	iSeries_secondary_wait_paca - -2: -	HMT_MEDIUM -	sync - -	LOAD_REG_ADDR(r3, nr_cpu_ids)	/* get number of pacas allocated */ -	lwz	r3,0(r3)		/* nr_cpus= or NR_CPUS can limit */ -	cmpld	0,r24,r3		/* is our cpu number allocated? */ -	bge	iSeries_secondary_yield	/* no, yield forever */ - -	/* Load our paca now that it's been allocated */ -	LOAD_REG_ADDR(r13, paca) -	ld	r13,0(r13) -	mulli	r0,r24,PACA_SIZE -	add	r13,r13,r0 -	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */ -	mfmsr	r23 -	ori	r23,r23,MSR_RI -	mtmsrd	r23			/* RI on */ - -iSeries_secondary_smp_loop: -	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor -					 * should start */ -	cmpwi	0,r23,0 -	bne	3f			/* go on when we are told */ - -	HMT_LOW -	/* Let the Hypervisor know we are alive */ -	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ -	lis	r3,0x8002 -	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */ -	li	r0,-1			/* r0=-1 indicates a Hypervisor call */ -	sc				/* Invoke the hypervisor via a system call */ -	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */ -	b	iSeries_secondary_smp_loop /* wait for signal to start */ - -3: -	HMT_MEDIUM -	sync -	LOAD_REG_ADDR(r3,current_set) -	sldi	r28,r24,3		/* get current_set[cpu#] */ -	ldx	r3,r3,r28 -	addi	r1,r3,THREAD_SIZE -	subi	r1,r1,STACK_FRAME_OVERHEAD - -	b	__secondary_start		/* Loop until told to go */ -#endif /* CONFIG_SMP */ - -iSeries_secondary_yield: -	/* Yield the processor.  This is required for non-SMP kernels -		which are running on multi-threaded machines. */ -	HMT_LOW -	lis	r3,0x8000 -	rldicr	r3,r3,32,15		/* r3 = (r3 << 32) & 0xffff000000000000 */ -	addi	r3,r3,18		/* r3 = 0x8000000000000012 which is "yield" */ -	li	r4,0			/* "yield timed" */ -	li	r5,-1			/* "yield forever" */ -	li	r0,-1			/* r0=-1 indicates a Hypervisor call */ -	sc				/* Invoke the hypervisor via a system call */ -	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */ -	b	iSeries_secondary_yield	/* If SMP not configured, secondaries -					 * loop forever */ - -/***  ISeries-LPAR interrupt handlers ***/ - -	STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC) - -	.globl data_access_iSeries -data_access_iSeries: -	mtspr	SPRN_SPRG_SCRATCH0,r13 -BEGIN_FTR_SECTION -	mfspr	r13,SPRN_SPRG_PACA -	std	r9,PACA_EXSLB+EX_R9(r13) -	std	r10,PACA_EXSLB+EX_R10(r13) -	mfspr	r10,SPRN_DAR -	mfspr	r9,SPRN_DSISR -	srdi	r10,r10,60 -	rlwimi	r10,r9,16,0x20 -	mfcr	r9 -	cmpwi	r10,0x2c -	beq	.do_stab_bolted_iSeries -	ld	r10,PACA_EXSLB+EX_R10(r13) -	std	r11,PACA_EXGEN+EX_R11(r13) -	ld	r11,PACA_EXSLB+EX_R9(r13) -	std	r12,PACA_EXGEN+EX_R12(r13) -	mfspr	r12,SPRN_SPRG_SCRATCH0 -	std	r10,PACA_EXGEN+EX_R10(r13) -	std	r11,PACA_EXGEN+EX_R9(r13) -	std	r12,PACA_EXGEN+EX_R13(r13) -	EXCEPTION_PROLOG_ISERIES_1 -FTR_SECTION_ELSE -	EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0) -	EXCEPTION_PROLOG_ISERIES_1 -ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) -	b	data_access_common - -.do_stab_bolted_iSeries: -	std	r11,PACA_EXSLB+EX_R11(r13) -	std	r12,PACA_EXSLB+EX_R12(r13) -	mfspr	r10,SPRN_SPRG_SCRATCH0 -	std	r10,PACA_EXSLB+EX_R13(r13) -	EXCEPTION_PROLOG_ISERIES_1 -	b	.do_stab_bolted - -	.globl	data_access_slb_iSeries -data_access_slb_iSeries: -	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */ -	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */ -	std	r3,PACA_EXSLB+EX_R3(r13) -	mfspr	r3,SPRN_DAR -	std	r9,PACA_EXSLB+EX_R9(r13) -	mfcr	r9 -#ifdef __DISABLED__ -	cmpdi	r3,0 -	bge	slb_miss_user_iseries -#endif -	std	r10,PACA_EXSLB+EX_R10(r13) -	std	r11,PACA_EXSLB+EX_R11(r13) -	std	r12,PACA_EXSLB+EX_R12(r13) -	mfspr	r10,SPRN_SPRG_SCRATCH0 -	std	r10,PACA_EXSLB+EX_R13(r13) -	ld	r12,PACALPPACAPTR(r13) -	ld	r12,LPPACASRR1(r12) -	b	.slb_miss_realmode - -	STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN) - -	.globl	instruction_access_slb_iSeries -instruction_access_slb_iSeries: -	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */ -	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */ -	std	r3,PACA_EXSLB+EX_R3(r13) -	ld	r3,PACALPPACAPTR(r13) -	ld	r3,LPPACASRR0(r3)	/* get SRR0 value */ -	std	r9,PACA_EXSLB+EX_R9(r13) -	mfcr	r9 -#ifdef __DISABLED__ -	cmpdi	r3,0 -	bge	slb_miss_user_iseries -#endif -	std	r10,PACA_EXSLB+EX_R10(r13) -	std	r11,PACA_EXSLB+EX_R11(r13) -	std	r12,PACA_EXSLB+EX_R12(r13) -	mfspr	r10,SPRN_SPRG_SCRATCH0 -	std	r10,PACA_EXSLB+EX_R13(r13) -	ld	r12,PACALPPACAPTR(r13) -	ld	r12,LPPACASRR1(r12) -	b	.slb_miss_realmode - -#ifdef __DISABLED__ -slb_miss_user_iseries: -	std	r10,PACA_EXGEN+EX_R10(r13) -	std	r11,PACA_EXGEN+EX_R11(r13) -	std	r12,PACA_EXGEN+EX_R12(r13) -	mfspr	r10,SPRG_SCRATCH0 -	ld	r11,PACA_EXSLB+EX_R9(r13) -	ld	r12,PACA_EXSLB+EX_R3(r13) -	std	r10,PACA_EXGEN+EX_R13(r13) -	std	r11,PACA_EXGEN+EX_R9(r13) -	std	r12,PACA_EXGEN+EX_R3(r13) -	EXCEPTION_PROLOG_ISERIES_1 -	b	slb_miss_user_common -#endif - -	MASKABLE_EXCEPTION_ISERIES(hardware_interrupt) -	STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN) -	STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN) -	STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN) -	MASKABLE_EXCEPTION_ISERIES(decrementer) -	STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN) -	STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN) - -	.globl	system_call_iSeries -system_call_iSeries: -	mr	r9,r13 -	mfspr	r13,SPRN_SPRG_PACA -	EXCEPTION_PROLOG_ISERIES_1 -	b	system_call_common - -	STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN) -	STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN) -	STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN) - -decrementer_iSeries_masked: -	/* We may not have a valid TOC pointer in here. */ -	li	r11,1 -	ld	r12,PACALPPACAPTR(r13) -	stb	r11,LPPACADECRINT(r12) -	li	r12,-1 -	clrldi	r12,r12,33	/* set DEC to 0x7fffffff */ -	mtspr	SPRN_DEC,r12 -	/* fall through */ - -hardware_interrupt_iSeries_masked: -	mtcrf	0x80,r9		/* Restore regs */ -	ld	r12,PACALPPACAPTR(r13) -	ld	r11,LPPACASRR0(r12) -	ld	r12,LPPACASRR1(r12) -	mtspr	SPRN_SRR0,r11 -	mtspr	SPRN_SRR1,r12 -	ld	r9,PACA_EXGEN+EX_R9(r13) -	ld	r10,PACA_EXGEN+EX_R10(r13) -	ld	r11,PACA_EXGEN+EX_R11(r13) -	ld	r12,PACA_EXGEN+EX_R12(r13) -	ld	r13,PACA_EXGEN+EX_R13(r13) -	rfid -	b	.	/* prevent speculative execution */ - -_INIT_STATIC(__start_initialization_iSeries) -	/* Clear out the BSS */ -	LOAD_REG_ADDR(r11,__bss_stop) -	LOAD_REG_ADDR(r8,__bss_start) -	sub	r11,r11,r8		/* bss size			*/ -	addi	r11,r11,7		/* round up to an even double word */ -	rldicl. r11,r11,61,3		/* shift right by 3		*/ -	beq	4f -	addi	r8,r8,-8 -	li	r0,0 -	mtctr	r11			/* zero this many doublewords	*/ -3:	stdu	r0,8(r8) -	bdnz	3b -4: -	LOAD_REG_ADDR(r1,init_thread_union) -	addi	r1,r1,THREAD_SIZE -	li	r0,0 -	stdu	r0,-STACK_FRAME_OVERHEAD(r1) - -	bl	.iSeries_early_setup -	bl	.early_setup - -	/* relocation is on at this point */ - -	b	.start_here_common diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h deleted file mode 100644 index 50271b550a9..00000000000 --- a/arch/powerpc/platforms/iseries/exception.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H -#define _ASM_POWERPC_ISERIES_EXCEPTION_H -/* - * Extracted from head_64.S - * - *  PowerPC version - *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - *  Adapted for Power Macintosh by Paul Mackerras. - *  Low-level exception handlers and MMU support - *  rewritten by Paul Mackerras. - *    Copyright (C) 1996 Paul Mackerras. - * - *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and - *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com - * - *  This file contains the low-level support and setup for the - *  PowerPC-64 platform, including trap and interrupt dispatch. - * - *  This program is free software; you can redistribute it and/or - *  modify it under the terms of the GNU General Public License - *  as published by the Free Software Foundation; either version - *  2 of the License, or (at your option) any later version. - */ -#include <asm/exception-64s.h> - -#define EXCEPTION_PROLOG_ISERIES_1					\ -	mfmsr	r10;							\ -	ld	r12,PACALPPACAPTR(r13);					\ -	ld	r11,LPPACASRR0(r12);					\ -	ld	r12,LPPACASRR1(r12);					\ -	ori	r10,r10,MSR_RI;						\ -	mtmsrd	r10,1 - -#define STD_EXCEPTION_ISERIES(label, area)				\ -	.globl label##_iSeries;						\ -label##_iSeries:							\ -	HMT_MEDIUM;							\ -	mtspr	SPRN_SPRG_SCRATCH0,r13;	/* save r13 */			\ -	EXCEPTION_PROLOG_1(area, NOTEST, 0);				\ -	EXCEPTION_PROLOG_ISERIES_1;					\ -	b	label##_common - -#define MASKABLE_EXCEPTION_ISERIES(label)				\ -	.globl label##_iSeries;						\ -label##_iSeries:							\ -	HMT_MEDIUM;							\ -	mtspr	SPRN_SPRG_SCRATCH0,r13;	/* save r13 */			\ -	EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0);			\ -	lbz	r10,PACASOFTIRQEN(r13);					\ -	cmpwi	0,r10,0;						\ -	beq-	label##_iSeries_masked;					\ -	EXCEPTION_PROLOG_ISERIES_1;					\ -	b	label##_common;						\ - -#endif	/* _ASM_POWERPC_ISERIES_EXCEPTION_H */ diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c deleted file mode 100644 index 3ae66ab9d5e..00000000000 --- a/arch/powerpc/platforms/iseries/htab.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * iSeries hashtable management. - *	Derived from pSeries_htab.c - * - * SMP scalability work: - *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <asm/machdep.h> -#include <asm/pgtable.h> -#include <asm/mmu.h> -#include <asm/mmu_context.h> -#include <asm/abs_addr.h> -#include <linux/spinlock.h> - -#include "call_hpt.h" - -static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp; - -/* - * Very primitive algorithm for picking up a lock - */ -static inline void iSeries_hlock(unsigned long slot) -{ -	if (slot & 0x8) -		slot = ~slot; -	spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]); -} - -static inline void iSeries_hunlock(unsigned long slot) -{ -	if (slot & 0x8) -		slot = ~slot; -	spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]); -} - -static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, -			 unsigned long pa, unsigned long rflags, -			 unsigned long vflags, int psize, int ssize) -{ -	long slot; -	struct hash_pte lhpte; -	int secondary = 0; - -	BUG_ON(psize != MMU_PAGE_4K); - -	/* -	 * The hypervisor tries both primary and secondary. -	 * If we are being called to insert in the secondary, -	 * it means we have already tried both primary and secondary, -	 * so we return failure immediately. -	 */ -	if (vflags & HPTE_V_SECONDARY) -		return -1; - -	iSeries_hlock(hpte_group); - -	slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT); -	if (unlikely(lhpte.v & HPTE_V_VALID)) { -		if (vflags & HPTE_V_BOLTED) { -			HvCallHpt_setSwBits(slot, 0x10, 0); -			HvCallHpt_setPp(slot, PP_RWXX); -			iSeries_hunlock(hpte_group); -			if (slot < 0) -				return 0x8 | (slot & 7); -			else -				return slot & 7; -		} -		BUG(); -	} - -	if (slot == -1)	{ /* No available entry found in either group */ -		iSeries_hunlock(hpte_group); -		return -1; -	} - -	if (slot < 0) {		/* MSB set means secondary group */ -		vflags |= HPTE_V_SECONDARY; -		secondary = 1; -		slot &= 0x7fffffffffffffff; -	} - - -	lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) | -		vflags | HPTE_V_VALID; -	lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags; - -	/* Now fill in the actual HPTE */ -	HvCallHpt_addValidate(slot, secondary, &lhpte); - -	iSeries_hunlock(hpte_group); - -	return (secondary << 3) | (slot & 7); -} - -static unsigned long iSeries_hpte_getword0(unsigned long slot) -{ -	struct hash_pte hpte; - -	HvCallHpt_get(&hpte, slot); -	return hpte.v; -} - -static long iSeries_hpte_remove(unsigned long hpte_group) -{ -	unsigned long slot_offset; -	int i; -	unsigned long hpte_v; - -	/* Pick a random slot to start at */ -	slot_offset = mftb() & 0x7; - -	iSeries_hlock(hpte_group); - -	for (i = 0; i < HPTES_PER_GROUP; i++) { -		hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset); - -		if (! (hpte_v & HPTE_V_BOLTED)) { -			HvCallHpt_invalidateSetSwBitsGet(hpte_group + -							 slot_offset, 0, 0); -			iSeries_hunlock(hpte_group); -			return i; -		} - -		slot_offset++; -		slot_offset &= 0x7; -	} - -	iSeries_hunlock(hpte_group); - -	return -1; -} - -/* - * The HyperVisor expects the "flags" argument in this form: - *	bits  0..59 : reserved - *	bit      60 : N - *	bits 61..63 : PP2,PP1,PP0 - */ -static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, -			unsigned long va, int psize, int ssize, int local) -{ -	struct hash_pte hpte; -	unsigned long want_v; - -	iSeries_hlock(slot); - -	HvCallHpt_get(&hpte, slot); -	want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M); - -	if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) { -		/* -		 * Hypervisor expects bits as NPPP, which is -		 * different from how they are mapped in our PP. -		 */ -		HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1)); -		iSeries_hunlock(slot); -		return 0; -	} -	iSeries_hunlock(slot); - -	return -1; -} - -/* - * Functions used to find the PTE for a particular virtual address. - * Only used during boot when bolting pages. - * - * Input : vpn      : virtual page number - * Output: PTE index within the page table of the entry - *         -1 on failure - */ -static long iSeries_hpte_find(unsigned long vpn) -{ -	struct hash_pte hpte; -	long slot; - -	/* -	 * The HvCallHpt_findValid interface is as follows: -	 * 0xffffffffffffffff : No entry found. -	 * 0x00000000xxxxxxxx : Entry found in primary group, slot x -	 * 0x80000000xxxxxxxx : Entry found in secondary group, slot x -	 */ -	slot = HvCallHpt_findValid(&hpte, vpn); -	if (hpte.v & HPTE_V_VALID) { -		if (slot < 0) { -			slot &= 0x7fffffffffffffff; -			slot = -slot; -		} -	} else -		slot = -1; -	return slot; -} - -/* - * Update the page protection bits. Intended to be used to create - * guard pages for kernel data structures on pages which are bolted - * in the HPT. Assumes pages being operated on will not be stolen. - * Does not work on large pages. - * - * No need to lock here because we should be the only user. - */ -static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, -					int psize, int ssize) -{ -	unsigned long vsid,va,vpn; -	long slot; - -	BUG_ON(psize != MMU_PAGE_4K); - -	vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); -	va = (vsid << 28) | (ea & 0x0fffffff); -	vpn = va >> HW_PAGE_SHIFT; -	slot = iSeries_hpte_find(vpn); -	if (slot == -1) -		panic("updateboltedpp: Could not find page to bolt\n"); -	HvCallHpt_setPp(slot, newpp); -} - -static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, -				    int psize, int ssize, int local) -{ -	unsigned long hpte_v; -	unsigned long avpn = va >> 23; -	unsigned long flags; - -	local_irq_save(flags); - -	iSeries_hlock(slot); - -	hpte_v = iSeries_hpte_getword0(slot); - -	if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID)) -		HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); - -	iSeries_hunlock(slot); - -	local_irq_restore(flags); -} - -void __init hpte_init_iSeries(void) -{ -	int i; - -	for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++) -		spin_lock_init(&iSeries_hlocks[i]); - -	ppc_md.hpte_invalidate	= iSeries_hpte_invalidate; -	ppc_md.hpte_updatepp	= iSeries_hpte_updatepp; -	ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; -	ppc_md.hpte_insert	= iSeries_hpte_insert; -	ppc_md.hpte_remove	= iSeries_hpte_remove; -} diff --git a/arch/powerpc/platforms/iseries/hvcall.S b/arch/powerpc/platforms/iseries/hvcall.S deleted file mode 100644 index 07ae6ad5f49..00000000000 --- a/arch/powerpc/platforms/iseries/hvcall.S +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file contains the code to perform calls to the - * iSeries LPAR hypervisor - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <asm/ppc_asm.h> -#include <asm/processor.h> -#include <asm/ptrace.h>		/* XXX for STACK_FRAME_OVERHEAD */ - -	.text - -/* - * Hypervisor call - * - * Invoke the iSeries hypervisor via the System Call instruction - * Parameters are passed to this routine in registers r3 - r10 - * - * r3 contains the HV function to be called - * r4-r10 contain the operands to the hypervisor function - * - */ - -_GLOBAL(HvCall) -_GLOBAL(HvCall0) -_GLOBAL(HvCall1) -_GLOBAL(HvCall2) -_GLOBAL(HvCall3) -_GLOBAL(HvCall4) -_GLOBAL(HvCall5) -_GLOBAL(HvCall6) -_GLOBAL(HvCall7) - - -	mfcr	r0 -	std	r0,-8(r1) -	stdu	r1,-(STACK_FRAME_OVERHEAD+16)(r1) - -	/* r0 = 0xffffffffffffffff indicates a hypervisor call */ - -	li	r0,-1 - -	/* Invoke the hypervisor */ - -	sc - -	ld	r1,0(r1) -	ld	r0,-8(r1) -	mtcrf	0xff,r0 - -	/*  return to caller, return value in r3 */ - -	blr - -_GLOBAL(HvCall0Ret16) -_GLOBAL(HvCall1Ret16) -_GLOBAL(HvCall2Ret16) -_GLOBAL(HvCall3Ret16) -_GLOBAL(HvCall4Ret16) -_GLOBAL(HvCall5Ret16) -_GLOBAL(HvCall6Ret16) -_GLOBAL(HvCall7Ret16) - -	mfcr	r0 -	std	r0,-8(r1) -	std	r31,-16(r1) -	stdu	r1,-(STACK_FRAME_OVERHEAD+32)(r1) - -	mr	r31,r4 -	li	r0,-1 -	mr	r4,r5 -	mr	r5,r6 -	mr	r6,r7 -	mr	r7,r8 -	mr	r8,r9 -	mr	r9,r10 - -	sc - -	std	r3,0(r31) -	std	r4,8(r31) - -	mr	r3,r5 - -	ld	r1,0(r1) -	ld	r0,-8(r1) -	mtcrf	0xff,r0 -	ld	r31,-16(r1) - -	blr diff --git a/arch/powerpc/platforms/iseries/hvlog.c b/arch/powerpc/platforms/iseries/hvlog.c deleted file mode 100644 index f476d71194f..00000000000 --- a/arch/powerpc/platforms/iseries/hvlog.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - *  - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <asm/page.h> -#include <asm/abs_addr.h> -#include <asm/iseries/hv_call.h> -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - - -void HvCall_writeLogBuffer(const void *buffer, u64 len) -{ -	struct HvLpBufferList hv_buf; -	u64 left_this_page; -	u64 cur = virt_to_abs(buffer); - -	while (len) { -		hv_buf.addr = cur; -		left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur; -		if (left_this_page > len) -			left_this_page = len; -		hv_buf.len = left_this_page; -		len -= left_this_page; -		HvCall2(HvCallBaseWriteLogBuffer, -				virt_to_abs(&hv_buf), -				left_this_page); -		cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE; -	} -} diff --git a/arch/powerpc/platforms/iseries/hvlpconfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c deleted file mode 100644 index f62a0c5fa67..00000000000 --- a/arch/powerpc/platforms/iseries/hvlpconfig.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2001  Kyle A. Lucke, IBM Corporation - *  - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - *  - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - *  - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ - -#include <linux/export.h> -#include <asm/iseries/hv_lp_config.h> -#include "it_lp_naca.h" - -HvLpIndex HvLpConfig_getLpIndex_outline(void) -{ -	return HvLpConfig_getLpIndex(); -} -EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline); - -HvLpIndex HvLpConfig_getLpIndex(void) -{ -	return itLpNaca.xLpIndex; -} -EXPORT_SYMBOL(HvLpConfig_getLpIndex); - -HvLpIndex HvLpConfig_getPrimaryLpIndex(void) -{ -	return itLpNaca.xPrimaryLpIndex; -} -EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex); diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c deleted file mode 100644 index 2f3d9110248..00000000000 --- a/arch/powerpc/platforms/iseries/iommu.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup: - * - * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation - * Copyright (C) 2006 Olof Johansson <olof@lixom.net> - * - * Dynamic DMA mapping support, iSeries-specific parts. - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ - -#include <linux/types.h> -#include <linux/dma-mapping.h> -#include <linux/list.h> -#include <linux/pci.h> -#include <linux/export.h> -#include <linux/slab.h> - -#include <asm/iommu.h> -#include <asm/vio.h> -#include <asm/tce.h> -#include <asm/machdep.h> -#include <asm/abs_addr.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/iommu.h> - -static int tce_build_iSeries(struct iommu_table *tbl, long index, long npages, -		unsigned long uaddr, enum dma_data_direction direction, -		struct dma_attrs *attrs) -{ -	u64 rc; -	u64 tce, rpn; - -	while (npages--) { -		rpn = virt_to_abs(uaddr) >> TCE_SHIFT; -		tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; - -		if (tbl->it_type == TCE_VB) { -			/* Virtual Bus */ -			tce |= TCE_VALID|TCE_ALLIO; -			if (direction != DMA_TO_DEVICE) -				tce |= TCE_VB_WRITE; -		} else { -			/* PCI Bus */ -			tce |= TCE_PCI_READ; /* Read allowed */ -			if (direction != DMA_TO_DEVICE) -				tce |= TCE_PCI_WRITE; -		} - -		rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce); -		if (rc) -			panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", -					rc); -		index++; -		uaddr += TCE_PAGE_SIZE; -	} -	return 0; -} - -static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) -{ -	u64 rc; - -	while (npages--) { -		rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0); -		if (rc) -			panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", -					rc); -		index++; -	} -} - -/* - * Structure passed to HvCallXm_getTceTableParms - */ -struct iommu_table_cb { -	unsigned long	itc_busno;	/* Bus number for this tce table */ -	unsigned long	itc_start;	/* Will be NULL for secondary */ -	unsigned long	itc_totalsize;	/* Size (in pages) of whole table */ -	unsigned long	itc_offset;	/* Index into real tce table of the -					   start of our section */ -	unsigned long	itc_size;	/* Size (in pages) of our section */ -	unsigned long	itc_index;	/* Index of this tce table */ -	unsigned short	itc_maxtables;	/* Max num of tables for partition */ -	unsigned char	itc_virtbus;	/* Flag to indicate virtual bus */ -	unsigned char	itc_slotno;	/* IOA Tce Slot Index */ -	unsigned char	itc_rsvd[4]; -}; - -/* - * Call Hv with the architected data structure to get TCE table info. - * info. Put the returned data into the Linux representation of the - * TCE table data. - * The Hardware Tce table comes in three flavors. - * 1. TCE table shared between Buses. - * 2. TCE table per Bus. - * 3. TCE Table per IOA. - */ -void iommu_table_getparms_iSeries(unsigned long busno, -				  unsigned char slotno, -				  unsigned char virtbus, -				  struct iommu_table* tbl) -{ -	struct iommu_table_cb *parms; - -	parms = kzalloc(sizeof(*parms), GFP_KERNEL); -	if (parms == NULL) -		panic("PCI_DMA: TCE Table Allocation failed."); - -	parms->itc_busno = busno; -	parms->itc_slotno = slotno; -	parms->itc_virtbus = virtbus; - -	HvCallXm_getTceTableParms(iseries_hv_addr(parms)); - -	if (parms->itc_size == 0) -		panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); - -	/* itc_size is in pages worth of table, it_size is in # of entries */ -	tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE; -	tbl->it_busno = parms->itc_busno; -	tbl->it_offset = parms->itc_offset; -	tbl->it_index = parms->itc_index; -	tbl->it_blocksize = 1; -	tbl->it_type = virtbus ? TCE_VB : TCE_PCI; - -	kfree(parms); -} - - -#ifdef CONFIG_PCI -/* - * This function compares the known tables to find an iommu_table - * that has already been built for hardware TCEs. - */ -static struct iommu_table *iommu_table_find(struct iommu_table * tbl) -{ -	struct device_node *node; - -	for (node = NULL; (node = of_find_all_nodes(node)); ) { -		struct pci_dn *pdn = PCI_DN(node); -		struct iommu_table *it; - -		if (pdn == NULL) -			continue; -		it = pdn->iommu_table; -		if ((it != NULL) && -		    (it->it_type == TCE_PCI) && -		    (it->it_offset == tbl->it_offset) && -		    (it->it_index == tbl->it_index) && -		    (it->it_size == tbl->it_size)) { -			of_node_put(node); -			return it; -		} -	} -	return NULL; -} - - -static void pci_dma_dev_setup_iseries(struct pci_dev *pdev) -{ -	struct iommu_table *tbl; -	struct device_node *dn = pci_device_to_OF_node(pdev); -	struct pci_dn *pdn = PCI_DN(dn); -	const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL); - -	BUG_ON(lsn == NULL); - -	tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL); - -	iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); - -	/* Look for existing tce table */ -	pdn->iommu_table = iommu_table_find(tbl); -	if (pdn->iommu_table == NULL) -		pdn->iommu_table = iommu_init_table(tbl, -1); -	else -		kfree(tbl); -	set_iommu_table_base(&pdev->dev, pdn->iommu_table); -} -#else -#define pci_dma_dev_setup_iseries	NULL -#endif - -static struct iommu_table veth_iommu_table; -static struct iommu_table vio_iommu_table; - -void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) -{ -	return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle, -				DMA_BIT_MASK(32), flag, -1); -} -EXPORT_SYMBOL_GPL(iseries_hv_alloc); - -void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle) -{ -	iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle); -} -EXPORT_SYMBOL_GPL(iseries_hv_free); - -dma_addr_t iseries_hv_map(void *vaddr, size_t size, -			enum dma_data_direction direction) -{ -	return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr), -			      (unsigned long)vaddr % PAGE_SIZE, size, -			      DMA_BIT_MASK(32), direction, NULL); -} - -void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, -			enum dma_data_direction direction) -{ -	iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL); -} - -void __init iommu_vio_init(void) -{ -	iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); -	veth_iommu_table.it_size /= 2; -	vio_iommu_table = veth_iommu_table; -	vio_iommu_table.it_offset += veth_iommu_table.it_size; - -	if (!iommu_init_table(&veth_iommu_table, -1)) -		printk("Virtual Bus VETH TCE table failed.\n"); -	if (!iommu_init_table(&vio_iommu_table, -1)) -		printk("Virtual Bus VIO TCE table failed.\n"); -} - -struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev) -{ -	if (strcmp(dev->type, "network") == 0) -		return &veth_iommu_table; -	return &vio_iommu_table; -} - -void iommu_init_early_iSeries(void) -{ -	ppc_md.tce_build = tce_build_iSeries; -	ppc_md.tce_free  = tce_free_iSeries; - -	ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries; -	set_pci_dma_ops(&dma_iommu_ops); -} diff --git a/arch/powerpc/platforms/iseries/ipl_parms.h b/arch/powerpc/platforms/iseries/ipl_parms.h deleted file mode 100644 index 83e4ca42fc5..00000000000 --- a/arch/powerpc/platforms/iseries/ipl_parms.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _ISERIES_IPL_PARMS_H -#define _ISERIES_IPL_PARMS_H - -/* - *	This struct maps the IPL Parameters DMA'd from the SP. - * - * Warning: - *	This data must map in exactly 64 bytes and match the architecture for - *	the IPL parms - */ - -#include <asm/types.h> - -struct ItIplParmsReal { -	u8	xFormat;		// Defines format of IplParms	x00-x00 -	u8	xRsvd01:6;		// Reserved			x01-x01 -	u8	xAlternateSearch:1;	// Alternate search indicator	... -	u8	xUaSupplied:1;		// UA Supplied on programmed IPL... -	u8	xLsUaFormat;		// Format byte for UA		x02-x02 -	u8	xRsvd02;		// Reserved			x03-x03 -	u32	xLsUa;			// LS UA			x04-x07 -	u32	xUnusedLsLid;		// First OS LID to load		x08-x0B -	u16	xLsBusNumber;		// LS Bus Number		x0C-x0D -	u8	xLsCardAdr;		// LS Card Address		x0E-x0E -	u8	xLsBoardAdr;		// LS Board Address		x0F-x0F -	u32	xRsvd03;		// Reserved			x10-x13 -	u8	xSpcnPresent:1;		// SPCN present			x14-x14 -	u8	xCpmPresent:1;		// CPM present			... -	u8	xRsvd04:6;		// Reserved			... -	u8	xRsvd05:4;		// Reserved			x15-x15 -	u8	xKeyLock:4;		// Keylock setting		... -	u8	xRsvd06:6;		// Reserved			x16-x16 -	u8	xIplMode:2;		// Ipl mode (A|B|C|D)		... -	u8	xHwIplType;		// Fast v slow v slow EC HW IPL	x17-x17 -	u16	xCpmEnabledIpl:1;	// CPM in effect when IPL initiatedx18-x19 -	u16	xPowerOnResetIpl:1;	// Indicate POR condition	... -	u16	xMainStorePreserved:1;	// Main Storage is preserved	... -	u16	xRsvd07:13;		// Reserved			... -	u16	xIplSource:16;		// Ipl source			x1A-x1B -	u8	xIplReason:8;		// Reason for this IPL		x1C-x1C -	u8	xRsvd08;		// Reserved			x1D-x1D -	u16	xRsvd09;		// Reserved			x1E-x1F -	u16	xSysBoxType;		// System Box Type		x20-x21 -	u16	xSysProcType;		// System Processor Type	x22-x23 -	u32	xRsvd10;		// Reserved			x24-x27 -	u64	xRsvd11;		// Reserved			x28-x2F -	u64	xRsvd12;		// Reserved			x30-x37 -	u64	xRsvd13;		// Reserved			x38-x3F -}; - -#endif /* _ISERIES_IPL_PARMS_H */ diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c deleted file mode 100644 index b2103453eb0..00000000000 --- a/arch/powerpc/platforms/iseries/irq.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * This module supports the iSeries PCI bus interrupt handling - * Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp> - * Copyright (C) 2004-2005 IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, - * Boston, MA  02111-1307  USA - * - * Change Activity: - *   Created, December 13, 2000 by Wayne Holm - * End Change Activity - */ -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/bootmem.h> -#include <linux/irq.h> -#include <linux/spinlock.h> - -#include <asm/paca.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/it_lp_queue.h> - -#include "irq.h" -#include "pci.h" -#include "call_pci.h" - -#ifdef CONFIG_PCI - -enum pci_event_type { -	pe_bus_created		= 0,	/* PHB has been created */ -	pe_bus_error		= 1,	/* PHB has failed */ -	pe_bus_failed		= 2,	/* Msg to Secondary, Primary failed bus */ -	pe_node_failed		= 4,	/* Multi-adapter bridge has failed */ -	pe_node_recovered	= 5,	/* Multi-adapter bridge has recovered */ -	pe_bus_recovered	= 12,	/* PHB has been recovered */ -	pe_unquiese_bus		= 18,	/* Secondary bus unqiescing */ -	pe_bridge_error		= 21,	/* Bridge Error */ -	pe_slot_interrupt	= 22	/* Slot interrupt */ -}; - -struct pci_event { -	struct HvLpEvent event; -	union { -		u64 __align;		/* Align on an 8-byte boundary */ -		struct { -			u32		fisr; -			HvBusNumber	bus_number; -			HvSubBusNumber	sub_bus_number; -			HvAgentId	dev_id; -		} slot; -		struct { -			HvBusNumber	bus_number; -			HvSubBusNumber	sub_bus_number; -		} bus; -		struct { -			HvBusNumber	bus_number; -			HvSubBusNumber	sub_bus_number; -			HvAgentId	dev_id; -		} node; -	} data; -}; - -static DEFINE_SPINLOCK(pending_irqs_lock); -static int num_pending_irqs; -static int pending_irqs[NR_IRQS]; - -static void int_received(struct pci_event *event) -{ -	int irq; - -	switch (event->event.xSubtype) { -	case pe_slot_interrupt: -		irq = event->event.xCorrelationToken; -		if (irq < NR_IRQS) { -			spin_lock(&pending_irqs_lock); -			pending_irqs[irq]++; -			num_pending_irqs++; -			spin_unlock(&pending_irqs_lock); -		} else { -			printk(KERN_WARNING "int_received: bad irq number %d\n", -					irq); -			HvCallPci_eoi(event->data.slot.bus_number, -					event->data.slot.sub_bus_number, -					event->data.slot.dev_id); -		} -		break; -		/* Ignore error recovery events for now */ -	case pe_bus_created: -		printk(KERN_INFO "int_received: system bus %d created\n", -			event->data.bus.bus_number); -		break; -	case pe_bus_error: -	case pe_bus_failed: -		printk(KERN_INFO "int_received: system bus %d failed\n", -			event->data.bus.bus_number); -		break; -	case pe_bus_recovered: -	case pe_unquiese_bus: -		printk(KERN_INFO "int_received: system bus %d recovered\n", -			event->data.bus.bus_number); -		break; -	case pe_node_failed: -	case pe_bridge_error: -		printk(KERN_INFO -			"int_received: multi-adapter bridge %d/%d/%d failed\n", -			event->data.node.bus_number, -			event->data.node.sub_bus_number, -			event->data.node.dev_id); -		break; -	case pe_node_recovered: -		printk(KERN_INFO -			"int_received: multi-adapter bridge %d/%d/%d recovered\n", -			event->data.node.bus_number, -			event->data.node.sub_bus_number, -			event->data.node.dev_id); -		break; -	default: -		printk(KERN_ERR -			"int_received: unrecognized event subtype 0x%x\n", -			event->event.xSubtype); -		break; -	} -} - -static void pci_event_handler(struct HvLpEvent *event) -{ -	if (event && (event->xType == HvLpEvent_Type_PciIo)) { -		if (hvlpevent_is_int(event)) -			int_received((struct pci_event *)event); -		else -			printk(KERN_ERR -				"pci_event_handler: unexpected ack received\n"); -	} else if (event) -		printk(KERN_ERR -			"pci_event_handler: Unrecognized PCI event type 0x%x\n", -			(int)event->xType); -	else -		printk(KERN_ERR "pci_event_handler: NULL event received\n"); -} - -#define REAL_IRQ_TO_SUBBUS(irq)	(((irq) >> 14) & 0xff) -#define REAL_IRQ_TO_BUS(irq)	((((irq) >> 6) & 0xff) + 1) -#define REAL_IRQ_TO_IDSEL(irq)	((((irq) >> 3) & 7) + 1) -#define REAL_IRQ_TO_FUNC(irq)	((irq) & 7) - -/* - * This will be called by device drivers (via enable_IRQ) - * to enable INTA in the bridge interrupt status register. - */ -static void iseries_enable_IRQ(struct irq_data *d) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - -	/* The IRQ has already been locked by the caller */ -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Unmask secondary INTA */ -	mask = 0x80000000; -	HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask); -} - -/* This is called by iseries_activate_IRQs */ -static unsigned int iseries_startup_IRQ(struct irq_data *d) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Link the IRQ number to the bridge */ -	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq); - -	/* Unmask bridge interrupts in the FISR */ -	mask = 0x01010000 << function; -	HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask); -	iseries_enable_IRQ(d); -	return 0; -} - -/* - * This is called out of iSeries_fixup to activate interrupt - * generation for usable slots - */ -void __init iSeries_activate_IRQs() -{ -	int irq; -	unsigned long flags; - -	for_each_irq (irq) { -		struct irq_desc *desc = irq_to_desc(irq); -		struct irq_chip *chip; - -		if (!desc) -			continue; - -		chip = irq_desc_get_chip(desc); -		if (chip && chip->irq_startup) { -			raw_spin_lock_irqsave(&desc->lock, flags); -			chip->irq_startup(&desc->irq_data); -			raw_spin_unlock_irqrestore(&desc->lock, flags); -		} -	} -} - -/*  this is not called anywhere currently */ -static void iseries_shutdown_IRQ(struct irq_data *d) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - -	/* irq should be locked by the caller */ -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Invalidate the IRQ number in the bridge */ -	HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0); - -	/* Mask bridge interrupts in the FISR */ -	mask = 0x01010000 << function; -	HvCallPci_maskFisr(bus, sub_bus, dev_id, mask); -} - -/* - * This will be called by device drivers (via disable_IRQ) - * to disable INTA in the bridge interrupt status register. - */ -static void iseries_disable_IRQ(struct irq_data *d) -{ -	u32 bus, dev_id, function, mask; -	const u32 sub_bus = 0; -	unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - -	/* The IRQ has already been locked by the caller */ -	bus = REAL_IRQ_TO_BUS(rirq); -	function = REAL_IRQ_TO_FUNC(rirq); -	dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - -	/* Mask secondary INTA   */ -	mask = 0x80000000; -	HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); -} - -static void iseries_end_IRQ(struct irq_data *d) -{ -	unsigned int rirq = (unsigned int)irqd_to_hwirq(d); - -	HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), -		(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); -} - -static struct irq_chip iseries_pic = { -	.name		= "iSeries", -	.irq_startup	= iseries_startup_IRQ, -	.irq_shutdown	= iseries_shutdown_IRQ, -	.irq_unmask	= iseries_enable_IRQ, -	.irq_mask	= iseries_disable_IRQ, -	.irq_eoi	= iseries_end_IRQ -}; - -/* - * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot - * It calculates the irq value for the slot. - * Note that sub_bus is always 0 (at the moment at least). - */ -int __init iSeries_allocate_IRQ(HvBusNumber bus, -		HvSubBusNumber sub_bus, u32 bsubbus) -{ -	unsigned int realirq; -	u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); -	u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); - -	realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) -		+ function; - -	return irq_create_mapping(NULL, realirq); -} - -#endif /* CONFIG_PCI */ - -/* - * Get the next pending IRQ. - */ -unsigned int iSeries_get_irq(void) -{ -	int irq = NO_IRQ_IGNORE; - -#ifdef CONFIG_SMP -	if (get_lppaca()->int_dword.fields.ipi_cnt) { -		get_lppaca()->int_dword.fields.ipi_cnt = 0; -		smp_ipi_demux(); -	} -#endif /* CONFIG_SMP */ -	if (hvlpevent_is_pending()) -		process_hvlpevents(); - -#ifdef CONFIG_PCI -	if (num_pending_irqs) { -		spin_lock(&pending_irqs_lock); -		for (irq = 0; irq < NR_IRQS; irq++) { -			if (pending_irqs[irq]) { -				pending_irqs[irq]--; -				num_pending_irqs--; -				break; -			} -		} -		spin_unlock(&pending_irqs_lock); -		if (irq >= NR_IRQS) -			irq = NO_IRQ_IGNORE; -	} -#endif - -	return irq; -} - -#ifdef CONFIG_PCI - -static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, -				irq_hw_number_t hw) -{ -	irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); - -	return 0; -} - -static int iseries_irq_host_match(struct irq_host *h, struct device_node *np) -{ -	/* Match all */ -	return 1; -} - -static struct irq_host_ops iseries_irq_host_ops = { -	.map = iseries_irq_host_map, -	.match = iseries_irq_host_match, -}; - -/* - * This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c - * It must be called before the bus walk. - */ -void __init iSeries_init_IRQ(void) -{ -	/* Register PCI event handler and open an event path */ -	struct irq_host *host; -	int ret; - -	/* -	 * The Hypervisor only allows us up to 256 interrupt -	 * sources (the irq number is passed in a u8). -	 */ -	irq_set_virq_count(256); - -	/* Create irq host. No need for a revmap since HV will give us -	 * back our virtual irq number -	 */ -	host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, -			      &iseries_irq_host_ops, 0); -	BUG_ON(host == NULL); -	irq_set_default_host(host); - -	ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, -			&pci_event_handler); -	if (ret == 0) { -		ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); -		if (ret != 0) -			printk(KERN_ERR "iseries_init_IRQ: open event path " -					"failed with rc 0x%x\n", ret); -	} else -		printk(KERN_ERR "iseries_init_IRQ: register handler " -				"failed with rc 0x%x\n", ret); -} - -#endif	/* CONFIG_PCI */ diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h deleted file mode 100644 index a1c23607403..00000000000 --- a/arch/powerpc/platforms/iseries/irq.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef	_ISERIES_IRQ_H -#define	_ISERIES_IRQ_H - -#ifdef CONFIG_PCI -extern void iSeries_init_IRQ(void); -extern int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32); -extern void iSeries_activate_IRQs(void); -#else -#define iSeries_init_IRQ	NULL -#endif -extern unsigned int iSeries_get_irq(void); - -#endif /* _ISERIES_IRQ_H */ diff --git a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h deleted file mode 100644 index 6de9097b7f5..00000000000 --- a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2002  Dave Boutcher IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H -#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H - -/* - *	This struct maps the panel information - * - * Warning: - *	This data must match the architecture for the panel information - */ - -#include <asm/types.h> - -struct ItExtVpdPanel { -	/* Definition of the Extended Vpd On Panel Data Area */ -	char	systemSerial[8]; -	char	mfgID[4]; -	char	reserved1[24]; -	char	machineType[4]; -	char	systemID[6]; -	char	somUniqueCnt[4]; -	char	serialNumberCount; -	char	reserved2[7]; -	u16	bbu3; -	u16	bbu2; -	u16	bbu1; -	char	xLocationLabel[8]; -	u8	xRsvd1[6]; -	u16	xFrameId; -	u8	xRsvd2[48]; -}; - -extern struct ItExtVpdPanel	xItExtVpdPanel; - -#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */ diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h deleted file mode 100644 index cf6dcf6ef07..00000000000 --- a/arch/powerpc/platforms/iseries/it_lp_naca.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H -#define _PLATFORMS_ISERIES_IT_LP_NACA_H - -#include <linux/types.h> - -/* - *	This control block contains the data that is shared between the - *	hypervisor (PLIC) and the OS. - */ - -struct ItLpNaca { -// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data -	u32	xDesc;			// Eye catcher			x00-x03 -	u16	xSize;			// Size of this class		x04-x05 -	u16	xIntHdlrOffset;		// Offset to IntHdlr array	x06-x07 -	u8	xMaxIntHdlrEntries;	// Number of entries in array	x08-x08 -	u8	xPrimaryLpIndex;	// LP Index of Primary		x09-x09 -	u8	xServiceLpIndex;	// LP Ind of Service Focal Pointx0A-x0A -	u8	xLpIndex;		// LP Index			x0B-x0B -	u16	xMaxLpQueues;		// Number of allocated queues	x0C-x0D -	u16	xLpQueueOffset;		// Offset to start of LP queues	x0E-x0F -	u8	xPirEnvironMode;	// Piranha or hardware		x10-x10 -	u8	xPirConsoleMode;	// Piranha console indicator	x11-x11 -	u8	xPirDasdMode;		// Piranha dasd indicator	x12-x12 -	u8	xRsvd1_0[5];		// Reserved for Piranha related	x13-x17 -	u8	flags;			// flags, see below		x18-x1F -	u8	xSpVpdFormat;		// VPD areas are in CSP format	... -	u8	xIntProcRatio;		// Ratio of int procs to procs	... -	u8	xRsvd1_2[5];		// Reserved			... -	u16	xRsvd1_3;		// Reserved			x20-x21 -	u16	xPlicVrmIndex;		// VRM index of PLIC		x22-x23 -	u16	xMinSupportedSlicVrmInd;// Min supported OS VRM index	x24-x25 -	u16	xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27 -	u64	xLoadAreaAddr;		// ER address of load area	x28-x2F -	u32	xLoadAreaChunks;	// Chunks for the load area	x30-x33 -	u32	xPaseSysCallCRMask;	// Mask used to test CR before  x34-x37 -					// doing an ASR switch on PASE -					// system call. -	u64	xSlicSegmentTablePtr;	// Pointer to Slic seg table.   x38-x3f -	u8	xRsvd1_4[64];		//				x40-x7F - -// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data -	u8	xRsvd2_0[128];		// Reserved			x00-x7F - -// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators -// NB: Padding required to keep xInterruptHdlr at x300 which is required -// for v4r4 PLIC. -	u8	xOldLpQueue[128];	// LP Queue needed for v4r4	100-17F -	u8	xRsvd3_0[384];		// Reserved			180-2FF - -// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt -//  handlers -	u64	xInterruptHdlr[32];	// Interrupt handlers		300-x3FF -}; - -extern struct ItLpNaca		itLpNaca; - -#define ITLPNACA_LPAR		0x80	/* Is LPAR installed on the system */ -#define ITLPNACA_PARTITIONED	0x40	/* Is the system partitioned */ -#define ITLPNACA_HWSYNCEDTBS	0x20	/* Hardware synced TBs */ -#define ITLPNACA_HMTINT		0x10	/* Utilize MHT for interrupts */ - -#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */ diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c deleted file mode 100644 index 997e234fb8b..00000000000 --- a/arch/powerpc/platforms/iseries/ksyms.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (C) 2001-2005 PPC 64 Team, IBM Corp - * - *      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/export.h> - -#include <asm/hw_irq.h> -#include <asm/iseries/hv_call_sc.h> - -EXPORT_SYMBOL(HvCall0); -EXPORT_SYMBOL(HvCall1); -EXPORT_SYMBOL(HvCall2); -EXPORT_SYMBOL(HvCall3); -EXPORT_SYMBOL(HvCall4); -EXPORT_SYMBOL(HvCall5); -EXPORT_SYMBOL(HvCall6); -EXPORT_SYMBOL(HvCall7); diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c deleted file mode 100644 index 00e0ec813a1..00000000000 --- a/arch/powerpc/platforms/iseries/lpardata.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2001 Mike Corrigan, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/types.h> -#include <linux/threads.h> -#include <linux/bitops.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/abs_addr.h> -#include <asm/lppaca.h> -#include <asm/paca.h> -#include <asm/iseries/lpar_map.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/alpaca.h> - -#include "naca.h" -#include "vpd_areas.h" -#include "spcomm_area.h" -#include "ipl_parms.h" -#include "processor_vpd.h" -#include "release_data.h" -#include "it_exp_vpd_panel.h" -#include "it_lp_naca.h" - -/* The HvReleaseData is the root of the information shared between - * the hypervisor and Linux. - */ -const struct HvReleaseData hvReleaseData = { -	.xDesc = 0xc8a5d9c4,	/* "HvRD" ebcdic */ -	.xSize = sizeof(struct HvReleaseData), -	.xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), -	.xSlicNacaAddr = &naca,		/* 64-bit Naca address */ -	.xMsNucDataOffset = LPARMAP_PHYS, -	.xFlags = HVREL_TAGSINACTIVE	/* tags inactive       */ -					/* 64 bit              */ -					/* shared processors   */ -					/* HMT allowed         */ -		  | 6,			/* TEMP: This allows non-GA driver */ -	.xVrmIndex = 4,			/* We are v5r2m0               */ -	.xMinSupportedPlicVrmIndex = 3,		/* v5r1m0 */ -	.xMinCompatablePlicVrmIndex = 3,	/* v5r1m0 */ -	.xVrmName = { 0xd3, 0x89, 0x95, 0xa4,	/* "Linux 2.4.64" ebcdic */ -		0xa7, 0x40, 0xf2, 0x4b, -		0xf4, 0x4b, 0xf6, 0xf4 }, -}; - -/* - * The NACA.  The first dword of the naca is required by the iSeries - * hypervisor to point to itVpdAreas.  The hypervisor finds the NACA - * through the pointer in hvReleaseData. - */ -struct naca_struct naca = { -	.xItVpdAreas = &itVpdAreas, -	.xRamDisk = 0, -	.xRamDiskSize = 0, -}; - -struct ItLpRegSave { -	u32	xDesc;		// Eye catcher  "LpRS" ebcdic	000-003 -	u16	xSize;		// Size of this class		004-005 -	u8	xInUse;         // Area is live                 006-007 -	u8	xRsvd1[9];	// Reserved			007-00F - -	u8      xFixedRegSave[352]; // Fixed Register Save Area 010-16F -	u32	xCTRL;		// Control Register		170-173 -	u32	xDEC;		// Decrementer			174-177 -	u32	xFPSCR;		// FP Status and Control Reg	178-17B -	u32	xPVR;		// Processor Version Number	17C-17F - -	u64	xMMCR0;		// Monitor Mode Control Reg 0	180-187 -	u32	xPMC1;		// Perf Monitor Counter 1	188-18B -	u32	xPMC2;		// Perf Monitor Counter 2	18C-18F -	u32	xPMC3;		// Perf Monitor Counter 3	190-193 -	u32	xPMC4;		// Perf Monitor Counter 4	194-197 -	u32	xPIR;		// Processor ID Reg		198-19B - -	u32	xMMCR1;		// Monitor Mode Control Reg 1	19C-19F -	u32	xMMCRA;		// Monitor Mode Control Reg A	1A0-1A3 -	u32	xPMC5;		// Perf Monitor Counter 5	1A4-1A7 -	u32	xPMC6;		// Perf Monitor Counter 6	1A8-1AB -	u32	xPMC7;		// Perf Monitor Counter 7	1AC-1AF -	u32	xPMC8;		// Perf Monitor Counter 8	1B0-1B3 -	u32	xTSC;		// Thread Switch Control	1B4-1B7 -	u32	xTST;		// Thread Switch Timeout	1B8-1BB -	u32	xRsvd;          // Reserved                     1BC-1BF - -	u64	xACCR;		// Address Compare Control Reg	1C0-1C7 -	u64	xIMR;		// Instruction Match Register	1C8-1CF -	u64	xSDR1;		// Storage Description Reg 1	1D0-1D7 -	u64	xSPRG0;		// Special Purpose Reg General0	1D8-1DF -	u64	xSPRG1;		// Special Purpose Reg General1	1E0-1E7 -	u64	xSPRG2;		// Special Purpose Reg General2	1E8-1EF -	u64	xSPRG3;		// Special Purpose Reg General3	1F0-1F7 -	u64	xTB;		// Time Base Register		1F8-1FF - -	u64	xFPR[32];	// Floating Point Registers	200-2FF - -	u64	xMSR;		// Machine State Register	300-307 -	u64	xNIA;		// Next Instruction Address	308-30F - -	u64	xDABR;		// Data Address Breakpoint Reg	310-317 -	u64	xIABR;		// Inst Address Breakpoint Reg	318-31F - -	u64	xHID0;		// HW Implementation Dependent0	320-327 - -	u64	xHID4;		// HW Implementation Dependent4	328-32F -	u64	xSCOMd;		// SCON Data Reg (SPRG4)	330-337 -	u64	xSCOMc;		// SCON Command Reg (SPRG5)	338-33F -	u64	xSDAR;		// Sample Data Address Register	340-347 -	u64	xSIAR;		// Sample Inst Address Register	348-34F - -	u8	xRsvd3[176];	// Reserved			350-3FF -}; - -extern void system_reset_iSeries(void); -extern void machine_check_iSeries(void); -extern void data_access_iSeries(void); -extern void instruction_access_iSeries(void); -extern void hardware_interrupt_iSeries(void); -extern void alignment_iSeries(void); -extern void program_check_iSeries(void); -extern void fp_unavailable_iSeries(void); -extern void decrementer_iSeries(void); -extern void trap_0a_iSeries(void); -extern void trap_0b_iSeries(void); -extern void system_call_iSeries(void); -extern void single_step_iSeries(void); -extern void trap_0e_iSeries(void); -extern void performance_monitor_iSeries(void); -extern void data_access_slb_iSeries(void); -extern void instruction_access_slb_iSeries(void); - -struct ItLpNaca itLpNaca = { -	.xDesc = 0xd397d581,		/* "LpNa" ebcdic */ -	.xSize = 0x0400,		/* size of ItLpNaca */ -	.xIntHdlrOffset = 0x0300,	/* offset to int array */ -	.xMaxIntHdlrEntries = 19,	/* # ents */ -	.xPrimaryLpIndex = 0,		/* Part # of primary */ -	.xServiceLpIndex = 0,		/* Part # of serv */ -	.xLpIndex = 0,			/* Part # of me */ -	.xMaxLpQueues = 0,		/* # of LP queues */ -	.xLpQueueOffset = 0x100,	/* offset of start of LP queues */ -	.xPirEnvironMode = 0,		/* Piranha stuff */ -	.xPirConsoleMode = 0, -	.xPirDasdMode = 0, -	.flags = 0, -	.xSpVpdFormat = 0, -	.xIntProcRatio = 0, -	.xPlicVrmIndex = 0,		/* VRM index of PLIC */ -	.xMinSupportedSlicVrmInd = 0,	/* min supported SLIC */ -	.xMinCompatableSlicVrmInd = 0,	/* min compat SLIC */ -	.xLoadAreaAddr = 0,		/* 64-bit addr of load area */ -	.xLoadAreaChunks = 0,		/* chunks for load area */ -	.xPaseSysCallCRMask = 0,	/* PASE mask */ -	.xSlicSegmentTablePtr = 0,	/* seg table */ -	.xOldLpQueue = { 0 },		/* Old LP Queue */ -	.xInterruptHdlr = { -		(u64)system_reset_iSeries,	/* 0x100 System Reset */ -		(u64)machine_check_iSeries,	/* 0x200 Machine Check */ -		(u64)data_access_iSeries,	/* 0x300 Data Access */ -		(u64)instruction_access_iSeries, /* 0x400 Instruction Access */ -		(u64)hardware_interrupt_iSeries, /* 0x500 External */ -		(u64)alignment_iSeries,		/* 0x600 Alignment */ -		(u64)program_check_iSeries,	/* 0x700 Program Check */ -		(u64)fp_unavailable_iSeries,	/* 0x800 FP Unavailable */ -		(u64)decrementer_iSeries,	/* 0x900 Decrementer */ -		(u64)trap_0a_iSeries,		/* 0xa00 Trap 0A */ -		(u64)trap_0b_iSeries,		/* 0xb00 Trap 0B */ -		(u64)system_call_iSeries,	/* 0xc00 System Call */ -		(u64)single_step_iSeries,	/* 0xd00 Single Step */ -		(u64)trap_0e_iSeries,		/* 0xe00 Trap 0E */ -		(u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */ -		0,				/* int 0x1000 */ -		0,				/* int 0x1010 */ -		0,				/* int 0x1020 CPU ctls */ -		(u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */ -		(u64)data_access_slb_iSeries,	/* 0x380 D-SLB */ -		(u64)instruction_access_slb_iSeries /* 0x480 I-SLB */ -	} -}; - -/* May be filled in by the hypervisor so cannot end up in the BSS */ -static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); - -/* May be filled in by the hypervisor so cannot end up in the BSS */ -struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data"))); - -#define maxPhysicalProcessors 32 - -struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = { -	{ -		.xInstCacheOperandSize = 32, -		.xDataCacheOperandSize = 32, -		.xProcFreq     = 50000000, -		.xTimeBaseFreq = 50000000, -		.xPVR = 0x3600 -	} -}; - -/* Space for Main Store Vpd 27,200 bytes */ -/* May be filled in by the hypervisor so cannot end up in the BSS */ -u64    xMsVpd[3400] __attribute__((__section__(".data"))); - -/* Space for Recovery Log Buffer */ -/* May be filled in by the hypervisor so cannot end up in the BSS */ -static u64    xRecoveryLogBuffer[32] __attribute__((__section__(".data"))); - -static const struct SpCommArea xSpCommArea = { -	.xDesc = 0xE2D7C3C2, -	.xFormat = 1, -}; - -static const struct ItLpRegSave iseries_reg_save[] = { -	[0 ... (NR_CPUS-1)] = { -		.xDesc = 0xd397d9e2,	/* "LpRS" */ -		.xSize = sizeof(struct ItLpRegSave), -	}, -}; - -#define ALPACA_INIT(number)						\ -{									\ -	.lppaca_ptr = &lppaca[number],					\ -	.reg_save_ptr = &iseries_reg_save[number],			\ -} - -const struct alpaca alpaca[] = { -	ALPACA_INIT( 0), -#if NR_CPUS > 1 -	ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3), -#if NR_CPUS > 4 -	ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7), -#if NR_CPUS > 8 -	ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11), -	ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15), -	ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19), -	ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23), -	ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27), -	ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31), -#if NR_CPUS > 32 -	ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35), -	ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39), -	ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43), -	ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47), -	ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51), -	ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55), -	ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59), -	ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63), -#endif -#endif -#endif -#endif -}; - -/* The LparMap data is now located at offset 0x6000 in head.S - * It was put there so that the HvReleaseData could address it - * with a 32-bit offset as required by the iSeries hypervisor - * - * The Naca has a pointer to the ItVpdAreas.  The hypervisor finds - * the Naca via the HvReleaseData area.  The HvReleaseData has the - * offset into the Naca of the pointer to the ItVpdAreas. - */ -const struct ItVpdAreas itVpdAreas = { -	.xSlicDesc = 0xc9a3e5c1,		/* "ItVA" */ -	.xSlicSize = sizeof(struct ItVpdAreas), -	.xSlicVpdEntries = ItVpdMaxEntries,	/* # VPD array entries */ -	.xSlicDmaEntries = ItDmaMaxEntries,	/* # DMA array entries */ -	.xSlicMaxLogicalProcs = NR_CPUS * 2,	/* Max logical procs */ -	.xSlicMaxPhysicalProcs = maxPhysicalProcessors,	/* Max physical procs */ -	.xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks), -	.xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs), -	.xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens), -	.xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens), -	.xSlicMaxSlotLabels = 0,		/* max slot labels */ -	.xSlicMaxLpQueues = 1,			/* max LP queues */ -	.xPlicDmaLens = { 0 },			/* DMA lengths */ -	.xPlicDmaToks = { 0 },			/* DMA tokens */ -	.xSlicVpdLens = {			/* VPD lengths */ -	        0,0,0,		        /*  0 - 2 */ -		sizeof(xItExtVpdPanel), /*       3 Extended VPD   */ -		sizeof(struct alpaca),	/*       4 length of (fake) Paca  */ -		0,			/*       5 */ -		sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */ -		26992,			/*	 7 length of MS VPD */ -		0,			/*       8 */ -		sizeof(struct ItLpNaca),/*       9 length of LP Naca */ -		0,			/*	10 */ -		256,			/*	11 length of Recovery Log Buf */ -		sizeof(struct SpCommArea), /*   12 length of SP Comm Area */ -		0,0,0,			/* 13 - 15 */ -		sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */ -		0,0,0,0,0,0,		/* 17 - 22  */ -		sizeof(struct hvlpevent_queue),	/* 23 length of Lp Queue */ -		0,0			/* 24 - 25 */ -		}, -	.xSlicVpdAdrs = {			/* VPD addresses */ -		0,0,0,			/*	 0 -  2 */ -		&xItExtVpdPanel,        /*       3 Extended VPD */ -		&alpaca[0],		/*       4 first (fake) Paca */ -		0,			/*       5 */ -		&xItIplParmsReal,	/*	 6 IPL parms */ -		&xMsVpd,		/*	 7 MS Vpd */ -		0,			/*       8 */ -		&itLpNaca,		/*       9 LpNaca */ -		0,			/*	10 */ -		&xRecoveryLogBuffer,	/*	11 Recovery Log Buffer */ -		&xSpCommArea,		/*	12 SP Comm Area */ -		0,0,0,			/* 13 - 15 */ -		&xIoHriProcessorVpd,	/*      16 Proc Vpd */ -		0,0,0,0,0,0,		/* 17 - 22 */ -		&hvlpevent_queue,	/*      23 Lp Queue */ -		0,0 -	} -}; diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c deleted file mode 100644 index 202e22798d3..00000000000 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan  IBM Corporation - * - * 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/stddef.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/seq_file.h> -#include <linux/proc_fs.h> -#include <linux/export.h> - -#include <asm/system.h> -#include <asm/paca.h> -#include <asm/firmware.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_event.h> -#include "it_lp_naca.h" - -/* - * The LpQueue is used to pass event data from the hypervisor to - * the partition.  This is where I/O interrupt events are communicated. - * - * It is written to by the hypervisor so cannot end up in the BSS. - */ -struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); - -DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); - -static char *event_types[HvLpEvent_Type_NumTypes] = { -	"Hypervisor", -	"Machine Facilities", -	"Session Manager", -	"SPD I/O", -	"Virtual Bus", -	"PCI I/O", -	"RIO I/O", -	"Virtual Lan", -	"Virtual I/O" -}; - -/* Array of LpEvent handler functions */ -static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; -static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; - -static struct HvLpEvent * get_next_hvlpevent(void) -{ -	struct HvLpEvent * event; -	event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; - -	if (hvlpevent_is_valid(event)) { -		/* rmb() needed only for weakly consistent machines (regatta) */ -		rmb(); -		/* Set pointer to next potential event */ -		hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 + -				IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) * -					IT_LP_EVENT_ALIGN; - -		/* Wrap to beginning if no room at end */ -		if (hvlpevent_queue.hq_current_event > -				hvlpevent_queue.hq_last_event) { -			hvlpevent_queue.hq_current_event = -				hvlpevent_queue.hq_event_stack; -		} -	} else { -		event = NULL; -	} - -	return event; -} - -static unsigned long spread_lpevents = NR_CPUS; - -int hvlpevent_is_pending(void) -{ -	struct HvLpEvent *next_event; - -	if (smp_processor_id() >= spread_lpevents) -		return 0; - -	next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; - -	return hvlpevent_is_valid(next_event) || -		hvlpevent_queue.hq_overflow_pending; -} - -static void hvlpevent_clear_valid(struct HvLpEvent * event) -{ -	/* Tell the Hypervisor that we're done with this event. -	 * Also clear bits within this event that might look like valid bits. -	 * ie. on 64-byte boundaries. -	 */ -	struct HvLpEvent *tmp; -	unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) / -				IT_LP_EVENT_ALIGN) - 1; - -	switch (extra) { -	case 3: -		tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN); -		hvlpevent_invalidate(tmp); -	case 2: -		tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN); -		hvlpevent_invalidate(tmp); -	case 1: -		tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN); -		hvlpevent_invalidate(tmp); -	} - -	mb(); - -	hvlpevent_invalidate(event); -} - -void process_hvlpevents(void) -{ -	struct HvLpEvent * event; - - restart: -	/* If we have recursed, just return */ -	if (!spin_trylock(&hvlpevent_queue.hq_lock)) -		return; - -	for (;;) { -		event = get_next_hvlpevent(); -		if (event) { -			/* Call appropriate handler here, passing -			 * a pointer to the LpEvent.  The handler -			 * must make a copy of the LpEvent if it -			 * needs it in a bottom half. (perhaps for -			 * an ACK) -			 * -			 *  Handlers are responsible for ACK processing -			 * -			 * The Hypervisor guarantees that LpEvents will -			 * only be delivered with types that we have -			 * registered for, so no type check is necessary -			 * here! -			 */ -			if (event->xType < HvLpEvent_Type_NumTypes) -				__get_cpu_var(hvlpevent_counts)[event->xType]++; -			if (event->xType < HvLpEvent_Type_NumTypes && -					lpEventHandler[event->xType]) -				lpEventHandler[event->xType](event); -			else { -				u8 type = event->xType; - -				/* -				 * Don't printk in the spinlock as printk -				 * may require ack events form the HV to send -				 * any characters there. -				 */ -				hvlpevent_clear_valid(event); -				spin_unlock(&hvlpevent_queue.hq_lock); -				printk(KERN_INFO -					"Unexpected Lp Event type=%d\n", type); -				goto restart; -			} - -			hvlpevent_clear_valid(event); -		} else if (hvlpevent_queue.hq_overflow_pending) -			/* -			 * No more valid events. If overflow events are -			 * pending process them -			 */ -			HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index); -		else -			break; -	} - -	spin_unlock(&hvlpevent_queue.hq_lock); -} - -static int set_spread_lpevents(char *str) -{ -	unsigned long val = simple_strtoul(str, NULL, 0); - -	/* -	 * The parameter is the number of processors to share in processing -	 * lp events. -	 */ -	if (( val > 0) && (val <= NR_CPUS)) { -		spread_lpevents = val; -		printk("lpevent processing spread over %ld processors\n", val); -	} else { -		printk("invalid spread_lpevents %ld\n", val); -	} - -	return 1; -} -__setup("spread_lpevents=", set_spread_lpevents); - -void __init setup_hvlpevent_queue(void) -{ -	void *eventStack; - -	spin_lock_init(&hvlpevent_queue.hq_lock); - -	/* Allocate a page for the Event Stack. */ -	eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE); -	memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE); - -	/* Invoke the hypervisor to initialize the event stack */ -	HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE); - -	hvlpevent_queue.hq_event_stack = eventStack; -	hvlpevent_queue.hq_current_event = eventStack; -	hvlpevent_queue.hq_last_event = (char *)eventStack + -		(IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE); -	hvlpevent_queue.hq_index = 0; -} - -/* Register a handler for an LpEvent type */ -int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler) -{ -	if (eventType < HvLpEvent_Type_NumTypes) { -		lpEventHandler[eventType] = handler; -		return 0; -	} -	return 1; -} -EXPORT_SYMBOL(HvLpEvent_registerHandler); - -int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType) -{ -	might_sleep(); - -	if (eventType < HvLpEvent_Type_NumTypes) { -		if (!lpEventHandlerPaths[eventType]) { -			lpEventHandler[eventType] = NULL; -			/* -			 * We now sleep until all other CPUs have scheduled. -			 * This ensures that the deletion is seen by all -			 * other CPUs, and that the deleted handler isn't -			 * still running on another CPU when we return. -			 */ -			synchronize_sched(); -			return 0; -		} -	} -	return 1; -} -EXPORT_SYMBOL(HvLpEvent_unregisterHandler); - -/* - * lpIndex is the partition index of the target partition. - * needed only for VirtualIo, VirtualLan and SessionMgr.  Zero - * indicates to use our partition index - for the other types. - */ -int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex) -{ -	if ((eventType < HvLpEvent_Type_NumTypes) && -			lpEventHandler[eventType]) { -		if (lpIndex == 0) -			lpIndex = itLpNaca.xLpIndex; -		HvCallEvent_openLpEventPath(lpIndex, eventType); -		++lpEventHandlerPaths[eventType]; -		return 0; -	} -	return 1; -} - -int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex) -{ -	if ((eventType < HvLpEvent_Type_NumTypes) && -			lpEventHandler[eventType] && -			lpEventHandlerPaths[eventType]) { -		if (lpIndex == 0) -			lpIndex = itLpNaca.xLpIndex; -		HvCallEvent_closeLpEventPath(lpIndex, eventType); -		--lpEventHandlerPaths[eventType]; -		return 0; -	} -	return 1; -} - -static int proc_lpevents_show(struct seq_file *m, void *v) -{ -	int cpu, i; -	unsigned long sum; -	static unsigned long cpu_totals[NR_CPUS]; - -	/* FIXME: do we care that there's no locking here? */ -	sum = 0; -	for_each_online_cpu(cpu) { -		cpu_totals[cpu] = 0; -		for (i = 0; i < HvLpEvent_Type_NumTypes; i++) { -			cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i]; -		} -		sum += cpu_totals[cpu]; -	} - -	seq_printf(m, "LpEventQueue 0\n"); -	seq_printf(m, "  events processed:\t%lu\n", sum); - -	for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) { -		sum = 0; -		for_each_online_cpu(cpu) { -			sum += per_cpu(hvlpevent_counts, cpu)[i]; -		} - -		seq_printf(m, "    %-20s %10lu\n", event_types[i], sum); -	} - -	seq_printf(m, "\n  events processed by processor:\n"); - -	for_each_online_cpu(cpu) { -		seq_printf(m, "    CPU%02d  %10lu\n", cpu, cpu_totals[cpu]); -	} - -	return 0; -} - -static int proc_lpevents_open(struct inode *inode, struct file *file) -{ -	return single_open(file, proc_lpevents_show, NULL); -} - -static const struct file_operations proc_lpevents_operations = { -	.open		= proc_lpevents_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -}; - -static int __init proc_lpevents_init(void) -{ -	if (!firmware_has_feature(FW_FEATURE_ISERIES)) -		return 0; - -	proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL, -		    &proc_lpevents_operations); -	return 0; -} -__initcall(proc_lpevents_init); - diff --git a/arch/powerpc/platforms/iseries/main_store.h b/arch/powerpc/platforms/iseries/main_store.h deleted file mode 100644 index 1a7a3f50e40..00000000000 --- a/arch/powerpc/platforms/iseries/main_store.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ - -#ifndef _ISERIES_MAIN_STORE_H -#define _ISERIES_MAIN_STORE_H - -/* Main Store Vpd for Condor,iStar,sStar */ -struct IoHriMainStoreSegment4 { -	u8	msArea0Exists:1; -	u8	msArea1Exists:1; -	u8	msArea2Exists:1; -	u8	msArea3Exists:1; -	u8	reserved1:4; -	u8	reserved2; - -	u8	msArea0Functional:1; -	u8	msArea1Functional:1; -	u8	msArea2Functional:1; -	u8	msArea3Functional:1; -	u8	reserved3:4; -	u8	reserved4; - -	u32	totalMainStore; - -	u64	msArea0Ptr; -	u64	msArea1Ptr; -	u64	msArea2Ptr; -	u64	msArea3Ptr; - -	u32	cardProductionLevel; - -	u32	msAdrHole; - -	u8	msArea0HasRiserVpd:1; -	u8	msArea1HasRiserVpd:1; -	u8	msArea2HasRiserVpd:1; -	u8	msArea3HasRiserVpd:1; -	u8	reserved5:4; -	u8	reserved6; -	u16	reserved7; - -	u8	reserved8[28]; - -	u64	nonInterleavedBlocksStartAdr; -	u64	nonInterleavedBlocksEndAdr; -}; - -/* Main Store VPD for Power4 */ -struct __attribute((packed)) IoHriMainStoreChipInfo1 { -	u32	chipMfgID; -	char	chipECLevel[4]; -}; - -struct IoHriMainStoreVpdIdData { -	char	typeNumber[4]; -	char	modelNumber[4]; -	char	partNumber[12]; -	char	serialNumber[12]; -}; - -struct	__attribute((packed)) IoHriMainStoreVpdFruData { -	char	fruLabel[8]; -	u8	numberOfSlots; -	u8	pluggingType; -	u16	slotMapIndex; -}; - -struct  __attribute((packed)) IoHriMainStoreAdrRangeBlock { -	void	*blockStart; -	void	*blockEnd; -	u32	blockProcChipId; -}; - -#define MaxAreaAdrRangeBlocks 4 - -struct __attribute((packed)) IoHriMainStoreArea4 { -	u32	msVpdFormat; -	u8	containedVpdType; -	u8	reserved1; -	u16	reserved2; - -	u64	msExists; -	u64	msFunctional; - -	u32	memorySize; -	u32	procNodeId; - -	u32	numAdrRangeBlocks; -	struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks]; - -	struct IoHriMainStoreChipInfo1	chipInfo0; -	struct IoHriMainStoreChipInfo1	chipInfo1; -	struct IoHriMainStoreChipInfo1	chipInfo2; -	struct IoHriMainStoreChipInfo1	chipInfo3; -	struct IoHriMainStoreChipInfo1	chipInfo4; -	struct IoHriMainStoreChipInfo1	chipInfo5; -	struct IoHriMainStoreChipInfo1	chipInfo6; -	struct IoHriMainStoreChipInfo1	chipInfo7; - -	void	*msRamAreaArray; -	u32	msRamAreaArrayNumEntries; -	u32	msRamAreaArrayEntrySize; - -	u32	numaDimmExists; -	u32	numaDimmFunctional; -	void	*numaDimmArray; -	u32	numaDimmArrayNumEntries; -	u32	numaDimmArrayEntrySize; - -	struct IoHriMainStoreVpdIdData idData; - -	u64	powerData; -	u64	cardAssemblyPartNum; -	u64	chipSerialNum; - -	u64	reserved3; -	char	reserved4[16]; - -	struct IoHriMainStoreVpdFruData fruData; - -	u8	vpdPortNum; -	u8	reserved5; -	u8	frameId; -	u8	rackUnit; -	char	asciiKeywordVpd[256]; -	u32	reserved6; -}; - - -struct IoHriMainStoreSegment5 { -	u16	reserved1; -	u8	reserved2; -	u8	msVpdFormat; - -	u32	totalMainStore; -	u64	maxConfiguredMsAdr; - -	struct IoHriMainStoreArea4	*msAreaArray; -	u32	msAreaArrayNumEntries; -	u32	msAreaArrayEntrySize; - -	u32	msAreaExists; -	u32	msAreaFunctional; - -	u64	reserved3; -}; - -extern u64	xMsVpd[]; - -#endif	/* _ISERIES_MAIN_STORE_H */ diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c deleted file mode 100644 index 254c1fc3d8d..00000000000 --- a/arch/powerpc/platforms/iseries/mf.c +++ /dev/null @@ -1,1275 +0,0 @@ -/* - * Copyright (C) 2001 Troy D. Armstrong  IBM Corporation - * Copyright (C) 2004-2005 Stephen Rothwell  IBM Corporation - * - * This modules exists as an interface between a Linux secondary partition - * running on an iSeries and the primary partition's Virtual Service - * Processor (VSP) object.  The VSP has final authority over powering on/off - * all partitions in the iSeries.  It also provides miscellaneous low-level - * machine facility type operations. - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/export.h> -#include <linux/proc_fs.h> -#include <linux/dma-mapping.h> -#include <linux/bcd.h> -#include <linux/rtc.h> -#include <linux/slab.h> - -#include <asm/time.h> -#include <asm/uaccess.h> -#include <asm/paca.h> -#include <asm/abs_addr.h> -#include <asm/firmware.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/it_lp_queue.h> - -#include "setup.h" - -static int mf_initialized; - -/* - * This is the structure layout for the Machine Facilities LPAR event - * flows. - */ -struct vsp_cmd_data { -	u64 token; -	u16 cmd; -	HvLpIndex lp_index; -	u8 result_code; -	u32 reserved; -	union { -		u64 state;	/* GetStateOut */ -		u64 ipl_type;	/* GetIplTypeOut, Function02SelectIplTypeIn */ -		u64 ipl_mode;	/* GetIplModeOut, Function02SelectIplModeIn */ -		u64 page[4];	/* GetSrcHistoryIn */ -		u64 flag;	/* GetAutoIplWhenPrimaryIplsOut, -				   SetAutoIplWhenPrimaryIplsIn, -				   WhiteButtonPowerOffIn, -				   Function08FastPowerOffIn, -				   IsSpcnRackPowerIncompleteOut */ -		struct { -			u64 token; -			u64 address_type; -			u64 side; -			u32 length; -			u32 offset; -		} kern;		/* SetKernelImageIn, GetKernelImageIn, -				   SetKernelCmdLineIn, GetKernelCmdLineIn */ -		u32 length_out;	/* GetKernelImageOut, GetKernelCmdLineOut */ -		u8 reserved[80]; -	} sub_data; -}; - -struct vsp_rsp_data { -	struct completion com; -	struct vsp_cmd_data *response; -}; - -struct alloc_data { -	u16 size; -	u16 type; -	u32 count; -	u16 reserved1; -	u8 reserved2; -	HvLpIndex target_lp; -}; - -struct ce_msg_data; - -typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp); - -struct ce_msg_comp_data { -	ce_msg_comp_hdlr handler; -	void *token; -}; - -struct ce_msg_data { -	u8 ce_msg[12]; -	char reserved[4]; -	struct ce_msg_comp_data *completion; -}; - -struct io_mf_lp_event { -	struct HvLpEvent hp_lp_event; -	u16 subtype_result_code; -	u16 reserved1; -	u32 reserved2; -	union { -		struct alloc_data alloc; -		struct ce_msg_data ce_msg; -		struct vsp_cmd_data vsp_cmd; -	} data; -}; - -#define subtype_data(a, b, c, d)	\ -		(((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -/* - * All outgoing event traffic is kept on a FIFO queue.  The first - * pointer points to the one that is outstanding, and all new - * requests get stuck on the end.  Also, we keep a certain number of - * preallocated pending events so that we can operate very early in - * the boot up sequence (before kmalloc is ready). - */ -struct pending_event { -	struct pending_event *next; -	struct io_mf_lp_event event; -	MFCompleteHandler hdlr; -	char dma_data[72]; -	unsigned dma_data_length; -	unsigned remote_address; -}; -static spinlock_t pending_event_spinlock; -static struct pending_event *pending_event_head; -static struct pending_event *pending_event_tail; -static struct pending_event *pending_event_avail; -#define PENDING_EVENT_PREALLOC_LEN 16 -static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN]; - -/* - * Put a pending event onto the available queue, so it can get reused. - * Attention! You must have the pending_event_spinlock before calling! - */ -static void free_pending_event(struct pending_event *ev) -{ -	if (ev != NULL) { -		ev->next = pending_event_avail; -		pending_event_avail = ev; -	} -} - -/* - * Enqueue the outbound event onto the stack.  If the queue was - * empty to begin with, we must also issue it via the Hypervisor - * interface.  There is a section of code below that will touch - * the first stack pointer without the protection of the pending_event_spinlock. - * This is OK, because we know that nobody else will be modifying - * the first pointer when we do this. - */ -static int signal_event(struct pending_event *ev) -{ -	int rc = 0; -	unsigned long flags; -	int go = 1; -	struct pending_event *ev1; -	HvLpEvent_Rc hv_rc; - -	/* enqueue the event */ -	if (ev != NULL) { -		ev->next = NULL; -		spin_lock_irqsave(&pending_event_spinlock, flags); -		if (pending_event_head == NULL) -			pending_event_head = ev; -		else { -			go = 0; -			pending_event_tail->next = ev; -		} -		pending_event_tail = ev; -		spin_unlock_irqrestore(&pending_event_spinlock, flags); -	} - -	/* send the event */ -	while (go) { -		go = 0; - -		/* any DMA data to send beforehand? */ -		if (pending_event_head->dma_data_length > 0) -			HvCallEvent_dmaToSp(pending_event_head->dma_data, -					pending_event_head->remote_address, -					pending_event_head->dma_data_length, -					HvLpDma_Direction_LocalToRemote); - -		hv_rc = HvCallEvent_signalLpEvent( -				&pending_event_head->event.hp_lp_event); -		if (hv_rc != HvLpEvent_Rc_Good) { -			printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() " -					"failed with %d\n", (int)hv_rc); - -			spin_lock_irqsave(&pending_event_spinlock, flags); -			ev1 = pending_event_head; -			pending_event_head = pending_event_head->next; -			if (pending_event_head != NULL) -				go = 1; -			spin_unlock_irqrestore(&pending_event_spinlock, flags); - -			if (ev1 == ev) -				rc = -EIO; -			else if (ev1->hdlr != NULL) -				(*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO); - -			spin_lock_irqsave(&pending_event_spinlock, flags); -			free_pending_event(ev1); -			spin_unlock_irqrestore(&pending_event_spinlock, flags); -		} -	} - -	return rc; -} - -/* - * Allocate a new pending_event structure, and initialize it. - */ -static struct pending_event *new_pending_event(void) -{ -	struct pending_event *ev = NULL; -	HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex(); -	unsigned long flags; -	struct HvLpEvent *hev; - -	spin_lock_irqsave(&pending_event_spinlock, flags); -	if (pending_event_avail != NULL) { -		ev = pending_event_avail; -		pending_event_avail = pending_event_avail->next; -	} -	spin_unlock_irqrestore(&pending_event_spinlock, flags); -	if (ev == NULL) { -		ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC); -		if (ev == NULL) { -			printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", -					sizeof(struct pending_event)); -			return NULL; -		} -	} -	memset(ev, 0, sizeof(struct pending_event)); -	hev = &ev->event.hp_lp_event; -	hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT; -	hev->xType = HvLpEvent_Type_MachineFac; -	hev->xSourceLp = HvLpConfig_getLpIndex(); -	hev->xTargetLp = primary_lp; -	hev->xSizeMinus1 = sizeof(ev->event) - 1; -	hev->xRc = HvLpEvent_Rc_Good; -	hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp, -			HvLpEvent_Type_MachineFac); -	hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp, -			HvLpEvent_Type_MachineFac); - -	return ev; -} - -static int __maybe_unused -signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) -{ -	struct pending_event *ev = new_pending_event(); -	int rc; -	struct vsp_rsp_data response; - -	if (ev == NULL) -		return -ENOMEM; - -	init_completion(&response.com); -	response.response = vsp_cmd; -	ev->event.hp_lp_event.xSubtype = 6; -	ev->event.hp_lp_event.x.xSubtypeData = -		subtype_data('M', 'F',  'V',  'I'); -	ev->event.data.vsp_cmd.token = (u64)&response; -	ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd; -	ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); -	ev->event.data.vsp_cmd.result_code = 0xFF; -	ev->event.data.vsp_cmd.reserved = 0; -	memcpy(&(ev->event.data.vsp_cmd.sub_data), -			&(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data)); -	mb(); - -	rc = signal_event(ev); -	if (rc == 0) -		wait_for_completion(&response.com); -	return rc; -} - - -/* - * Send a 12-byte CE message to the primary partition VSP object - */ -static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion) -{ -	struct pending_event *ev = new_pending_event(); - -	if (ev == NULL) -		return -ENOMEM; - -	ev->event.hp_lp_event.xSubtype = 0; -	ev->event.hp_lp_event.x.xSubtypeData = -		subtype_data('M',  'F',  'C',  'E'); -	memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); -	ev->event.data.ce_msg.completion = completion; -	return signal_event(ev); -} - -/* - * Send a 12-byte CE message (with no data) to the primary partition VSP object - */ -static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion) -{ -	u8 ce_msg[12]; - -	memset(ce_msg, 0, sizeof(ce_msg)); -	ce_msg[3] = ce_op; -	return signal_ce_msg(ce_msg, completion); -} - -/* - * Send a 12-byte CE message and DMA data to the primary partition VSP object - */ -static int dma_and_signal_ce_msg(char *ce_msg, -		struct ce_msg_comp_data *completion, void *dma_data, -		unsigned dma_data_length, unsigned remote_address) -{ -	struct pending_event *ev = new_pending_event(); - -	if (ev == NULL) -		return -ENOMEM; - -	ev->event.hp_lp_event.xSubtype = 0; -	ev->event.hp_lp_event.x.xSubtypeData = -		subtype_data('M', 'F', 'C', 'E'); -	memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); -	ev->event.data.ce_msg.completion = completion; -	memcpy(ev->dma_data, dma_data, dma_data_length); -	ev->dma_data_length = dma_data_length; -	ev->remote_address = remote_address; -	return signal_event(ev); -} - -/* - * Initiate a nice (hopefully) shutdown of Linux.  We simply are - * going to try and send the init process a SIGINT signal.  If - * this fails (why?), we'll simply force it off in a not-so-nice - * manner. - */ -static int shutdown(void) -{ -	int rc = kill_cad_pid(SIGINT, 1); - -	if (rc) { -		printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " -				"hard shutdown commencing\n", rc); -		mf_power_off(); -	} else -		printk(KERN_INFO "mf.c: init has been successfully notified " -				"to proceed with shutdown\n"); -	return rc; -} - -/* - * The primary partition VSP object is sending us a new - * event flow.  Handle it... - */ -static void handle_int(struct io_mf_lp_event *event) -{ -	struct ce_msg_data *ce_msg_data; -	struct ce_msg_data *pce_msg_data; -	unsigned long flags; -	struct pending_event *pev; - -	/* ack the interrupt */ -	event->hp_lp_event.xRc = HvLpEvent_Rc_Good; -	HvCallEvent_ackLpEvent(&event->hp_lp_event); - -	/* process interrupt */ -	switch (event->hp_lp_event.xSubtype) { -	case 0:	/* CE message */ -		ce_msg_data = &event->data.ce_msg; -		switch (ce_msg_data->ce_msg[3]) { -		case 0x5B:	/* power control notification */ -			if ((ce_msg_data->ce_msg[5] & 0x20) != 0) { -				printk(KERN_INFO "mf.c: Commencing partition shutdown\n"); -				if (shutdown() == 0) -					signal_ce_msg_simple(0xDB, NULL); -			} -			break; -		case 0xC0:	/* get time */ -			spin_lock_irqsave(&pending_event_spinlock, flags); -			pev = pending_event_head; -			if (pev != NULL) -				pending_event_head = pending_event_head->next; -			spin_unlock_irqrestore(&pending_event_spinlock, flags); -			if (pev == NULL) -				break; -			pce_msg_data = &pev->event.data.ce_msg; -			if (pce_msg_data->ce_msg[3] != 0x40) -				break; -			if (pce_msg_data->completion != NULL) { -				ce_msg_comp_hdlr handler = -					pce_msg_data->completion->handler; -				void *token = pce_msg_data->completion->token; - -				if (handler != NULL) -					(*handler)(token, ce_msg_data); -			} -			spin_lock_irqsave(&pending_event_spinlock, flags); -			free_pending_event(pev); -			spin_unlock_irqrestore(&pending_event_spinlock, flags); -			/* send next waiting event */ -			if (pending_event_head != NULL) -				signal_event(NULL); -			break; -		} -		break; -	case 1:	/* IT sys shutdown */ -		printk(KERN_INFO "mf.c: Commencing system shutdown\n"); -		shutdown(); -		break; -	} -} - -/* - * The primary partition VSP object is acknowledging the receipt - * of a flow we sent to them.  If there are other flows queued - * up, we must send another one now... - */ -static void handle_ack(struct io_mf_lp_event *event) -{ -	unsigned long flags; -	struct pending_event *two = NULL; -	unsigned long free_it = 0; -	struct ce_msg_data *ce_msg_data; -	struct ce_msg_data *pce_msg_data; -	struct vsp_rsp_data *rsp; - -	/* handle current event */ -	if (pending_event_head == NULL) { -		printk(KERN_ERR "mf.c: stack empty for receiving ack\n"); -		return; -	} - -	switch (event->hp_lp_event.xSubtype) { -	case 0:     /* CE msg */ -		ce_msg_data = &event->data.ce_msg; -		if (ce_msg_data->ce_msg[3] != 0x40) { -			free_it = 1; -			break; -		} -		if (ce_msg_data->ce_msg[2] == 0) -			break; -		free_it = 1; -		pce_msg_data = &pending_event_head->event.data.ce_msg; -		if (pce_msg_data->completion != NULL) { -			ce_msg_comp_hdlr handler = -				pce_msg_data->completion->handler; -			void *token = pce_msg_data->completion->token; - -			if (handler != NULL) -				(*handler)(token, ce_msg_data); -		} -		break; -	case 4:	/* allocate */ -	case 5:	/* deallocate */ -		if (pending_event_head->hdlr != NULL) -			(*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count); -		free_it = 1; -		break; -	case 6: -		free_it = 1; -		rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token; -		if (rsp == NULL) { -			printk(KERN_ERR "mf.c: no rsp\n"); -			break; -		} -		if (rsp->response != NULL) -			memcpy(rsp->response, &event->data.vsp_cmd, -					sizeof(event->data.vsp_cmd)); -		complete(&rsp->com); -		break; -	} - -	/* remove from queue */ -	spin_lock_irqsave(&pending_event_spinlock, flags); -	if ((pending_event_head != NULL) && (free_it == 1)) { -		struct pending_event *oldHead = pending_event_head; - -		pending_event_head = pending_event_head->next; -		two = pending_event_head; -		free_pending_event(oldHead); -	} -	spin_unlock_irqrestore(&pending_event_spinlock, flags); - -	/* send next waiting event */ -	if (two != NULL) -		signal_event(NULL); -} - -/* - * This is the generic event handler we are registering with - * the Hypervisor.  Ensure the flows are for us, and then - * parse it enough to know if it is an interrupt or an - * acknowledge. - */ -static void hv_handler(struct HvLpEvent *event) -{ -	if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { -		if (hvlpevent_is_ack(event)) -			handle_ack((struct io_mf_lp_event *)event); -		else -			handle_int((struct io_mf_lp_event *)event); -	} else -		printk(KERN_ERR "mf.c: alien event received\n"); -} - -/* - * Global kernel interface to allocate and seed events into the - * Hypervisor. - */ -void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, -		unsigned size, unsigned count, MFCompleteHandler hdlr, -		void *user_token) -{ -	struct pending_event *ev = new_pending_event(); -	int rc; - -	if (ev == NULL) { -		rc = -ENOMEM; -	} else { -		ev->event.hp_lp_event.xSubtype = 4; -		ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; -		ev->event.hp_lp_event.x.xSubtypeData = -			subtype_data('M', 'F', 'M', 'A'); -		ev->event.data.alloc.target_lp = target_lp; -		ev->event.data.alloc.type = type; -		ev->event.data.alloc.size = size; -		ev->event.data.alloc.count = count; -		ev->hdlr = hdlr; -		rc = signal_event(ev); -	} -	if ((rc != 0) && (hdlr != NULL)) -		(*hdlr)(user_token, rc); -} -EXPORT_SYMBOL(mf_allocate_lp_events); - -/* - * Global kernel interface to unseed and deallocate events already in - * Hypervisor. - */ -void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, -		unsigned count, MFCompleteHandler hdlr, void *user_token) -{ -	struct pending_event *ev = new_pending_event(); -	int rc; - -	if (ev == NULL) -		rc = -ENOMEM; -	else { -		ev->event.hp_lp_event.xSubtype = 5; -		ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; -		ev->event.hp_lp_event.x.xSubtypeData = -			subtype_data('M', 'F', 'M', 'D'); -		ev->event.data.alloc.target_lp = target_lp; -		ev->event.data.alloc.type = type; -		ev->event.data.alloc.count = count; -		ev->hdlr = hdlr; -		rc = signal_event(ev); -	} -	if ((rc != 0) && (hdlr != NULL)) -		(*hdlr)(user_token, rc); -} -EXPORT_SYMBOL(mf_deallocate_lp_events); - -/* - * Global kernel interface to tell the VSP object in the primary - * partition to power this partition off. - */ -void mf_power_off(void) -{ -	printk(KERN_INFO "mf.c: Down it goes...\n"); -	signal_ce_msg_simple(0x4d, NULL); -	for (;;) -		; -} - -/* - * Global kernel interface to tell the VSP object in the primary - * partition to reboot this partition. - */ -void mf_reboot(char *cmd) -{ -	printk(KERN_INFO "mf.c: Preparing to bounce...\n"); -	signal_ce_msg_simple(0x4e, NULL); -	for (;;) -		; -} - -/* - * Display a single word SRC onto the VSP control panel. - */ -void mf_display_src(u32 word) -{ -	u8 ce[12]; - -	memset(ce, 0, sizeof(ce)); -	ce[3] = 0x4a; -	ce[7] = 0x01; -	ce[8] = word >> 24; -	ce[9] = word >> 16; -	ce[10] = word >> 8; -	ce[11] = word; -	signal_ce_msg(ce, NULL); -} - -/* - * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. - */ -static __init void mf_display_progress_src(u16 value) -{ -	u8 ce[12]; -	u8 src[72]; - -	memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12); -	memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" -		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" -		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" -		"\x00\x00\x00\x00PROGxxxx                        ", -		72); -	src[6] = value >> 8; -	src[7] = value & 255; -	src[44] = "0123456789ABCDEF"[(value >> 12) & 15]; -	src[45] = "0123456789ABCDEF"[(value >> 8) & 15]; -	src[46] = "0123456789ABCDEF"[(value >> 4) & 15]; -	src[47] = "0123456789ABCDEF"[value & 15]; -	dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024); -} - -/* - * Clear the VSP control panel.  Used to "erase" an SRC that was - * previously displayed. - */ -static void mf_clear_src(void) -{ -	signal_ce_msg_simple(0x4b, NULL); -} - -void __init mf_display_progress(u16 value) -{ -	if (!mf_initialized) -		return; - -	if (0xFFFF == value) -		mf_clear_src(); -	else -		mf_display_progress_src(value); -} - -/* - * Initialization code here. - */ -void __init mf_init(void) -{ -	int i; - -	spin_lock_init(&pending_event_spinlock); - -	for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++) -		free_pending_event(&pending_event_prealloc[i]); - -	HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler); - -	/* virtual continue ack */ -	signal_ce_msg_simple(0x57, NULL); - -	mf_initialized = 1; -	mb(); - -	printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities " -			"initialized\n"); -} - -struct rtc_time_data { -	struct completion com; -	struct ce_msg_data ce_msg; -	int rc; -}; - -static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) -{ -	struct rtc_time_data *rtc = token; - -	memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); -	rtc->rc = 0; -	complete(&rtc->com); -} - -static int mf_set_rtc(struct rtc_time *tm) -{ -	char ce_time[12]; -	u8 day, mon, hour, min, sec, y1, y2; -	unsigned year; - -	year = 1900 + tm->tm_year; -	y1 = year / 100; -	y2 = year % 100; - -	sec = tm->tm_sec; -	min = tm->tm_min; -	hour = tm->tm_hour; -	day = tm->tm_mday; -	mon = tm->tm_mon + 1; - -	sec = bin2bcd(sec); -	min = bin2bcd(min); -	hour = bin2bcd(hour); -	mon = bin2bcd(mon); -	day = bin2bcd(day); -	y1 = bin2bcd(y1); -	y2 = bin2bcd(y2); - -	memset(ce_time, 0, sizeof(ce_time)); -	ce_time[3] = 0x41; -	ce_time[4] = y1; -	ce_time[5] = y2; -	ce_time[6] = sec; -	ce_time[7] = min; -	ce_time[8] = hour; -	ce_time[10] = day; -	ce_time[11] = mon; - -	return signal_ce_msg(ce_time, NULL); -} - -static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) -{ -	tm->tm_wday = 0; -	tm->tm_yday = 0; -	tm->tm_isdst = 0; -	if (rc) { -		tm->tm_sec = 0; -		tm->tm_min = 0; -		tm->tm_hour = 0; -		tm->tm_mday = 15; -		tm->tm_mon = 5; -		tm->tm_year = 52; -		return rc; -	} - -	if ((ce_msg[2] == 0xa9) || -	    (ce_msg[2] == 0xaf)) { -		/* TOD clock is not set */ -		tm->tm_sec = 1; -		tm->tm_min = 1; -		tm->tm_hour = 1; -		tm->tm_mday = 10; -		tm->tm_mon = 8; -		tm->tm_year = 71; -		mf_set_rtc(tm); -	} -	{ -		u8 year = ce_msg[5]; -		u8 sec = ce_msg[6]; -		u8 min = ce_msg[7]; -		u8 hour = ce_msg[8]; -		u8 day = ce_msg[10]; -		u8 mon = ce_msg[11]; - -		sec = bcd2bin(sec); -		min = bcd2bin(min); -		hour = bcd2bin(hour); -		day = bcd2bin(day); -		mon = bcd2bin(mon); -		year = bcd2bin(year); - -		if (year <= 69) -			year += 100; - -		tm->tm_sec = sec; -		tm->tm_min = min; -		tm->tm_hour = hour; -		tm->tm_mday = day; -		tm->tm_mon = mon; -		tm->tm_year = year; -	} - -	return 0; -} - -static int mf_get_rtc(struct rtc_time *tm) -{ -	struct ce_msg_comp_data ce_complete; -	struct rtc_time_data rtc_data; -	int rc; - -	memset(&ce_complete, 0, sizeof(ce_complete)); -	memset(&rtc_data, 0, sizeof(rtc_data)); -	init_completion(&rtc_data.com); -	ce_complete.handler = &get_rtc_time_complete; -	ce_complete.token = &rtc_data; -	rc = signal_ce_msg_simple(0x40, &ce_complete); -	if (rc) -		return rc; -	wait_for_completion(&rtc_data.com); -	return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); -} - -struct boot_rtc_time_data { -	int busy; -	struct ce_msg_data ce_msg; -	int rc; -}; - -static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) -{ -	struct boot_rtc_time_data *rtc = token; - -	memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); -	rtc->rc = 0; -	rtc->busy = 0; -} - -static int mf_get_boot_rtc(struct rtc_time *tm) -{ -	struct ce_msg_comp_data ce_complete; -	struct boot_rtc_time_data rtc_data; -	int rc; - -	memset(&ce_complete, 0, sizeof(ce_complete)); -	memset(&rtc_data, 0, sizeof(rtc_data)); -	rtc_data.busy = 1; -	ce_complete.handler = &get_boot_rtc_time_complete; -	ce_complete.token = &rtc_data; -	rc = signal_ce_msg_simple(0x40, &ce_complete); -	if (rc) -		return rc; -	/* We need to poll here as we are not yet taking interrupts */ -	while (rtc_data.busy) { -		if (hvlpevent_is_pending()) -			process_hvlpevents(); -	} -	return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); -} - -#ifdef CONFIG_PROC_FS -static int mf_cmdline_proc_show(struct seq_file *m, void *v) -{ -	char *page, *p; -	struct vsp_cmd_data vsp_cmd; -	int rc; -	dma_addr_t dma_addr; - -	/* The HV appears to return no more than 256 bytes of command line */ -	page = kmalloc(256, GFP_KERNEL); -	if (!page) -		return -ENOMEM; - -	dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE); -	if (dma_addr == DMA_ERROR_CODE) { -		kfree(page); -		return -ENOMEM; -	} -	memset(page, 0, 256); -	memset(&vsp_cmd, 0, sizeof(vsp_cmd)); -	vsp_cmd.cmd = 33; -	vsp_cmd.sub_data.kern.token = dma_addr; -	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; -	vsp_cmd.sub_data.kern.side = (u64)m->private; -	vsp_cmd.sub_data.kern.length = 256; -	mb(); -	rc = signal_vsp_instruction(&vsp_cmd); -	iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE); -	if (rc) { -		kfree(page); -		return rc; -	} -	if (vsp_cmd.result_code != 0) { -		kfree(page); -		return -ENOMEM; -	} -	p = page; -	while (p - page < 256) { -		if (*p == '\0' || *p == '\n') { -			*p = '\n'; -			break; -		} -		p++; - -	} -	seq_write(m, page, p - page); -	kfree(page); -	return 0; -} - -static int mf_cmdline_proc_open(struct inode *inode, struct file *file) -{ -	return single_open(file, mf_cmdline_proc_show, PDE(inode)->data); -} - -#if 0 -static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) -{ -	struct vsp_cmd_data vsp_cmd; -	int rc; -	int len = *size; -	dma_addr_t dma_addr; - -	dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE); -	memset(buffer, 0, len); -	memset(&vsp_cmd, 0, sizeof(vsp_cmd)); -	vsp_cmd.cmd = 32; -	vsp_cmd.sub_data.kern.token = dma_addr; -	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; -	vsp_cmd.sub_data.kern.side = side; -	vsp_cmd.sub_data.kern.offset = offset; -	vsp_cmd.sub_data.kern.length = len; -	mb(); -	rc = signal_vsp_instruction(&vsp_cmd); -	if (rc == 0) { -		if (vsp_cmd.result_code == 0) -			*size = vsp_cmd.sub_data.length_out; -		else -			rc = -ENOMEM; -	} - -	iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE); - -	return rc; -} - -static int proc_mf_dump_vmlinux(char *page, char **start, off_t off, -		int count, int *eof, void *data) -{ -	int sizeToGet = count; - -	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; - -	if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) { -		if (sizeToGet != 0) { -			*start = page + off; -			return sizeToGet; -		} -		*eof = 1; -		return 0; -	} -	*eof = 1; -	return 0; -} -#endif - -static int mf_side_proc_show(struct seq_file *m, void *v) -{ -	char mf_current_side = ' '; -	struct vsp_cmd_data vsp_cmd; - -	memset(&vsp_cmd, 0, sizeof(vsp_cmd)); -	vsp_cmd.cmd = 2; -	vsp_cmd.sub_data.ipl_type = 0; -	mb(); - -	if (signal_vsp_instruction(&vsp_cmd) == 0) { -		if (vsp_cmd.result_code == 0) { -			switch (vsp_cmd.sub_data.ipl_type) { -			case 0:	mf_current_side = 'A'; -				break; -			case 1:	mf_current_side = 'B'; -				break; -			case 2:	mf_current_side = 'C'; -				break; -			default:	mf_current_side = 'D'; -				break; -			} -		} -	} - -	seq_printf(m, "%c\n", mf_current_side); -	return 0; -} - -static int mf_side_proc_open(struct inode *inode, struct file *file) -{ -	return single_open(file, mf_side_proc_show, NULL); -} - -static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer, -				  size_t count, loff_t *pos) -{ -	char side; -	u64 newSide; -	struct vsp_cmd_data vsp_cmd; - -	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; - -	if (count == 0) -		return 0; - -	if (get_user(side, buffer)) -		return -EFAULT; - -	switch (side) { -	case 'A':	newSide = 0; -			break; -	case 'B':	newSide = 1; -			break; -	case 'C':	newSide = 2; -			break; -	case 'D':	newSide = 3; -			break; -	default: -		printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); -		return -EINVAL; -	} - -	memset(&vsp_cmd, 0, sizeof(vsp_cmd)); -	vsp_cmd.sub_data.ipl_type = newSide; -	vsp_cmd.cmd = 10; - -	(void)signal_vsp_instruction(&vsp_cmd); - -	return count; -} - -static const struct file_operations mf_side_proc_fops = { -	.owner		= THIS_MODULE, -	.open		= mf_side_proc_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -	.write		= mf_side_proc_write, -}; - -static int mf_src_proc_show(struct seq_file *m, void *v) -{ -	return 0; -} - -static int mf_src_proc_open(struct inode *inode, struct file *file) -{ -	return single_open(file, mf_src_proc_show, NULL); -} - -static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer, -				 size_t count, loff_t *pos) -{ -	char stkbuf[10]; - -	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; - -	if ((count < 4) && (count != 1)) { -		printk(KERN_ERR "mf_proc: invalid src\n"); -		return -EINVAL; -	} - -	if (count > (sizeof(stkbuf) - 1)) -		count = sizeof(stkbuf) - 1; -	if (copy_from_user(stkbuf, buffer, count)) -		return -EFAULT; - -	if ((count == 1) && (*stkbuf == '\0')) -		mf_clear_src(); -	else -		mf_display_src(*(u32 *)stkbuf); - -	return count; -} - -static const struct file_operations mf_src_proc_fops = { -	.owner		= THIS_MODULE, -	.open		= mf_src_proc_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -	.write		= mf_src_proc_write, -}; - -static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer, -				     size_t count, loff_t *pos) -{ -	void *data = PDE(file->f_path.dentry->d_inode)->data; -	struct vsp_cmd_data vsp_cmd; -	dma_addr_t dma_addr; -	char *page; -	int ret = -EACCES; - -	if (!capable(CAP_SYS_ADMIN)) -		goto out; - -	dma_addr = 0; -	page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); -	ret = -ENOMEM; -	if (page == NULL) -		goto out; - -	ret = -EFAULT; -	if (copy_from_user(page, buffer, count)) -		goto out_free; - -	memset(&vsp_cmd, 0, sizeof(vsp_cmd)); -	vsp_cmd.cmd = 31; -	vsp_cmd.sub_data.kern.token = dma_addr; -	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; -	vsp_cmd.sub_data.kern.side = (u64)data; -	vsp_cmd.sub_data.kern.length = count; -	mb(); -	(void)signal_vsp_instruction(&vsp_cmd); -	ret = count; - -out_free: -	iseries_hv_free(count, page, dma_addr); -out: -	return ret; -} - -static const struct file_operations mf_cmdline_proc_fops = { -	.owner		= THIS_MODULE, -	.open		= mf_cmdline_proc_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -	.write		= mf_cmdline_proc_write, -}; - -static ssize_t proc_mf_change_vmlinux(struct file *file, -				      const char __user *buf, -				      size_t count, loff_t *ppos) -{ -	struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); -	ssize_t rc; -	dma_addr_t dma_addr; -	char *page; -	struct vsp_cmd_data vsp_cmd; - -	rc = -EACCES; -	if (!capable(CAP_SYS_ADMIN)) -		goto out; - -	dma_addr = 0; -	page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); -	rc = -ENOMEM; -	if (page == NULL) { -		printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); -		goto out; -	} -	rc = -EFAULT; -	if (copy_from_user(page, buf, count)) -		goto out_free; - -	memset(&vsp_cmd, 0, sizeof(vsp_cmd)); -	vsp_cmd.cmd = 30; -	vsp_cmd.sub_data.kern.token = dma_addr; -	vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; -	vsp_cmd.sub_data.kern.side = (u64)dp->data; -	vsp_cmd.sub_data.kern.offset = *ppos; -	vsp_cmd.sub_data.kern.length = count; -	mb(); -	rc = signal_vsp_instruction(&vsp_cmd); -	if (rc) -		goto out_free; -	rc = -ENOMEM; -	if (vsp_cmd.result_code != 0) -		goto out_free; - -	*ppos += count; -	rc = count; -out_free: -	iseries_hv_free(count, page, dma_addr); -out: -	return rc; -} - -static const struct file_operations proc_vmlinux_operations = { -	.write		= proc_mf_change_vmlinux, -	.llseek		= default_llseek, -}; - -static int __init mf_proc_init(void) -{ -	struct proc_dir_entry *mf_proc_root; -	struct proc_dir_entry *ent; -	struct proc_dir_entry *mf; -	char name[2]; -	int i; - -	if (!firmware_has_feature(FW_FEATURE_ISERIES)) -		return 0; - -	mf_proc_root = proc_mkdir("iSeries/mf", NULL); -	if (!mf_proc_root) -		return 1; - -	name[1] = '\0'; -	for (i = 0; i < 4; i++) { -		name[0] = 'A' + i; -		mf = proc_mkdir(name, mf_proc_root); -		if (!mf) -			return 1; - -		ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf, -				       &mf_cmdline_proc_fops, (void *)(long)i); -		if (!ent) -			return 1; - -		if (i == 3)	/* no vmlinux entry for 'D' */ -			continue; - -		ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf, -				       &proc_vmlinux_operations, -				       (void *)(long)i); -		if (!ent) -			return 1; -	} - -	ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, -			  &mf_side_proc_fops); -	if (!ent) -		return 1; - -	ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, -			  &mf_src_proc_fops); -	if (!ent) -		return 1; - -	return 0; -} - -__initcall(mf_proc_init); - -#endif /* CONFIG_PROC_FS */ - -/* - * Get the RTC from the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -void iSeries_get_rtc_time(struct rtc_time *rtc_tm) -{ -	mf_get_rtc(rtc_tm); -	rtc_tm->tm_mon--; -} - -/* - * Set the RTC in the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -int iSeries_set_rtc_time(struct rtc_time *tm) -{ -	mf_set_rtc(tm); -	return 0; -} - -unsigned long iSeries_get_boot_time(void) -{ -	struct rtc_time tm; - -	mf_get_boot_rtc(&tm); -	return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, -		      tm.tm_hour, tm.tm_min, tm.tm_sec); -} diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S deleted file mode 100644 index 2c6ff0fdac9..00000000000 --- a/arch/powerpc/platforms/iseries/misc.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file contains miscellaneous low-level functions. - *    Copyright (C) 1995-2005 IBM Corp - * - * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras. - * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) - * PPC64 updates by Dave Engebretsen (engebret@us.ibm.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. - */ - -#include <asm/processor.h> -#include <asm/asm-offsets.h> -#include <asm/ppc_asm.h> - -	.text - -/* Handle pending interrupts in interrupt context */ -_GLOBAL(iseries_handle_interrupts) -	li	r0,0x5555 -	sc -	blr diff --git a/arch/powerpc/platforms/iseries/naca.h b/arch/powerpc/platforms/iseries/naca.h deleted file mode 100644 index f01708e1286..00000000000 --- a/arch/powerpc/platforms/iseries/naca.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _PLATFORMS_ISERIES_NACA_H -#define _PLATFORMS_ISERIES_NACA_H - -/* - * c 2001 PPC 64 Team, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <asm/types.h> - -struct naca_struct { -	/* Kernel only data - undefined for user space */ -	const void *xItVpdAreas;	/* VPD Data                  0x00 */ -	void *xRamDisk;                 /* iSeries ramdisk           0x08 */ -	u64   xRamDiskSize;		/* In pages                  0x10 */ -}; - -extern struct naca_struct naca; - -#endif /* _PLATFORMS_ISERIES_NACA_H */ diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c deleted file mode 100644 index c7541288462..00000000000 --- a/arch/powerpc/platforms/iseries/pci.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * Copyright (C) 2001 Allan Trautman, IBM Corporation - * Copyright (C) 2005,2007  Stephen Rothwell, IBM Corp - * - * iSeries specific routines for PCI. - * - * Based on code from pci.c and iSeries_pci.c 32bit - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ - -#undef DEBUG - -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/of.h> -#include <linux/ratelimit.h> - -#include <asm/types.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/abs_addr.h> -#include <asm/firmware.h> - -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/iommu.h> - -#include <asm/ppc-pci.h> - -#include "irq.h" -#include "pci.h" -#include "call_pci.h" - -#define PCI_RETRY_MAX	3 -static int limit_pci_retries = 1;	/* Set Retry Error on. */ - -/* - * Table defines - * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. - */ -#define IOMM_TABLE_MAX_ENTRIES	1024 -#define IOMM_TABLE_ENTRY_SIZE	0x0000000000400000UL -#define BASE_IO_MEMORY		0xE000000000000000UL -#define END_IO_MEMORY		0xEFFFFFFFFFFFFFFFUL - -static unsigned long max_io_memory = BASE_IO_MEMORY; -static long current_iomm_table_entry; - -/* - * Lookup Tables. - */ -static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; -static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES]; - -static DEFINE_SPINLOCK(iomm_table_lock); - -/* - * Generate a Direct Select Address for the Hypervisor - */ -static inline u64 iseries_ds_addr(struct device_node *node) -{ -	struct pci_dn *pdn = PCI_DN(node); -	const u32 *sbp = of_get_property(node, "linux,subbus", NULL); - -	return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40) -			+ ((u64)0x10 << 32); -} - -/* - * Size of Bus VPD data - */ -#define BUS_VPDSIZE      1024 - -/* - * Bus Vpd Tags - */ -#define VPD_END_OF_AREA		0x79 -#define VPD_ID_STRING		0x82 -#define VPD_VENDOR_AREA		0x84 - -/* - * Mfg Area Tags - */ -#define VPD_FRU_FRAME_ID	0x4649	/* "FI" */ -#define VPD_SLOT_MAP_FORMAT	0x4D46	/* "MF" */ -#define VPD_SLOT_MAP		0x534D	/* "SM" */ - -/* - * Structures of the areas - */ -struct mfg_vpd_area { -	u16	tag; -	u8	length; -	u8	data1; -	u8	data2; -}; -#define MFG_ENTRY_SIZE   3 - -struct slot_map { -	u8	agent; -	u8	secondary_agent; -	u8	phb; -	char	card_location[3]; -	char	parms[8]; -	char	reserved[2]; -}; -#define SLOT_ENTRY_SIZE   16 - -/* - * Parse the Slot Area - */ -static void __init iseries_parse_slot_area(struct slot_map *map, int len, -		HvAgentId agent, u8 *phb, char card[4]) -{ -	/* -	 * Parse Slot label until we find the one requested -	 */ -	while (len > 0) { -		if (map->agent == agent) { -			/* -			 * If Phb wasn't found, grab the entry first one found. -			 */ -			if (*phb == 0xff) -				*phb = map->phb; -			/* Found it, extract the data. */ -			if (map->phb == *phb) { -				memcpy(card, &map->card_location, 3); -				card[3]  = 0; -				break; -			} -		} -		/* Point to the next Slot */ -		map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE); -		len -= SLOT_ENTRY_SIZE; -	} -} - -/* - * Parse the Mfg Area - */ -static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len, -		HvAgentId agent, u8 *phb, u8 *frame, char card[4]) -{ -	u16 slot_map_fmt = 0; - -	/* Parse Mfg Data */ -	while (len > 0) { -		int mfg_tag_len = area->length; -		/* Frame ID         (FI 4649020310 ) */ -		if (area->tag == VPD_FRU_FRAME_ID) -			*frame = area->data1; -		/* Slot Map Format  (MF 4D46020004 ) */ -		else if (area->tag == VPD_SLOT_MAP_FORMAT) -			slot_map_fmt = (area->data1 * 256) -				+ area->data2; -		/* Slot Map         (SM 534D90 */ -		else if (area->tag == VPD_SLOT_MAP) { -			struct slot_map *slot_map; - -			if (slot_map_fmt == 0x1004) -				slot_map = (struct slot_map *)((char *)area -						+ MFG_ENTRY_SIZE + 1); -			else -				slot_map = (struct slot_map *)((char *)area -						+ MFG_ENTRY_SIZE); -			iseries_parse_slot_area(slot_map, mfg_tag_len, -					agent, phb, card); -		} -		/* -		 * Point to the next Mfg Area -		 * Use defined size, sizeof give wrong answer -		 */ -		area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len -				+ MFG_ENTRY_SIZE); -		len -= (mfg_tag_len + MFG_ENTRY_SIZE); -	} -} - -/* - * Look for "BUS".. Data is not Null terminated. - * PHBID of 0xFF indicates PHB was not found in VPD Data. - */ -static u8 __init iseries_parse_phbid(u8 *area, int len) -{ -	while (len > 0) { -		if ((*area == 'B') && (*(area + 1) == 'U') -				&& (*(area + 2) == 'S')) { -			area += 3; -			while (*area == ' ') -				area++; -			return *area & 0x0F; -		} -		area++; -		len--; -	} -	return 0xff; -} - -/* - * Parse out the VPD Areas - */ -static void __init iseries_parse_vpd(u8 *data, int data_len, -		HvAgentId agent, u8 *frame, char card[4]) -{ -	u8 phb = 0xff; - -	while (data_len > 0) { -		int len; -		u8 tag = *data; - -		if (tag == VPD_END_OF_AREA) -			break; -		len = *(data + 1) + (*(data + 2) * 256); -		data += 3; -		data_len -= 3; -		if (tag == VPD_ID_STRING) -			phb = iseries_parse_phbid(data, len); -		else if (tag == VPD_VENDOR_AREA) -			iseries_parse_mfg_area((struct mfg_vpd_area *)data, len, -					agent, &phb, frame, card); -		/* Point to next Area. */ -		data += len; -		data_len -= len; -	} -} - -static int __init iseries_get_location_code(u16 bus, HvAgentId agent, -		u8 *frame, char card[4]) -{ -	int status = 0; -	int bus_vpd_len = 0; -	u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL); - -	if (bus_vpd == NULL) { -		printk("PCI: Bus VPD Buffer allocation failure.\n"); -		return 0; -	} -	bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd), -					BUS_VPDSIZE); -	if (bus_vpd_len == 0) { -		printk("PCI: Bus VPD Buffer zero length.\n"); -		goto out_free; -	} -	/* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */ -	/* Make sure this is what I think it is */ -	if (*bus_vpd != VPD_ID_STRING) { -		printk("PCI: Bus VPD Buffer missing starting tag.\n"); -		goto out_free; -	} -	iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card); -	status = 1; -out_free: -	kfree(bus_vpd); -	return status; -} - -/* - * Prints the device information. - * - Pass in pci_dev* pointer to the device. - * - Pass in the device count - * - * Format: - * PCI: Bus  0, Device 26, Vendor 0x12AE  Frame  1, Card  C10  Ethernet - * controller - */ -static void __init iseries_device_information(struct pci_dev *pdev, -					      u16 bus, HvSubBusNumber subbus) -{ -	u8 frame = 0; -	char card[4]; -	HvAgentId agent; - -	agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), -			ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); - -	if (iseries_get_location_code(bus, agent, &frame, card)) { -		printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, " -		       "Card %4s  0x%04X\n", pci_name(pdev), pdev->vendor, -		       frame, card, (int)(pdev->class >> 8)); -	} -} - -/* - * iomm_table_allocate_entry - * - * Adds pci_dev entry in address translation table - * - * - Allocates the number of entries required in table base on BAR - *   size. - * - Allocates starting at BASE_IO_MEMORY and increases. - * - The size is round up to be a multiple of entry size. - * - CurrentIndex is incremented to keep track of the last entry. - * - Builds the resource entry for allocated BARs. - */ -static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) -{ -	struct resource *bar_res = &dev->resource[bar_num]; -	long bar_size = pci_resource_len(dev, bar_num); -	struct device_node *dn = pci_device_to_OF_node(dev); - -	/* -	 * No space to allocate, quick exit, skip Allocation. -	 */ -	if (bar_size == 0) -		return; -	/* -	 * Set Resource values. -	 */ -	spin_lock(&iomm_table_lock); -	bar_res->start = BASE_IO_MEMORY + -		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; -	bar_res->end = bar_res->start + bar_size - 1; -	/* -	 * Allocate the number of table entries needed for BAR. -	 */ -	while (bar_size > 0 ) { -		iomm_table[current_iomm_table_entry] = dn; -		ds_addr_table[current_iomm_table_entry] = -			iseries_ds_addr(dn) | (bar_num << 24); -		bar_size -= IOMM_TABLE_ENTRY_SIZE; -		++current_iomm_table_entry; -	} -	max_io_memory = BASE_IO_MEMORY + -		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; -	spin_unlock(&iomm_table_lock); -} - -/* - * allocate_device_bars - * - * - Allocates ALL pci_dev BAR's and updates the resources with the - *   BAR value.  BARS with zero length will have the resources - *   The HvCallPci_getBarParms is used to get the size of the BAR - *   space.  It calls iomm_table_allocate_entry to allocate - *   each entry. - * - Loops through The Bar resources(0 - 5) including the ROM - *   is resource(6). - */ -static void __init allocate_device_bars(struct pci_dev *dev) -{ -	int bar_num; - -	for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) -		iomm_table_allocate_entry(dev, bar_num); -} - -/* - * Log error information to system console. - * Filter out the device not there errors. - * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx - * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx - * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx - */ -static void pci_log_error(char *error, int bus, int subbus, -		int agent, int hv_res) -{ -	if (hv_res == 0x0302) -		return; -	printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", -	       error, bus, subbus, agent, hv_res); -} - -/* - * Look down the chain to find the matching Device Device - */ -static struct device_node *find_device_node(int bus, int devfn) -{ -	struct device_node *node; - -	for (node = NULL; (node = of_find_all_nodes(node)); ) { -		struct pci_dn *pdn = PCI_DN(node); - -		if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn)) -			return node; -	} -	return NULL; -} - -/* - * iSeries_pcibios_fixup_resources - * - * Fixes up all resources for devices - */ -void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev) -{ -	const u32 *agent; -	const u32 *sub_bus; -	unsigned char bus = pdev->bus->number; -	struct device_node *node; -	int i; - -	node = pci_device_to_OF_node(pdev); -	pr_debug("PCI: iSeries %s, pdev %p, node %p\n", -		 pci_name(pdev), pdev, node); -	if (!node) { -		printk("PCI: %s disabled, device tree entry not found !\n", -		       pci_name(pdev)); -		for (i = 0; i <= PCI_ROM_RESOURCE; i++) -			pdev->resource[i].flags = 0; -		return; -	} -	sub_bus = of_get_property(node, "linux,subbus", NULL); -	agent = of_get_property(node, "linux,agent-id", NULL); -	if (agent && sub_bus) { -		u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); -		int err; - -		err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq); -		if (err) -			pci_log_error("Connect Bus Unit", -				      bus, *sub_bus, *agent, err); -		else { -			err = HvCallPci_configStore8(bus, *sub_bus, -					*agent, PCI_INTERRUPT_LINE, irq); -			if (err) -				pci_log_error("PciCfgStore Irq Failed!", -						bus, *sub_bus, *agent, err); -			else -				pdev->irq = irq; -		} -	} - -	allocate_device_bars(pdev); -	if (likely(sub_bus)) -		iseries_device_information(pdev, bus, *sub_bus); -	else -		printk(KERN_ERR "PCI: Device node %s has missing or invalid " -				"linux,subbus property\n", node->full_name); -} - -/* - * iSeries_pci_final_fixup(void) - */ -void __init iSeries_pci_final_fixup(void) -{ -	/* Fix up at the device node and pci_dev relationship */ -	mf_display_src(0xC9000100); -	iSeries_activate_IRQs(); -	mf_display_src(0xC9000200); -} - -/* - * Config space read and write functions. - * For now at least, we look for the device node for the bus and devfn - * that we are asked to access.  It may be possible to translate the devfn - * to a subbus and deviceid more directly. - */ -static u64 hv_cfg_read_func[4]  = { -	HvCallPciConfigLoad8, HvCallPciConfigLoad16, -	HvCallPciConfigLoad32, HvCallPciConfigLoad32 -}; - -static u64 hv_cfg_write_func[4] = { -	HvCallPciConfigStore8, HvCallPciConfigStore16, -	HvCallPciConfigStore32, HvCallPciConfigStore32 -}; - -/* - * Read PCI config space - */ -static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, -		int offset, int size, u32 *val) -{ -	struct device_node *node = find_device_node(bus->number, devfn); -	u64 fn; -	struct HvCallPci_LoadReturn ret; - -	if (node == NULL) -		return PCIBIOS_DEVICE_NOT_FOUND; -	if (offset > 255) { -		*val = ~0; -		return PCIBIOS_BAD_REGISTER_NUMBER; -	} - -	fn = hv_cfg_read_func[(size - 1) & 3]; -	HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0); - -	if (ret.rc != 0) { -		*val = ~0; -		return PCIBIOS_DEVICE_NOT_FOUND;	/* or something */ -	} - -	*val = ret.value; -	return 0; -} - -/* - * Write PCI config space - */ - -static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, -		int offset, int size, u32 val) -{ -	struct device_node *node = find_device_node(bus->number, devfn); -	u64 fn; -	u64 ret; - -	if (node == NULL) -		return PCIBIOS_DEVICE_NOT_FOUND; -	if (offset > 255) -		return PCIBIOS_BAD_REGISTER_NUMBER; - -	fn = hv_cfg_write_func[(size - 1) & 3]; -	ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0); - -	if (ret != 0) -		return PCIBIOS_DEVICE_NOT_FOUND; - -	return 0; -} - -static struct pci_ops iSeries_pci_ops = { -	.read = iSeries_pci_read_config, -	.write = iSeries_pci_write_config -}; - -/* - * Check Return Code - * -> On Failure, print and log information. - *    Increment Retry Count, if exceeds max, panic partition. - * - * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 - * PCI: Device 23.90 ReadL Retry( 1) - * PCI: Device 23.90 ReadL Retry Successful(1) - */ -static int check_return_code(char *type, struct device_node *dn, -		int *retry, u64 ret) -{ -	if (ret != 0)  { -		struct pci_dn *pdn = PCI_DN(dn); - -		(*retry)++; -		printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n", -				type, pdn->busno, pdn->devfn, -				*retry, (int)ret); -		/* -		 * Bump the retry and check for retry count exceeded. -		 * If, Exceeded, panic the system. -		 */ -		if (((*retry) > PCI_RETRY_MAX) && -				(limit_pci_retries > 0)) { -			mf_display_src(0xB6000103); -			panic_timeout = 0; -			panic("PCI: Hardware I/O Error, SRC B6000103, " -					"Automatic Reboot Disabled.\n"); -		} -		return -1;	/* Retry Try */ -	} -	return 0; -} - -/* - * Translate the I/O Address into a device node, bar, and bar offset. - * Note: Make sure the passed variable end up on the stack to avoid - * the exposure of being device global. - */ -static inline struct device_node *xlate_iomm_address( -		const volatile void __iomem *addr, -		u64 *dsaptr, u64 *bar_offset, const char *func) -{ -	unsigned long orig_addr; -	unsigned long base_addr; -	unsigned long ind; -	struct device_node *dn; - -	orig_addr = (unsigned long __force)addr; -	if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) { -		static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10); - -		if (__ratelimit(&ratelimit)) -			printk(KERN_ERR -				"iSeries_%s: invalid access at IO address %p\n", -				func, addr); -		return NULL; -	} -	base_addr = orig_addr - BASE_IO_MEMORY; -	ind = base_addr / IOMM_TABLE_ENTRY_SIZE; -	dn = iomm_table[ind]; - -	if (dn != NULL) { -		*dsaptr = ds_addr_table[ind]; -		*bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE; -	} else -		panic("PCI: Invalid PCI IO address detected!\n"); -	return dn; -} - -/* - * Read MM I/O Instructions for the iSeries - * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal - * else, data is returned in Big Endian format. - */ -static u8 iseries_readb(const volatile void __iomem *addr) -{ -	u64 bar_offset; -	u64 dsa; -	int retry = 0; -	struct HvCallPci_LoadReturn ret; -	struct device_node *dn = -		xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte"); - -	if (dn == NULL) -		return 0xff; -	do { -		HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0); -	} while (check_return_code("RDB", dn, &retry, ret.rc) != 0); - -	return ret.value; -} - -static u16 iseries_readw_be(const volatile void __iomem *addr) -{ -	u64 bar_offset; -	u64 dsa; -	int retry = 0; -	struct HvCallPci_LoadReturn ret; -	struct device_node *dn = -		xlate_iomm_address(addr, &dsa, &bar_offset, "read_word"); - -	if (dn == NULL) -		return 0xffff; -	do { -		HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, -				bar_offset, 0); -	} while (check_return_code("RDW", dn, &retry, ret.rc) != 0); - -	return ret.value; -} - -static u32 iseries_readl_be(const volatile void __iomem *addr) -{ -	u64 bar_offset; -	u64 dsa; -	int retry = 0; -	struct HvCallPci_LoadReturn ret; -	struct device_node *dn = -		xlate_iomm_address(addr, &dsa, &bar_offset, "read_long"); - -	if (dn == NULL) -		return 0xffffffff; -	do { -		HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, -				bar_offset, 0); -	} while (check_return_code("RDL", dn, &retry, ret.rc) != 0); - -	return ret.value; -} - -/* - * Write MM I/O Instructions for the iSeries - * - */ -static void iseries_writeb(u8 data, volatile void __iomem *addr) -{ -	u64 bar_offset; -	u64 dsa; -	int retry = 0; -	u64 rc; -	struct device_node *dn = -		xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte"); - -	if (dn == NULL) -		return; -	do { -		rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0); -	} while (check_return_code("WWB", dn, &retry, rc) != 0); -} - -static void iseries_writew_be(u16 data, volatile void __iomem *addr) -{ -	u64 bar_offset; -	u64 dsa; -	int retry = 0; -	u64 rc; -	struct device_node *dn = -		xlate_iomm_address(addr, &dsa, &bar_offset, "write_word"); - -	if (dn == NULL) -		return; -	do { -		rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0); -	} while (check_return_code("WWW", dn, &retry, rc) != 0); -} - -static void iseries_writel_be(u32 data, volatile void __iomem *addr) -{ -	u64 bar_offset; -	u64 dsa; -	int retry = 0; -	u64 rc; -	struct device_node *dn = -		xlate_iomm_address(addr, &dsa, &bar_offset, "write_long"); - -	if (dn == NULL) -		return; -	do { -		rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0); -	} while (check_return_code("WWL", dn, &retry, rc) != 0); -} - -static u16 iseries_readw(const volatile void __iomem *addr) -{ -	return le16_to_cpu(iseries_readw_be(addr)); -} - -static u32 iseries_readl(const volatile void __iomem *addr) -{ -	return le32_to_cpu(iseries_readl_be(addr)); -} - -static void iseries_writew(u16 data, volatile void __iomem *addr) -{ -	iseries_writew_be(cpu_to_le16(data), addr); -} - -static void iseries_writel(u32 data, volatile void __iomem *addr) -{ -	iseries_writel(cpu_to_le32(data), addr); -} - -static void iseries_readsb(const volatile void __iomem *addr, void *buf, -			   unsigned long count) -{ -	u8 *dst = buf; -	while(count-- > 0) -		*(dst++) = iseries_readb(addr); -} - -static void iseries_readsw(const volatile void __iomem *addr, void *buf, -			   unsigned long count) -{ -	u16 *dst = buf; -	while(count-- > 0) -		*(dst++) = iseries_readw_be(addr); -} - -static void iseries_readsl(const volatile void __iomem *addr, void *buf, -			   unsigned long count) -{ -	u32 *dst = buf; -	while(count-- > 0) -		*(dst++) = iseries_readl_be(addr); -} - -static void iseries_writesb(volatile void __iomem *addr, const void *buf, -			    unsigned long count) -{ -	const u8 *src = buf; -	while(count-- > 0) -		iseries_writeb(*(src++), addr); -} - -static void iseries_writesw(volatile void __iomem *addr, const void *buf, -			    unsigned long count) -{ -	const u16 *src = buf; -	while(count-- > 0) -		iseries_writew_be(*(src++), addr); -} - -static void iseries_writesl(volatile void __iomem *addr, const void *buf, -			    unsigned long count) -{ -	const u32 *src = buf; -	while(count-- > 0) -		iseries_writel_be(*(src++), addr); -} - -static void iseries_memset_io(volatile void __iomem *addr, int c, -			      unsigned long n) -{ -	volatile char __iomem *d = addr; - -	while (n-- > 0) -		iseries_writeb(c, d++); -} - -static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src, -				  unsigned long n) -{ -	char *d = dest; -	const volatile char __iomem *s = src; - -	while (n-- > 0) -		*d++ = iseries_readb(s++); -} - -static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src, -				unsigned long n) -{ -	const char *s = src; -	volatile char __iomem *d = dest; - -	while (n-- > 0) -		iseries_writeb(*s++, d++); -} - -/* We only set MMIO ops. The default PIO ops will be default - * to the MMIO ops + pci_io_base which is 0 on iSeries as - * expected so both should work. - * - * Note that we don't implement the readq/writeq versions as - * I don't know of an HV call for doing so. Thus, the default - * operation will be used instead, which will fault a the value - * return by iSeries for MMIO addresses always hits a non mapped - * area. This is as good as the BUG() we used to have there. - */ -static struct ppc_pci_io __initdata iseries_pci_io = { -	.readb = iseries_readb, -	.readw = iseries_readw, -	.readl = iseries_readl, -	.readw_be = iseries_readw_be, -	.readl_be = iseries_readl_be, -	.writeb = iseries_writeb, -	.writew = iseries_writew, -	.writel = iseries_writel, -	.writew_be = iseries_writew_be, -	.writel_be = iseries_writel_be, -	.readsb = iseries_readsb, -	.readsw = iseries_readsw, -	.readsl = iseries_readsl, -	.writesb = iseries_writesb, -	.writesw = iseries_writesw, -	.writesl = iseries_writesl, -	.memset_io = iseries_memset_io, -	.memcpy_fromio = iseries_memcpy_fromio, -	.memcpy_toio = iseries_memcpy_toio, -}; - -/* - * iSeries_pcibios_init - * - * Description: - *   This function checks for all possible system PCI host bridges that connect - *   PCI buses.  The system hypervisor is queried as to the guest partition - *   ownership status.  A pci_controller is built for any bus which is partially - *   owned or fully owned by this guest partition. - */ -void __init iSeries_pcibios_init(void) -{ -	struct pci_controller *phb; -	struct device_node *root = of_find_node_by_path("/"); -	struct device_node *node = NULL; - -	/* Install IO hooks */ -	ppc_pci_io = iseries_pci_io; - -	pci_probe_only = 1; - -	/* iSeries has no IO space in the common sense, it needs to set -	 * the IO base to 0 -	 */ -	pci_io_base = 0; - -	if (root == NULL) { -		printk(KERN_CRIT "iSeries_pcibios_init: can't find root " -				"of device tree\n"); -		return; -	} -	while ((node = of_get_next_child(root, node)) != NULL) { -		HvBusNumber bus; -		const u32 *busp; - -		if ((node->type == NULL) || (strcmp(node->type, "pci") != 0)) -			continue; - -		busp = of_get_property(node, "bus-range", NULL); -		if (busp == NULL) -			continue; -		bus = *busp; -		printk("bus %d appears to exist\n", bus); -		phb = pcibios_alloc_controller(node); -		if (phb == NULL) -			continue; -		/* All legacy iSeries PHBs are in domain zero */ -		phb->global_number = 0; - -		phb->first_busno = bus; -		phb->last_busno = bus; -		phb->ops = &iSeries_pci_ops; -		phb->io_base_virt = (void __iomem *)_IO_BASE; -		phb->io_resource.flags = IORESOURCE_IO; -		phb->io_resource.start = BASE_IO_MEMORY; -		phb->io_resource.end = END_IO_MEMORY; -		phb->io_resource.name = "iSeries PCI IO"; -		phb->mem_resources[0].flags = IORESOURCE_MEM; -		phb->mem_resources[0].start = BASE_IO_MEMORY; -		phb->mem_resources[0].end = END_IO_MEMORY; -		phb->mem_resources[0].name = "Series PCI MEM"; -	} - -	of_node_put(root); - -	pci_devs_phb_init(); -} - diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h deleted file mode 100644 index d9cf974c271..00000000000 --- a/arch/powerpc/platforms/iseries/pci.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _PLATFORMS_ISERIES_PCI_H -#define _PLATFORMS_ISERIES_PCI_H - -/* - * Created by Allan Trautman on Tue Feb 20, 2001. - * - * Define some useful macros for the iSeries pci routines. - * Copyright (C) 2001  Allan H Trautman, IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, - * Boston, MA  02111-1307  USA - * - * Change Activity: - *   Created Feb 20, 2001 - *   Added device reset, March 22, 2001 - *   Ported to ppc64, May 25, 2001 - * End Change Activity - */ - -/* - * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. - * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h - */ - -#define ISERIES_PCI_AGENTID(idsel, func)	\ -	(((idsel & 0x0F) << 4) | (func & 0x07)) -#define ISERIES_ENCODE_DEVICE(agentid)		\ -	((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07)) - -#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus)		((subbus >> 5) & 0x7) -#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)	((subbus >> 2) & 0x7) - -struct pci_dev; - -#ifdef CONFIG_PCI -extern void	iSeries_pcibios_init(void); -extern void	iSeries_pci_final_fixup(void); -extern void 	iSeries_pcibios_fixup_resources(struct pci_dev *dev); -#else -static inline void	iSeries_pcibios_init(void) { } -static inline void	iSeries_pci_final_fixup(void) { } -static inline void 	iSeries_pcibios_fixup_resources(struct pci_dev *dev) {} -#endif - -#endif /* _PLATFORMS_ISERIES_PCI_H */ diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c deleted file mode 100644 index 06763682db4..00000000000 --- a/arch/powerpc/platforms/iseries/proc.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2001  Kyle A. Lucke IBM Corporation - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/param.h>		/* for HZ */ -#include <asm/paca.h> -#include <asm/processor.h> -#include <asm/time.h> -#include <asm/lppaca.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_call_xm.h> - -#include "processor_vpd.h" -#include "main_store.h" - -static int __init iseries_proc_create(void) -{ -	struct proc_dir_entry *e; - -	if (!firmware_has_feature(FW_FEATURE_ISERIES)) -		return 0; - -	e = proc_mkdir("iSeries", 0); -	if (!e) -		return 1; - -	return 0; -} -core_initcall(iseries_proc_create); - -static unsigned long startTitan = 0; -static unsigned long startTb = 0; - -static int proc_titantod_show(struct seq_file *m, void *v) -{ -	unsigned long tb0, titan_tod; - -	tb0 = get_tb(); -	titan_tod = HvCallXm_loadTod(); - -	seq_printf(m, "Titan\n" ); -	seq_printf(m, "  time base =          %016lx\n", tb0); -	seq_printf(m, "  titan tod =          %016lx\n", titan_tod); -	seq_printf(m, "  xProcFreq =          %016x\n", -		   xIoHriProcessorVpd[0].xProcFreq); -	seq_printf(m, "  xTimeBaseFreq =      %016x\n", -		   xIoHriProcessorVpd[0].xTimeBaseFreq); -	seq_printf(m, "  tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy); -	seq_printf(m, "  tb_ticks_per_usec  = %lu\n", tb_ticks_per_usec); - -	if (!startTitan) { -		startTitan = titan_tod; -		startTb = tb0; -	} else { -		unsigned long titan_usec = (titan_tod - startTitan) >> 12; -		unsigned long tb_ticks = (tb0 - startTb); -		unsigned long titan_jiffies = titan_usec / (1000000/HZ); -		unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ); -		unsigned long titan_jiff_rem_usec = -			titan_usec - titan_jiff_usec; -		unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy; -		unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy; -		unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks; -		unsigned long tb_jiff_rem_usec = -			tb_jiff_rem_ticks / tb_ticks_per_usec; -		unsigned long new_tb_ticks_per_jiffy = -			(tb_ticks * (1000000/HZ))/titan_usec; - -		seq_printf(m, "  titan elapsed = %lu uSec\n", titan_usec); -		seq_printf(m, "  tb elapsed    = %lu ticks\n", tb_ticks); -		seq_printf(m, "  titan jiffies = %lu.%04lu\n", titan_jiffies, -			   titan_jiff_rem_usec); -		seq_printf(m, "  tb jiffies    = %lu.%04lu\n", tb_jiffies, -			   tb_jiff_rem_usec); -		seq_printf(m, "  new tb_ticks_per_jiffy = %lu\n", -			   new_tb_ticks_per_jiffy); -	} - -	return 0; -} - -static int proc_titantod_open(struct inode *inode, struct file *file) -{ -	return single_open(file, proc_titantod_show, NULL); -} - -static const struct file_operations proc_titantod_operations = { -	.open		= proc_titantod_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -}; - -static int __init iseries_proc_init(void) -{ -	if (!firmware_has_feature(FW_FEATURE_ISERIES)) -		return 0; - -	proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL, -		    &proc_titantod_operations); -	return 0; -} -__initcall(iseries_proc_init); diff --git a/arch/powerpc/platforms/iseries/processor_vpd.h b/arch/powerpc/platforms/iseries/processor_vpd.h deleted file mode 100644 index 7ac5d0d0dbf..00000000000 --- a/arch/powerpc/platforms/iseries/processor_vpd.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _ISERIES_PROCESSOR_VPD_H -#define _ISERIES_PROCESSOR_VPD_H - -#include <asm/types.h> - -/* - * This struct maps Processor Vpd that is DMAd to SLIC by CSP - */ -struct IoHriProcessorVpd { -	u8	xFormat;		// VPD format indicator		x00-x00 -	u8	xProcStatus:8;		// Processor State		x01-x01 -	u8	xSecondaryThreadCount;	// Secondary thread cnt		x02-x02 -	u8	xSrcType:1;		// Src Type			x03-x03 -	u8	xSrcSoft:1;		// Src stay soft		... -	u8	xSrcParable:1;		// Src parable			... -	u8	xRsvd1:5;		// Reserved			... -	u16	xHvPhysicalProcIndex;	// Hypervisor physical proc index04-x05 -	u16	xRsvd2;			// Reserved			x06-x07 -	u32	xHwNodeId;		// Hardware node id		x08-x0B -	u32	xHwProcId;		// Hardware processor id	x0C-x0F - -	u32	xTypeNum;		// Card Type/CCIN number	x10-x13 -	u32	xModelNum;		// Model/Feature number		x14-x17 -	u64	xSerialNum;		// Serial number		x18-x1F -	char	xPartNum[12];		// Book Part or FPU number	x20-x2B -	char	xMfgID[4];		// Manufacturing ID		x2C-x2F - -	u32	xProcFreq;		// Processor Frequency		x30-x33 -	u32	xTimeBaseFreq;		// Time Base Frequency		x34-x37 - -	u32	xChipEcLevel;		// Chip EC Levels		x38-x3B -	u32	xProcIdReg;		// PIR SPR value		x3C-x3F -	u32	xPVR;			// PVR value			x40-x43 -	u8	xRsvd3[12];		// Reserved			x44-x4F - -	u32	xInstCacheSize;		// Instruction cache size in KB	x50-x53 -	u32	xInstBlockSize;		// Instruction cache block size	x54-x57 -	u32	xDataCacheOperandSize;	// Data cache operand size	x58-x5B -	u32	xInstCacheOperandSize;	// Inst cache operand size	x5C-x5F - -	u32	xDataL1CacheSizeKB;	// L1 data cache size in KB	x60-x63 -	u32	xDataL1CacheLineSize;	// L1 data cache block size	x64-x67 -	u64	xRsvd4;			// Reserved			x68-x6F - -	u32	xDataL2CacheSizeKB;	// L2 data cache size in KB	x70-x73 -	u32	xDataL2CacheLineSize;	// L2 data cache block size	x74-x77 -	u64	xRsvd5;			// Reserved			x78-x7F - -	u32	xDataL3CacheSizeKB;	// L3 data cache size in KB	x80-x83 -	u32	xDataL3CacheLineSize;	// L3 data cache block size	x84-x87 -	u64	xRsvd6;			// Reserved			x88-x8F - -	u64	xFruLabel;		// Card Location Label		x90-x97 -	u8	xSlotsOnCard;		// Slots on card (0=no slots)	x98-x98 -	u8	xPartLocFlag;		// Location flag (0-pluggable 1-imbedded) x99-x99 -	u16	xSlotMapIndex;		// Index in slot map table	x9A-x9B -	u8	xSmartCardPortNo;	// Smart card port number	x9C-x9C -	u8	xRsvd7;			// Reserved			x9D-x9D -	u16	xFrameIdAndRackUnit;	// Frame ID and rack unit adr	x9E-x9F - -	u8	xRsvd8[24];		// Reserved			xA0-xB7 - -	char	xProcSrc[72];		// CSP format SRC		xB8-xFF -}; - -extern struct IoHriProcessorVpd	xIoHriProcessorVpd[]; - -#endif /* _ISERIES_PROCESSOR_VPD_H */ diff --git a/arch/powerpc/platforms/iseries/release_data.h b/arch/powerpc/platforms/iseries/release_data.h deleted file mode 100644 index 6ad7d843e8f..00000000000 --- a/arch/powerpc/platforms/iseries/release_data.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _ISERIES_RELEASE_DATA_H -#define _ISERIES_RELEASE_DATA_H - -/* - * This control block contains the critical information about the - * release so that it can be changed in the future (ie, the virtual - * address of the OS's NACA). - */ -#include <asm/types.h> -#include "naca.h" - -/* - * When we IPL a secondary partition, we will check if if the - * secondary xMinPlicVrmIndex > the primary xVrmIndex. - * If it is then this tells PLIC that this secondary is not - * supported running on this "old" of a level of PLIC. - * - * Likewise, we will compare the primary xMinSlicVrmIndex to - * the secondary xVrmIndex. - * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we - * know that this PLIC does not support running an OS "that old". - */ - -#define	HVREL_TAGSINACTIVE	0x8000 -#define HVREL_32BIT		0x4000 -#define HVREL_NOSHAREDPROCS	0x2000 -#define HVREL_NOHMT		0x1000 - -struct HvReleaseData { -	u32	xDesc;		/* Descriptor "HvRD" ebcdic	x00-x03 */ -	u16	xSize;		/* Size of this control block	x04-x05 */ -	u16	xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */ -	struct  naca_struct	*xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */ -	u32	xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */ -	u32	xRsvd1;		/* Reserved			x14-x17 */ -	u16	xFlags; -	u16	xVrmIndex;	/* VRM Index of OS image	x1A-x1B */ -	u16	xMinSupportedPlicVrmIndex; /* Min PLIC level  (soft) x1C-x1D */ -	u16	xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */ -	char	xVrmName[12];	/* Displayable name		x20-x2B */ -	char	xRsvd3[20];	/* Reserved			x2C-x3F */ -}; - -extern const struct HvReleaseData	hvReleaseData; - -#endif /* _ISERIES_RELEASE_DATA_H */ diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c deleted file mode 100644 index 8fc62586a97..00000000000 --- a/arch/powerpc/platforms/iseries/setup.c +++ /dev/null @@ -1,722 +0,0 @@ -/* - *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - *    Description: - *      Architecture- / platform-specific boot-time initialization code for - *      the IBM iSeries LPAR.  Adapted from original code by Grant Erickson and - *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek - *      <dan@net4x.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. - */ - -#undef DEBUG - -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/export.h> -#include <linux/seq_file.h> -#include <linux/kdev_t.h> -#include <linux/kexec.h> -#include <linux/major.h> -#include <linux/root_dev.h> -#include <linux/kernel.h> -#include <linux/hrtimer.h> -#include <linux/tick.h> - -#include <asm/processor.h> -#include <asm/machdep.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/mmu_context.h> -#include <asm/cputable.h> -#include <asm/sections.h> -#include <asm/iommu.h> -#include <asm/firmware.h> -#include <asm/system.h> -#include <asm/time.h> -#include <asm/paca.h> -#include <asm/cache.h> -#include <asm/abs_addr.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/lpar_map.h> -#include <asm/udbg.h> -#include <asm/irq.h> - -#include "naca.h" -#include "setup.h" -#include "irq.h" -#include "vpd_areas.h" -#include "processor_vpd.h" -#include "it_lp_naca.h" -#include "main_store.h" -#include "call_sm.h" -#include "call_hpt.h" -#include "pci.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* Function Prototypes */ -static unsigned long build_iSeries_Memory_Map(void); -static void iseries_shared_idle(void); -static void iseries_dedicated_idle(void); - - -struct MemoryBlock { -	unsigned long absStart; -	unsigned long absEnd; -	unsigned long logicalStart; -	unsigned long logicalEnd; -}; - -/* - * Process the main store vpd to determine where the holes in memory are - * and return the number of physical blocks and fill in the array of - * block data. - */ -static unsigned long iSeries_process_Condor_mainstore_vpd( -		struct MemoryBlock *mb_array, unsigned long max_entries) -{ -	unsigned long holeFirstChunk, holeSizeChunks; -	unsigned long numMemoryBlocks = 1; -	struct IoHriMainStoreSegment4 *msVpd = -		(struct IoHriMainStoreSegment4 *)xMsVpd; -	unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr; -	unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr; -	unsigned long holeSize = holeEnd - holeStart; - -	printk("Mainstore_VPD: Condor\n"); -	/* -	 * Determine if absolute memory has any -	 * holes so that we can interpret the -	 * access map we get back from the hypervisor -	 * correctly. -	 */ -	mb_array[0].logicalStart = 0; -	mb_array[0].logicalEnd = 0x100000000UL; -	mb_array[0].absStart = 0; -	mb_array[0].absEnd = 0x100000000UL; - -	if (holeSize) { -		numMemoryBlocks = 2; -		holeStart = holeStart & 0x000fffffffffffffUL; -		holeStart = addr_to_chunk(holeStart); -		holeFirstChunk = holeStart; -		holeSize = addr_to_chunk(holeSize); -		holeSizeChunks = holeSize; -		printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n", -				holeFirstChunk, holeSizeChunks ); -		mb_array[0].logicalEnd = holeFirstChunk; -		mb_array[0].absEnd = holeFirstChunk; -		mb_array[1].logicalStart = holeFirstChunk; -		mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks; -		mb_array[1].absStart = holeFirstChunk + holeSizeChunks; -		mb_array[1].absEnd = 0x100000000UL; -	} -	return numMemoryBlocks; -} - -#define MaxSegmentAreas			32 -#define MaxSegmentAdrRangeBlocks	128 -#define MaxAreaRangeBlocks		4 - -static unsigned long iSeries_process_Regatta_mainstore_vpd( -		struct MemoryBlock *mb_array, unsigned long max_entries) -{ -	struct IoHriMainStoreSegment5 *msVpdP = -		(struct IoHriMainStoreSegment5 *)xMsVpd; -	unsigned long numSegmentBlocks = 0; -	u32 existsBits = msVpdP->msAreaExists; -	unsigned long area_num; - -	printk("Mainstore_VPD: Regatta\n"); - -	for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) { -		unsigned long numAreaBlocks; -		struct IoHriMainStoreArea4 *currentArea; - -		if (existsBits & 0x80000000) { -			unsigned long block_num; - -			currentArea = &msVpdP->msAreaArray[area_num]; -			numAreaBlocks = currentArea->numAdrRangeBlocks; -			printk("ms_vpd: processing area %2ld  blocks=%ld", -					area_num, numAreaBlocks); -			for (block_num = 0; block_num < numAreaBlocks; -					++block_num ) { -				/* Process an address range block */ -				struct MemoryBlock tempBlock; -				unsigned long i; - -				tempBlock.absStart = -					(unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart; -				tempBlock.absEnd = -					(unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd; -				tempBlock.logicalStart = 0; -				tempBlock.logicalEnd   = 0; -				printk("\n          block %ld absStart=%016lx absEnd=%016lx", -						block_num, tempBlock.absStart, -						tempBlock.absEnd); - -				for (i = 0; i < numSegmentBlocks; ++i) { -					if (mb_array[i].absStart == -							tempBlock.absStart) -						break; -				} -				if (i == numSegmentBlocks) { -					if (numSegmentBlocks == max_entries) -						panic("iSeries_process_mainstore_vpd: too many memory blocks"); -					mb_array[numSegmentBlocks] = tempBlock; -					++numSegmentBlocks; -				} else -					printk(" (duplicate)"); -			} -			printk("\n"); -		} -		existsBits <<= 1; -	} -	/* Now sort the blocks found into ascending sequence */ -	if (numSegmentBlocks > 1) { -		unsigned long m, n; - -		for (m = 0; m < numSegmentBlocks - 1; ++m) { -			for (n = numSegmentBlocks - 1; m < n; --n) { -				if (mb_array[n].absStart < -						mb_array[n-1].absStart) { -					struct MemoryBlock tempBlock; - -					tempBlock = mb_array[n]; -					mb_array[n] = mb_array[n-1]; -					mb_array[n-1] = tempBlock; -				} -			} -		} -	} -	/* -	 * Assign "logical" addresses to each block.  These -	 * addresses correspond to the hypervisor "bitmap" space. -	 * Convert all addresses into units of 256K chunks. -	 */ -	{ -	unsigned long i, nextBitmapAddress; - -	printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks); -	nextBitmapAddress = 0; -	for (i = 0; i < numSegmentBlocks; ++i) { -		unsigned long length = mb_array[i].absEnd - -			mb_array[i].absStart; - -		mb_array[i].logicalStart = nextBitmapAddress; -		mb_array[i].logicalEnd = nextBitmapAddress + length; -		nextBitmapAddress += length; -		printk("          Bitmap range: %016lx - %016lx\n" -				"        Absolute range: %016lx - %016lx\n", -				mb_array[i].logicalStart, -				mb_array[i].logicalEnd, -				mb_array[i].absStart, mb_array[i].absEnd); -		mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart & -				0x000fffffffffffffUL); -		mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd & -				0x000fffffffffffffUL); -		mb_array[i].logicalStart = -			addr_to_chunk(mb_array[i].logicalStart); -		mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd); -	} -	} - -	return numSegmentBlocks; -} - -static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, -		unsigned long max_entries) -{ -	unsigned long i; -	unsigned long mem_blocks = 0; - -	if (mmu_has_feature(MMU_FTR_SLB)) -		mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, -				max_entries); -	else -		mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array, -				max_entries); - -	printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks); -	for (i = 0; i < mem_blocks; ++i) { -		printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n" -		       "                             abs chunks %016lx - %016lx\n", -			i, mb_array[i].logicalStart, mb_array[i].logicalEnd, -			mb_array[i].absStart, mb_array[i].absEnd); -	} -	return mem_blocks; -} - -static void __init iSeries_get_cmdline(void) -{ -	char *p, *q; - -	/* copy the command line parameter from the primary VSP  */ -	HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, -			HvLpDma_Direction_RemoteToLocal); - -	p = cmd_line; -	q = cmd_line + 255; -	while(p < q) { -		if (!*p || *p == '\n') -			break; -		++p; -	} -	*p = 0; -} - -static void __init iSeries_init_early(void) -{ -	DBG(" -> iSeries_init_early()\n"); - -	/* Snapshot the timebase, for use in later recalibration */ -	iSeries_time_init_early(); - -	/* -	 * Initialize the DMA/TCE management -	 */ -	iommu_init_early_iSeries(); - -	/* Initialize machine-dependency vectors */ -#ifdef CONFIG_SMP -	smp_init_iSeries(); -#endif - -	/* Associate Lp Event Queue 0 with processor 0 */ -	HvCallEvent_setLpEventQueueInterruptProc(0, 0); - -	mf_init(); - -	DBG(" <- iSeries_init_early()\n"); -} - -struct mschunks_map mschunks_map = { -	/* XXX We don't use these, but Piranha might need them. */ -	.chunk_size  = MSCHUNKS_CHUNK_SIZE, -	.chunk_shift = MSCHUNKS_CHUNK_SHIFT, -	.chunk_mask  = MSCHUNKS_OFFSET_MASK, -}; -EXPORT_SYMBOL(mschunks_map); - -static void mschunks_alloc(unsigned long num_chunks) -{ -	klimit = _ALIGN(klimit, sizeof(u32)); -	mschunks_map.mapping = (u32 *)klimit; -	klimit += num_chunks * sizeof(u32); -	mschunks_map.num_chunks = num_chunks; -} - -/* - * The iSeries may have very large memories ( > 128 GB ) and a partition - * may get memory in "chunks" that may be anywhere in the 2**52 real - * address space.  The chunks are 256K in size.  To map this to the - * memory model Linux expects, the AS/400 specific code builds a - * translation table to translate what Linux thinks are "physical" - * addresses to the actual real addresses.  This allows us to make - * it appear to Linux that we have contiguous memory starting at - * physical address zero while in fact this could be far from the truth. - * To avoid confusion, I'll let the words physical and/or real address - * apply to the Linux addresses while I'll use "absolute address" to - * refer to the actual hardware real address. - * - * build_iSeries_Memory_Map gets information from the Hypervisor and - * looks at the Main Store VPD to determine the absolute addresses - * of the memory that has been assigned to our partition and builds - * a table used to translate Linux's physical addresses to these - * absolute addresses.  Absolute addresses are needed when - * communicating with the hypervisor (e.g. to build HPT entries) - * - * Returns the physical memory size - */ - -static unsigned long __init build_iSeries_Memory_Map(void) -{ -	u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; -	u32 nextPhysChunk; -	u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; -	u32 totalChunks,moreChunks; -	u32 currChunk, thisChunk, absChunk; -	u32 currDword; -	u32 chunkBit; -	u64 map; -	struct MemoryBlock mb[32]; -	unsigned long numMemoryBlocks, curBlock; - -	/* Chunk size on iSeries is 256K bytes */ -	totalChunks = (u32)HvLpConfig_getMsChunks(); -	mschunks_alloc(totalChunks); - -	/* -	 * Get absolute address of our load area -	 * and map it to physical address 0 -	 * This guarantees that the loadarea ends up at physical 0 -	 * otherwise, it might not be returned by PLIC as the first -	 * chunks -	 */ - -	loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr); -	loadAreaSize =  itLpNaca.xLoadAreaChunks; - -	/* -	 * Only add the pages already mapped here. -	 * Otherwise we might add the hpt pages -	 * The rest of the pages of the load area -	 * aren't in the HPT yet and can still -	 * be assigned an arbitrary physical address -	 */ -	if ((loadAreaSize * 64) > HvPagesToMap) -		loadAreaSize = HvPagesToMap / 64; - -	loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; - -	/* -	 * TODO Do we need to do something if the HPT is in the 64MB load area? -	 * This would be required if the itLpNaca.xLoadAreaChunks includes -	 * the HPT size -	 */ - -	printk("Mapping load area - physical addr = 0000000000000000\n" -		"                    absolute addr = %016lx\n", -		chunk_to_addr(loadAreaFirstChunk)); -	printk("Load area size %dK\n", loadAreaSize * 256); - -	for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) -		mschunks_map.mapping[nextPhysChunk] = -			loadAreaFirstChunk + nextPhysChunk; - -	/* -	 * Get absolute address of our HPT and remember it so -	 * we won't map it to any physical address -	 */ -	hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); -	hptSizePages = (u32)HvCallHpt_getHptPages(); -	hptSizeChunks = hptSizePages >> -		(MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT); -	hptLastChunk = hptFirstChunk + hptSizeChunks - 1; - -	printk("HPT absolute addr = %016lx, size = %dK\n", -			chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); - -	/* -	 * Determine if absolute memory has any -	 * holes so that we can interpret the -	 * access map we get back from the hypervisor -	 * correctly. -	 */ -	numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32); - -	/* -	 * Process the main store access map from the hypervisor -	 * to build up our physical -> absolute translation table -	 */ -	curBlock = 0; -	currChunk = 0; -	currDword = 0; -	moreChunks = totalChunks; - -	while (moreChunks) { -		map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex, -				currDword); -		thisChunk = currChunk; -		while (map) { -			chunkBit = map >> 63; -			map <<= 1; -			if (chunkBit) { -				--moreChunks; -				while (thisChunk >= mb[curBlock].logicalEnd) { -					++curBlock; -					if (curBlock >= numMemoryBlocks) -						panic("out of memory blocks"); -				} -				if (thisChunk < mb[curBlock].logicalStart) -					panic("memory block error"); - -				absChunk = mb[curBlock].absStart + -					(thisChunk - mb[curBlock].logicalStart); -				if (((absChunk < hptFirstChunk) || -				     (absChunk > hptLastChunk)) && -				    ((absChunk < loadAreaFirstChunk) || -				     (absChunk > loadAreaLastChunk))) { -					mschunks_map.mapping[nextPhysChunk] = -						absChunk; -					++nextPhysChunk; -				} -			} -			++thisChunk; -		} -		++currDword; -		currChunk += 64; -	} - -	/* -	 * main store size (in chunks) is -	 *   totalChunks - hptSizeChunks -	 * which should be equal to -	 *   nextPhysChunk -	 */ -	return chunk_to_addr(nextPhysChunk); -} - -/* - * Document me. - */ -static void __init iSeries_setup_arch(void) -{ -	if (get_lppaca()->shared_proc) { -		ppc_md.idle_loop = iseries_shared_idle; -		printk(KERN_DEBUG "Using shared processor idle loop\n"); -	} else { -		ppc_md.idle_loop = iseries_dedicated_idle; -		printk(KERN_DEBUG "Using dedicated idle loop\n"); -	} - -	/* Setup the Lp Event Queue */ -	setup_hvlpevent_queue(); - -	printk("Max  logical processors = %d\n", -			itVpdAreas.xSlicMaxLogicalProcs); -	printk("Max physical processors = %d\n", -			itVpdAreas.xSlicMaxPhysicalProcs); - -	iSeries_pcibios_init(); -} - -static void iSeries_show_cpuinfo(struct seq_file *m) -{ -	seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n"); -} - -static void __init iSeries_progress(char * st, unsigned short code) -{ -	printk("Progress: [%04x] - %s\n", (unsigned)code, st); -	mf_display_progress(code); -} - -static void __init iSeries_fixup_klimit(void) -{ -	/* -	 * Change klimit to take into account any ram disk -	 * that may be included -	 */ -	if (naca.xRamDisk) -		klimit = KERNELBASE + (u64)naca.xRamDisk + -			(naca.xRamDiskSize * HW_PAGE_SIZE); -} - -static int __init iSeries_src_init(void) -{ -        /* clear the progress line */ -	if (firmware_has_feature(FW_FEATURE_ISERIES)) -		ppc_md.progress(" ", 0xffff); -        return 0; -} - -late_initcall(iSeries_src_init); - -static inline void process_iSeries_events(void) -{ -	asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); -} - -static void yield_shared_processor(void) -{ -	unsigned long tb; - -	HvCall_setEnabledInterrupts(HvCall_MaskIPI | -				    HvCall_MaskLpEvent | -				    HvCall_MaskLpProd | -				    HvCall_MaskTimeout); - -	tb = get_tb(); -	/* Compute future tb value when yield should expire */ -	HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); - -	/* -	 * The decrementer stops during the yield.  Force a fake decrementer -	 * here and let the timer_interrupt code sort out the actual time. -	 */ -	get_lppaca()->int_dword.fields.decr_int = 1; -	ppc64_runlatch_on(); -	process_iSeries_events(); -} - -static void iseries_shared_idle(void) -{ -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		while (!need_resched() && !hvlpevent_is_pending()) { -			local_irq_disable(); -			ppc64_runlatch_off(); - -			/* Recheck with irqs off */ -			if (!need_resched() && !hvlpevent_is_pending()) -				yield_shared_processor(); - -			HMT_medium(); -			local_irq_enable(); -		} - -		ppc64_runlatch_on(); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); - -		if (hvlpevent_is_pending()) -			process_iSeries_events(); - -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -	} -} - -static void iseries_dedicated_idle(void) -{ -	set_thread_flag(TIF_POLLING_NRFLAG); - -	while (1) { -		tick_nohz_idle_enter(); -		rcu_idle_enter(); -		if (!need_resched()) { -			while (!need_resched()) { -				ppc64_runlatch_off(); -				HMT_low(); - -				if (hvlpevent_is_pending()) { -					HMT_medium(); -					ppc64_runlatch_on(); -					process_iSeries_events(); -				} -			} - -			HMT_medium(); -		} - -		ppc64_runlatch_on(); -		rcu_idle_exit(); -		tick_nohz_idle_exit(); -		preempt_enable_no_resched(); -		schedule(); -		preempt_disable(); -	} -} - -static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size, -				     unsigned long flags, void *caller) -{ -	return (void __iomem *)address; -} - -static void iseries_iounmap(volatile void __iomem *token) -{ -} - -static int __init iseries_probe(void) -{ -	unsigned long root = of_get_flat_dt_root(); -	if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) -		return 0; - -	hpte_init_iSeries(); -	/* iSeries does not support 16M pages */ -	cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE; - -	return 1; -} - -#ifdef CONFIG_KEXEC -static int iseries_kexec_prepare(struct kimage *image) -{ -	return -ENOSYS; -} -#endif - -define_machine(iseries) { -	.name			= "iSeries", -	.setup_arch		= iSeries_setup_arch, -	.show_cpuinfo		= iSeries_show_cpuinfo, -	.init_IRQ		= iSeries_init_IRQ, -	.get_irq		= iSeries_get_irq, -	.init_early		= iSeries_init_early, -	.pcibios_fixup		= iSeries_pci_final_fixup, -	.pcibios_fixup_resources= iSeries_pcibios_fixup_resources, -	.restart		= mf_reboot, -	.power_off		= mf_power_off, -	.halt			= mf_power_off, -	.get_boot_time		= iSeries_get_boot_time, -	.set_rtc_time		= iSeries_set_rtc_time, -	.get_rtc_time		= iSeries_get_rtc_time, -	.calibrate_decr		= generic_calibrate_decr, -	.progress		= iSeries_progress, -	.probe			= iseries_probe, -	.ioremap		= iseries_ioremap, -	.iounmap		= iseries_iounmap, -#ifdef CONFIG_KEXEC -	.machine_kexec_prepare	= iseries_kexec_prepare, -#endif -	/* XXX Implement enable_pmcs for iSeries */ -}; - -void * __init iSeries_early_setup(void) -{ -	unsigned long phys_mem_size; - -	/* Identify CPU type. This is done again by the common code later -	 * on but calling this function multiple times is fine. -	 */ -	identify_cpu(0, mfspr(SPRN_PVR)); -	initialise_paca(&boot_paca, 0); - -	powerpc_firmware_features |= FW_FEATURE_ISERIES; -	powerpc_firmware_features |= FW_FEATURE_LPAR; - -#ifdef CONFIG_SMP -	/* On iSeries we know we can never have more than 64 cpus */ -	nr_cpu_ids = max(nr_cpu_ids, 64); -#endif - -	iSeries_fixup_klimit(); - -	/* -	 * Initialize the table which translate Linux physical addresses to -	 * AS/400 absolute addresses -	 */ -	phys_mem_size = build_iSeries_Memory_Map(); - -	iSeries_get_cmdline(); - -	return (void *) __pa(build_flat_dt(phys_mem_size)); -} - -static void hvputc(char c) -{ -	if (c == '\n') -		hvputc('\r'); - -	HvCall_writeLogBuffer(&c, 1); -} - -void __init udbg_init_iseries(void) -{ -	udbg_putc = hvputc; -} diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h deleted file mode 100644 index 729754bbb01..00000000000 --- a/arch/powerpc/platforms/iseries/setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - *    Description: - *      Architecture- / platform-specific boot-time initialization code for - *      the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and - *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek - *      <dan@netx4.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. - */ - -#ifndef	__ISERIES_SETUP_H__ -#define	__ISERIES_SETUP_H__ - -extern void *iSeries_early_setup(void); -extern unsigned long iSeries_get_boot_time(void); -extern int iSeries_set_rtc_time(struct rtc_time *tm); -extern void iSeries_get_rtc_time(struct rtc_time *tm); - -extern void *build_flat_dt(unsigned long phys_mem_size); - -#endif /* __ISERIES_SETUP_H__ */ diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c deleted file mode 100644 index 02df49fb59f..00000000000 --- a/arch/powerpc/platforms/iseries/smp.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SMP support for iSeries machines. - * - * Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com - * - * Plus various changes from other IBM teams... - * - *      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. - */ - -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/cache.h> -#include <linux/err.h> -#include <linux/device.h> -#include <linux/cpu.h> - -#include <asm/ptrace.h> -#include <linux/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/paca.h> -#include <asm/iseries/hv_call.h> -#include <asm/time.h> -#include <asm/machdep.h> -#include <asm/cputable.h> -#include <asm/system.h> - -static void smp_iSeries_cause_ipi(int cpu, unsigned long data) -{ -	HvCall_sendIPI(&(paca[cpu])); -} - -static int smp_iSeries_probe(void) -{ -	return cpumask_weight(cpu_possible_mask); -} - -static int smp_iSeries_kick_cpu(int nr) -{ -	BUG_ON((nr < 0) || (nr >= NR_CPUS)); - -	/* Verify that our partition has a processor nr */ -	if (lppaca_of(nr).dyn_proc_status >= 2) -		return -ENOENT; - -	/* The processor is currently spinning, waiting -	 * for the cpu_start field to become non-zero -	 * After we set cpu_start, the processor will -	 * continue on to secondary_start in iSeries_head.S -	 */ -	paca[nr].cpu_start = 1; - -	return 0; -} - -static void __devinit smp_iSeries_setup_cpu(int nr) -{ -} - -static struct smp_ops_t iSeries_smp_ops = { -	.message_pass = NULL,	/* Use smp_muxed_ipi_message_pass */ -	.cause_ipi    = smp_iSeries_cause_ipi, -	.probe        = smp_iSeries_probe, -	.kick_cpu     = smp_iSeries_kick_cpu, -	.setup_cpu    = smp_iSeries_setup_cpu, -}; - -/* This is called very early. */ -void __init smp_init_iSeries(void) -{ -	smp_ops = &iSeries_smp_ops; -} diff --git a/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h deleted file mode 100644 index 598b7c14573..00000000000 --- a/arch/powerpc/platforms/iseries/spcomm_area.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ - -#ifndef _ISERIES_SPCOMM_AREA_H -#define _ISERIES_SPCOMM_AREA_H - - -struct SpCommArea { -	u32	xDesc;			// Descriptor (only in new formats)	000-003 -	u8	xFormat;		// Format (only in new formats)		004-004 -	u8	xRsvd1[11];		// Reserved				005-00F -	u64	xRawTbAtIplStart;	// Raw HW TB value when IPL is started	010-017 -	u64	xRawTodAtIplStart;	// Raw HW TOD value when IPL is started	018-01F -	u64	xBcdTimeAtIplStart;	// BCD time when IPL is started		020-027 -	u64	xBcdTimeAtOsStart;	// BCD time when OS passed control	028-02F -	u8	xRsvd2[80];		// Reserved				030-07F -}; - -#endif /* _ISERIES_SPCOMM_AREA_H */ diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c deleted file mode 100644 index 04be62d368a..00000000000 --- a/arch/powerpc/platforms/iseries/vio.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Legacy iSeries specific vio initialisation - * that needs to be built in (not a module). - * - * © Copyright 2007 IBM Corporation - *	Author: Stephen Rothwell - *	Some parts collected from various other files - * - * This program is free software;  you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/of.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/completion.h> -#include <linux/proc_fs.h> -#include <linux/export.h> - -#include <asm/firmware.h> -#include <asm/vio.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/iommu.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> - -#define FIRST_VTY	0 -#define NUM_VTYS	1 -#define FIRST_VSCSI	(FIRST_VTY + NUM_VTYS) -#define NUM_VSCSIS	1 -#define FIRST_VLAN	(FIRST_VSCSI + NUM_VSCSIS) -#define NUM_VLANS	HVMAXARCHITECTEDVIRTUALLANS -#define FIRST_VIODASD	(FIRST_VLAN + NUM_VLANS) -#define NUM_VIODASDS	HVMAXARCHITECTEDVIRTUALDISKS -#define FIRST_VIOCD	(FIRST_VIODASD + NUM_VIODASDS) -#define NUM_VIOCDS	HVMAXARCHITECTEDVIRTUALCDROMS -#define FIRST_VIOTAPE	(FIRST_VIOCD + NUM_VIOCDS) -#define NUM_VIOTAPES	HVMAXARCHITECTEDVIRTUALTAPES - -struct vio_waitevent { -	struct completion	com; -	int			rc; -	u16			sub_result; -}; - -struct vio_resource { -	char	rsrcname[10]; -	char	type[4]; -	char	model[3]; -}; - -static struct property *new_property(const char *name, int length, -		const void *value) -{ -	struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, -			GFP_KERNEL); - -	if (!np) -		return NULL; -	np->name = (char *)(np + 1); -	np->value = np->name + strlen(name) + 1; -	strcpy(np->name, name); -	memcpy(np->value, value, length); -	np->length = length; -	return np; -} - -static void free_property(struct property *np) -{ -	kfree(np); -} - -static struct device_node *new_node(const char *path, -		struct device_node *parent) -{ -	struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); - -	if (!np) -		return NULL; -	np->full_name = kstrdup(path, GFP_KERNEL); -	if (!np->full_name) { -		kfree(np); -		return NULL; -	} -	of_node_set_flag(np, OF_DYNAMIC); -	kref_init(&np->kref); -	np->parent = of_node_get(parent); -	return np; -} - -static void free_node(struct device_node *np) -{ -	struct property *next; -	struct property *prop; - -	next = np->properties; -	while (next) { -		prop = next; -		next = prop->next; -		free_property(prop); -	} -	of_node_put(np->parent); -	kfree(np->full_name); -	kfree(np); -} - -static int add_string_property(struct device_node *np, const char *name, -		const char *value) -{ -	struct property *nprop = new_property(name, strlen(value) + 1, value); - -	if (!nprop) -		return 0; -	prom_add_property(np, nprop); -	return 1; -} - -static int add_raw_property(struct device_node *np, const char *name, -		int length, const void *value) -{ -	struct property *nprop = new_property(name, length, value); - -	if (!nprop) -		return 0; -	prom_add_property(np, nprop); -	return 1; -} - -static struct device_node *do_device_node(struct device_node *parent, -		const char *name, u32 reg, u32 unit, const char *type, -		const char *compat, struct vio_resource *res) -{ -	struct device_node *np; -	char path[32]; - -	snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); -	np = new_node(path, parent); -	if (!np) -		return NULL; -	if (!add_string_property(np, "name", name) || -		!add_string_property(np, "device_type", type) || -		!add_string_property(np, "compatible", compat) || -		!add_raw_property(np, "reg", sizeof(reg), ®) || -		!add_raw_property(np, "linux,unit_address", -			sizeof(unit), &unit)) { -		goto node_free; -	} -	if (res) { -		if (!add_raw_property(np, "linux,vio_rsrcname", -				sizeof(res->rsrcname), res->rsrcname) || -			!add_raw_property(np, "linux,vio_type", -				sizeof(res->type), res->type) || -			!add_raw_property(np, "linux,vio_model", -				sizeof(res->model), res->model)) -			goto node_free; -	} -	np->name = of_get_property(np, "name", NULL); -	np->type = of_get_property(np, "device_type", NULL); -	of_attach_node(np); -#ifdef CONFIG_PROC_DEVICETREE -	if (parent->pde) { -		struct proc_dir_entry *ent; - -		ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); -		if (ent) -			proc_device_tree_add_node(np, ent); -	} -#endif -	return np; - - node_free: -	free_node(np); -	return NULL; -} - -/* - * This is here so that we can dynamically add viodasd - * devices without exposing all the above infrastructure. - */ -struct vio_dev *vio_create_viodasd(u32 unit) -{ -	struct device_node *vio_root; -	struct device_node *np; -	struct vio_dev *vdev = NULL; - -	vio_root = of_find_node_by_path("/vdevice"); -	if (!vio_root) -		return NULL; -	np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, -			"block", "IBM,iSeries-viodasd", NULL); -	of_node_put(vio_root); -	if (np) { -		vdev = vio_register_device_node(np); -		if (!vdev) -			free_node(np); -	} -	return vdev; -} -EXPORT_SYMBOL_GPL(vio_create_viodasd); - -static void __init handle_block_event(struct HvLpEvent *event) -{ -	struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; -	struct vio_waitevent *pwe; - -	if (event == NULL) -		/* Notification that a partition went away! */ -		return; -	/* First, we should NEVER get an int here...only acks */ -	if (hvlpevent_is_int(event)) { -		printk(KERN_WARNING "handle_viod_request: " -		       "Yikes! got an int in viodasd event handler!\n"); -		if (hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -		return; -	} - -	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { -	case vioblockopen: -		/* -		 * Handle a response to an open request.  We get all the -		 * disk information in the response, so update it.  The -		 * correlation token contains a pointer to a waitevent -		 * structure that has a completion in it.  update the -		 * return code in the waitevent structure and post the -		 * completion to wake up the guy who sent the request -		 */ -		pwe = (struct vio_waitevent *)event->xCorrelationToken; -		pwe->rc = event->xRc; -		pwe->sub_result = bevent->sub_result; -		complete(&pwe->com); -		break; -	case vioblockclose: -		break; -	default: -		printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); -		if (hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -	} -} - -static void __init probe_disk(struct device_node *vio_root, u32 unit) -{ -	HvLpEvent_Rc hvrc; -	struct vio_waitevent we; -	u16 flags = 0; - -retry: -	init_completion(&we.com); - -	/* Send the open event to OS/400 */ -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_blockio | vioblockopen, -			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)(unsigned long)&we, VIOVERSION << 16, -			((u64)unit << 48) | ((u64)flags<< 32), -			0, 0, 0); -	if (hvrc != 0) { -		printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", -			(int)hvrc); -		return; -	} - -	wait_for_completion(&we.com); - -	if (we.rc != 0) { -		if (flags != 0) -			return; -		/* try again with read only flag set */ -		flags = vioblockflags_ro; -		goto retry; -	} - -	/* Send the close event to OS/400.  We DON'T expect a response */ -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_blockio | vioblockclose, -			HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			0, VIOVERSION << 16, -			((u64)unit << 48) | ((u64)flags << 32), -			0, 0, 0); -	if (hvrc != 0) { -		printk(KERN_WARNING "probe_disk: " -		       "bad rc sending event to OS/400 %d\n", (int)hvrc); -		return; -	} - -	do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, -			"block", "IBM,iSeries-viodasd", NULL); -} - -static void __init get_viodasd_info(struct device_node *vio_root) -{ -	int rc; -	u32 unit; - -	rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); -	if (rc) { -		printk(KERN_WARNING "get_viodasd_info: " -		       "error opening path to host partition %d\n", -		       viopath_hostLp); -		return; -	} - -	/* Initialize our request handler */ -	vio_setHandler(viomajorsubtype_blockio, handle_block_event); - -	for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) -		probe_disk(vio_root, unit); - -	vio_clearHandler(viomajorsubtype_blockio); -	viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); -} - -static void __init handle_cd_event(struct HvLpEvent *event) -{ -	struct viocdlpevent *bevent; -	struct vio_waitevent *pwe; - -	if (!event) -		/* Notification that a partition went away! */ -		return; - -	/* First, we should NEVER get an int here...only acks */ -	if (hvlpevent_is_int(event)) { -		printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); -		if (hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -		return; -	} - -	bevent = (struct viocdlpevent *)event; - -	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { -	case viocdgetinfo: -		pwe = (struct vio_waitevent *)event->xCorrelationToken; -		pwe->rc = event->xRc; -		pwe->sub_result = bevent->sub_result; -		complete(&pwe->com); -		break; - -	default: -		printk(KERN_WARNING "handle_cd_event: " -			"message with unexpected subtype %0x04X!\n", -			event->xSubtype & VIOMINOR_SUBTYPE_MASK); -		if (hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -	} -} - -static void __init get_viocd_info(struct device_node *vio_root) -{ -	HvLpEvent_Rc hvrc; -	u32 unit; -	struct vio_waitevent we; -	struct vio_resource *unitinfo; -	dma_addr_t unitinfo_dmaaddr; -	int ret; - -	ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); -	if (ret) { -		printk(KERN_WARNING -			"get_viocd_info: error opening path to host partition %d\n", -			viopath_hostLp); -		return; -	} - -	/* Initialize our request handler */ -	vio_setHandler(viomajorsubtype_cdio, handle_cd_event); - -	unitinfo = iseries_hv_alloc( -			sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, -			&unitinfo_dmaaddr, GFP_ATOMIC); -	if (!unitinfo) { -		printk(KERN_WARNING -			"get_viocd_info: error allocating unitinfo\n"); -		goto clear_handler; -	} - -	memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); - -	init_completion(&we.com); - -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_cdio | viocdgetinfo, -			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, -			sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); -	if (hvrc != HvLpEvent_Rc_Good) { -		printk(KERN_WARNING -			"get_viocd_info: cdrom error sending event. rc %d\n", -			(int)hvrc); -		goto hv_free; -	} - -	wait_for_completion(&we.com); - -	if (we.rc) { -		printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", -			we.rc, we.sub_result); -		goto hv_free; -	} - -	for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && -			unitinfo[unit].rsrcname[0]; unit++) { -		if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, -				"block", "IBM,iSeries-viocd", &unitinfo[unit])) -			break; -	} - - hv_free: -	iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, -			unitinfo, unitinfo_dmaaddr); - clear_handler: -	vio_clearHandler(viomajorsubtype_cdio); -	viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); -} - -/* Handle interrupt events for tape */ -static void __init handle_tape_event(struct HvLpEvent *event) -{ -	struct vio_waitevent *we; -	struct viotapelpevent *tevent = (struct viotapelpevent *)event; - -	if (event == NULL) -		/* Notification that a partition went away! */ -		return; - -	we = (struct vio_waitevent *)event->xCorrelationToken; -	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { -	case viotapegetinfo: -		we->rc = tevent->sub_type_result; -		complete(&we->com); -		break; -	default: -		printk(KERN_WARNING "handle_tape_event: weird ack\n"); -	} -} - -static void __init get_viotape_info(struct device_node *vio_root) -{ -	HvLpEvent_Rc hvrc; -	u32 unit; -	struct vio_resource *unitinfo; -	dma_addr_t unitinfo_dmaaddr; -	size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES; -	struct vio_waitevent we; -	int ret; - -	init_completion(&we.com); - -	ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); -	if (ret) { -		printk(KERN_WARNING "get_viotape_info: " -			"error on viopath_open to hostlp %d\n", ret); -		return; -	} - -	vio_setHandler(viomajorsubtype_tape, handle_tape_event); - -	unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC); -	if (!unitinfo) -		goto clear_handler; - -	memset(unitinfo, 0, len); - -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_tape | viotapegetinfo, -			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)(unsigned long)&we, VIOVERSION << 16, -			unitinfo_dmaaddr, len, 0, 0); -	if (hvrc != HvLpEvent_Rc_Good) { -		printk(KERN_WARNING "get_viotape_info: hv error on op %d\n", -				(int)hvrc); -		goto hv_free; -	} - -	wait_for_completion(&we.com); - -	for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && -			unitinfo[unit].rsrcname[0]; unit++) { -		if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, -				unit, "byte", "IBM,iSeries-viotape", -				&unitinfo[unit])) -			break; -	} - - hv_free: -	iseries_hv_free(len, unitinfo, unitinfo_dmaaddr); - clear_handler: -	vio_clearHandler(viomajorsubtype_tape); -	viopath_close(viopath_hostLp, viomajorsubtype_tape, 2); -} - -static int __init iseries_vio_init(void) -{ -	struct device_node *vio_root; -	int ret = -ENODEV; - -	if (!firmware_has_feature(FW_FEATURE_ISERIES)) -		goto out; - -	iommu_vio_init(); - -	vio_root = of_find_node_by_path("/vdevice"); -	if (!vio_root) -		goto out; - -	if (viopath_hostLp == HvLpIndexInvalid) { -		vio_set_hostlp(); -		/* If we don't have a host, bail out */ -		if (viopath_hostLp == HvLpIndexInvalid) -			goto put_node; -	} - -	get_viodasd_info(vio_root); -	get_viocd_info(vio_root); -	get_viotape_info(vio_root); - -	ret = 0; - - put_node: -	of_node_put(vio_root); - out: -	return ret; -} -arch_initcall(iseries_vio_init); diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c deleted file mode 100644 index 40dad0840eb..00000000000 --- a/arch/powerpc/platforms/iseries/viopath.c +++ /dev/null @@ -1,677 +0,0 @@ -/* -*- linux-c -*- - * - *  iSeries Virtual I/O Message Path code - * - *  Authors: Dave Boutcher <boutcher@us.ibm.com> - *           Ryan Arnold <ryanarn@us.ibm.com> - *           Colin Devilbiss <devilbis@us.ibm.com> - * - * (C) Copyright 2000-2005 IBM Corporation - * - * This code is used by the iSeries virtual disk, cd, - * tape, and console to communicate with OS/400 in another - * partition. - * - * 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) anyu later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#include <linux/export.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/vmalloc.h> -#include <linux/string.h> -#include <linux/proc_fs.h> -#include <linux/dma-mapping.h> -#include <linux/wait.h> -#include <linux/seq_file.h> -#include <linux/interrupt.h> -#include <linux/completion.h> - -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/prom.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/vio.h> - -/* Status of the path to each other partition in the system. - * This is overkill, since we will only ever establish connections - * to our hosting partition and the primary partition on the system. - * But this allows for other support in the future. - */ -static struct viopathStatus { -	int isOpen;		/* Did we open the path?            */ -	int isActive;		/* Do we have a mon msg outstanding */ -	int users[VIO_MAX_SUBTYPES]; -	HvLpInstanceId mSourceInst; -	HvLpInstanceId mTargetInst; -	int numberAllocated; -} viopathStatus[HVMAXARCHITECTEDLPS]; - -static DEFINE_SPINLOCK(statuslock); - -/* - * For each kind of event we allocate a buffer that is - * guaranteed not to cross a page boundary - */ -static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256] -	__attribute__((__aligned__(4096))); -static atomic_t event_buffer_available[VIO_MAX_SUBTYPES]; -static int event_buffer_initialised; - -static void handleMonitorEvent(struct HvLpEvent *event); - -/* - * We use this structure to handle asynchronous responses.  The caller - * blocks on the semaphore and the handler posts the semaphore.  However, - * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ... - */ -struct alloc_parms { -	struct completion done; -	int number; -	atomic_t wait_atomic; -	int used_wait_atomic; -}; - -/* Put a sequence number in each mon msg.  The value is not - * important.  Start at something other than 0 just for - * readability.  wrapping this is ok. - */ -static u8 viomonseq = 22; - -/* Our hosting logical partition.  We get this at startup - * time, and different modules access this variable directly. - */ -HvLpIndex viopath_hostLp = HvLpIndexInvalid; -EXPORT_SYMBOL(viopath_hostLp); -HvLpIndex viopath_ourLp = HvLpIndexInvalid; -EXPORT_SYMBOL(viopath_ourLp); - -/* For each kind of incoming event we set a pointer to a - * routine to call. - */ -static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES]; - -#define VIOPATH_KERN_WARN	KERN_WARNING "viopath: " -#define VIOPATH_KERN_INFO	KERN_INFO "viopath: " - -static int proc_viopath_show(struct seq_file *m, void *v) -{ -	char *buf; -	u16 vlanMap; -	dma_addr_t handle; -	HvLpEvent_Rc hvrc; -	DECLARE_COMPLETION_ONSTACK(done); -	struct device_node *node; -	const char *sysid; - -	buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL); -	if (!buf) -		return 0; - -	handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); - -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_config | vioconfigget, -			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)(unsigned long)&done, VIOVERSION << 16, -			((u64)handle) << 32, HW_PAGE_SIZE, 0, 0); - -	if (hvrc != HvLpEvent_Rc_Good) -		printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc); - -	wait_for_completion(&done); - -	vlanMap = HvLpConfig_getVirtualLanIndexMap(); - -	buf[HW_PAGE_SIZE-1] = '\0'; -	seq_printf(m, "%s", buf); - -	iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); -	kfree(buf); - -	seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); - -	node = of_find_node_by_path("/"); -	sysid = NULL; -	if (node != NULL) -		sysid = of_get_property(node, "system-id", NULL); - -	if (sysid == NULL) -		seq_printf(m, "SRLNBR=<UNKNOWN>\n"); -	else -		/* Skip "IBM," on front of serial number, see dt.c */ -		seq_printf(m, "SRLNBR=%s\n", sysid + 4); - -	of_node_put(node); - -	return 0; -} - -static int proc_viopath_open(struct inode *inode, struct file *file) -{ -	return single_open(file, proc_viopath_show, NULL); -} - -static const struct file_operations proc_viopath_operations = { -	.open		= proc_viopath_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -}; - -static int __init vio_proc_init(void) -{ -	if (!firmware_has_feature(FW_FEATURE_ISERIES)) -		return 0; - -	proc_create("iSeries/config", 0, NULL, &proc_viopath_operations); -        return 0; -} -__initcall(vio_proc_init); - -/* See if a given LP is active.  Allow for invalid lps to be passed in - * and just return invalid - */ -int viopath_isactive(HvLpIndex lp) -{ -	if (lp == HvLpIndexInvalid) -		return 0; -	if (lp < HVMAXARCHITECTEDLPS) -		return viopathStatus[lp].isActive; -	else -		return 0; -} -EXPORT_SYMBOL(viopath_isactive); - -/* - * We cache the source and target instance ids for each - * partition. - */ -HvLpInstanceId viopath_sourceinst(HvLpIndex lp) -{ -	return viopathStatus[lp].mSourceInst; -} -EXPORT_SYMBOL(viopath_sourceinst); - -HvLpInstanceId viopath_targetinst(HvLpIndex lp) -{ -	return viopathStatus[lp].mTargetInst; -} -EXPORT_SYMBOL(viopath_targetinst); - -/* - * Send a monitor message.  This is a message with the acknowledge - * bit on that the other side will NOT explicitly acknowledge.  When - * the other side goes down, the hypervisor will acknowledge any - * outstanding messages....so we will know when the other side dies. - */ -static void sendMonMsg(HvLpIndex remoteLp) -{ -	HvLpEvent_Rc hvrc; - -	viopathStatus[remoteLp].mSourceInst = -		HvCallEvent_getSourceLpInstanceId(remoteLp, -				HvLpEvent_Type_VirtualIo); -	viopathStatus[remoteLp].mTargetInst = -		HvCallEvent_getTargetLpInstanceId(remoteLp, -				HvLpEvent_Type_VirtualIo); - -	/* -	 * Deliberately ignore the return code here.  if we call this -	 * more than once, we don't care. -	 */ -	vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent); - -	hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, -			viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck, -			HvLpEvent_AckType_DeferredAck, -			viopathStatus[remoteLp].mSourceInst, -			viopathStatus[remoteLp].mTargetInst, -			viomonseq++, 0, 0, 0, 0, 0); - -	if (hvrc == HvLpEvent_Rc_Good) -		viopathStatus[remoteLp].isActive = 1; -	else { -		printk(VIOPATH_KERN_WARN "could not connect to partition %d\n", -				remoteLp); -		viopathStatus[remoteLp].isActive = 0; -	} -} - -static void handleMonitorEvent(struct HvLpEvent *event) -{ -	HvLpIndex remoteLp; -	int i; - -	/* -	 * This handler is _also_ called as part of the loop -	 * at the end of this routine, so it must be able to -	 * ignore NULL events... -	 */ -	if (!event) -		return; - -	/* -	 * First see if this is just a normal monitor message from the -	 * other partition -	 */ -	if (hvlpevent_is_int(event)) { -		remoteLp = event->xSourceLp; -		if (!viopathStatus[remoteLp].isActive) -			sendMonMsg(remoteLp); -		return; -	} - -	/* -	 * This path is for an acknowledgement; the other partition -	 * died -	 */ -	remoteLp = event->xTargetLp; -	if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) || -	    (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) { -		printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n"); -		return; -	} - -	printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp); - -	viopathStatus[remoteLp].isActive = 0; - -	/* -	 * For each active handler, pass them a NULL -	 * message to indicate that the other partition -	 * died -	 */ -	for (i = 0; i < VIO_MAX_SUBTYPES; i++) { -		if (vio_handler[i] != NULL) -			(*vio_handler[i])(NULL); -	} -} - -int vio_setHandler(int subtype, vio_event_handler_t *beh) -{ -	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; -	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) -		return -EINVAL; -	if (vio_handler[subtype] != NULL) -		return -EBUSY; -	vio_handler[subtype] = beh; -	return 0; -} -EXPORT_SYMBOL(vio_setHandler); - -int vio_clearHandler(int subtype) -{ -	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; -	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) -		return -EINVAL; -	if (vio_handler[subtype] == NULL) -		return -EAGAIN; -	vio_handler[subtype] = NULL; -	return 0; -} -EXPORT_SYMBOL(vio_clearHandler); - -static void handleConfig(struct HvLpEvent *event) -{ -	if (!event) -		return; -	if (hvlpevent_is_int(event)) { -		printk(VIOPATH_KERN_WARN -		       "unexpected config request from partition %d", -		       event->xSourceLp); - -		if (hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -		return; -	} - -	complete((struct completion *)event->xCorrelationToken); -} - -/* - * Initialization of the hosting partition - */ -void vio_set_hostlp(void) -{ -	/* -	 * If this has already been set then we DON'T want to either change -	 * it or re-register the proc file system -	 */ -	if (viopath_hostLp != HvLpIndexInvalid) -		return; - -	/* -	 * Figure out our hosting partition.  This isn't allowed to change -	 * while we're active -	 */ -	viopath_ourLp = HvLpConfig_getLpIndex(); -	viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp); - -	if (viopath_hostLp != HvLpIndexInvalid) -		vio_setHandler(viomajorsubtype_config, handleConfig); -} -EXPORT_SYMBOL(vio_set_hostlp); - -static void vio_handleEvent(struct HvLpEvent *event) -{ -	HvLpIndex remoteLp; -	int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK) -		>> VIOMAJOR_SUBTYPE_SHIFT; - -	if (hvlpevent_is_int(event)) { -		remoteLp = event->xSourceLp; -		/* -		 * The isActive is checked because if the hosting partition -		 * went down and came back up it would not be active but it -		 * would have different source and target instances, in which -		 * case we'd want to reset them.  This case really protects -		 * against an unauthorized active partition sending interrupts -		 * or acks to this linux partition. -		 */ -		if (viopathStatus[remoteLp].isActive -		    && (event->xSourceInstanceId != -			viopathStatus[remoteLp].mTargetInst)) { -			printk(VIOPATH_KERN_WARN -			       "message from invalid partition. " -			       "int msg rcvd, source inst (%d) doesn't match (%d)\n", -			       viopathStatus[remoteLp].mTargetInst, -			       event->xSourceInstanceId); -			return; -		} - -		if (viopathStatus[remoteLp].isActive -		    && (event->xTargetInstanceId != -			viopathStatus[remoteLp].mSourceInst)) { -			printk(VIOPATH_KERN_WARN -			       "message from invalid partition. " -			       "int msg rcvd, target inst (%d) doesn't match (%d)\n", -			       viopathStatus[remoteLp].mSourceInst, -			       event->xTargetInstanceId); -			return; -		} -	} else { -		remoteLp = event->xTargetLp; -		if (event->xSourceInstanceId != -		    viopathStatus[remoteLp].mSourceInst) { -			printk(VIOPATH_KERN_WARN -			       "message from invalid partition. " -			       "ack msg rcvd, source inst (%d) doesn't match (%d)\n", -			       viopathStatus[remoteLp].mSourceInst, -			       event->xSourceInstanceId); -			return; -		} - -		if (event->xTargetInstanceId != -		    viopathStatus[remoteLp].mTargetInst) { -			printk(VIOPATH_KERN_WARN -			       "message from invalid partition. " -			       "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n", -			       viopathStatus[remoteLp].mTargetInst, -			       event->xTargetInstanceId); -			return; -		} -	} - -	if (vio_handler[subtype] == NULL) { -		printk(VIOPATH_KERN_WARN -		       "unexpected virtual io event subtype %d from partition %d\n", -		       event->xSubtype, remoteLp); -		/* No handler.  Ack if necessary */ -		if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -		return; -	} - -	/* This innocuous little line is where all the real work happens */ -	(*vio_handler[subtype])(event); -} - -static void viopath_donealloc(void *parm, int number) -{ -	struct alloc_parms *parmsp = parm; - -	parmsp->number = number; -	if (parmsp->used_wait_atomic) -		atomic_set(&parmsp->wait_atomic, 0); -	else -		complete(&parmsp->done); -} - -static int allocateEvents(HvLpIndex remoteLp, int numEvents) -{ -	struct alloc_parms parms; - -	if (system_state != SYSTEM_RUNNING) { -		parms.used_wait_atomic = 1; -		atomic_set(&parms.wait_atomic, 1); -	} else { -		parms.used_wait_atomic = 0; -		init_completion(&parms.done); -	} -	mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250,	/* It would be nice to put a real number here! */ -			    numEvents, &viopath_donealloc, &parms); -	if (system_state != SYSTEM_RUNNING) { -		while (atomic_read(&parms.wait_atomic)) -			mb(); -	} else -		wait_for_completion(&parms.done); -	return parms.number; -} - -int viopath_open(HvLpIndex remoteLp, int subtype, int numReq) -{ -	int i; -	unsigned long flags; -	int tempNumAllocated; - -	if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) -		return -EINVAL; - -	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; -	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) -		return -EINVAL; - -	spin_lock_irqsave(&statuslock, flags); - -	if (!event_buffer_initialised) { -		for (i = 0; i < VIO_MAX_SUBTYPES; i++) -			atomic_set(&event_buffer_available[i], 1); -		event_buffer_initialised = 1; -	} - -	viopathStatus[remoteLp].users[subtype]++; - -	if (!viopathStatus[remoteLp].isOpen) { -		viopathStatus[remoteLp].isOpen = 1; -		HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo); - -		/* -		 * Don't hold the spinlock during an operation that -		 * can sleep. -		 */ -		spin_unlock_irqrestore(&statuslock, flags); -		tempNumAllocated = allocateEvents(remoteLp, 1); -		spin_lock_irqsave(&statuslock, flags); - -		viopathStatus[remoteLp].numberAllocated += tempNumAllocated; - -		if (viopathStatus[remoteLp].numberAllocated == 0) { -			HvCallEvent_closeLpEventPath(remoteLp, -					HvLpEvent_Type_VirtualIo); - -			spin_unlock_irqrestore(&statuslock, flags); -			return -ENOMEM; -		} - -		viopathStatus[remoteLp].mSourceInst = -			HvCallEvent_getSourceLpInstanceId(remoteLp, -					HvLpEvent_Type_VirtualIo); -		viopathStatus[remoteLp].mTargetInst = -			HvCallEvent_getTargetLpInstanceId(remoteLp, -					HvLpEvent_Type_VirtualIo); -		HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo, -					  &vio_handleEvent); -		sendMonMsg(remoteLp); -		printk(VIOPATH_KERN_INFO "opening connection to partition %d, " -				"setting sinst %d, tinst %d\n", -				remoteLp, viopathStatus[remoteLp].mSourceInst, -				viopathStatus[remoteLp].mTargetInst); -	} - -	spin_unlock_irqrestore(&statuslock, flags); -	tempNumAllocated = allocateEvents(remoteLp, numReq); -	spin_lock_irqsave(&statuslock, flags); -	viopathStatus[remoteLp].numberAllocated += tempNumAllocated; -	spin_unlock_irqrestore(&statuslock, flags); - -	return 0; -} -EXPORT_SYMBOL(viopath_open); - -int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) -{ -	unsigned long flags; -	int i; -	int numOpen; -	struct alloc_parms parms; - -	if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) -		return -EINVAL; - -	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; -	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) -		return -EINVAL; - -	spin_lock_irqsave(&statuslock, flags); -	/* -	 * If the viopath_close somehow gets called before a -	 * viopath_open it could decrement to -1 which is a non -	 * recoverable state so we'll prevent this from -	 * happening. -	 */ -	if (viopathStatus[remoteLp].users[subtype] > 0) -		viopathStatus[remoteLp].users[subtype]--; - -	spin_unlock_irqrestore(&statuslock, flags); - -	parms.used_wait_atomic = 0; -	init_completion(&parms.done); -	mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, -			      numReq, &viopath_donealloc, &parms); -	wait_for_completion(&parms.done); - -	spin_lock_irqsave(&statuslock, flags); -	for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++) -		numOpen += viopathStatus[remoteLp].users[i]; - -	if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { -		printk(VIOPATH_KERN_INFO "closing connection to partition %d\n", -				remoteLp); - -		HvCallEvent_closeLpEventPath(remoteLp, -					     HvLpEvent_Type_VirtualIo); -		viopathStatus[remoteLp].isOpen = 0; -		viopathStatus[remoteLp].isActive = 0; - -		for (i = 0; i < VIO_MAX_SUBTYPES; i++) -			atomic_set(&event_buffer_available[i], 0); -		event_buffer_initialised = 0; -	} -	spin_unlock_irqrestore(&statuslock, flags); -	return 0; -} -EXPORT_SYMBOL(viopath_close); - -void *vio_get_event_buffer(int subtype) -{ -	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; -	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) -		return NULL; - -	if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0) -		return &event_buffer[subtype * 256]; -	else -		return NULL; -} -EXPORT_SYMBOL(vio_get_event_buffer); - -void vio_free_event_buffer(int subtype, void *buffer) -{ -	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; -	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) { -		printk(VIOPATH_KERN_WARN -		       "unexpected subtype %d freeing event buffer\n", subtype); -		return; -	} - -	if (atomic_read(&event_buffer_available[subtype]) != 0) { -		printk(VIOPATH_KERN_WARN -		       "freeing unallocated event buffer, subtype %d\n", -		       subtype); -		return; -	} - -	if (buffer != &event_buffer[subtype * 256]) { -		printk(VIOPATH_KERN_WARN -		       "freeing invalid event buffer, subtype %d\n", subtype); -	} - -	atomic_set(&event_buffer_available[subtype], 1); -} -EXPORT_SYMBOL(vio_free_event_buffer); - -static const struct vio_error_entry vio_no_error = -    { 0, 0, "Non-VIO Error" }; -static const struct vio_error_entry vio_unknown_error = -    { 0, EIO, "Unknown Error" }; - -static const struct vio_error_entry vio_default_errors[] = { -	{0x0001, EIO, "No Connection"}, -	{0x0002, EIO, "No Receiver"}, -	{0x0003, EIO, "No Buffer Available"}, -	{0x0004, EBADRQC, "Invalid Message Type"}, -	{0x0000, 0, NULL}, -}; - -const struct vio_error_entry *vio_lookup_rc( -		const struct vio_error_entry *local_table, u16 rc) -{ -	const struct vio_error_entry *cur; - -	if (!rc) -		return &vio_no_error; -	if (local_table) -		for (cur = local_table; cur->rc; ++cur) -			if (cur->rc == rc) -				return cur; -	for (cur = vio_default_errors; cur->rc; ++cur) -		if (cur->rc == rc) -			return cur; -	return &vio_unknown_error; -} -EXPORT_SYMBOL(vio_lookup_rc); diff --git a/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h deleted file mode 100644 index feb001f3a5f..00000000000 --- a/arch/powerpc/platforms/iseries/vpd_areas.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2001  Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA - */ -#ifndef _ISERIES_VPD_AREAS_H -#define _ISERIES_VPD_AREAS_H - -/* - * This file defines the address and length of all of the VPD area passed to - * the OS from PLIC (most of which start from the SP). - */ - -#include <asm/types.h> - -/* VPD Entry index is carved in stone - cannot be changed (easily). */ -#define ItVpdCecVpd				0 -#define ItVpdDynamicSpace			1 -#define ItVpdExtVpd				2 -#define ItVpdExtVpdOnPanel			3 -#define ItVpdFirstPaca				4 -#define ItVpdIoVpd				5 -#define ItVpdIplParms				6 -#define ItVpdMsVpd				7 -#define ItVpdPanelVpd				8 -#define ItVpdLpNaca				9 -#define ItVpdBackplaneAndMaybeClockCardVpd	10 -#define ItVpdRecoveryLogBuffer			11 -#define ItVpdSpCommArea				12 -#define ItVpdSpLogBuffer			13 -#define ItVpdSpLogBufferSave			14 -#define ItVpdSpCardVpd				15 -#define ItVpdFirstProcVpd			16 -#define ItVpdApModelVpd				17 -#define ItVpdClockCardVpd			18 -#define ItVpdBusExtCardVpd			19 -#define ItVpdProcCapacityVpd			20 -#define ItVpdInteractiveCapacityVpd		21 -#define ItVpdFirstSlotLabel			22 -#define ItVpdFirstLpQueue			23 -#define ItVpdFirstL3CacheVpd			24 -#define ItVpdFirstProcFruVpd			25 - -#define ItVpdMaxEntries				26 - -#define ItDmaMaxEntries				10 - -#define ItVpdAreasMaxSlotLabels			192 - - -struct ItVpdAreas { -	u32	xSlicDesc;		// Descriptor			000-003 -	u16	xSlicSize;		// Size of this control block	004-005 -	u16	xPlicAdjustVpdLens:1;	// Flag to indicate new interface006-007 -	u16	xRsvd1:15;		// Reserved bits		... -	u16	xSlicVpdEntries;	// Number of VPD entries	008-009 -	u16	xSlicDmaEntries;	// Number of DMA entries	00A-00B -	u16	xSlicMaxLogicalProcs;	// Maximum logical processors	00C-00D -	u16	xSlicMaxPhysicalProcs;	// Maximum physical processors	00E-00F -	u16	xSlicDmaToksOffset;	// Offset into this of array	010-011 -	u16	xSlicVpdAdrsOffset;	// Offset into this of array	012-013 -	u16	xSlicDmaLensOffset;	// Offset into this of array	014-015 -	u16	xSlicVpdLensOffset;	// Offset into this of array	016-017 -	u16	xSlicMaxSlotLabels;	// Maximum number of slot labels018-019 -	u16	xSlicMaxLpQueues;	// Maximum number of LP Queues	01A-01B -	u8	xRsvd2[4];		// Reserved			01C-01F -	u64	xRsvd3[12];		// Reserved			020-07F -	u32	xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths	080-0A7 -	u32	xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens	0A8-0CF -	u32	xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths	0D0-12F -	const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF -}; - -extern const struct ItVpdAreas	itVpdAreas; - -#endif /* _ISERIES_VPD_AREAS_H */ diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 401e3f3f74c..465ee8f5c08 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -620,7 +620,7 @@ void __init maple_pci_init(void)  	}  	/* Tell pci.c to not change any resource allocations.  */ -	pci_probe_only = 1; +	pci_add_flags(PCI_PROBE_ONLY);  }  int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 0bcbfe7b2c5..3b7545a51aa 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -262,7 +262,7 @@ static void __init maple_init_IRQ(void)  		flags |= MPIC_BIG_ENDIAN;  	/* XXX Maple specific bits */ -	flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET; +	flags |= MPIC_U3_HT_IRQS;  	/* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */  	flags |= MPIC_BIG_ENDIAN; diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index b6a0ec45c69..aa862713258 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -229,9 +229,6 @@ void __init pas_pci_init(void)  	/* Setup the linkage between OF nodes and PHBs */  	pci_devs_phb_init(); - -	/* Use the common resource allocation mechanism */ -	pci_probe_only = 1;  }  void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset) diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 98b7a7c1317..e777ad471a4 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -224,7 +224,7 @@ static __init void pas_init_IRQ(void)  	openpic_addr = of_read_number(opprop, naddr);  	printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); -	mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS; +	mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET;  	nmiprop = of_get_property(mpic_node, "nmi-source", NULL);  	if (nmiprop) diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 54d227127c9..da18b26dcc6 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c @@ -279,7 +279,7 @@ static u32 core99_check(u8* datas)  static int sm_erase_bank(int bank)  { -	int stat, i; +	int stat;  	unsigned long timeout;  	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; @@ -301,11 +301,10 @@ static int sm_erase_bank(int bank)  	out_8(base, SM_FLASH_CMD_CLEAR_STATUS);  	out_8(base, SM_FLASH_CMD_RESET); -	for (i=0; i<NVRAM_SIZE; i++) -		if (base[i] != 0xff) { -			printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); -			return -ENXIO; -		} +	if (memchr_inv(base, 0xff, NVRAM_SIZE)) { +		printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); +		return -ENXIO; +	}  	return 0;  } @@ -336,17 +335,16 @@ static int sm_write_bank(int bank, u8* datas)  	}  	out_8(base, SM_FLASH_CMD_CLEAR_STATUS);  	out_8(base, SM_FLASH_CMD_RESET); -	for (i=0; i<NVRAM_SIZE; i++) -		if (base[i] != datas[i]) { -			printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); -			return -ENXIO; -		} +	if (memcmp(base, datas, NVRAM_SIZE)) { +		printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); +		return -ENXIO; +	}  	return 0;  }  static int amd_erase_bank(int bank)  { -	int i, stat = 0; +	int stat = 0;  	unsigned long timeout;  	u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; @@ -382,12 +380,11 @@ static int amd_erase_bank(int bank)  	/* Reset */  	out_8(base, 0xf0);  	udelay(1); -	 -	for (i=0; i<NVRAM_SIZE; i++) -		if (base[i] != 0xff) { -			printk(KERN_ERR "nvram: AMD flash erase failed !\n"); -			return -ENXIO; -		} + +	if (memchr_inv(base, 0xff, NVRAM_SIZE)) { +		printk(KERN_ERR "nvram: AMD flash erase failed !\n"); +		return -ENXIO; +	}  	return 0;  } @@ -429,11 +426,10 @@ static int amd_write_bank(int bank, u8* datas)  	out_8(base, 0xf0);  	udelay(1); -	for (i=0; i<NVRAM_SIZE; i++) -		if (base[i] != datas[i]) { -			printk(KERN_ERR "nvram: AMD flash write failed !\n"); -			return -ENXIO; -		} +	if (memcmp(base, datas, NVRAM_SIZE)) { +		printk(KERN_ERR "nvram: AMD flash write failed !\n"); +		return -ENXIO; +	}  	return 0;  } diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 31a7d3a7ce2..43bbe1bda93 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1059,9 +1059,6 @@ void __init pmac_pci_init(void)  	}  	/* pmac_check_ht_link(); */ -	/* We can allocate missing resources if any */ -	pci_probe_only = 0; -  #else /* CONFIG_PPC64 */  	init_p2pbridge();  	init_second_ohare(); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 7761aabfc29..66ad93de1d5 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -61,7 +61,7 @@ static DEFINE_RAW_SPINLOCK(pmac_pic_lock);  static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];  static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];  static int pmac_irq_cascade = -1; -static struct irq_host *pmac_pic_host; +static struct irq_domain *pmac_pic_host;  static void __pmac_retrigger(unsigned int irq_nr)  { @@ -268,13 +268,13 @@ static struct irqaction gatwick_cascade_action = {  	.name		= "cascade",  }; -static int pmac_pic_host_match(struct irq_host *h, struct device_node *node) +static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node)  {  	/* We match all, we don't always have a node anyway */  	return 1;  } -static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, +static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq,  			     irq_hw_number_t hw)  {  	if (hw >= max_irqs) @@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct, -			       const u32 *intspec, unsigned int intsize, -			       irq_hw_number_t *out_hwirq, -			       unsigned int *out_flags) - -{ -	*out_flags = IRQ_TYPE_NONE; -	*out_hwirq = *intspec; -	return 0; -} - -static struct irq_host_ops pmac_pic_host_ops = { +static const struct irq_domain_ops pmac_pic_host_ops = {  	.match = pmac_pic_host_match,  	.map = pmac_pic_host_map, -	.xlate = pmac_pic_host_xlate, +	.xlate = irq_domain_xlate_onecell,  };  static void __init pmac_pic_probe_oldstyle(void) @@ -352,9 +341,8 @@ static void __init pmac_pic_probe_oldstyle(void)  	/*  	 * Allocate an irq host  	 */ -	pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs, -				       &pmac_pic_host_ops, -				       max_irqs); +	pmac_pic_host = irq_domain_add_linear(master, max_irqs, +					      &pmac_pic_host_ops, NULL);  	BUG_ON(pmac_pic_host == NULL);  	irq_set_default_host(pmac_pic_host); @@ -469,7 +457,6 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,  	pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); -	flags |= MPIC_WANTS_RESET;  	if (of_get_property(np, "big-endian", NULL))  		flags |= MPIC_BIG_ENDIAN; diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 44d769258eb..a81e5a88fbd 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -125,7 +125,7 @@ static volatile u32 __iomem *psurge_start;  static int psurge_type = PSURGE_NONE;  /* irq for secondary cpus to report */ -static struct irq_host *psurge_host; +static struct irq_domain *psurge_host;  int psurge_secondary_virq;  /* @@ -176,7 +176,7 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data)  	psurge_set_ipi(cpu);  } -static int psurge_host_map(struct irq_host *h, unsigned int virq, +static int psurge_host_map(struct irq_domain *h, unsigned int virq,  			 irq_hw_number_t hw)  {  	irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq); @@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -struct irq_host_ops psurge_host_ops = { +static const struct irq_domain_ops psurge_host_ops = {  	.map	= psurge_host_map,  }; @@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void)  {  	int rc = -ENOMEM; -	psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, -		&psurge_host_ops, 0); +	psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL);  	if (psurge_host)  		psurge_secondary_virq = irq_create_direct_mapping(psurge_host); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index f31162cfdaa..fbdd74dac3a 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -204,11 +204,10 @@ static void __devinit pnv_ioda_offset_bus(struct pci_bus *bus,  	pr_devel("  -> OBR %s [%x] +%016llx\n",  		 bus->self ? pci_name(bus->self) : "root", flags, offset); -	for (i = 0; i < 2; i++) { -		r = bus->resource[i]; +	pci_bus_for_each_resource(bus, r, i) {  		if (r && (r->flags & flags)) { -			bus->resource[i]->start += offset; -			bus->resource[i]->end += offset; +			r->start += offset; +			r->end += offset;  		}  	}  	list_for_each_entry(dev, &bus->devices, bus_list) @@ -288,12 +287,17 @@ static void __devinit pnv_ioda_calc_bus(struct pci_bus *bus, unsigned int flags,  	 * assignment algorithm is going to be uber-trivial for now, we  	 * can try to be smarter later at filling out holes.  	 */ -	start = bus->self ? 0 : bus->resource[bres]->start; - -	/* Don't hand out IO 0 */ -	if ((flags & IORESOURCE_IO) && !bus->self) -		start += 0x1000; - +	if (bus->self) { +		/* No offset for downstream bridges */ +		start = 0; +	} else { +		/* Offset from the root */ +		if (flags & IORESOURCE_IO) +			/* Don't hand out IO 0 */ +			start = hose->io_resource.start + 0x1000; +		else +			start = hose->mem_resources[0].start; +	}  	while(!list_empty(&head)) {  		w = list_first_entry(&head, struct resource_wrap, link);  		list_del(&w->link); @@ -321,13 +325,20 @@ static void __devinit pnv_ioda_calc_bus(struct pci_bus *bus, unsigned int flags,   empty:  	/* Only setup P2P's, not the PHB itself */  	if (bus->self) { -		WARN_ON(bus->resource[bres] == NULL); -		bus->resource[bres]->start = 0; -		bus->resource[bres]->flags = (*size) ? flags : 0; -		bus->resource[bres]->end = (*size) ? (*size - 1) : 0; +		struct resource *res = bus->resource[bres]; + +		if (WARN_ON(res == NULL)) +			return; -		/* Clear prefetch bus resources for now */ -		bus->resource[2]->flags = 0; +		/* +		 * FIXME: We should probably export and call +		 * pci_bridge_check_ranges() to properly re-initialize +		 * the PCI portion of the flags here, and to detect +		 * what the bridge actually supports. +		 */ +		res->start = 0; +		res->flags = (*size) ? flags : 0; +		res->end = (*size) ? (*size - 1) : 0;  	}  	pr_devel("<- CBR %s [%x] *size=%016llx *align=%016llx\n", @@ -1288,15 +1299,14 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np)  	/* Setup MSI support */  	pnv_pci_init_ioda_msis(phb); -	/* We set both probe_only and PCI_REASSIGN_ALL_RSRC. This is an +	/* We set both PCI_PROBE_ONLY and PCI_REASSIGN_ALL_RSRC. This is an  	 * odd combination which essentially means that we skip all resource  	 * fixups and assignments in the generic code, and do it all  	 * ourselves here  	 */ -	pci_probe_only = 1;  	ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb;  	ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook; -	pci_add_flags(PCI_REASSIGN_ALL_RSRC); +	pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC);  	/* Reset IODA tables to a clean state */  	rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET); diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index a70bc1e385e..be3cfc5ceab 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -31,6 +31,7 @@  #include <asm/iommu.h>  #include <asm/tce.h>  #include <asm/abs_addr.h> +#include <asm/firmware.h>  #include "powernv.h"  #include "pci.h" @@ -52,32 +53,38 @@ static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type)  static unsigned int pnv_get_one_msi(struct pnv_phb *phb)  { -	unsigned int id; +	unsigned long flags; +	unsigned int id, rc; + +	spin_lock_irqsave(&phb->lock, flags); -	spin_lock(&phb->lock);  	id = find_next_zero_bit(phb->msi_map, phb->msi_count, phb->msi_next);  	if (id >= phb->msi_count && phb->msi_next)  		id = find_next_zero_bit(phb->msi_map, phb->msi_count, 0);  	if (id >= phb->msi_count) { -		spin_unlock(&phb->lock); -		return 0; +		rc = 0; +		goto out;  	}  	__set_bit(id, phb->msi_map); -	spin_unlock(&phb->lock); -	return id + phb->msi_base; +	rc = id + phb->msi_base; +out: +	spin_unlock_irqrestore(&phb->lock, flags); +	return rc;  }  static void pnv_put_msi(struct pnv_phb *phb, unsigned int hwirq)  { +	unsigned long flags;  	unsigned int id;  	if (WARN_ON(hwirq < phb->msi_base ||  		    hwirq >= (phb->msi_base + phb->msi_count)))  		return;  	id = hwirq - phb->msi_base; -	spin_lock(&phb->lock); + +	spin_lock_irqsave(&phb->lock, flags);  	__clear_bit(id, phb->msi_map); -	spin_unlock(&phb->lock); +	spin_unlock_irqrestore(&phb->lock, flags);  }  static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) @@ -555,10 +562,7 @@ void __init pnv_pci_init(void)  {  	struct device_node *np; -	pci_set_flags(PCI_CAN_SKIP_ISA_ALIGN); - -	/* We do not want to just probe */ -	pci_probe_only = 0; +	pci_add_flags(PCI_CAN_SKIP_ISA_ALIGN);  	/* OPAL absent, try POPAL first then RTAS detection of PHBs */  	if (!firmware_has_feature(FW_FEATURE_OPAL)) { diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 467bd4ac682..db1ad1c8f68 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -31,7 +31,6 @@  #include <asm/xics.h>  #include <asm/rtas.h>  #include <asm/opal.h> -#include <asm/xics.h>  #include "powernv.h" diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 617efa12a3a..2a4ff86cc21 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -667,7 +667,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,  static void dump_bmp(struct ps3_private* pd) {};  #endif /* defined(DEBUG) */ -static int ps3_host_map(struct irq_host *h, unsigned int virq, +static int ps3_host_map(struct irq_domain *h, unsigned int virq,  	irq_hw_number_t hwirq)  {  	DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, @@ -678,13 +678,13 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,  	return 0;  } -static int ps3_host_match(struct irq_host *h, struct device_node *np) +static int ps3_host_match(struct irq_domain *h, struct device_node *np)  {  	/* Match all */  	return 1;  } -static struct irq_host_ops ps3_host_ops = { +static const struct irq_domain_ops ps3_host_ops = {  	.map = ps3_host_map,  	.match = ps3_host_match,  }; @@ -751,10 +751,9 @@ void __init ps3_init_IRQ(void)  {  	int result;  	unsigned cpu; -	struct irq_host *host; +	struct irq_domain *host; -	host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, -		PS3_INVALID_OUTLET); +	host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL);  	irq_set_default_host(host);  	irq_set_virq_count(PS3_PLUG_MAX + 1); diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index ae7b6d41fed..aadbe4f6d53 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -3,6 +3,7 @@ config PPC_PSERIES  	bool "IBM pSeries & new (POWER5-based) iSeries"  	select HAVE_PCSPKR_PLATFORM  	select MPIC +	select OF_DYNAMIC  	select PCI_MSI  	select PPC_XICS  	select PPC_ICP_NATIVE @@ -72,7 +73,7 @@ config IO_EVENT_IRQ  config LPARCFG  	bool "LPAR Configuration Data" -	depends on PPC_PSERIES || PPC_ISERIES +	depends on PPC_PSERIES  	help  	Provide system capacity information via human readable  	<key word>=<value> pairs through a /proc/ppc64/lparcfg interface. @@ -122,7 +123,7 @@ config DTL  	  Say N if you are unsure.  config PSERIES_IDLE -	tristate "Cpuidle driver for pSeries platforms" +	bool "Cpuidle driver for pSeries platforms"  	depends on CPU_IDLE  	depends on PPC_PSERIES  	default y diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 236db46b407..c222189f5bb 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -6,7 +6,8 @@ obj-y			:= lpar.o hvCall.o nvram.o reconfig.o \  			   firmware.o power.o dlpar.o mobility.o  obj-$(CONFIG_SMP)	+= smp.o  obj-$(CONFIG_SCANLOG)	+= scanlog.o -obj-$(CONFIG_EEH)	+= eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o +obj-$(CONFIG_EEH)	+= eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \ +			   eeh_event.o eeh_sysfs.o eeh_pseries.o  obj-$(CONFIG_KEXEC)	+= kexec.o  obj-$(CONFIG_PCI)	+= pci.o pci_dlpar.o  obj-$(CONFIG_PSERIES_MSI)	+= msi.o @@ -18,7 +19,6 @@ obj-$(CONFIG_MEMORY_HOTPLUG)	+= hotplug-memory.o  obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o  obj-$(CONFIG_HVCS)		+= hvcserver.o  obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o -obj-$(CONFIG_PHYP_DUMP)		+= phyp_dump.o  obj-$(CONFIG_CMM)		+= cmm.o  obj-$(CONFIG_DTL)		+= dtl.o  obj-$(CONFIG_IO_EVENT_IRQ)	+= io_event_irq.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 565869022e3..309d38ef732 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1,8 +1,8 @@  /* - * eeh.c   * Copyright IBM Corporation 2001, 2005, 2006   * Copyright Dave Engebretsen & Todd Inglett 2001   * Copyright Linas Vepstas 2005, 2006 + * Copyright 2001-2012 IBM Corporation.   *   * 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 @@ -22,7 +22,7 @@   */  #include <linux/delay.h> -#include <linux/sched.h>	/* for init_mm */ +#include <linux/sched.h>  #include <linux/init.h>  #include <linux/list.h>  #include <linux/pci.h> @@ -86,16 +86,8 @@  /* Time to wait for a PCI slot to report status, in milliseconds */  #define PCI_BUS_RESET_WAIT_MSEC (60*1000) -/* RTAS tokens */ -static int ibm_set_eeh_option; -static int ibm_set_slot_reset; -static int ibm_read_slot_reset_state; -static int ibm_read_slot_reset_state2; -static int ibm_slot_error_detail; -static int ibm_get_config_addr_info; -static int ibm_get_config_addr_info2; -static int ibm_configure_bridge; -static int ibm_configure_pe; +/* Platform dependent EEH operations */ +struct eeh_ops *eeh_ops = NULL;  int eeh_subsystem_enabled;  EXPORT_SYMBOL(eeh_subsystem_enabled); @@ -103,14 +95,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled);  /* Lock to avoid races due to multiple reports of an error */  static DEFINE_RAW_SPINLOCK(confirm_error_lock); -/* Buffer for reporting slot-error-detail rtas calls. Its here - * in BSS, and not dynamically alloced, so that it ends up in - * RMO where RTAS can access it. - */ -static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; -static DEFINE_SPINLOCK(slot_errbuf_lock); -static int eeh_error_buf_size; -  /* Buffer for reporting pci register dumps. Its here in BSS, and   * not dynamically alloced, so that it ends up in RMO where RTAS   * can access it. @@ -118,74 +102,50 @@ static int eeh_error_buf_size;  #define EEH_PCI_REGS_LOG_LEN 4096  static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; -/* System monitoring statistics */ -static unsigned long no_device; -static unsigned long no_dn; -static unsigned long no_cfg_addr; -static unsigned long ignored_check; -static unsigned long total_mmio_ffs; -static unsigned long false_positives; -static unsigned long slot_resets; - -#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) - -/* --------------------------------------------------------------- */ -/* Below lies the EEH event infrastructure */ - -static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, -                                   char *driver_log, size_t loglen) -{ -	int config_addr; -	unsigned long flags; -	int rc; - -	/* Log the error with the rtas logger */ -	spin_lock_irqsave(&slot_errbuf_lock, flags); -	memset(slot_errbuf, 0, eeh_error_buf_size); - -	/* Use PE configuration address, if present */ -	config_addr = pdn->eeh_config_addr; -	if (pdn->eeh_pe_config_addr) -		config_addr = pdn->eeh_pe_config_addr; +/* + * The struct is used to maintain the EEH global statistic + * information. Besides, the EEH global statistics will be + * exported to user space through procfs + */ +struct eeh_stats { +	u64 no_device;		/* PCI device not found		*/ +	u64 no_dn;		/* OF node not found		*/ +	u64 no_cfg_addr;	/* Config address not found	*/ +	u64 ignored_check;	/* EEH check skipped		*/ +	u64 total_mmio_ffs;	/* Total EEH checks		*/ +	u64 false_positives;	/* Unnecessary EEH checks	*/ +	u64 slot_resets;	/* PE reset			*/ +}; -	rc = rtas_call(ibm_slot_error_detail, -	               8, 1, NULL, config_addr, -	               BUID_HI(pdn->phb->buid), -	               BUID_LO(pdn->phb->buid), -	               virt_to_phys(driver_log), loglen, -	               virt_to_phys(slot_errbuf), -	               eeh_error_buf_size, -	               severity); +static struct eeh_stats eeh_stats; -	if (rc == 0) -		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); -	spin_unlock_irqrestore(&slot_errbuf_lock, flags); -} +#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)  /** - * gather_pci_data - copy assorted PCI config space registers to buff - * @pdn: device to report data for + * eeh_gather_pci_data - Copy assorted PCI config space registers to buff + * @edev: device to report data for   * @buf: point to buffer in which to log   * @len: amount of room in buffer   *   * This routine captures assorted PCI configuration space data,   * and puts them into a buffer for RTAS error logging.   */ -static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) +static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)  { -	struct pci_dev *dev = pdn->pcidev; +	struct device_node *dn = eeh_dev_to_of_node(edev); +	struct pci_dev *dev = eeh_dev_to_pci_dev(edev);  	u32 cfg;  	int cap, i;  	int n = 0; -	n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name); -	printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name); +	n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); +	printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); -	rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg); +	eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg);  	n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);  	printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); -	rtas_read_config(pdn, PCI_COMMAND, 4, &cfg); +	eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg);  	n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);  	printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); @@ -196,11 +156,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)  	/* Gather bridge-specific registers */  	if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { -		rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); +		eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);  		n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);  		printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); -		rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); +		eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg);  		n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);  		printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg);  	} @@ -208,11 +168,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)  	/* Dump out the PCI-X command and status regs */  	cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);  	if (cap) { -		rtas_read_config(pdn, cap, 4, &cfg); +		eeh_ops->read_config(dn, cap, 4, &cfg);  		n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);  		printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); -		rtas_read_config(pdn, cap+4, 4, &cfg); +		eeh_ops->read_config(dn, cap+4, 4, &cfg);  		n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);  		printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);  	} @@ -225,7 +185,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)  		       "EEH: PCI-E capabilities and status follow:\n");  		for (i=0; i<=8; i++) { -			rtas_read_config(pdn, cap+4*i, 4, &cfg); +			eeh_ops->read_config(dn, cap+4*i, 4, &cfg);  			n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);  			printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);  		} @@ -237,7 +197,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)  			       "EEH: PCI-E AER capability register set follows:\n");  			for (i=0; i<14; i++) { -				rtas_read_config(pdn, cap+4*i, 4, &cfg); +				eeh_ops->read_config(dn, cap+4*i, 4, &cfg);  				n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);  				printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);  			} @@ -246,111 +206,46 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)  	/* Gather status on devices under the bridge */  	if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { -		struct device_node *dn; +		struct device_node *child; -		for_each_child_of_node(pdn->node, dn) { -			pdn = PCI_DN(dn); -			if (pdn) -				n += gather_pci_data(pdn, buf+n, len-n); +		for_each_child_of_node(dn, child) { +			if (of_node_to_eeh_dev(child)) +				n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n);  		}  	}  	return n;  } -void eeh_slot_error_detail(struct pci_dn *pdn, int severity) -{ -	size_t loglen = 0; -	pci_regs_buf[0] = 0; - -	rtas_pci_enable(pdn, EEH_THAW_MMIO); -	rtas_configure_bridge(pdn); -	eeh_restore_bars(pdn); -	loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); - -	rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); -} - -/** - * read_slot_reset_state - Read the reset state of a device node's slot - * @dn: device node to read - * @rets: array to return results in - */ -static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) -{ -	int token, outputs; -	int config_addr; - -	if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { -		token = ibm_read_slot_reset_state2; -		outputs = 4; -	} else { -		token = ibm_read_slot_reset_state; -		rets[2] = 0; /* fake PE Unavailable info */ -		outputs = 3; -	} - -	/* Use PE configuration address, if present */ -	config_addr = pdn->eeh_config_addr; -	if (pdn->eeh_pe_config_addr) -		config_addr = pdn->eeh_pe_config_addr; - -	return rtas_call(token, 3, outputs, rets, config_addr, -			 BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); -} -  /** - * eeh_wait_for_slot_status - returns error status of slot - * @pdn pci device node - * @max_wait_msecs maximum number to millisecs to wait + * eeh_slot_error_detail - Generate combined log including driver log and error log + * @edev: device to report error log for + * @severity: temporary or permanent error log   * - * Return negative value if a permanent error, else return - * Partition Endpoint (PE) status value. - * - * If @max_wait_msecs is positive, then this routine will - * sleep until a valid status can be obtained, or until - * the max allowed wait time is exceeded, in which case - * a -2 is returned. + * This routine should be called to generate the combined log, which + * is comprised of driver log and error log. The driver log is figured + * out from the config space of the corresponding PCI device, while + * the error log is fetched through platform dependent function call.   */ -int -eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs) +void eeh_slot_error_detail(struct eeh_dev *edev, int severity)  { -	int rc; -	int rets[3]; -	int mwait; - -	while (1) { -		rc = read_slot_reset_state(pdn, rets); -		if (rc) return rc; -		if (rets[1] == 0) return -1;  /* EEH is not supported */ - -		if (rets[0] != 5) return rets[0]; /* return actual status */ - -		if (rets[2] == 0) return -1; /* permanently unavailable */ - -		if (max_wait_msecs <= 0) break; +	size_t loglen = 0; +	pci_regs_buf[0] = 0; -		mwait = rets[2]; -		if (mwait <= 0) { -			printk (KERN_WARNING -			        "EEH: Firmware returned bad wait value=%d\n", mwait); -			mwait = 1000; -		} else if (mwait > 300*1000) { -			printk (KERN_WARNING -			        "EEH: Firmware is taking too long, time=%d\n", mwait); -			mwait = 300*1000; -		} -		max_wait_msecs -= mwait; -		msleep (mwait); -	} +	eeh_pci_enable(edev, EEH_OPT_THAW_MMIO); +	eeh_ops->configure_bridge(eeh_dev_to_of_node(edev)); +	eeh_restore_bars(edev); +	loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); -	printk(KERN_WARNING "EEH: Timed out waiting for slot status\n"); -	return -2; +	eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen);  }  /** - * eeh_token_to_phys - convert EEH address token to phys address - * @token i/o token, should be address in the form 0xA.... + * eeh_token_to_phys - Convert EEH address token to phys address + * @token: I/O token, should be address in the form 0xA.... + * + * This routine should be called to convert virtual I/O address + * to physical one.   */  static inline unsigned long eeh_token_to_phys(unsigned long token)  { @@ -365,36 +260,43 @@ static inline unsigned long eeh_token_to_phys(unsigned long token)  	return pa | (token & (PAGE_SIZE-1));  } -/**  - * Return the "partitionable endpoint" (pe) under which this device lies +/** + * eeh_find_device_pe - Retrieve the PE for the given device + * @dn: device node + * + * Return the PE under which this device lies   */ -struct device_node * find_device_pe(struct device_node *dn) +struct device_node *eeh_find_device_pe(struct device_node *dn)  { -	while ((dn->parent) && PCI_DN(dn->parent) && -	      (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { +	while (dn->parent && of_node_to_eeh_dev(dn->parent) && +	       (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) {  		dn = dn->parent;  	}  	return dn;  } -/** Mark all devices that are children of this device as failed. - *  Mark the device driver too, so that it can see the failure - *  immediately; this is critical, since some drivers poll - *  status registers in interrupts ... If a driver is polling, - *  and the slot is frozen, then the driver can deadlock in - *  an interrupt context, which is bad. +/** + * __eeh_mark_slot - Mark all child devices as failed + * @parent: parent device + * @mode_flag: failure flag + * + * Mark all devices that are children of this device as failed. + * Mark the device driver too, so that it can see the failure + * immediately; this is critical, since some drivers poll + * status registers in interrupts ... If a driver is polling, + * and the slot is frozen, then the driver can deadlock in + * an interrupt context, which is bad.   */ -  static void __eeh_mark_slot(struct device_node *parent, int mode_flag)  {  	struct device_node *dn;  	for_each_child_of_node(parent, dn) { -		if (PCI_DN(dn)) { +		if (of_node_to_eeh_dev(dn)) {  			/* Mark the pci device driver too */ -			struct pci_dev *dev = PCI_DN(dn)->pcidev; +			struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; -			PCI_DN(dn)->eeh_mode |= mode_flag; +			of_node_to_eeh_dev(dn)->mode |= mode_flag;  			if (dev && dev->driver)  				dev->error_state = pci_channel_io_frozen; @@ -404,92 +306,81 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag)  	}  } -void eeh_mark_slot (struct device_node *dn, int mode_flag) +/** + * eeh_mark_slot - Mark the indicated device and its children as failed + * @dn: parent device + * @mode_flag: failure flag + * + * Mark the indicated device and its child devices as failed. + * The device drivers are marked as failed as well. + */ +void eeh_mark_slot(struct device_node *dn, int mode_flag)  {  	struct pci_dev *dev; -	dn = find_device_pe (dn); +	dn = eeh_find_device_pe(dn);  	/* Back up one, since config addrs might be shared */ -	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) +	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))  		dn = dn->parent; -	PCI_DN(dn)->eeh_mode |= mode_flag; +	of_node_to_eeh_dev(dn)->mode |= mode_flag;  	/* Mark the pci device too */ -	dev = PCI_DN(dn)->pcidev; +	dev = of_node_to_eeh_dev(dn)->pdev;  	if (dev)  		dev->error_state = pci_channel_io_frozen;  	__eeh_mark_slot(dn, mode_flag);  } +/** + * __eeh_clear_slot - Clear failure flag for the child devices + * @parent: parent device + * @mode_flag: flag to be cleared + * + * Clear failure flag for the child devices. + */  static void __eeh_clear_slot(struct device_node *parent, int mode_flag)  {  	struct device_node *dn;  	for_each_child_of_node(parent, dn) { -		if (PCI_DN(dn)) { -			PCI_DN(dn)->eeh_mode &= ~mode_flag; -			PCI_DN(dn)->eeh_check_count = 0; +		if (of_node_to_eeh_dev(dn)) { +			of_node_to_eeh_dev(dn)->mode &= ~mode_flag; +			of_node_to_eeh_dev(dn)->check_count = 0;  			__eeh_clear_slot(dn, mode_flag);  		}  	}  } -void eeh_clear_slot (struct device_node *dn, int mode_flag) +/** + * eeh_clear_slot - Clear failure flag for the indicated device and its children + * @dn: parent device + * @mode_flag: flag to be cleared + * + * Clear failure flag for the indicated device and its children. + */ +void eeh_clear_slot(struct device_node *dn, int mode_flag)  {  	unsigned long flags;  	raw_spin_lock_irqsave(&confirm_error_lock, flags); -	dn = find_device_pe (dn); +	dn = eeh_find_device_pe(dn);  	/* Back up one, since config addrs might be shared */ -	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) +	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))  		dn = dn->parent; -	PCI_DN(dn)->eeh_mode &= ~mode_flag; -	PCI_DN(dn)->eeh_check_count = 0; +	of_node_to_eeh_dev(dn)->mode &= ~mode_flag; +	of_node_to_eeh_dev(dn)->check_count = 0;  	__eeh_clear_slot(dn, mode_flag);  	raw_spin_unlock_irqrestore(&confirm_error_lock, flags);  } -void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) -{ -	struct device_node *dn; - -	for_each_child_of_node(parent, dn) { -		if (PCI_DN(dn)) { - -			struct pci_dev *dev = PCI_DN(dn)->pcidev; - -			if (dev && dev->driver) -				*freset |= dev->needs_freset; - -			__eeh_set_pe_freset(dn, freset); -		} -	} -} - -void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) -{ -	struct pci_dev *dev; -	dn = find_device_pe(dn); - -	/* Back up one, since config addrs might be shared */ -	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) -		dn = dn->parent; - -	dev = PCI_DN(dn)->pcidev; -	if (dev) -		*freset |= dev->needs_freset; - -	__eeh_set_pe_freset(dn, freset); -} -  /** - * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze - * @dn device node - * @dev pci device, if known + * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze + * @dn: device node + * @dev: pci device, if known   *   * Check for an EEH failure for the given device node.  Call this   * routine if the result of a read was all 0xff's and you want to @@ -504,35 +395,34 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)  int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)  {  	int ret; -	int rets[3];  	unsigned long flags; -	struct pci_dn *pdn; +	struct eeh_dev *edev;  	int rc = 0;  	const char *location; -	total_mmio_ffs++; +	eeh_stats.total_mmio_ffs++;  	if (!eeh_subsystem_enabled)  		return 0;  	if (!dn) { -		no_dn++; +		eeh_stats.no_dn++;  		return 0;  	} -	dn = find_device_pe(dn); -	pdn = PCI_DN(dn); +	dn = eeh_find_device_pe(dn); +	edev = of_node_to_eeh_dev(dn);  	/* Access to IO BARs might get this far and still not want checking. */ -	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || -	    pdn->eeh_mode & EEH_MODE_NOCHECK) { -		ignored_check++; +	if (!(edev->mode & EEH_MODE_SUPPORTED) || +	    edev->mode & EEH_MODE_NOCHECK) { +		eeh_stats.ignored_check++;  		pr_debug("EEH: Ignored check (%x) for %s %s\n", -			 pdn->eeh_mode, eeh_pci_name(dev), dn->full_name); +			edev->mode, eeh_pci_name(dev), dn->full_name);  		return 0;  	} -	if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) { -		no_cfg_addr++; +	if (!edev->config_addr && !edev->pe_config_addr) { +		eeh_stats.no_cfg_addr++;  		return 0;  	} @@ -544,16 +434,16 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)  	 */  	raw_spin_lock_irqsave(&confirm_error_lock, flags);  	rc = 1; -	if (pdn->eeh_mode & EEH_MODE_ISOLATED) { -		pdn->eeh_check_count ++; -		if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) { +	if (edev->mode & EEH_MODE_ISOLATED) { +		edev->check_count++; +		if (edev->check_count % EEH_MAX_FAILS == 0) {  			location = of_get_property(dn, "ibm,loc-code", NULL); -			printk (KERN_ERR "EEH: %d reads ignored for recovering device at " +			printk(KERN_ERR "EEH: %d reads ignored for recovering device at "  				"location=%s driver=%s pci addr=%s\n", -				pdn->eeh_check_count, location, -				dev->driver->name, eeh_pci_name(dev)); -			printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n", -				dev->driver->name); +				edev->check_count, location, +				eeh_driver_name(dev), eeh_pci_name(dev)); +			printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n", +				eeh_driver_name(dev));  			dump_stack();  		}  		goto dn_unlock; @@ -566,58 +456,39 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)  	 * function zero of a multi-function device.  	 * In any case they must share a common PHB.  	 */ -	ret = read_slot_reset_state(pdn, rets); - -	/* If the call to firmware failed, punt */ -	if (ret != 0) { -		printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", -		       ret, dn->full_name); -		false_positives++; -		pdn->eeh_false_positives ++; -		rc = 0; -		goto dn_unlock; -	} +	ret = eeh_ops->get_state(dn, NULL);  	/* Note that config-io to empty slots may fail; -	 * they are empty when they don't have children. */ -	if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) { -		false_positives++; -		pdn->eeh_false_positives ++; -		rc = 0; -		goto dn_unlock; -	} - -	/* If EEH is not supported on this device, punt. */ -	if (rets[1] != 1) { -		printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", -		       ret, dn->full_name); -		false_positives++; -		pdn->eeh_false_positives ++; -		rc = 0; -		goto dn_unlock; -	} - -	/* If not the kind of error we know about, punt. */ -	if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { -		false_positives++; -		pdn->eeh_false_positives ++; +	 * they are empty when they don't have children. +	 * We will punt with the following conditions: Failure to get +	 * PE's state, EEH not support and Permanently unavailable +	 * state, PE is in good state. +	 */ +	if ((ret < 0) || +	    (ret == EEH_STATE_NOT_SUPPORT) || +	    (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == +	    (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) { +		eeh_stats.false_positives++; +		edev->false_positives ++;  		rc = 0;  		goto dn_unlock;  	} -	slot_resets++; +	eeh_stats.slot_resets++;  	/* Avoid repeated reports of this failure, including problems  	 * with other functions on this device, and functions under -	 * bridges. */ -	eeh_mark_slot (dn, EEH_MODE_ISOLATED); +	 * bridges. +	 */ +	eeh_mark_slot(dn, EEH_MODE_ISOLATED);  	raw_spin_unlock_irqrestore(&confirm_error_lock, flags); -	eeh_send_failure_event (dn, dev); +	eeh_send_failure_event(edev);  	/* Most EEH events are due to device driver bugs.  Having  	 * a stack trace will help the device-driver authors figure -	 * out what happened.  So print that out. */ +	 * out what happened.  So print that out. +	 */  	dump_stack();  	return 1; @@ -629,9 +500,9 @@ dn_unlock:  EXPORT_SYMBOL_GPL(eeh_dn_check_failure);  /** - * eeh_check_failure - check if all 1's data is due to EEH slot freeze - * @token i/o token, should be address in the form 0xA.... - * @val value, should be all 1's (XXX why do we need this arg??) + * eeh_check_failure - Check if all 1's data is due to EEH slot freeze + * @token: I/O token, should be address in the form 0xA.... + * @val: value, should be all 1's (XXX why do we need this arg??)   *   * Check for an EEH failure at the given token address.  Call this   * routine if the result of a read was all 0xff's and you want to @@ -648,14 +519,14 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon  	/* Finding the phys addr + pci device; this is pretty quick. */  	addr = eeh_token_to_phys((unsigned long __force) token); -	dev = pci_get_device_by_addr(addr); +	dev = pci_addr_cache_get_device(addr);  	if (!dev) { -		no_device++; +		eeh_stats.no_device++;  		return val;  	}  	dn = pci_device_to_OF_node(dev); -	eeh_dn_check_failure (dn, dev); +	eeh_dn_check_failure(dn, dev);  	pci_dev_put(dev);  	return val; @@ -663,115 +534,54 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon  EXPORT_SYMBOL(eeh_check_failure); -/* ------------------------------------------------------------- */ -/* The code below deals with error recovery */  /** - * rtas_pci_enable - enable MMIO or DMA transfers for this slot - * @pdn pci device node + * eeh_pci_enable - Enable MMIO or DMA transfers for this slot + * @edev: pci device node + * + * This routine should be called to reenable frozen MMIO or DMA + * so that it would work correctly again. It's useful while doing + * recovery or log collection on the indicated device.   */ - -int -rtas_pci_enable(struct pci_dn *pdn, int function) +int eeh_pci_enable(struct eeh_dev *edev, int function)  { -	int config_addr;  	int rc; +	struct device_node *dn = eeh_dev_to_of_node(edev); -	/* Use PE configuration address, if present */ -	config_addr = pdn->eeh_config_addr; -	if (pdn->eeh_pe_config_addr) -		config_addr = pdn->eeh_pe_config_addr; - -	rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL, -	               config_addr, -	               BUID_HI(pdn->phb->buid), -	               BUID_LO(pdn->phb->buid), -		            function); - +	rc = eeh_ops->set_option(dn, function);  	if (rc)  		printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", -		        function, rc, pdn->node->full_name); +		        function, rc, dn->full_name); -	rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC); -	if ((rc == 4) && (function == EEH_THAW_MMIO)) +	rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); +	if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && +	   (function == EEH_OPT_THAW_MMIO))  		return 0;  	return rc;  }  /** - * rtas_pci_slot_reset - raises/lowers the pci #RST line - * @pdn pci device node - * @state: 1/0 to raise/lower the #RST - * - * Clear the EEH-frozen condition on a slot.  This routine - * asserts the PCI #RST line if the 'state' argument is '1', - * and drops the #RST line if 'state is '0'.  This routine is - * safe to call in an interrupt context. - * - */ - -static void -rtas_pci_slot_reset(struct pci_dn *pdn, int state) -{ -	int config_addr; -	int rc; - -	BUG_ON (pdn==NULL);  - -	if (!pdn->phb) { -		printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", -		        pdn->node->full_name); -		return; -	} - -	/* Use PE configuration address, if present */ -	config_addr = pdn->eeh_config_addr; -	if (pdn->eeh_pe_config_addr) -		config_addr = pdn->eeh_pe_config_addr; - -	rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, -	               config_addr, -	               BUID_HI(pdn->phb->buid), -	               BUID_LO(pdn->phb->buid), -	               state); - -	/* Fundamental-reset not supported on this PE, try hot-reset */ -	if (rc == -8 && state == 3) { -		rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, -			       config_addr, -			       BUID_HI(pdn->phb->buid), -			       BUID_LO(pdn->phb->buid), 1); -		if (rc) -			printk(KERN_WARNING -				"EEH: Unable to reset the failed slot," -				" #RST=%d dn=%s\n", -				rc, pdn->node->full_name); -	} -} - -/**   * pcibios_set_pcie_slot_reset - Set PCI-E reset state - * @dev:	pci device struct - * @state:	reset state to enter + * @dev: pci device struct + * @state: reset state to enter   *   * Return value:   * 	0 if success - **/ + */  int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)  {  	struct device_node *dn = pci_device_to_OF_node(dev); -	struct pci_dn *pdn = PCI_DN(dn);  	switch (state) {  	case pcie_deassert_reset: -		rtas_pci_slot_reset(pdn, 0); +		eeh_ops->reset(dn, EEH_RESET_DEACTIVATE);  		break;  	case pcie_hot_reset: -		rtas_pci_slot_reset(pdn, 1); +		eeh_ops->reset(dn, EEH_RESET_HOT);  		break;  	case pcie_warm_reset: -		rtas_pci_slot_reset(pdn, 3); +		eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL);  		break;  	default:  		return -EINVAL; @@ -781,13 +591,66 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat  }  /** - * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second - * @pdn: pci device node to be reset. + * __eeh_set_pe_freset - Check the required reset for child devices + * @parent: parent device + * @freset: return value + * + * Each device might have its preferred reset type: fundamental or + * hot reset. The routine is used to collect the information from + * the child devices so that they could be reset accordingly.   */ +void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) +{ +	struct device_node *dn; + +	for_each_child_of_node(parent, dn) { +		if (of_node_to_eeh_dev(dn)) { +			struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; + +			if (dev && dev->driver) +				*freset |= dev->needs_freset; + +			__eeh_set_pe_freset(dn, freset); +		} +	} +} -static void __rtas_set_slot_reset(struct pci_dn *pdn) +/** + * eeh_set_pe_freset - Check the required reset for the indicated device and its children + * @dn: parent device + * @freset: return value + * + * Each device might have its preferred reset type: fundamental or + * hot reset. The routine is used to collected the information for + * the indicated device and its children so that the bunch of the + * devices could be reset properly. + */ +void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) +{ +	struct pci_dev *dev; +	dn = eeh_find_device_pe(dn); + +	/* Back up one, since config addrs might be shared */ +	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) +		dn = dn->parent; + +	dev = of_node_to_eeh_dev(dn)->pdev; +	if (dev) +		*freset |= dev->needs_freset; + +	__eeh_set_pe_freset(dn, freset); +} + +/** + * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second + * @edev: pci device node to be reset. + * + * Assert the PCI #RST line for 1/4 second. + */ +static void eeh_reset_pe_once(struct eeh_dev *edev)  {  	unsigned int freset = 0; +	struct device_node *dn = eeh_dev_to_of_node(edev);  	/* Determine type of EEH reset required for  	 * Partitionable Endpoint, a hot-reset (1) @@ -795,58 +658,68 @@ static void __rtas_set_slot_reset(struct pci_dn *pdn)  	 * A fundamental reset required by any device under  	 * Partitionable Endpoint trumps hot-reset.    	 */ -	eeh_set_pe_freset(pdn->node, &freset); +	eeh_set_pe_freset(dn, &freset);  	if (freset) -		rtas_pci_slot_reset(pdn, 3); +		eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL);  	else -		rtas_pci_slot_reset(pdn, 1); +		eeh_ops->reset(dn, EEH_RESET_HOT);  	/* The PCI bus requires that the reset be held high for at least -	 * a 100 milliseconds. We wait a bit longer 'just in case'.  */ - +	 * a 100 milliseconds. We wait a bit longer 'just in case'. +	 */  #define PCI_BUS_RST_HOLD_TIME_MSEC 250 -	msleep (PCI_BUS_RST_HOLD_TIME_MSEC); +	msleep(PCI_BUS_RST_HOLD_TIME_MSEC);  	/* We might get hit with another EEH freeze as soon as the   	 * pci slot reset line is dropped. Make sure we don't miss -	 * these, and clear the flag now. */ -	eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED); +	 * these, and clear the flag now. +	 */ +	eeh_clear_slot(dn, EEH_MODE_ISOLATED); -	rtas_pci_slot_reset (pdn, 0); +	eeh_ops->reset(dn, EEH_RESET_DEACTIVATE);  	/* After a PCI slot has been reset, the PCI Express spec requires  	 * a 1.5 second idle time for the bus to stabilize, before starting -	 * up traffic. */ +	 * up traffic. +	 */  #define PCI_BUS_SETTLE_TIME_MSEC 1800 -	msleep (PCI_BUS_SETTLE_TIME_MSEC); +	msleep(PCI_BUS_SETTLE_TIME_MSEC);  } -int rtas_set_slot_reset(struct pci_dn *pdn) +/** + * eeh_reset_pe - Reset the indicated PE + * @edev: PCI device associated EEH device + * + * This routine should be called to reset indicated device, including + * PE. A PE might include multiple PCI devices and sometimes PCI bridges + * might be involved as well. + */ +int eeh_reset_pe(struct eeh_dev *edev)  {  	int i, rc; +	struct device_node *dn = eeh_dev_to_of_node(edev);  	/* Take three shots at resetting the bus */  	for (i=0; i<3; i++) { -		__rtas_set_slot_reset(pdn); +		eeh_reset_pe_once(edev); -		rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC); -		if (rc == 0) +		rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); +		if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))  			return 0;  		if (rc < 0) {  			printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", -			       pdn->node->full_name); +			       dn->full_name);  			return -1;  		}  		printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", -		       i+1, pdn->node->full_name, rc); +		       i+1, dn->full_name, rc);  	}  	return -1;  } -/* ------------------------------------------------------- */  /** Save and restore of PCI BARs   *   * Although firmware will set up BARs during boot, it doesn't @@ -856,181 +729,122 @@ int rtas_set_slot_reset(struct pci_dn *pdn)   */  /** - * __restore_bars - Restore the Base Address Registers - * @pdn: pci device node + * eeh_restore_one_device_bars - Restore the Base Address Registers for one device + * @edev: PCI device associated EEH device   *   * Loads the PCI configuration space base address registers,   * the expansion ROM base address, the latency timer, and etc.   * from the saved values in the device node.   */ -static inline void __restore_bars (struct pci_dn *pdn) +static inline void eeh_restore_one_device_bars(struct eeh_dev *edev)  {  	int i;  	u32 cmd; +	struct device_node *dn = eeh_dev_to_of_node(edev); + +	if (!edev->phb) +		return; -	if (NULL==pdn->phb) return;  	for (i=4; i<10; i++) { -		rtas_write_config(pdn, i*4, 4, pdn->config_space[i]); +		eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);  	}  	/* 12 == Expansion ROM Address */ -	rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]); +	eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);  #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) -#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)]) +#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) -	rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1, +	eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,  	            SAVED_BYTE(PCI_CACHE_LINE_SIZE)); -	rtas_write_config (pdn, PCI_LATENCY_TIMER, 1, +	eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,  	            SAVED_BYTE(PCI_LATENCY_TIMER));  	/* max latency, min grant, interrupt pin and line */ -	rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); +	eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);  	/* Restore PERR & SERR bits, some devices require it, -	   don't touch the other command bits */ -	rtas_read_config(pdn, PCI_COMMAND, 4, &cmd); -	if (pdn->config_space[1] & PCI_COMMAND_PARITY) +	 * don't touch the other command bits +	 */ +	eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); +	if (edev->config_space[1] & PCI_COMMAND_PARITY)  		cmd |= PCI_COMMAND_PARITY;  	else  		cmd &= ~PCI_COMMAND_PARITY; -	if (pdn->config_space[1] & PCI_COMMAND_SERR) +	if (edev->config_space[1] & PCI_COMMAND_SERR)  		cmd |= PCI_COMMAND_SERR;  	else  		cmd &= ~PCI_COMMAND_SERR; -	rtas_write_config(pdn, PCI_COMMAND, 4, cmd); +	eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);  }  /** - * eeh_restore_bars - restore the PCI config space info + * eeh_restore_bars - Restore the PCI config space info + * @edev: EEH device   *   * This routine performs a recursive walk to the children   * of this device as well.   */ -void eeh_restore_bars(struct pci_dn *pdn) +void eeh_restore_bars(struct eeh_dev *edev)  {  	struct device_node *dn; -	if (!pdn)  +	if (!edev)  		return; -	if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) -		__restore_bars (pdn); +	if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) +		eeh_restore_one_device_bars(edev); -	for_each_child_of_node(pdn->node, dn) -		eeh_restore_bars (PCI_DN(dn)); +	for_each_child_of_node(eeh_dev_to_of_node(edev), dn) +		eeh_restore_bars(of_node_to_eeh_dev(dn));  }  /** - * eeh_save_bars - save device bars + * eeh_save_bars - Save device bars + * @edev: PCI device associated EEH device   *   * Save the values of the device bars. Unlike the restore   * routine, this routine is *not* recursive. This is because   * PCI devices are added individually; but, for the restore,   * an entire slot is reset at a time.   */ -static void eeh_save_bars(struct pci_dn *pdn) +static void eeh_save_bars(struct eeh_dev *edev)  {  	int i; +	struct device_node *dn; -	if (!pdn ) +	if (!edev)  		return; +	dn = eeh_dev_to_of_node(edev);  	for (i = 0; i < 16; i++) -		rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]); +		eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]);  } -void -rtas_configure_bridge(struct pci_dn *pdn) -{ -	int config_addr; -	int rc; -	int token; - -	/* Use PE configuration address, if present */ -	config_addr = pdn->eeh_config_addr; -	if (pdn->eeh_pe_config_addr) -		config_addr = pdn->eeh_pe_config_addr; - -	/* Use new configure-pe function, if supported */ -	if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) -		token = ibm_configure_pe; -	else -		token = ibm_configure_bridge; - -	rc = rtas_call(token, 3, 1, NULL, -	               config_addr, -	               BUID_HI(pdn->phb->buid), -	               BUID_LO(pdn->phb->buid)); -	if (rc) { -		printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", -		        rc, pdn->node->full_name); -	} -} - -/* ------------------------------------------------------------- */ -/* The code below deals with enabling EEH for devices during  the - * early boot sequence.  EEH must be enabled before any PCI probing - * can be done. +/** + * eeh_early_enable - Early enable EEH on the indicated device + * @dn: device node + * @data: BUID + * + * Enable EEH functionality on the specified PCI device. The function + * is expected to be called before real PCI probing is done. However, + * the PHBs have been initialized at this point.   */ - -#define EEH_ENABLE 1 - -struct eeh_early_enable_info { -	unsigned int buid_hi; -	unsigned int buid_lo; -}; - -static int get_pe_addr (int config_addr, -                        struct eeh_early_enable_info *info) -{ -	unsigned int rets[3]; -	int ret; - -	/* Use latest config-addr token on power6 */ -	if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { -		/* Make sure we have a PE in hand */ -		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, -			config_addr, info->buid_hi, info->buid_lo, 1); -		if (ret || (rets[0]==0)) -			return 0; - -		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, -			config_addr, info->buid_hi, info->buid_lo, 0); -		if (ret) -			return 0; -		return rets[0]; -	} - -	/* Use older config-addr token on power5 */ -	if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { -		ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, -			config_addr, info->buid_hi, info->buid_lo, 0); -		if (ret) -			return 0; -		return rets[0]; -	} -	return 0; -} - -/* Enable eeh for the given device node. */ -static void *early_enable_eeh(struct device_node *dn, void *data) +static void *eeh_early_enable(struct device_node *dn, void *data)  { -	unsigned int rets[3]; -	struct eeh_early_enable_info *info = data;  	int ret;  	const u32 *class_code = of_get_property(dn, "class-code", NULL);  	const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);  	const u32 *device_id = of_get_property(dn, "device-id", NULL);  	const u32 *regs;  	int enable; -	struct pci_dn *pdn = PCI_DN(dn); +	struct eeh_dev *edev = of_node_to_eeh_dev(dn); -	pdn->class_code = 0; -	pdn->eeh_mode = 0; -	pdn->eeh_check_count = 0; -	pdn->eeh_freeze_count = 0; -	pdn->eeh_false_positives = 0; +	edev->class_code = 0; +	edev->mode = 0; +	edev->check_count = 0; +	edev->freeze_count = 0; +	edev->false_positives = 0;  	if (!of_device_is_available(dn))  		return NULL; @@ -1041,54 +855,56 @@ static void *early_enable_eeh(struct device_node *dn, void *data)  	/* There is nothing to check on PCI to ISA bridges */  	if (dn->type && !strcmp(dn->type, "isa")) { -		pdn->eeh_mode |= EEH_MODE_NOCHECK; +		edev->mode |= EEH_MODE_NOCHECK;  		return NULL;  	} -	pdn->class_code = *class_code; +	edev->class_code = *class_code;  	/* Ok... see if this device supports EEH.  Some do, some don't, -	 * and the only way to find out is to check each and every one. */ +	 * and the only way to find out is to check each and every one. +	 */  	regs = of_get_property(dn, "reg", NULL);  	if (regs) {  		/* First register entry is addr (00BBSS00)  */  		/* Try to enable eeh */ -		ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, -		                regs[0], info->buid_hi, info->buid_lo, -		                EEH_ENABLE); +		ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE);  		enable = 0;  		if (ret == 0) { -			pdn->eeh_config_addr = regs[0]; +			edev->config_addr = regs[0];  			/* If the newer, better, ibm,get-config-addr-info is supported,  -			 * then use that instead. */ -			pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info); +			 * then use that instead. +			 */ +			edev->pe_config_addr = eeh_ops->get_pe_addr(dn);  			/* Some older systems (Power4) allow the  			 * ibm,set-eeh-option call to succeed even on nodes  			 * where EEH is not supported. Verify support -			 * explicitly. */ -			ret = read_slot_reset_state(pdn, rets); -			if ((ret == 0) && (rets[1] == 1)) +			 * explicitly. +			 */ +			ret = eeh_ops->get_state(dn, NULL); +			if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT)  				enable = 1;  		}  		if (enable) {  			eeh_subsystem_enabled = 1; -			pdn->eeh_mode |= EEH_MODE_SUPPORTED; +			edev->mode |= EEH_MODE_SUPPORTED;  			pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", -				 dn->full_name, pdn->eeh_config_addr, -				 pdn->eeh_pe_config_addr); +				 dn->full_name, edev->config_addr, +				 edev->pe_config_addr);  		} else {  			/* This device doesn't support EEH, but it may have an -			 * EEH parent, in which case we mark it as supported. */ -			if (dn->parent && PCI_DN(dn->parent) -			    && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { +			 * EEH parent, in which case we mark it as supported. +			 */ +			if (dn->parent && of_node_to_eeh_dev(dn->parent) && +			    (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) {  				/* Parent supports EEH. */ -				pdn->eeh_mode |= EEH_MODE_SUPPORTED; -				pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; +				edev->mode |= EEH_MODE_SUPPORTED; +				edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr;  				return NULL;  			}  		} @@ -1097,11 +913,63 @@ static void *early_enable_eeh(struct device_node *dn, void *data)  		       dn->full_name);  	} -	eeh_save_bars(pdn); +	eeh_save_bars(edev);  	return NULL;  } -/* +/** + * eeh_ops_register - Register platform dependent EEH operations + * @ops: platform dependent EEH operations + * + * Register the platform dependent EEH operation callback + * functions. The platform should call this function before + * any other EEH operations. + */ +int __init eeh_ops_register(struct eeh_ops *ops) +{ +	if (!ops->name) { +		pr_warning("%s: Invalid EEH ops name for %p\n", +			__func__, ops); +		return -EINVAL; +	} + +	if (eeh_ops && eeh_ops != ops) { +		pr_warning("%s: EEH ops of platform %s already existing (%s)\n", +			__func__, eeh_ops->name, ops->name); +		return -EEXIST; +	} + +	eeh_ops = ops; + +	return 0; +} + +/** + * eeh_ops_unregister - Unreigster platform dependent EEH operations + * @name: name of EEH platform operations + * + * Unregister the platform dependent EEH operation callback + * functions. + */ +int __exit eeh_ops_unregister(const char *name) +{ +	if (!name || !strlen(name)) { +		pr_warning("%s: Invalid EEH ops name\n", +			__func__); +		return -EINVAL; +	} + +	if (eeh_ops && !strcmp(eeh_ops->name, name)) { +		eeh_ops = NULL; +		return 0; +	} + +	return -EEXIST; +} + +/** + * eeh_init - EEH initialization + *   * Initialize EEH by trying to enable it for all of the adapters in the system.   * As a side effect we can determine here if eeh is supported at all.   * Note that we leave EEH on so failed config cycles won't cause a machine @@ -1116,51 +984,27 @@ static void *early_enable_eeh(struct device_node *dn, void *data)   */  void __init eeh_init(void)  { -	struct device_node *phb, *np; -	struct eeh_early_enable_info info; - -	raw_spin_lock_init(&confirm_error_lock); -	spin_lock_init(&slot_errbuf_lock); +	struct pci_controller *hose, *tmp; +	struct device_node *phb; +	int ret; -	np = of_find_node_by_path("/rtas"); -	if (np == NULL) +	/* call platform initialization function */ +	if (!eeh_ops) { +		pr_warning("%s: Platform EEH operation not found\n", +			__func__);  		return; - -	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); -	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); -	ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); -	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); -	ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); -	ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); -	ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); -	ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); -	ibm_configure_pe = rtas_token("ibm,configure-pe"); - -	if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) +	} else if ((ret = eeh_ops->init())) { +		pr_warning("%s: Failed to call platform init function (%d)\n", +			__func__, ret);  		return; - -	eeh_error_buf_size = rtas_token("rtas-error-log-max"); -	if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { -		eeh_error_buf_size = 1024;  	} -	if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { -		printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated " -		      "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX); -		eeh_error_buf_size = RTAS_ERROR_LOG_MAX; -	} - -	/* Enable EEH for all adapters.  Note that eeh requires buid's */ -	for (phb = of_find_node_by_name(NULL, "pci"); phb; -	     phb = of_find_node_by_name(phb, "pci")) { -		unsigned long buid; -		buid = get_phb_buid(phb); -		if (buid == 0 || PCI_DN(phb) == NULL) -			continue; +	raw_spin_lock_init(&confirm_error_lock); -		info.buid_lo = BUID_LO(buid); -		info.buid_hi = BUID_HI(buid); -		traverse_pci_devices(phb, early_enable_eeh, &info); +	/* Enable EEH for all adapters */ +	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { +		phb = hose->dn; +		traverse_pci_devices(phb, eeh_early_enable, NULL);  	}  	if (eeh_subsystem_enabled) @@ -1170,7 +1014,7 @@ void __init eeh_init(void)  }  /** - * eeh_add_device_early - enable EEH for the indicated device_node + * eeh_add_device_early - Enable EEH for the indicated device_node   * @dn: device node for which to set up EEH   *   * This routine must be used to perform EEH initialization for PCI @@ -1184,21 +1028,26 @@ void __init eeh_init(void)  static void eeh_add_device_early(struct device_node *dn)  {  	struct pci_controller *phb; -	struct eeh_early_enable_info info; -	if (!dn || !PCI_DN(dn)) +	if (!dn || !of_node_to_eeh_dev(dn))  		return; -	phb = PCI_DN(dn)->phb; +	phb = of_node_to_eeh_dev(dn)->phb;  	/* USB Bus children of PCI devices will not have BUID's */  	if (NULL == phb || 0 == phb->buid)  		return; -	info.buid_hi = BUID_HI(phb->buid); -	info.buid_lo = BUID_LO(phb->buid); -	early_enable_eeh(dn, &info); +	eeh_early_enable(dn, NULL);  } +/** + * eeh_add_device_tree_early - Enable EEH for the indicated device + * @dn: device node + * + * This routine must be used to perform EEH initialization for the + * indicated PCI device that was added after system boot (e.g. + * hotplug, dlpar). + */  void eeh_add_device_tree_early(struct device_node *dn)  {  	struct device_node *sib; @@ -1210,7 +1059,7 @@ void eeh_add_device_tree_early(struct device_node *dn)  EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);  /** - * eeh_add_device_late - perform EEH initialization for the indicated pci device + * eeh_add_device_late - Perform EEH initialization for the indicated pci device   * @dev: pci device for which to set up EEH   *   * This routine must be used to complete EEH initialization for PCI @@ -1219,7 +1068,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);  static void eeh_add_device_late(struct pci_dev *dev)  {  	struct device_node *dn; -	struct pci_dn *pdn; +	struct eeh_dev *edev;  	if (!dev || !eeh_subsystem_enabled)  		return; @@ -1227,20 +1076,29 @@ static void eeh_add_device_late(struct pci_dev *dev)  	pr_debug("EEH: Adding device %s\n", pci_name(dev));  	dn = pci_device_to_OF_node(dev); -	pdn = PCI_DN(dn); -	if (pdn->pcidev == dev) { +	edev = pci_dev_to_eeh_dev(dev); +	if (edev->pdev == dev) {  		pr_debug("EEH: Already referenced !\n");  		return;  	} -	WARN_ON(pdn->pcidev); +	WARN_ON(edev->pdev); -	pci_dev_get (dev); -	pdn->pcidev = dev; +	pci_dev_get(dev); +	edev->pdev = dev; +	dev->dev.archdata.edev = edev;  	pci_addr_cache_insert_device(dev);  	eeh_sysfs_add_device(dev);  } +/** + * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus + * @bus: PCI bus + * + * This routine must be used to perform EEH initialization for PCI + * devices which are attached to the indicated PCI bus. The PCI bus + * is added after system boot through hotplug or dlpar. + */  void eeh_add_device_tree_late(struct pci_bus *bus)  {  	struct pci_dev *dev; @@ -1257,7 +1115,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus)  EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);  /** - * eeh_remove_device - undo EEH setup for the indicated pci device + * eeh_remove_device - Undo EEH setup for the indicated pci device   * @dev: pci device to be removed   *   * This routine should be called when a device is removed from @@ -1268,25 +1126,35 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);   */  static void eeh_remove_device(struct pci_dev *dev)  { -	struct device_node *dn; +	struct eeh_dev *edev; +  	if (!dev || !eeh_subsystem_enabled)  		return; +	edev = pci_dev_to_eeh_dev(dev);  	/* Unregister the device with the EEH/PCI address search system */  	pr_debug("EEH: Removing device %s\n", pci_name(dev)); -	dn = pci_device_to_OF_node(dev); -	if (PCI_DN(dn)->pcidev == NULL) { +	if (!edev || !edev->pdev) {  		pr_debug("EEH: Not referenced !\n");  		return;  	} -	PCI_DN(dn)->pcidev = NULL; -	pci_dev_put (dev); +	edev->pdev = NULL; +	dev->dev.archdata.edev = NULL; +	pci_dev_put(dev);  	pci_addr_cache_remove_device(dev);  	eeh_sysfs_remove_device(dev);  } +/** + * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device + * @dev: PCI device + * + * This routine must be called when a device is removed from the + * running system through hotplug or dlpar. The corresponding + * PCI address cache will be removed. + */  void eeh_remove_bus_device(struct pci_dev *dev)  {  	struct pci_bus *bus = dev->subordinate; @@ -1305,21 +1173,24 @@ static int proc_eeh_show(struct seq_file *m, void *v)  {  	if (0 == eeh_subsystem_enabled) {  		seq_printf(m, "EEH Subsystem is globally disabled\n"); -		seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_ffs); +		seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);  	} else {  		seq_printf(m, "EEH Subsystem is enabled\n");  		seq_printf(m, -				"no device=%ld\n" -				"no device node=%ld\n" -				"no config address=%ld\n" -				"check not wanted=%ld\n" -				"eeh_total_mmio_ffs=%ld\n" -				"eeh_false_positives=%ld\n" -				"eeh_slot_resets=%ld\n", -				no_device, no_dn, no_cfg_addr,  -				ignored_check, total_mmio_ffs,  -				false_positives, -				slot_resets); +				"no device=%llu\n" +				"no device node=%llu\n" +				"no config address=%llu\n" +				"check not wanted=%llu\n" +				"eeh_total_mmio_ffs=%llu\n" +				"eeh_false_positives=%llu\n" +				"eeh_slot_resets=%llu\n", +				eeh_stats.no_device, +				eeh_stats.no_dn, +				eeh_stats.no_cfg_addr, +				eeh_stats.ignored_check, +				eeh_stats.total_mmio_ffs, +				eeh_stats.false_positives, +				eeh_stats.slot_resets);  	}  	return 0; diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index fc5ae767989..e5ae1c687c6 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -1,5 +1,4 @@  /* - * eeh_cache.c   * PCI address cache; allows the lookup of PCI devices based on I/O address   *   * Copyright IBM Corporation 2004 @@ -47,8 +46,7 @@   * than any hash algo I could think of for this problem, even   * with the penalty of slow pointer chases for d-cache misses).   */ -struct pci_io_addr_range -{ +struct pci_io_addr_range {  	struct rb_node rb_node;  	unsigned long addr_lo;  	unsigned long addr_hi; @@ -56,13 +54,12 @@ struct pci_io_addr_range  	unsigned int flags;  }; -static struct pci_io_addr_cache -{ +static struct pci_io_addr_cache {  	struct rb_root rb_root;  	spinlock_t piar_lock;  } pci_io_addr_cache_root; -static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) +static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr)  {  	struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; @@ -86,7 +83,7 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)  }  /** - * pci_get_device_by_addr - Get device, given only address + * pci_addr_cache_get_device - Get device, given only address   * @addr: mmio (PIO) phys address or i/o port number   *   * Given an mmio phys address, or a port number, find a pci device @@ -95,13 +92,13 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr)   * from zero (that is, they do *not* have pci_io_addr added in).   * It is safe to call this function within an interrupt.   */ -struct pci_dev *pci_get_device_by_addr(unsigned long addr) +struct pci_dev *pci_addr_cache_get_device(unsigned long addr)  {  	struct pci_dev *dev;  	unsigned long flags;  	spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); -	dev = __pci_get_device_by_addr(addr); +	dev = __pci_addr_cache_get_device(addr);  	spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);  	return dev;  } @@ -166,7 +163,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,  #ifdef DEBUG  	printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", -	                  alo, ahi, pci_name (dev)); +	                  alo, ahi, pci_name(dev));  #endif  	rb_link_node(&piar->rb_node, parent, p); @@ -178,7 +175,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,  static void __pci_addr_cache_insert_device(struct pci_dev *dev)  {  	struct device_node *dn; -	struct pci_dn *pdn; +	struct eeh_dev *edev;  	int i;  	dn = pci_device_to_OF_node(dev); @@ -187,13 +184,19 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev)  		return;  	} +	edev = of_node_to_eeh_dev(dn); +	if (!edev) { +		pr_warning("PCI: no EEH dev found for dn=%s\n", +			dn->full_name); +		return; +	} +  	/* Skip any devices for which EEH is not enabled. */ -	pdn = PCI_DN(dn); -	if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || -	    pdn->eeh_mode & EEH_MODE_NOCHECK) { +	if (!(edev->mode & EEH_MODE_SUPPORTED) || +	    edev->mode & EEH_MODE_NOCHECK) {  #ifdef DEBUG -		printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n", -		       pci_name(dev), pdn->node->full_name); +		pr_info("PCI: skip building address cache for=%s - %s\n", +			pci_name(dev), dn->full_name);  #endif  		return;  	} @@ -284,6 +287,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev)  void __init pci_addr_cache_build(void)  {  	struct device_node *dn; +	struct eeh_dev *edev;  	struct pci_dev *dev = NULL;  	spin_lock_init(&pci_io_addr_cache_root.piar_lock); @@ -294,8 +298,14 @@ void __init pci_addr_cache_build(void)  		dn = pci_device_to_OF_node(dev);  		if (!dn)  			continue; + +		edev = of_node_to_eeh_dev(dn); +		if (!edev) +			continue; +  		pci_dev_get(dev);  /* matching put is in eeh_remove_device() */ -		PCI_DN(dn)->pcidev = dev; +		dev->dev.archdata.edev = edev; +		edev->pdev = dev;  		eeh_sysfs_add_device(dev);  	} diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c new file mode 100644 index 00000000000..c4507d09590 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_dev.c @@ -0,0 +1,102 @@ +/* + * The file intends to implement dynamic creation of EEH device, which will + * be bound with OF node and PCI device simutaneously. The EEH devices would + * be foundamental information for EEH core components to work proerly. Besides, + * We have to support multiple situations where dynamic creation of EEH device + * is required: + * + * 1) Before PCI emunation starts, we need create EEH devices according to the + *    PCI sensitive OF nodes. + * 2) When PCI emunation is done, we need do the binding between PCI device and + *    the associated EEH device. + * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device + *    will be created while PCI sensitive OF node is detected from DR. + * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If + *    PHB is newly inserted, we also need create EEH devices accordingly. + * + * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + */ + +#include <linux/export.h> +#include <linux/gfp.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/string.h> + +#include <asm/pci-bridge.h> +#include <asm/ppc-pci.h> + +/** + * eeh_dev_init - Create EEH device according to OF node + * @dn: device node + * @data: PHB + * + * It will create EEH device according to the given OF node. The function + * might be called by PCI emunation, DR, PHB hotplug. + */ +void * __devinit eeh_dev_init(struct device_node *dn, void *data) +{ +	struct pci_controller *phb = data; +	struct eeh_dev *edev; + +	/* Allocate EEH device */ +	edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL); +	if (!edev) { +		pr_warning("%s: out of memory\n", __func__); +		return NULL; +	} + +	/* Associate EEH device with OF node */ +	PCI_DN(dn)->edev = edev; +	edev->dn  = dn; +	edev->phb = phb; + +	return NULL; +} + +/** + * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB + * @phb: PHB + * + * Scan the PHB OF node and its child association, then create the + * EEH devices accordingly + */ +void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb) +{ +	struct device_node *dn = phb->dn; + +	/* EEH device for PHB */ +	eeh_dev_init(dn, phb); + +	/* EEH devices for children OF nodes */ +	traverse_pci_devices(dn, eeh_dev_init, phb); +} + +/** + * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs + * + * Scan all the existing PHBs and create EEH devices for their OF + * nodes and their children OF nodes + */ +void __init eeh_dev_phb_init(void) +{ +	struct pci_controller *phb, *tmp; + +	list_for_each_entry_safe(phb, tmp, &hose_list, list_node) +		eeh_dev_phb_init_dynamic(phb); +} diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 1b6cb10589e..baf92cd9dfa 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -33,8 +33,14 @@  #include <asm/prom.h>  #include <asm/rtas.h> - -static inline const char * pcid_name (struct pci_dev *pdev) +/** + * eeh_pcid_name - Retrieve name of PCI device driver + * @pdev: PCI device + * + * This routine is used to retrieve the name of PCI device driver + * if that's valid. + */ +static inline const char *eeh_pcid_name(struct pci_dev *pdev)  {  	if (pdev && pdev->dev.driver)  		return pdev->dev.driver->name; @@ -64,48 +70,59 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent)  #endif  /** - * eeh_disable_irq - disable interrupt for the recovering device + * eeh_disable_irq - Disable interrupt for the recovering device + * @dev: PCI device + * + * This routine must be called when reporting temporary or permanent + * error to the particular PCI device to disable interrupt of that + * device. If the device has enabled MSI or MSI-X interrupt, we needn't + * do real work because EEH should freeze DMA transfers for those PCI + * devices encountering EEH errors, which includes MSI or MSI-X.   */  static void eeh_disable_irq(struct pci_dev *dev)  { -	struct device_node *dn = pci_device_to_OF_node(dev); +	struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);  	/* Don't disable MSI and MSI-X interrupts. They are  	 * effectively disabled by the DMA Stopped state  	 * when an EEH error occurs. -	*/ +	 */  	if (dev->msi_enabled || dev->msix_enabled)  		return;  	if (!irq_has_action(dev->irq))  		return; -	PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; +	edev->mode |= EEH_MODE_IRQ_DISABLED;  	disable_irq_nosync(dev->irq);  }  /** - * eeh_enable_irq - enable interrupt for the recovering device + * eeh_enable_irq - Enable interrupt for the recovering device + * @dev: PCI device + * + * This routine must be called to enable interrupt while failed + * device could be resumed.   */  static void eeh_enable_irq(struct pci_dev *dev)  { -	struct device_node *dn = pci_device_to_OF_node(dev); +	struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); -	if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { -		PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; +	if ((edev->mode) & EEH_MODE_IRQ_DISABLED) { +		edev->mode &= ~EEH_MODE_IRQ_DISABLED;  		enable_irq(dev->irq);  	}  } -/* ------------------------------------------------------- */  /** - * eeh_report_error - report pci error to each device driver + * eeh_report_error - Report pci error to each device driver + * @dev: PCI device + * @userdata: return value   *    * Report an EEH error to each device driver, collect up and    * merge the device driver responses. Cumulative response    * passed back in "userdata".   */ -  static int eeh_report_error(struct pci_dev *dev, void *userdata)  {  	enum pci_ers_result rc, *res = userdata; @@ -122,7 +139,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata)  	    !driver->err_handler->error_detected)  		return 0; -	rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); +	rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen);  	/* A driver that needs a reset trumps all others */  	if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; @@ -132,13 +149,14 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata)  }  /** - * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled + * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled + * @dev: PCI device + * @userdata: return value   *   * Tells each device driver that IO ports, MMIO and config space I/O   * are now enabled. Collects up and merges the device driver responses.   * Cumulative response passed back in "userdata".   */ -  static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)  {  	enum pci_ers_result rc, *res = userdata; @@ -149,7 +167,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)  	    !driver->err_handler->mmio_enabled)  		return 0; -	rc = driver->err_handler->mmio_enabled (dev); +	rc = driver->err_handler->mmio_enabled(dev);  	/* A driver that needs a reset trumps all others */  	if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; @@ -159,9 +177,15 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)  }  /** - * eeh_report_reset - tell device that slot has been reset + * eeh_report_reset - Tell device that slot has been reset + * @dev: PCI device + * @userdata: return value + * + * This routine must be called while EEH tries to reset particular + * PCI device so that the associated PCI device driver could take + * some actions, usually to save data the driver needs so that the + * driver can work again while the device is recovered.   */ -  static int eeh_report_reset(struct pci_dev *dev, void *userdata)  {  	enum pci_ers_result rc, *res = userdata; @@ -188,9 +212,14 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata)  }  /** - * eeh_report_resume - tell device to resume normal operations + * eeh_report_resume - Tell device to resume normal operations + * @dev: PCI device + * @userdata: return value + * + * This routine must be called to notify the device driver that it + * could resume so that the device driver can do some initialization + * to make the recovered device work again.   */ -  static int eeh_report_resume(struct pci_dev *dev, void *userdata)  {  	struct pci_driver *driver = dev->driver; @@ -212,12 +241,13 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata)  }  /** - * eeh_report_failure - tell device driver that device is dead. + * eeh_report_failure - Tell device driver that device is dead. + * @dev: PCI device + * @userdata: return value   *   * This informs the device driver that the device is permanently   * dead, and that no further recovery attempts will be made on it.   */ -  static int eeh_report_failure(struct pci_dev *dev, void *userdata)  {  	struct pci_driver *driver = dev->driver; @@ -238,65 +268,46 @@ static int eeh_report_failure(struct pci_dev *dev, void *userdata)  	return 0;  } -/* ------------------------------------------------------- */  /** - * handle_eeh_events -- reset a PCI device after hard lockup. - * - * pSeries systems will isolate a PCI slot if the PCI-Host - * bridge detects address or data parity errors, DMA's - * occurring to wild addresses (which usually happen due to - * bugs in device drivers or in PCI adapter firmware). - * Slot isolations also occur if #SERR, #PERR or other misc - * PCI-related errors are detected. + * eeh_reset_device - Perform actual reset of a pci slot + * @edev: PE associated EEH device + * @bus: PCI bus corresponding to the isolcated slot   * - * Recovery process consists of unplugging the device driver - * (which generated hotplug events to userspace), then issuing - * a PCI #RST to the device, then reconfiguring the PCI config - * space for all bridges & devices under this slot, and then - * finally restarting the device drivers (which cause a second - * set of hotplug events to go out to userspace). + * This routine must be called to do reset on the indicated PE. + * During the reset, udev might be invoked because those affected + * PCI devices will be removed and then added.   */ - -/** - * eeh_reset_device() -- perform actual reset of a pci slot - * @bus: pointer to the pci bus structure corresponding - *            to the isolated slot. A non-null value will - *            cause all devices under the bus to be removed - *            and then re-added. - * @pe_dn: pointer to a "Partionable Endpoint" device node. - *            This is the top-level structure on which pci - *            bus resets can be performed. - */ - -static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) +static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus)  {  	struct device_node *dn;  	int cnt, rc;  	/* pcibios will clear the counter; save the value */ -	cnt = pe_dn->eeh_freeze_count; +	cnt = edev->freeze_count;  	if (bus)  		pcibios_remove_pci_devices(bus);  	/* Reset the pci controller. (Asserts RST#; resets config space).  	 * Reconfigure bridges and devices. Don't try to bring the system -	 * up if the reset failed for some reason. */ -	rc = rtas_set_slot_reset(pe_dn); +	 * up if the reset failed for some reason. +	 */ +	rc = eeh_reset_pe(edev);  	if (rc)  		return rc; -	/* Walk over all functions on this device.  */ -	dn = pe_dn->node; -	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) +	/* Walk over all functions on this device. */ +	dn = eeh_dev_to_of_node(edev); +	if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent))  		dn = dn->parent->child;  	while (dn) { -		struct pci_dn *ppe = PCI_DN(dn); +		struct eeh_dev *pedev = of_node_to_eeh_dev(dn); +  		/* On Power4, always true because eeh_pe_config_addr=0 */ -		if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { -			rtas_configure_bridge(ppe); -			eeh_restore_bars(ppe); +		if (edev->pe_config_addr == pedev->pe_config_addr) { +			eeh_ops->configure_bridge(dn); +			eeh_restore_bars(pedev);   		}  		dn = dn->sibling;  	} @@ -308,10 +319,10 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)  	 * potentially weird things happen.  	 */  	if (bus) { -		ssleep (5); +		ssleep(5);  		pcibios_add_pci_devices(bus);  	} -	pe_dn->eeh_freeze_count = cnt; +	edev->freeze_count = cnt;  	return 0;  } @@ -321,23 +332,39 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)   */  #define MAX_WAIT_FOR_RECOVERY 150 -struct pci_dn * handle_eeh_events (struct eeh_event *event) +/** + * eeh_handle_event - Reset a PCI device after hard lockup. + * @event: EEH event + * + * While PHB detects address or data parity errors on particular PCI + * slot, the associated PE will be frozen. Besides, DMA's occurring + * to wild addresses (which usually happen due to bugs in device + * drivers or in PCI adapter firmware) can cause EEH error. #SERR, + * #PERR or other misc PCI-related errors also can trigger EEH errors. + * + * Recovery process consists of unplugging the device driver (which + * generated hotplug events to userspace), then issuing a PCI #RST to + * the device, then reconfiguring the PCI config space for all bridges + * & devices under this slot, and then finally restarting the device + * drivers (which cause a second set of hotplug events to go out to + * userspace). + */ +struct eeh_dev *handle_eeh_events(struct eeh_event *event)  {  	struct device_node *frozen_dn; -	struct pci_dn *frozen_pdn; +	struct eeh_dev *frozen_edev;  	struct pci_bus *frozen_bus;  	int rc = 0;  	enum pci_ers_result result = PCI_ERS_RESULT_NONE;  	const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; -	frozen_dn = find_device_pe(event->dn); +	frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev));  	if (!frozen_dn) { - -		location = of_get_property(event->dn, "ibm,loc-code", NULL); +		location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL);  		location = location ? location : "unknown";  		printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "  		                "for location=%s pci addr=%s\n", -		        location, eeh_pci_name(event->dev)); +			location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev)));  		return NULL;  	} @@ -350,9 +377,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  	 * which was always an EADS pci bridge.  In the new style,  	 * there might not be any EADS bridges, and even when there are,  	 * the firmware marks them as "EEH incapable". So another -	 * two-step is needed to find the pci bus.. */ +	 * two-step is needed to find the pci bus.. +	 */  	if (!frozen_bus) -		frozen_bus = pcibios_find_pci_bus (frozen_dn->parent); +		frozen_bus = pcibios_find_pci_bus(frozen_dn->parent);  	if (!frozen_bus) {  		printk(KERN_ERR "EEH: Cannot find PCI bus " @@ -361,22 +389,21 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  		return NULL;  	} -	frozen_pdn = PCI_DN(frozen_dn); -	frozen_pdn->eeh_freeze_count++; +	frozen_edev = of_node_to_eeh_dev(frozen_dn); +	frozen_edev->freeze_count++; +	pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev)); +	drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev)); -	pci_str = eeh_pci_name(event->dev); -	drv_str = pcid_name(event->dev); -	 -	if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) +	if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES)  		goto excess_failures;  	printk(KERN_WARNING  	   "EEH: This PCI device has failed %d times in the last hour:\n", -		frozen_pdn->eeh_freeze_count); +		frozen_edev->freeze_count); -	if (frozen_pdn->pcidev) { -		bus_pci_str = pci_name(frozen_pdn->pcidev); -		bus_drv_str = pcid_name(frozen_pdn->pcidev); +	if (frozen_edev->pdev) { +		bus_pci_str = pci_name(frozen_edev->pdev); +		bus_drv_str = eeh_pcid_name(frozen_edev->pdev);  		printk(KERN_WARNING  			"EEH: Bus location=%s driver=%s pci addr=%s\n",  			location, bus_drv_str, bus_pci_str); @@ -395,9 +422,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  	pci_walk_bus(frozen_bus, eeh_report_error, &result);  	/* Get the current PCI slot state. This can take a long time, -	 * sometimes over 3 seconds for certain systems. */ -	rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); -	if (rc < 0) { +	 * sometimes over 3 seconds for certain systems. +	 */ +	rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000); +	if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {  		printk(KERN_WARNING "EEH: Permanent failure\n");  		goto hard_fail;  	} @@ -406,14 +434,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  	 * don't post the error log until after all dev drivers  	 * have been informed.  	 */ -	eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE); +	eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP);  	/* If all device drivers were EEH-unaware, then shut  	 * down all of the device drivers, and hope they  	 * go down willingly, without panicing the system.  	 */  	if (result == PCI_ERS_RESULT_NONE) { -		rc = eeh_reset_device(frozen_pdn, frozen_bus); +		rc = eeh_reset_device(frozen_edev, frozen_bus);  		if (rc) {  			printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc);  			goto hard_fail; @@ -422,7 +450,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  	/* If all devices reported they can proceed, then re-enable MMIO */  	if (result == PCI_ERS_RESULT_CAN_RECOVER) { -		rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO); +		rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO);  		if (rc < 0)  			goto hard_fail; @@ -436,7 +464,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  	/* If all devices reported they can proceed, then re-enable DMA */  	if (result == PCI_ERS_RESULT_CAN_RECOVER) { -		rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA); +		rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA);  		if (rc < 0)  			goto hard_fail; @@ -454,7 +482,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  	/* If any device called out for a reset, then reset the slot */  	if (result == PCI_ERS_RESULT_NEED_RESET) { -		rc = eeh_reset_device(frozen_pdn, NULL); +		rc = eeh_reset_device(frozen_edev, NULL);  		if (rc) {  			printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc);  			goto hard_fail; @@ -473,7 +501,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)  	/* Tell all device drivers that they can resume operations */  	pci_walk_bus(frozen_bus, eeh_report_resume, NULL); -	return frozen_pdn; +	return frozen_edev;  excess_failures:  	/* @@ -486,7 +514,7 @@ excess_failures:  		"has failed %d times in the last hour "  		"and has been permanently disabled.\n"  		"Please try reseating this device or replacing it.\n", -		location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); +		location, drv_str, pci_str, frozen_edev->freeze_count);  	goto perm_error;  hard_fail: @@ -497,7 +525,7 @@ hard_fail:  		location, drv_str, pci_str);  perm_error: -	eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE); +	eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM);  	/* Notify all devices that they're about to go down. */  	pci_walk_bus(frozen_bus, eeh_report_failure, NULL); @@ -508,4 +536,3 @@ perm_error:  	return NULL;  } -/* ---------- end of file ---------- */ diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index d2383cfb6df..4a475256585 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -1,6 +1,4 @@  /* - * eeh_event.c - *   * 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 @@ -46,7 +44,7 @@ DECLARE_WORK(eeh_event_wq, eeh_thread_launcher);  DEFINE_MUTEX(eeh_event_mutex);  /** - * eeh_event_handler - dispatch EEH events. + * eeh_event_handler - Dispatch EEH events.   * @dummy - unused   *   * The detection of a frozen slot can occur inside an interrupt, @@ -58,10 +56,10 @@ DEFINE_MUTEX(eeh_event_mutex);  static int eeh_event_handler(void * dummy)  {  	unsigned long flags; -	struct eeh_event	*event; -	struct pci_dn *pdn; +	struct eeh_event *event; +	struct eeh_dev *edev; -	daemonize ("eehd"); +	daemonize("eehd");  	set_current_state(TASK_INTERRUPTIBLE);  	spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -79,31 +77,37 @@ static int eeh_event_handler(void * dummy)  	/* Serialize processing of EEH events */  	mutex_lock(&eeh_event_mutex); -	eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); +	edev = event->edev; +	eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING);  	printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", -	       eeh_pci_name(event->dev)); +	       eeh_pci_name(edev->pdev)); + +	edev = handle_eeh_events(event); -	pdn = handle_eeh_events(event); +	eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); +	pci_dev_put(edev->pdev); -	eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); -	pci_dev_put(event->dev);  	kfree(event);  	mutex_unlock(&eeh_event_mutex);  	/* If there are no new errors after an hour, clear the counter. */ -	if (pdn && pdn->eeh_freeze_count>0) { -		msleep_interruptible (3600*1000); -		if (pdn->eeh_freeze_count>0) -			pdn->eeh_freeze_count--; +	if (edev && edev->freeze_count>0) { +		msleep_interruptible(3600*1000); +		if (edev->freeze_count>0) +			edev->freeze_count--; +  	}  	return 0;  }  /** - * eeh_thread_launcher + * eeh_thread_launcher - Start kernel thread to handle EEH events   * @dummy - unused + * + * This routine is called to start the kernel thread for processing + * EEH event.   */  static void eeh_thread_launcher(struct work_struct *dummy)  { @@ -112,18 +116,18 @@ static void eeh_thread_launcher(struct work_struct *dummy)  }  /** - * eeh_send_failure_event - generate a PCI error event - * @dev pci device + * eeh_send_failure_event - Generate a PCI error event + * @edev: EEH device   *   * This routine can be called within an interrupt context;   * the actual event will be delivered in a normal context   * (from a workqueue).   */ -int eeh_send_failure_event (struct device_node *dn, -                            struct pci_dev *dev) +int eeh_send_failure_event(struct eeh_dev *edev)  {  	unsigned long flags;  	struct eeh_event *event; +	struct device_node *dn = eeh_dev_to_of_node(edev);  	const char *location;  	if (!mem_init_done) { @@ -135,15 +139,14 @@ int eeh_send_failure_event (struct device_node *dn,  	}  	event = kmalloc(sizeof(*event), GFP_ATOMIC);  	if (event == NULL) { -		printk (KERN_ERR "EEH: out of memory, event not handled\n"); +		printk(KERN_ERR "EEH: out of memory, event not handled\n");  		return 1;   	} -	if (dev) -		pci_dev_get(dev); +	if (edev->pdev) +		pci_dev_get(edev->pdev); -	event->dn = dn; -	event->dev = dev; +	event->edev = edev;  	/* We may or may not be called in an interrupt context */  	spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -154,5 +157,3 @@ int eeh_send_failure_event (struct device_node *dn,  	return 0;  } - -/********************** END OF FILE ******************************/ diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c new file mode 100644 index 00000000000..8752f79a6af --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -0,0 +1,565 @@ +/* + * The file intends to implement the platform dependent EEH operations on pseries. + * Actually, the pseries platform is built based on RTAS heavily. That means the + * pseries platform dependent EEH operations will be built on RTAS calls. The functions + * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has + * been done. + * + * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011. + * Copyright IBM Corporation 2001, 2005, 2006 + * Copyright Dave Engebretsen & Todd Inglett 2001 + * Copyright Linas Vepstas 2005, 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + */ + +#include <linux/atomic.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/of.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <linux/rbtree.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/spinlock.h> + +#include <asm/eeh.h> +#include <asm/eeh_event.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/ppc-pci.h> +#include <asm/rtas.h> + +/* RTAS tokens */ +static int ibm_set_eeh_option; +static int ibm_set_slot_reset; +static int ibm_read_slot_reset_state; +static int ibm_read_slot_reset_state2; +static int ibm_slot_error_detail; +static int ibm_get_config_addr_info; +static int ibm_get_config_addr_info2; +static int ibm_configure_bridge; +static int ibm_configure_pe; + +/* + * Buffer for reporting slot-error-detail rtas calls. Its here + * in BSS, and not dynamically alloced, so that it ends up in + * RMO where RTAS can access it. + */ +static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; +static DEFINE_SPINLOCK(slot_errbuf_lock); +static int eeh_error_buf_size; + +/** + * pseries_eeh_init - EEH platform dependent initialization + * + * EEH platform dependent initialization on pseries. + */ +static int pseries_eeh_init(void) +{ +	/* figure out EEH RTAS function call tokens */ +	ibm_set_eeh_option		= rtas_token("ibm,set-eeh-option"); +	ibm_set_slot_reset		= rtas_token("ibm,set-slot-reset"); +	ibm_read_slot_reset_state2	= rtas_token("ibm,read-slot-reset-state2"); +	ibm_read_slot_reset_state	= rtas_token("ibm,read-slot-reset-state"); +	ibm_slot_error_detail		= rtas_token("ibm,slot-error-detail"); +	ibm_get_config_addr_info2	= rtas_token("ibm,get-config-addr-info2"); +	ibm_get_config_addr_info	= rtas_token("ibm,get-config-addr-info"); +	ibm_configure_pe		= rtas_token("ibm,configure-pe"); +	ibm_configure_bridge		= rtas_token ("ibm,configure-bridge"); + +	/* necessary sanity check */ +	if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) { +		pr_warning("%s: RTAS service <ibm,set-eeh-option> invalid\n", +			__func__); +		return -EINVAL; +	} else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) { +		pr_warning("%s: RTAS service <ibm, set-slot-reset> invalid\n", +			__func__); +		return -EINVAL; +	} else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE && +		   ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) { +		pr_warning("%s: RTAS service <ibm,read-slot-reset-state2> and " +			"<ibm,read-slot-reset-state> invalid\n", +			__func__); +		return -EINVAL; +	} else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) { +		pr_warning("%s: RTAS service <ibm,slot-error-detail> invalid\n", +			__func__); +		return -EINVAL; +	} else if (ibm_get_config_addr_info2 == RTAS_UNKNOWN_SERVICE && +		   ibm_get_config_addr_info == RTAS_UNKNOWN_SERVICE) { +		pr_warning("%s: RTAS service <ibm,get-config-addr-info2> and " +			"<ibm,get-config-addr-info> invalid\n", +			__func__); +		return -EINVAL; +	} else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE && +		   ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) { +		pr_warning("%s: RTAS service <ibm,configure-pe> and " +			"<ibm,configure-bridge> invalid\n", +			__func__); +		return -EINVAL; +	} + +	/* Initialize error log lock and size */ +	spin_lock_init(&slot_errbuf_lock); +	eeh_error_buf_size = rtas_token("rtas-error-log-max"); +	if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { +		pr_warning("%s: unknown EEH error log size\n", +			__func__); +		eeh_error_buf_size = 1024; +	} else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { +		pr_warning("%s: EEH error log size %d exceeds the maximal %d\n", +			__func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX); +		eeh_error_buf_size = RTAS_ERROR_LOG_MAX; +	} + +	return 0; +} + +/** + * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable + * @dn: device node + * @option: operation to be issued + * + * The function is used to control the EEH functionality globally. + * Currently, following options are support according to PAPR: + * Enable EEH, Disable EEH, Enable MMIO and Enable DMA + */ +static int pseries_eeh_set_option(struct device_node *dn, int option) +{ +	int ret = 0; +	struct eeh_dev *edev; +	const u32 *reg; +	int config_addr; + +	edev = of_node_to_eeh_dev(dn); + +	/* +	 * When we're enabling or disabling EEH functioality on +	 * the particular PE, the PE config address is possibly +	 * unavailable. Therefore, we have to figure it out from +	 * the FDT node. +	 */ +	switch (option) { +	case EEH_OPT_DISABLE: +	case EEH_OPT_ENABLE: +		reg = of_get_property(dn, "reg", NULL); +		config_addr = reg[0]; +		break; + +	case EEH_OPT_THAW_MMIO: +	case EEH_OPT_THAW_DMA: +		config_addr = edev->config_addr; +		if (edev->pe_config_addr) +			config_addr = edev->pe_config_addr; +		break; + +	default: +		pr_err("%s: Invalid option %d\n", +			__func__, option); +		return -EINVAL; +	} + +	ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, +			config_addr, BUID_HI(edev->phb->buid), +			BUID_LO(edev->phb->buid), option); + +	return ret; +} + +/** + * pseries_eeh_get_pe_addr - Retrieve PE address + * @dn: device node + * + * Retrieve the assocated PE address. Actually, there're 2 RTAS + * function calls dedicated for the purpose. We need implement + * it through the new function and then the old one. Besides, + * you should make sure the config address is figured out from + * FDT node before calling the function. + * + * It's notable that zero'ed return value means invalid PE config + * address. + */ +static int pseries_eeh_get_pe_addr(struct device_node *dn) +{ +	struct eeh_dev *edev; +	int ret = 0; +	int rets[3]; + +	edev = of_node_to_eeh_dev(dn); + +	if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { +		/* +		 * First of all, we need to make sure there has one PE +		 * associated with the device. Otherwise, PE address is +		 * meaningless. +		 */ +		ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, +				edev->config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid), 1); +		if (ret || (rets[0] == 0)) +			return 0; + +		/* Retrieve the associated PE config address */ +		ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, +				edev->config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid), 0); +		if (ret) { +			pr_warning("%s: Failed to get PE address for %s\n", +				__func__, dn->full_name); +			return 0; +		} + +		return rets[0]; +	} + +	if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { +		ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, +				edev->config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid), 0); +		if (ret) { +			pr_warning("%s: Failed to get PE address for %s\n", +				__func__, dn->full_name); +			return 0; +		} + +		return rets[0]; +	} + +	return ret; +} + +/** + * pseries_eeh_get_state - Retrieve PE state + * @dn: PE associated device node + * @state: return value + * + * Retrieve the state of the specified PE. On RTAS compliant + * pseries platform, there already has one dedicated RTAS function + * for the purpose. It's notable that the associated PE config address + * might be ready when calling the function. Therefore, endeavour to + * use the PE config address if possible. Further more, there're 2 + * RTAS calls for the purpose, we need to try the new one and back + * to the old one if the new one couldn't work properly. + */ +static int pseries_eeh_get_state(struct device_node *dn, int *state) +{ +	struct eeh_dev *edev; +	int config_addr; +	int ret; +	int rets[4]; +	int result; + +	/* Figure out PE config address if possible */ +	edev = of_node_to_eeh_dev(dn); +	config_addr = edev->config_addr; +	if (edev->pe_config_addr) +		config_addr = edev->pe_config_addr; + +	if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { +		ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, +				config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid)); +	} else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { +		/* Fake PE unavailable info */ +		rets[2] = 0; +		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, +				config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid)); +	} else { +		return EEH_STATE_NOT_SUPPORT; +	} + +	if (ret) +		return ret; + +	/* Parse the result out */ +	result = 0; +	if (rets[1]) { +		switch(rets[0]) { +		case 0: +			result &= ~EEH_STATE_RESET_ACTIVE; +			result |= EEH_STATE_MMIO_ACTIVE; +			result |= EEH_STATE_DMA_ACTIVE; +			break; +		case 1: +			result |= EEH_STATE_RESET_ACTIVE; +			result |= EEH_STATE_MMIO_ACTIVE; +			result |= EEH_STATE_DMA_ACTIVE; +			break; +		case 2: +			result &= ~EEH_STATE_RESET_ACTIVE; +			result &= ~EEH_STATE_MMIO_ACTIVE; +			result &= ~EEH_STATE_DMA_ACTIVE; +			break; +		case 4: +			result &= ~EEH_STATE_RESET_ACTIVE; +			result &= ~EEH_STATE_MMIO_ACTIVE; +			result &= ~EEH_STATE_DMA_ACTIVE; +			result |= EEH_STATE_MMIO_ENABLED; +			break; +		case 5: +			if (rets[2]) { +				if (state) *state = rets[2]; +				result = EEH_STATE_UNAVAILABLE; +			} else { +				result = EEH_STATE_NOT_SUPPORT; +			} +		default: +			result = EEH_STATE_NOT_SUPPORT; +		} +	} else { +		result = EEH_STATE_NOT_SUPPORT; +	} + +	return result; +} + +/** + * pseries_eeh_reset - Reset the specified PE + * @dn: PE associated device node + * @option: reset option + * + * Reset the specified PE + */ +static int pseries_eeh_reset(struct device_node *dn, int option) +{ +	struct eeh_dev *edev; +	int config_addr; +	int ret; + +	/* Figure out PE address */ +	edev = of_node_to_eeh_dev(dn); +	config_addr = edev->config_addr; +	if (edev->pe_config_addr) +		config_addr = edev->pe_config_addr; + +	/* Reset PE through RTAS call */ +	ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, +			config_addr, BUID_HI(edev->phb->buid), +			BUID_LO(edev->phb->buid), option); + +	/* If fundamental-reset not supported, try hot-reset */ +	if (option == EEH_RESET_FUNDAMENTAL && +	    ret == -8) { +		ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, +				config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid), EEH_RESET_HOT); +	} + +	return ret; +} + +/** + * pseries_eeh_wait_state - Wait for PE state + * @dn: PE associated device node + * @max_wait: maximal period in microsecond + * + * Wait for the state of associated PE. It might take some time + * to retrieve the PE's state. + */ +static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) +{ +	int ret; +	int mwait; + +	/* +	 * According to PAPR, the state of PE might be temporarily +	 * unavailable. Under the circumstance, we have to wait +	 * for indicated time determined by firmware. The maximal +	 * wait time is 5 minutes, which is acquired from the original +	 * EEH implementation. Also, the original implementation +	 * also defined the minimal wait time as 1 second. +	 */ +#define EEH_STATE_MIN_WAIT_TIME	(1000) +#define EEH_STATE_MAX_WAIT_TIME	(300 * 1000) + +	while (1) { +		ret = pseries_eeh_get_state(dn, &mwait); + +		/* +		 * If the PE's state is temporarily unavailable, +		 * we have to wait for the specified time. Otherwise, +		 * the PE's state will be returned immediately. +		 */ +		if (ret != EEH_STATE_UNAVAILABLE) +			return ret; + +		if (max_wait <= 0) { +			pr_warning("%s: Timeout when getting PE's state (%d)\n", +				__func__, max_wait); +			return EEH_STATE_NOT_SUPPORT; +		} + +		if (mwait <= 0) { +			pr_warning("%s: Firmware returned bad wait value %d\n", +				__func__, mwait); +			mwait = EEH_STATE_MIN_WAIT_TIME; +		} else if (mwait > EEH_STATE_MAX_WAIT_TIME) { +			pr_warning("%s: Firmware returned too long wait value %d\n", +				__func__, mwait); +			mwait = EEH_STATE_MAX_WAIT_TIME; +		} + +		max_wait -= mwait; +		msleep(mwait); +	} + +	return EEH_STATE_NOT_SUPPORT; +} + +/** + * pseries_eeh_get_log - Retrieve error log + * @dn: device node + * @severity: temporary or permanent error log + * @drv_log: driver log to be combined with retrieved error log + * @len: length of driver log + * + * Retrieve the temporary or permanent error from the PE. + * Actually, the error will be retrieved through the dedicated + * RTAS call. + */ +static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len) +{ +	struct eeh_dev *edev; +	int config_addr; +	unsigned long flags; +	int ret; + +	edev = of_node_to_eeh_dev(dn); +	spin_lock_irqsave(&slot_errbuf_lock, flags); +	memset(slot_errbuf, 0, eeh_error_buf_size); + +	/* Figure out the PE address */ +	config_addr = edev->config_addr; +	if (edev->pe_config_addr) +		config_addr = edev->pe_config_addr; + +	ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, +			BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), +			virt_to_phys(drv_log), len, +			virt_to_phys(slot_errbuf), eeh_error_buf_size, +			severity); +	if (!ret) +		log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); +	spin_unlock_irqrestore(&slot_errbuf_lock, flags); + +	return ret; +} + +/** + * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE + * @dn: PE associated device node + * + * The function will be called to reconfigure the bridges included + * in the specified PE so that the mulfunctional PE would be recovered + * again. + */ +static int pseries_eeh_configure_bridge(struct device_node *dn) +{ +	struct eeh_dev *edev; +	int config_addr; +	int ret; + +	/* Figure out the PE address */ +	edev = of_node_to_eeh_dev(dn); +	config_addr = edev->config_addr; +	if (edev->pe_config_addr) +		config_addr = edev->pe_config_addr; + +	/* Use new configure-pe function, if supported */ +	if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { +		ret = rtas_call(ibm_configure_pe, 3, 1, NULL, +				config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid)); +	} else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { +		ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, +				config_addr, BUID_HI(edev->phb->buid), +				BUID_LO(edev->phb->buid)); +	} else { +		return -EFAULT; +	} + +	if (ret) +		pr_warning("%s: Unable to configure bridge %d for %s\n", +			__func__, ret, dn->full_name); + +	return ret; +} + +/** + * pseries_eeh_read_config - Read PCI config space + * @dn: device node + * @where: PCI address + * @size: size to read + * @val: return value + * + * Read config space from the speicifed device + */ +static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val) +{ +	struct pci_dn *pdn; + +	pdn = PCI_DN(dn); + +	return rtas_read_config(pdn, where, size, val); +} + +/** + * pseries_eeh_write_config - Write PCI config space + * @dn: device node + * @where: PCI address + * @size: size to write + * @val: value to be written + * + * Write config space to the specified device + */ +static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val) +{ +	struct pci_dn *pdn; + +	pdn = PCI_DN(dn); + +	return rtas_write_config(pdn, where, size, val); +} + +static struct eeh_ops pseries_eeh_ops = { +	.name			= "pseries", +	.init			= pseries_eeh_init, +	.set_option		= pseries_eeh_set_option, +	.get_pe_addr		= pseries_eeh_get_pe_addr, +	.get_state		= pseries_eeh_get_state, +	.reset			= pseries_eeh_reset, +	.wait_state		= pseries_eeh_wait_state, +	.get_log		= pseries_eeh_get_log, +	.configure_bridge       = pseries_eeh_configure_bridge, +	.read_config		= pseries_eeh_read_config, +	.write_config		= pseries_eeh_write_config +}; + +/** + * eeh_pseries_init - Register platform dependent EEH operations + * + * EEH initialization on pseries platform. This function should be + * called before any EEH related functions. + */ +int __init eeh_pseries_init(void) +{ +	return eeh_ops_register(&pseries_eeh_ops); +} diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index eb744ee234d..243b3510d70 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -28,7 +28,7 @@  #include <asm/pci-bridge.h>  /** - * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic + * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic   * @_name: name of file in sysfs directory   * @_memb: name of member in struct pci_dn to access   * @_format: printf format for display @@ -41,24 +41,21 @@ static ssize_t eeh_show_##_name(struct device *dev,      \  		struct device_attribute *attr, char *buf)          \  {                                                        \  	struct pci_dev *pdev = to_pci_dev(dev);               \ -	struct device_node *dn = pci_device_to_OF_node(pdev); \ -	struct pci_dn *pdn;                                   \ +	struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);      \  	                                                      \ -	if (!dn || PCI_DN(dn) == NULL)                        \ -		return 0;                                          \ +	if (!edev)                                            \ +		return 0;                                     \  	                                                      \ -	pdn = PCI_DN(dn);                                     \ -	return sprintf(buf, _format "\n", pdn->_memb);        \ +	return sprintf(buf, _format "\n", edev->_memb);       \  }                                                        \  static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); - -EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x"); -EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); -EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); -EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); -EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); -EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d"); +EEH_SHOW_ATTR(eeh_mode,            mode,            "0x%x"); +EEH_SHOW_ATTR(eeh_config_addr,     config_addr,     "0x%x"); +EEH_SHOW_ATTR(eeh_pe_config_addr,  pe_config_addr,  "0x%x"); +EEH_SHOW_ATTR(eeh_check_count,     check_count,     "%d"  ); +EEH_SHOW_ATTR(eeh_freeze_count,    freeze_count,    "%d"  ); +EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d"  );  void eeh_sysfs_add_device(struct pci_dev *pdev)  { diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c index 1a709bc48ce..ef9d9d84c7d 100644 --- a/arch/powerpc/platforms/pseries/io_event_irq.c +++ b/arch/powerpc/platforms/pseries/io_event_irq.c @@ -63,73 +63,9 @@ EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list);  static int ioei_check_exception_token; -/* pSeries event log format */ - -/* Two bytes ASCII section IDs */ -#define PSERIES_ELOG_SECT_ID_PRIV_HDR		(('P' << 8) | 'H') -#define PSERIES_ELOG_SECT_ID_USER_HDR		(('U' << 8) | 'H') -#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC	(('P' << 8) | 'S') -#define PSERIES_ELOG_SECT_ID_EXTENDED_UH	(('E' << 8) | 'H') -#define PSERIES_ELOG_SECT_ID_FAILING_MTMS	(('M' << 8) | 'T') -#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC	(('S' << 8) | 'S') -#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR	(('D' << 8) | 'H') -#define PSERIES_ELOG_SECT_ID_FW_ERROR		(('S' << 8) | 'W') -#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID	(('L' << 8) | 'P') -#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID	(('L' << 8) | 'R') -#define PSERIES_ELOG_SECT_ID_HMC_ID		(('H' << 8) | 'M') -#define PSERIES_ELOG_SECT_ID_EPOW		(('E' << 8) | 'P') -#define PSERIES_ELOG_SECT_ID_IO_EVENT		(('I' << 8) | 'E') -#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO	(('M' << 8) | 'I') -#define PSERIES_ELOG_SECT_ID_CALL_HOME		(('C' << 8) | 'H') -#define PSERIES_ELOG_SECT_ID_USER_DEF		(('U' << 8) | 'D') - -/* Vendor specific Platform Event Log Format, Version 6, section header */ -struct pseries_elog_section { -	uint16_t id;			/* 0x00 2-byte ASCII section ID	*/ -	uint16_t length;		/* 0x02 Section length in bytes	*/ -	uint8_t version;		/* 0x04 Section version		*/ -	uint8_t subtype;		/* 0x05 Section subtype		*/ -	uint16_t creator_component;	/* 0x06 Creator component ID	*/ -	uint8_t data[];			/* 0x08 Start of section data	*/ -}; -  static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;  /** - * Find data portion of a specific section in RTAS extended event log. - * @elog: RTAS error/event log. - * @sect_id: secsion ID. - * - * Return: - *	pointer to the section data of the specified section - *	NULL if not found - */ -static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog, -						       uint16_t sect_id) -{ -	struct rtas_ext_event_log_v6 *xelog = -		(struct rtas_ext_event_log_v6 *) elog->buffer; -	struct pseries_elog_section *sect; -	unsigned char *p, *log_end; - -	/* Check that we understand the format */ -	if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) || -	    xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG || -	    xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM) -		return NULL; - -	log_end = elog->buffer + elog->extended_log_length; -	p = xelog->vendor_log; -	while (p < log_end) { -		sect = (struct pseries_elog_section *)p; -		if (sect->id == sect_id) -			return sect; -		p += sect->length; -	} -	return NULL; -} - -/**   * Find the data portion of an IO Event section from event log.   * @elog: RTAS error/event log.   * @@ -138,7 +74,7 @@ static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *el   */  static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)  { -	struct pseries_elog_section *sect; +	struct pseries_errorlog *sect;  	/* We should only ever get called for io-event interrupts, but if  	 * we do get called for another type then something went wrong so @@ -152,7 +88,7 @@ static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)  		return NULL;  	} -	sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT); +	sect = get_pseries_errorlog(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);  	if (unlikely(!sect)) {  		printk_once(KERN_WARNING "io_event_irq: RTAS extended event "  			    "log does not contain an IO Event section. " diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index c442f2b1980..0915b1ad66c 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -809,8 +809,7 @@ machine_arch_initcall(pseries, find_existing_ddw_windows);  static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,  			struct ddw_query_response *query)  { -	struct device_node *dn; -	struct pci_dn *pcidn; +	struct eeh_dev *edev;  	u32 cfg_addr;  	u64 buid;  	int ret; @@ -821,12 +820,12 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,  	 * Retrieve them from the pci device, not the node with the  	 * dma-window property  	 */ -	dn = pci_device_to_OF_node(dev); -	pcidn = PCI_DN(dn); -	cfg_addr = pcidn->eeh_config_addr; -	if (pcidn->eeh_pe_config_addr) -		cfg_addr = pcidn->eeh_pe_config_addr; -	buid = pcidn->phb->buid; +	edev = pci_dev_to_eeh_dev(dev); +	cfg_addr = edev->config_addr; +	if (edev->pe_config_addr) +		cfg_addr = edev->pe_config_addr; +	buid = edev->phb->buid; +  	ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query,  		  cfg_addr, BUID_HI(buid), BUID_LO(buid));  	dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x" @@ -839,8 +838,7 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,  			struct ddw_create_response *create, int page_shift,  			int window_shift)  { -	struct device_node *dn; -	struct pci_dn *pcidn; +	struct eeh_dev *edev;  	u32 cfg_addr;  	u64 buid;  	int ret; @@ -851,12 +849,11 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,  	 * Retrieve them from the pci device, not the node with the  	 * dma-window property  	 */ -	dn = pci_device_to_OF_node(dev); -	pcidn = PCI_DN(dn); -	cfg_addr = pcidn->eeh_config_addr; -	if (pcidn->eeh_pe_config_addr) -		cfg_addr = pcidn->eeh_pe_config_addr; -	buid = pcidn->phb->buid; +	edev = pci_dev_to_eeh_dev(dev); +	cfg_addr = edev->config_addr; +	if (edev->pe_config_addr) +		cfg_addr = edev->pe_config_addr; +	buid = edev->phb->buid;  	do {  		/* extra outputs are LIOBN and dma-addr (hi, lo) */ diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 7bc73af6c7b..5f3ef876ded 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -41,6 +41,7 @@  #include <asm/udbg.h>  #include <asm/smp.h>  #include <asm/trace.h> +#include <asm/firmware.h>  #include "plpar_wrappers.h"  #include "pseries.h" diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 38d24e7e7bb..109fdb75578 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -217,7 +217,7 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total)  	if (!dn)  		return NULL; -	dn = find_device_pe(dn); +	dn = eeh_find_device_pe(dn);  	if (!dn)  		return NULL; diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 55d4ec1bd1a..8b7bafa489c 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -84,7 +84,7 @@ void pcibios_remove_pci_devices(struct pci_bus *bus)  	list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {  		pr_debug("     * Removing %s...\n", pci_name(dev));  		eeh_remove_bus_device(dev); - 		pci_remove_bus_device(dev); + 		pci_stop_and_remove_bus_device(dev);   	}  }  EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); @@ -147,6 +147,9 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)  	pci_devs_phb_init_dynamic(phb); +	/* Create EEH devices for the PHB */ +	eeh_dev_phb_init_dynamic(phb); +  	if (dn->child)  		eeh_add_device_tree_early(dn); diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c deleted file mode 100644 index 6e7742da007..00000000000 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Hypervisor-assisted dump - * - * Linas Vepstas, Manish Ahuja 2008 - * Copyright 2008 IBM Corp. - * - *      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/gfp.h> -#include <linux/init.h> -#include <linux/kobject.h> -#include <linux/mm.h> -#include <linux/of.h> -#include <linux/pfn.h> -#include <linux/swap.h> -#include <linux/sysfs.h> - -#include <asm/page.h> -#include <asm/phyp_dump.h> -#include <asm/machdep.h> -#include <asm/prom.h> -#include <asm/rtas.h> - -/* Variables, used to communicate data between early boot and late boot */ -static struct phyp_dump phyp_dump_vars; -struct phyp_dump *phyp_dump_info = &phyp_dump_vars; - -static int ibm_configure_kernel_dump; -/* ------------------------------------------------- */ -/* RTAS interfaces to declare the dump regions */ - -struct dump_section { -	u32 dump_flags; -	u16 source_type; -	u16 error_flags; -	u64 source_address; -	u64 source_length; -	u64 length_copied; -	u64 destination_address; -}; - -struct phyp_dump_header { -	u32 version; -	u16 num_of_sections; -	u16 status; - -	u32 first_offset_section; -	u32 dump_disk_section; -	u64 block_num_dd; -	u64 num_of_blocks_dd; -	u32 offset_dd; -	u32 maxtime_to_auto; -	/* No dump disk path string used */ - -	struct dump_section cpu_data; -	struct dump_section hpte_data; -	struct dump_section kernel_data; -}; - -/* The dump header *must be* in low memory, so .bss it */ -static struct phyp_dump_header phdr; - -#define NUM_DUMP_SECTIONS	3 -#define DUMP_HEADER_VERSION	0x1 -#define DUMP_REQUEST_FLAG	0x1 -#define DUMP_SOURCE_CPU		0x0001 -#define DUMP_SOURCE_HPTE	0x0002 -#define DUMP_SOURCE_RMO		0x0011 -#define DUMP_ERROR_FLAG		0x2000 -#define DUMP_TRIGGERED		0x4000 -#define DUMP_PERFORMED		0x8000 - - -/** - * init_dump_header() - initialize the header declaring a dump - * Returns: length of dump save area. - * - * When the hypervisor saves crashed state, it needs to put - * it somewhere. The dump header tells the hypervisor where - * the data can be saved. - */ -static unsigned long init_dump_header(struct phyp_dump_header *ph) -{ -	unsigned long addr_offset = 0; - -	/* Set up the dump header */ -	ph->version = DUMP_HEADER_VERSION; -	ph->num_of_sections = NUM_DUMP_SECTIONS; -	ph->status = 0; - -	ph->first_offset_section = -		(u32)offsetof(struct phyp_dump_header, cpu_data); -	ph->dump_disk_section = 0; -	ph->block_num_dd = 0; -	ph->num_of_blocks_dd = 0; -	ph->offset_dd = 0; - -	ph->maxtime_to_auto = 0; /* disabled */ - -	/* The first two sections are mandatory */ -	ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG; -	ph->cpu_data.source_type = DUMP_SOURCE_CPU; -	ph->cpu_data.source_address = 0; -	ph->cpu_data.source_length = phyp_dump_info->cpu_state_size; -	ph->cpu_data.destination_address = addr_offset; -	addr_offset += phyp_dump_info->cpu_state_size; - -	ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG; -	ph->hpte_data.source_type = DUMP_SOURCE_HPTE; -	ph->hpte_data.source_address = 0; -	ph->hpte_data.source_length = phyp_dump_info->hpte_region_size; -	ph->hpte_data.destination_address = addr_offset; -	addr_offset += phyp_dump_info->hpte_region_size; - -	/* This section describes the low kernel region */ -	ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG; -	ph->kernel_data.source_type = DUMP_SOURCE_RMO; -	ph->kernel_data.source_address = PHYP_DUMP_RMR_START; -	ph->kernel_data.source_length = PHYP_DUMP_RMR_END; -	ph->kernel_data.destination_address = addr_offset; -	addr_offset += ph->kernel_data.source_length; - -	return addr_offset; -} - -static void print_dump_header(const struct phyp_dump_header *ph) -{ -#ifdef DEBUG -	if (ph == NULL) -		return; - -	printk(KERN_INFO "dump header:\n"); -	/* setup some ph->sections required */ -	printk(KERN_INFO "version = %d\n", ph->version); -	printk(KERN_INFO "Sections = %d\n", ph->num_of_sections); -	printk(KERN_INFO "Status = 0x%x\n", ph->status); - -	/* No ph->disk, so all should be set to 0 */ -	printk(KERN_INFO "Offset to first section 0x%x\n", -		ph->first_offset_section); -	printk(KERN_INFO "dump disk sections should be zero\n"); -	printk(KERN_INFO "dump disk section = %d\n", ph->dump_disk_section); -	printk(KERN_INFO "block num = %lld\n", ph->block_num_dd); -	printk(KERN_INFO "number of blocks = %lld\n", ph->num_of_blocks_dd); -	printk(KERN_INFO "dump disk offset = %d\n", ph->offset_dd); -	printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto); - -	/*set cpu state and hpte states as well scratch pad area */ -	printk(KERN_INFO " CPU AREA\n"); -	printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags); -	printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type); -	printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags); -	printk(KERN_INFO "cpu source_address =%llx\n", -		ph->cpu_data.source_address); -	printk(KERN_INFO "cpu source_length =%llx\n", -		ph->cpu_data.source_length); -	printk(KERN_INFO "cpu length_copied =%llx\n", -		ph->cpu_data.length_copied); - -	printk(KERN_INFO " HPTE AREA\n"); -	printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags); -	printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type); -	printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags); -	printk(KERN_INFO "HPTE source_address =%llx\n", -		ph->hpte_data.source_address); -	printk(KERN_INFO "HPTE source_length =%llx\n", -		ph->hpte_data.source_length); -	printk(KERN_INFO "HPTE length_copied =%llx\n", -		ph->hpte_data.length_copied); - -	printk(KERN_INFO " SRSD AREA\n"); -	printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags); -	printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type); -	printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags); -	printk(KERN_INFO "SRSD source_address =%llx\n", -		ph->kernel_data.source_address); -	printk(KERN_INFO "SRSD source_length =%llx\n", -		ph->kernel_data.source_length); -	printk(KERN_INFO "SRSD length_copied =%llx\n", -		ph->kernel_data.length_copied); -#endif -} - -static ssize_t show_phyp_dump_active(struct kobject *kobj, -			struct kobj_attribute *attr, char *buf) -{ - -	/* create filesystem entry so kdump is phyp-dump aware */ -	return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot); -} - -static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600, -					show_phyp_dump_active, -					NULL); - -static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) -{ -	int rc; - -	/* Add addr value if not initialized before */ -	if (ph->cpu_data.destination_address == 0) { -		ph->cpu_data.destination_address += addr; -		ph->hpte_data.destination_address += addr; -		ph->kernel_data.destination_address += addr; -	} - -	/* ToDo Invalidate kdump and free memory range. */ - -	do { -		rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, -				1, ph, sizeof(struct phyp_dump_header)); -	} while (rtas_busy_delay(rc)); - -	if (rc) { -		printk(KERN_ERR "phyp-dump: unexpected error (%d) on " -						"register\n", rc); -		print_dump_header(ph); -		return; -	} - -	rc = sysfs_create_file(kernel_kobj, &pdl.attr); -	if (rc) -		printk(KERN_ERR "phyp-dump: unable to create sysfs" -				" file (%d)\n", rc); -} - -static -void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr) -{ -	int rc; - -	/* Add addr value if not initialized before */ -	if (ph->cpu_data.destination_address == 0) { -		ph->cpu_data.destination_address += addr; -		ph->hpte_data.destination_address += addr; -		ph->kernel_data.destination_address += addr; -	} - -	do { -		rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, -				2, ph, sizeof(struct phyp_dump_header)); -	} while (rtas_busy_delay(rc)); - -	if (rc) { -		printk(KERN_ERR "phyp-dump: unexpected error (%d) " -						"on invalidate\n", rc); -		print_dump_header(ph); -	} -} - -/* ------------------------------------------------- */ -/** - * release_memory_range -- release memory previously memblock_reserved - * @start_pfn: starting physical frame number - * @nr_pages: number of pages to free. - * - * This routine will release memory that had been previously - * memblock_reserved in early boot. The released memory becomes - * available for genreal use. - */ -static void release_memory_range(unsigned long start_pfn, -			unsigned long nr_pages) -{ -	struct page *rpage; -	unsigned long end_pfn; -	long i; - -	end_pfn = start_pfn + nr_pages; - -	for (i = start_pfn; i <= end_pfn; i++) { -		rpage = pfn_to_page(i); -		if (PageReserved(rpage)) { -			ClearPageReserved(rpage); -			init_page_count(rpage); -			__free_page(rpage); -			totalram_pages++; -		} -	} -} - -/** - * track_freed_range -- Counts the range being freed. - * Once the counter goes to zero, it re-registers dump for - * future use. - */ -static void -track_freed_range(unsigned long addr, unsigned long length) -{ -	static unsigned long scratch_area_size, reserved_area_size; - -	if (addr < phyp_dump_info->init_reserve_start) -		return; - -	if ((addr >= phyp_dump_info->init_reserve_start) && -	    (addr <= phyp_dump_info->init_reserve_start + -	     phyp_dump_info->init_reserve_size)) -		reserved_area_size += length; - -	if ((addr >= phyp_dump_info->reserved_scratch_addr) && -	    (addr <= phyp_dump_info->reserved_scratch_addr + -	     phyp_dump_info->reserved_scratch_size)) -		scratch_area_size += length; - -	if ((reserved_area_size == phyp_dump_info->init_reserve_size) && -	    (scratch_area_size == phyp_dump_info->reserved_scratch_size)) { - -		invalidate_last_dump(&phdr, -				phyp_dump_info->reserved_scratch_addr); -		register_dump_area(&phdr, -				phyp_dump_info->reserved_scratch_addr); -	} -} - -/* ------------------------------------------------- */ -/** - * sysfs_release_region -- sysfs interface to release memory range. - * - * Usage: - *   "echo <start addr> <length> > /sys/kernel/release_region" - * - * Example: - *   "echo 0x40000000 0x10000000 > /sys/kernel/release_region" - * - * will release 256MB starting at 1GB. - */ -static ssize_t store_release_region(struct kobject *kobj, -				struct kobj_attribute *attr, -				const char *buf, size_t count) -{ -	unsigned long start_addr, length, end_addr; -	unsigned long start_pfn, nr_pages; -	ssize_t ret; - -	ret = sscanf(buf, "%lx %lx", &start_addr, &length); -	if (ret != 2) -		return -EINVAL; - -	track_freed_range(start_addr, length); - -	/* Range-check - don't free any reserved memory that -	 * wasn't reserved for phyp-dump */ -	if (start_addr < phyp_dump_info->init_reserve_start) -		start_addr = phyp_dump_info->init_reserve_start; - -	end_addr = phyp_dump_info->init_reserve_start + -			phyp_dump_info->init_reserve_size; -	if (start_addr+length > end_addr) -		length = end_addr - start_addr; - -	/* Release the region of memory assed in by user */ -	start_pfn = PFN_DOWN(start_addr); -	nr_pages = PFN_DOWN(length); -	release_memory_range(start_pfn, nr_pages); - -	return count; -} - -static ssize_t show_release_region(struct kobject *kobj, -			struct kobj_attribute *attr, char *buf) -{ -	u64 second_addr_range; - -	/* total reserved size - start of scratch area */ -	second_addr_range = phyp_dump_info->init_reserve_size - -				phyp_dump_info->reserved_scratch_size; -	return sprintf(buf, "CPU:0x%llx-0x%llx: HPTE:0x%llx-0x%llx:" -			    " DUMP:0x%llx-0x%llx, 0x%lx-0x%llx:\n", -		phdr.cpu_data.destination_address, -		phdr.cpu_data.length_copied, -		phdr.hpte_data.destination_address, -		phdr.hpte_data.length_copied, -		phdr.kernel_data.destination_address, -		phdr.kernel_data.length_copied, -		phyp_dump_info->init_reserve_start, -		second_addr_range); -} - -static struct kobj_attribute rr = __ATTR(release_region, 0600, -					show_release_region, -					store_release_region); - -static int __init phyp_dump_setup(void) -{ -	struct device_node *rtas; -	const struct phyp_dump_header *dump_header = NULL; -	unsigned long dump_area_start; -	unsigned long dump_area_length; -	int header_len = 0; -	int rc; - -	/* If no memory was reserved in early boot, there is nothing to do */ -	if (phyp_dump_info->init_reserve_size == 0) -		return 0; - -	/* Return if phyp dump not supported */ -	if (!phyp_dump_info->phyp_dump_configured) -		return -ENOSYS; - -	/* Is there dump data waiting for us? If there isn't, -	 * then register a new dump area, and release all of -	 * the rest of the reserved ram. -	 * -	 * The /rtas/ibm,kernel-dump rtas node is present only -	 * if there is dump data waiting for us. -	 */ -	rtas = of_find_node_by_path("/rtas"); -	if (rtas) { -		dump_header = of_get_property(rtas, "ibm,kernel-dump", -						&header_len); -		of_node_put(rtas); -	} - -	ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump"); - -	print_dump_header(dump_header); -	dump_area_length = init_dump_header(&phdr); -	/* align down */ -	dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK; - -	if (dump_header == NULL) { -		register_dump_area(&phdr, dump_area_start); -		return 0; -	} - -	/* re-register the dump area, if old dump was invalid */ -	if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) { -		invalidate_last_dump(&phdr, dump_area_start); -		register_dump_area(&phdr, dump_area_start); -		return 0; -	} - -	if (dump_header) { -		phyp_dump_info->reserved_scratch_addr = -				dump_header->cpu_data.destination_address; -		phyp_dump_info->reserved_scratch_size = -				dump_header->cpu_data.source_length + -				dump_header->hpte_data.source_length + -				dump_header->kernel_data.source_length; -	} - -	/* Should we create a dump_subsys, analogous to s390/ipl.c ? */ -	rc = sysfs_create_file(kernel_kobj, &rr.attr); -	if (rc) -		printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", -									rc); - -	/* ToDo: re-register the dump area, for next time. */ -	return 0; -} -machine_subsys_initcall(pseries, phyp_dump_setup); - -int __init early_init_dt_scan_phyp_dump(unsigned long node, -		const char *uname, int depth, void *data) -{ -	const unsigned int *sizes; - -	phyp_dump_info->phyp_dump_configured = 0; -	phyp_dump_info->phyp_dump_is_active = 0; - -	if (depth != 1 || strcmp(uname, "rtas") != 0) -		return 0; - -	if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL)) -		phyp_dump_info->phyp_dump_configured++; - -	if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL)) -		phyp_dump_info->phyp_dump_is_active++; - -	sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", -				    NULL); -	if (!sizes) -		return 0; - -	if (sizes[0] == 1) -		phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]); - -	if (sizes[3] == 2) -		phyp_dump_info->hpte_region_size = -						*((unsigned long *)&sizes[4]); -	return 1; -} - -/* Look for phyp_dump= cmdline option */ -static int __init early_phyp_dump_enabled(char *p) -{ -	phyp_dump_info->phyp_dump_at_boot = 1; - -        if (!p) -                return 0; - -        if (strncmp(p, "1", 1) == 0) -		phyp_dump_info->phyp_dump_at_boot = 1; -        else if (strncmp(p, "0", 1) == 0) -		phyp_dump_info->phyp_dump_at_boot = 0; - -        return 0; -} -early_param("phyp_dump", early_phyp_dump_enabled); - -/* Look for phyp_dump_reserve_size= cmdline option */ -static int __init early_phyp_dump_reserve_size(char *p) -{ -        if (p) -		phyp_dump_info->reserve_bootvar = memparse(p, &p); - -        return 0; -} -early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size); diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 085fd3f45ad..a12e95af693 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -96,6 +96,20 @@ out:  	return index;  } +static void check_and_cede_processor(void) +{ +	/* +	 * Interrupts are soft-disabled at this point, +	 * but not hard disabled. So an interrupt might have +	 * occurred before entering NAP, and would be potentially +	 * lost (edge events, decrementer events, etc...) unless +	 * we first hard disable then check. +	 */ +	hard_irq_disable(); +	if (get_paca()->irq_happened == 0) +		cede_processor(); +} +  static int dedicated_cede_loop(struct cpuidle_device *dev,  				struct cpuidle_driver *drv,  				int index) @@ -108,7 +122,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,  	ppc64_runlatch_off();  	HMT_medium(); -	cede_processor(); +	check_and_cede_processor();  	get_lppaca()->donate_dedicated_cpu = 0;  	dev->last_residency = @@ -132,7 +146,7 @@ static int shared_cede_loop(struct cpuidle_device *dev,  	 * processor. When returning here, external interrupts  	 * are enabled.  	 */ -	cede_processor(); +	check_and_cede_processor();  	dev->last_residency =  		(int)idle_loop_epilog(in_purr, kt_before); diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 086d2ae4e06..c4dfccd3a3d 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -16,37 +16,15 @@   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA   */ -/* Change Activity: - * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support. - * End Change Activity - */ - -#include <linux/errno.h> -#include <linux/threads.h> -#include <linux/kernel_stat.h> -#include <linux/signal.h>  #include <linux/sched.h> -#include <linux/ioport.h>  #include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/init.h> -#include <linux/delay.h>  #include <linux/irq.h> -#include <linux/random.h> -#include <linux/sysrq.h> -#include <linux/bitops.h> +#include <linux/of.h> +#include <linux/fs.h> +#include <linux/reboot.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/cache.h> -#include <asm/prom.h> -#include <asm/ptrace.h>  #include <asm/machdep.h>  #include <asm/rtas.h> -#include <asm/udbg.h>  #include <asm/firmware.h>  #include "pseries.h" @@ -57,7 +35,6 @@ static DEFINE_SPINLOCK(ras_log_buf_lock);  static char global_mce_data_buf[RTAS_ERROR_LOG_MAX];  static DEFINE_PER_CPU(__u64, mce_data_buf); -static int ras_get_sensor_state_token;  static int ras_check_exception_token;  #define EPOW_SENSOR_TOKEN	9 @@ -75,7 +52,6 @@ static int __init init_ras_IRQ(void)  {  	struct device_node *np; -	ras_get_sensor_state_token = rtas_token("get-sensor-state");  	ras_check_exception_token = rtas_token("check-exception");  	/* Internal Errors */ @@ -95,26 +71,126 @@ static int __init init_ras_IRQ(void)  	return 0;  } -__initcall(init_ras_IRQ); +subsys_initcall(init_ras_IRQ); -/* - * Handle power subsystem events (EPOW). - * - * Presently we just log the event has occurred.  This should be fixed - * to examine the type of power failure and take appropriate action where - * the time horizon permits something useful to be done. - */ +#define EPOW_SHUTDOWN_NORMAL				1 +#define EPOW_SHUTDOWN_ON_UPS				2 +#define EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS	3 +#define EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH	4 + +static void handle_system_shutdown(char event_modifier) +{ +	switch (event_modifier) { +	case EPOW_SHUTDOWN_NORMAL: +		pr_emerg("Firmware initiated power off"); +		orderly_poweroff(1); +		break; + +	case EPOW_SHUTDOWN_ON_UPS: +		pr_emerg("Loss of power reported by firmware, system is " +			"running on UPS/battery"); +		break; + +	case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS: +		pr_emerg("Loss of system critical functions reported by " +			"firmware"); +		pr_emerg("Check RTAS error log for details"); +		orderly_poweroff(1); +		break; + +	case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH: +		pr_emerg("Ambient temperature too high reported by firmware"); +		pr_emerg("Check RTAS error log for details"); +		orderly_poweroff(1); +		break; + +	default: +		pr_err("Unknown power/cooling shutdown event (modifier %d)", +			event_modifier); +	} +} + +struct epow_errorlog { +	unsigned char sensor_value; +	unsigned char event_modifier; +	unsigned char extended_modifier; +	unsigned char reserved; +	unsigned char platform_reason; +}; + +#define EPOW_RESET			0 +#define EPOW_WARN_COOLING		1 +#define EPOW_WARN_POWER			2 +#define EPOW_SYSTEM_SHUTDOWN		3 +#define EPOW_SYSTEM_HALT		4 +#define EPOW_MAIN_ENCLOSURE		5 +#define EPOW_POWER_OFF			7 + +void rtas_parse_epow_errlog(struct rtas_error_log *log) +{ +	struct pseries_errorlog *pseries_log; +	struct epow_errorlog *epow_log; +	char action_code; +	char modifier; + +	pseries_log = get_pseries_errorlog(log, PSERIES_ELOG_SECT_ID_EPOW); +	if (pseries_log == NULL) +		return; + +	epow_log = (struct epow_errorlog *)pseries_log->data; +	action_code = epow_log->sensor_value & 0xF;	/* bottom 4 bits */ +	modifier = epow_log->event_modifier & 0xF;	/* bottom 4 bits */ + +	switch (action_code) { +	case EPOW_RESET: +		pr_err("Non critical power or cooling issue cleared"); +		break; + +	case EPOW_WARN_COOLING: +		pr_err("Non critical cooling issue reported by firmware"); +		pr_err("Check RTAS error log for details"); +		break; + +	case EPOW_WARN_POWER: +		pr_err("Non critical power issue reported by firmware"); +		pr_err("Check RTAS error log for details"); +		break; + +	case EPOW_SYSTEM_SHUTDOWN: +		handle_system_shutdown(epow_log->event_modifier); +		break; + +	case EPOW_SYSTEM_HALT: +		pr_emerg("Firmware initiated power off"); +		orderly_poweroff(1); +		break; + +	case EPOW_MAIN_ENCLOSURE: +	case EPOW_POWER_OFF: +		pr_emerg("Critical power/cooling issue reported by firmware"); +		pr_emerg("Check RTAS error log for details"); +		pr_emerg("Immediate power off"); +		emergency_sync(); +		kernel_power_off(); +		break; + +	default: +		pr_err("Unknown power/cooling event (action code %d)", +			action_code); +	} +} + +/* Handle environmental and power warning (EPOW) interrupts. */  static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)  { -	int status = 0xdeadbeef; -	int state = 0; +	int status; +	int state;  	int critical; -	status = rtas_call(ras_get_sensor_state_token, 2, 2, &state, -			   EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX); +	status = rtas_get_sensor(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state);  	if (state > 3) -		critical = 1;  /* Time Critical */ +		critical = 1;		/* Time Critical */  	else  		critical = 0; @@ -123,18 +199,14 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)  	status = rtas_call(ras_check_exception_token, 6, 1, NULL,  			   RTAS_VECTOR_EXTERNAL_INTERRUPT,  			   virq_to_hw(irq), -			   RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, +			   RTAS_EPOW_WARNING,  			   critical, __pa(&ras_log_buf),  				rtas_get_error_log_max()); -	udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n", -		    *((unsigned long *)&ras_log_buf), status, state); -	printk(KERN_WARNING "EPOW <0x%lx 0x%x 0x%x>\n", -	       *((unsigned long *)&ras_log_buf), status, state); - -	/* format and print the extended information */  	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); +	rtas_parse_epow_errlog((struct rtas_error_log *)ras_log_buf); +  	spin_unlock(&ras_log_buf_lock);  	return IRQ_HANDLED;  } @@ -150,7 +222,7 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)  static irqreturn_t ras_error_interrupt(int irq, void *dev_id)  {  	struct rtas_error_log *rtas_elog; -	int status = 0xdeadbeef; +	int status;  	int fatal;  	spin_lock(&ras_log_buf_lock); @@ -158,7 +230,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)  	status = rtas_call(ras_check_exception_token, 6, 1, NULL,  			   RTAS_VECTOR_EXTERNAL_INTERRUPT,  			   virq_to_hw(irq), -			   RTAS_INTERNAL_ERROR, 1 /*Time Critical */, +			   RTAS_INTERNAL_ERROR, 1 /* Time Critical */,  			   __pa(&ras_log_buf),  				rtas_get_error_log_max()); @@ -173,24 +245,13 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)  	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);  	if (fatal) { -		udbg_printf("Fatal HW Error <0x%lx 0x%x>\n", -			    *((unsigned long *)&ras_log_buf), status); -		printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n", -		       *((unsigned long *)&ras_log_buf), status); - -#ifndef DEBUG_RTAS_POWER_OFF -		/* Don't actually power off when debugging so we can test -		 * without actually failing while injecting errors. -		 * Error data will not be logged to syslog. -		 */ -		ppc_md.power_off(); -#endif +		pr_emerg("Fatal hardware error reported by firmware"); +		pr_emerg("Check RTAS error log for details"); +		pr_emerg("Immediate power off"); +		emergency_sync(); +		kernel_power_off();  	} else { -		udbg_printf("Recoverable HW Error <0x%lx 0x%x>\n", -			    *((unsigned long *)&ras_log_buf), status); -		printk(KERN_WARNING -		       "Warning: Recoverable hardware error <0x%lx 0x%x>\n", -		       *((unsigned long *)&ras_log_buf), status); +		pr_err("Recoverable hardware error reported by firmware");  	}  	spin_unlock(&ras_log_buf_lock); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f79f1278dfc..51ecac920dd 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -190,9 +190,8 @@ static void __init pseries_mpic_init_IRQ(void)  	BUG_ON(openpic_addr == 0);  	/* Setup the openpic driver */ -	mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, 0, -			  16, 250, /* isu size, irq count */ -			  " MPIC     "); +	mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, +			MPIC_NO_RESET, 16, 0, " MPIC     ");  	BUG_ON(mpic == NULL);  	/* Add ISUs */ @@ -261,8 +260,12 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act  	switch (action) {  	case PSERIES_RECONFIG_ADD:  		pci = np->parent->data; -		if (pci) +		if (pci) {  			update_dn_pci_info(np, pci->phb); + +			/* Create EEH device for the OF node */ +			eeh_dev_init(np, pci->phb); +		}  		break;  	default:  		err = NOTIFY_DONE; @@ -380,8 +383,12 @@ static void __init pSeries_setup_arch(void)  	fwnmi_init(); +	/* By default, only probe PCI (can be overriden by rtas_pci) */ +	pci_add_flags(PCI_PROBE_ONLY); +  	/* Find and initialize PCI host bridges */  	init_pci_config_tokens(); +	eeh_pseries_init();  	find_and_init_phbs();  	pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);  	eeh_init(); diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c index b84a8b2238d..47226e04126 100644 --- a/arch/powerpc/platforms/pseries/suspend.c +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -24,6 +24,7 @@  #include <asm/machdep.h>  #include <asm/mmu.h>  #include <asm/rtas.h> +#include <asm/topology.h>  static u64 stream_id;  static struct device suspend_dev; @@ -138,8 +139,11 @@ static ssize_t store_hibernate(struct device *dev,  			ssleep(1);  	} while (rc == -EAGAIN); -	if (!rc) +	if (!rc) { +		stop_topology_update();  		rc = pm_suspend(PM_SUSPEND_MEM); +		start_topology_update(); +	}  	stream_id = 0; diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig index 57d22a2f4ba..79d2225b760 100644 --- a/arch/powerpc/platforms/wsp/Kconfig +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -25,6 +25,7 @@ config PPC_CHROMA  	bool "PowerEN PCIe Chroma Card"  	select EPAPR_BOOT  	select PPC_WSP +	select OF_DYNAMIC  	default y  endmenu diff --git a/arch/powerpc/platforms/wsp/ics.c b/arch/powerpc/platforms/wsp/ics.c index 57687439254..97fe82ee863 100644 --- a/arch/powerpc/platforms/wsp/ics.c +++ b/arch/powerpc/platforms/wsp/ics.c @@ -346,7 +346,7 @@ static int wsp_chip_set_affinity(struct irq_data *d,  	 * For the moment only implement delivery to all cpus or one cpu.  	 * Get current irq_server for the given irq  	 */ -	ret = cache_hwirq_map(ics, d->irq, cpumask); +	ret = cache_hwirq_map(ics, hw_irq, cpumask);  	if (ret == -1) {  		char cpulist[128];  		cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c index 19f353dfcd0..cb565bf9365 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -30,7 +30,7 @@  static int opb_index = 0;  struct opb_pic { -	struct irq_host *host; +	struct irq_domain *host;  	void *regs;  	int index;  	spinlock_t lock; @@ -179,7 +179,7 @@ static struct irq_chip opb_irq_chip = {  	.irq_set_type	= opb_set_irq_type  }; -static int opb_host_map(struct irq_host *host, unsigned int virq, +static int opb_host_map(struct irq_domain *host, unsigned int virq,  		irq_hw_number_t hwirq)  {  	struct opb_pic *opb; @@ -196,20 +196,9 @@ static int opb_host_map(struct irq_host *host, unsigned int virq,  	return 0;  } -static int opb_host_xlate(struct irq_host *host, struct device_node *dn, -		const u32 *intspec, unsigned int intsize, -		irq_hw_number_t *out_hwirq, unsigned int *out_type) -{ -	/* Interrupt size must == 2 */ -	BUG_ON(intsize != 2); -	*out_hwirq = intspec[0]; -	*out_type = intspec[1]; -	return 0; -} - -static struct irq_host_ops opb_host_ops = { +static const struct irq_domain_ops opb_host_ops = {  	.map = opb_host_map, -	.xlate = opb_host_xlate, +	.xlate = irq_domain_xlate_twocell,  };  irqreturn_t opb_irq_handler(int irq, void *private) @@ -263,13 +252,11 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)  		goto free_opb;  	} -	/* Allocate an irq host so that Linux knows that despite only +	/* Allocate an irq domain so that Linux knows that despite only  	 * having one interrupt to issue, we're the controller for multiple  	 * hardware IRQs, so later we can lookup their virtual IRQs. */ -	opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR, -			OPB_NR_IRQS, &opb_host_ops, -1); - +	opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb);  	if (!opb->host) {  		printk(KERN_ERR "opb: Failed to allocate IRQ host!\n");  		goto free_regs; @@ -277,7 +264,6 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn)  	opb->index = opb_index++;  	spin_lock_init(&opb->lock); -	opb->host->host_data = opb;  	/* Disable all interrupts by default */  	opb_out(opb, OPB_MLSASIER, 0); diff --git a/arch/powerpc/platforms/wsp/smp.c b/arch/powerpc/platforms/wsp/smp.c index 71bd105f386..0ba103ae83a 100644 --- a/arch/powerpc/platforms/wsp/smp.c +++ b/arch/powerpc/platforms/wsp/smp.c @@ -71,7 +71,7 @@ int __devinit smp_a2_kick_cpu(int nr)  static int __init smp_a2_probe(void)  { -	return cpus_weight(cpu_possible_map); +	return num_possible_cpus();  }  static struct smp_ops_t a2_smp_ops = { diff --git a/arch/powerpc/platforms/wsp/wsp_pci.c b/arch/powerpc/platforms/wsp/wsp_pci.c index e0262cd0e2d..763014cd1e6 100644 --- a/arch/powerpc/platforms/wsp/wsp_pci.c +++ b/arch/powerpc/platforms/wsp/wsp_pci.c @@ -468,15 +468,15 @@ static void __init wsp_pcie_configure_hw(struct pci_controller *hose)  #define DUMP_REG(x) \  	pr_debug("%-30s : 0x%016llx\n", #x, in_be64(hose->cfg_data + x)) -#ifdef CONFIG_WSP_DD1_WORKAROUND_BAD_PCIE_CLASS -	/* WSP DD1 has a bogus class code by default in the PCI-E -	 * root complex's built-in P2P bridge */ +	/* +	 * Some WSP variants  has a bogus class code by default in the PCI-E +	 * root complex's built-in P2P bridge +	 */  	val = in_be64(hose->cfg_data + PCIE_REG_SYS_CFG1);  	pr_debug("PCI-E SYS_CFG1 : 0x%llx\n", val);  	out_be64(hose->cfg_data + PCIE_REG_SYS_CFG1,  		 (val & ~PCIE_REG_SYS_CFG1_CLASS_CODE) | (PCI_CLASS_BRIDGE_PCI << 8));  	pr_debug("PCI-E SYS_CFG1 : 0x%llx\n", in_be64(hose->cfg_data + PCIE_REG_SYS_CFG1)); -#endif /* CONFIG_WSP_DD1_WORKAROUND_BAD_PCIE_CLASS */  #ifdef CONFIG_WSP_DD1_WORKAROUND_DD1_TCE_BUGS  	/* XXX Disable TCE caching, it doesn't work on DD1 */ @@ -682,7 +682,6 @@ static int __init wsp_setup_one_phb(struct device_node *np)  	/* XXX Force re-assigning of everything for now */  	pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC |  		      PCI_ENABLE_PROC_DOMAINS); -	pci_probe_only = 0;  	/* Calculate how the TCE space is divided */  	phb->dma32_base		= 0;  |