Browse Source

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

Pull a few more things for powerpc by Benjamin Herrenschmidt:
 - Anton's did some recent improvements to EPOW event reporting on
   pSeries (power supply failures and such).  The patches are self
   contained enough and replace really nasty code so I felt it should
   still go in
 - I did the vio driver registration change Greg requested, I don't see
   the point of leaving that til the next merge window
 - The remaining EEH changes I said were still pending to get rid of the
   EEH references from the generic struct device_node
 - A few more iSeries removal bits
 - A perf bug fix on 970

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  powerpc/perf: Fix instruction address sampling on 970 and Power4
  powerpc+sparc/vio: Modernize driver registration
  powerpc: Random little legacy iSeries removal tidy ups
  powerpc: Remove NO_IRQ_IGNORE
  powerpc/pseries: Cut down on enthusiastic use of defines in RAS code
  powerpc/pseries: Clean up ras_error_interrupt code
  powerpc/pseries: Remove RTAS_POWERMGM_EVENTS
  powerpc/pseries: Use rtas_get_sensor in RAS code
  powerpc/pseries: Parse and handle EPOW interrupts
  powerpc: Make function that parses RTAS error logs global
  powerpc/eeh: Retrieve PHB from global list
  powerpc/eeh: Remove eeh information from pci_dn
  powerpc/eeh: Remove eeh device from OF node
Linus Torvalds 13 years ago
parent
commit
47b816ff7d
38 changed files with 321 additions and 273 deletions
  1. 0 1
      arch/powerpc/boot/.gitignore
  2. 0 1
      arch/powerpc/include/asm/iommu.h
  3. 0 6
      arch/powerpc/include/asm/irq.h
  4. 1 3
      arch/powerpc/include/asm/machdep.h
  5. 0 12
      arch/powerpc/include/asm/mmu-hash64.h
  6. 8 8
      arch/powerpc/include/asm/pci-bridge.h
  7. 2 0
      arch/powerpc/include/asm/perf_event_server.h
  8. 33 1
      arch/powerpc/include/asm/rtas.h
  9. 0 1
      arch/powerpc/include/asm/smp.h
  10. 0 1
      arch/powerpc/include/asm/udbg.h
  11. 9 1
      arch/powerpc/include/asm/vio.h
  12. 4 4
      arch/powerpc/kernel/irq.c
  13. 1 1
      arch/powerpc/kernel/prom_init.c
  14. 34 0
      arch/powerpc/kernel/rtas.c
  15. 0 3
      arch/powerpc/kernel/udbg.c
  16. 2 2
      arch/powerpc/kernel/vdso.c
  17. 8 4
      arch/powerpc/kernel/vio.c
  18. 41 5
      arch/powerpc/perf/core-book3s.c
  19. 1 0
      arch/powerpc/perf/power4-pmu.c
  20. 1 0
      arch/powerpc/perf/ppc970-pmu.c
  21. 0 2
      arch/powerpc/platforms/cell/beat_htab.c
  22. 5 14
      arch/powerpc/platforms/pseries/eeh.c
  23. 1 1
      arch/powerpc/platforms/pseries/eeh_dev.c
  24. 2 66
      arch/powerpc/platforms/pseries/io_event_irq.c
  25. 13 16
      arch/powerpc/platforms/pseries/iommu.c
  26. 128 67
      arch/powerpc/platforms/pseries/ras.c
  27. 8 1
      arch/sparc/include/asm/vio.h
  28. 1 4
      arch/sparc/kernel/ds.c
  29. 6 2
      arch/sparc/kernel/vio.c
  30. 1 4
      drivers/block/sunvdc.c
  31. 2 5
      drivers/net/ethernet/ibm/ibmveth.c
  32. 1 4
      drivers/net/ethernet/sun/sunvnet.c
  33. 2 5
      drivers/scsi/ibmvscsi/ibmvfc.c
  34. 2 5
      drivers/scsi/ibmvscsi/ibmvscsi.c
  35. 1 4
      drivers/scsi/ibmvscsi/ibmvstgt.c
  36. 2 5
      drivers/tty/hvc/hvc_vio.c
  37. 1 4
      drivers/tty/hvc/hvcs.c
  38. 0 10
      include/linux/of.h

+ 0 - 1
arch/powerpc/boot/.gitignore

@@ -27,7 +27,6 @@ zImage.bin.*
 zImage.chrp
 zImage.chrp
 zImage.coff
 zImage.coff
 zImage.holly
 zImage.holly
-zImage.iseries
 zImage.*lds
 zImage.*lds
 zImage.miboot
 zImage.miboot
 zImage.pmac
 zImage.pmac

+ 0 - 1
arch/powerpc/include/asm/iommu.h

@@ -112,7 +112,6 @@ extern void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
 			     struct dma_attrs *attrs);
 			     struct dma_attrs *attrs);
 
 
 extern void iommu_init_early_pSeries(void);
 extern void iommu_init_early_pSeries(void);
-extern void iommu_init_early_iSeries(void);
 extern void iommu_init_early_dart(void);
 extern void iommu_init_early_dart(void);
 extern void iommu_init_early_pasemi(void);
 extern void iommu_init_early_pasemi(void);
 
 

+ 0 - 6
arch/powerpc/include/asm/irq.h

@@ -27,12 +27,6 @@ extern atomic_t ppc_n_lost_interrupts;
 /* This number is used when no interrupt has been assigned */
 /* This number is used when no interrupt has been assigned */
 #define NO_IRQ			(0)
 #define NO_IRQ			(0)
 
 
-/* This is a special irq number to return from get_irq() to tell that
- * no interrupt happened _and_ ignore it (don't count it as bad). Some
- * platforms like iSeries rely on that.
- */
-#define NO_IRQ_IGNORE		((unsigned int)-1)
-
 /* Total number of virq in the platform */
 /* Total number of virq in the platform */
 #define NR_IRQS		CONFIG_NR_IRQS
 #define NR_IRQS		CONFIG_NR_IRQS
 
 

+ 1 - 3
arch/powerpc/include/asm/machdep.h

@@ -99,9 +99,7 @@ struct machdep_calls {
 
 
 	void		(*init_IRQ)(void);
 	void		(*init_IRQ)(void);
 
 
-	/* Return an irq, or NO_IRQ to indicate there are none pending.
-	 * If for some reason there is no irq, but the interrupt
-	 * shouldn't be counted as spurious, return NO_IRQ_IGNORE. */
+	/* Return an irq, or NO_IRQ to indicate there are none pending. */
 	unsigned int	(*get_irq)(void);
 	unsigned int	(*get_irq)(void);
 
 
 	/* PCI stuff */
 	/* PCI stuff */

+ 0 - 12
arch/powerpc/include/asm/mmu-hash64.h

@@ -267,7 +267,6 @@ extern void demote_segment_4k(struct mm_struct *mm, unsigned long addr);
 
 
 extern void hpte_init_native(void);
 extern void hpte_init_native(void);
 extern void hpte_init_lpar(void);
 extern void hpte_init_lpar(void);
-extern void hpte_init_iSeries(void);
 extern void hpte_init_beat(void);
 extern void hpte_init_beat(void);
 extern void hpte_init_beat_v3(void);
 extern void hpte_init_beat_v3(void);
 
 
@@ -325,9 +324,6 @@ extern void slb_set_size(u16 size);
  * WARNING - If you change these you must make sure the asm
  * WARNING - If you change these you must make sure the asm
  * implementations in slb_allocate (slb_low.S), do_stab_bolted
  * implementations in slb_allocate (slb_low.S), do_stab_bolted
  * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
  * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
- *
- * You'll also need to change the precomputed VSID values in head.S
- * which are used by the iSeries firmware.
  */
  */
 
 
 #define VSID_MULTIPLIER_256M	ASM_CONST(200730139)	/* 28-bit prime */
 #define VSID_MULTIPLIER_256M	ASM_CONST(200730139)	/* 28-bit prime */
@@ -484,14 +480,6 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea,
 			     | (ea >> SID_SHIFT_1T), 1T);
 			     | (ea >> SID_SHIFT_1T), 1T);
 }
 }
 
 
-/*
- * This is only used on legacy iSeries in lparmap.c,
- * hence the 256MB segment assumption.
- */
-#define VSID_SCRAMBLE(pvsid)	(((pvsid) * VSID_MULTIPLIER_256M) %	\
-				 VSID_MODULUS_256M)
-#define KERNEL_VSID(ea)		VSID_SCRAMBLE(GET_ESID(ea))
-
 #endif /* __ASSEMBLY__ */
 #endif /* __ASSEMBLY__ */
 
 
 #endif /* _ASM_POWERPC_MMU_HASH64_H_ */
 #endif /* _ASM_POWERPC_MMU_HASH64_H_ */

+ 8 - 8
arch/powerpc/include/asm/pci-bridge.h

@@ -155,14 +155,7 @@ struct pci_dn {
 
 
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 #ifdef CONFIG_EEH
 #ifdef CONFIG_EEH
-	int	class_code;		/* pci device class */
-	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
-	int	eeh_config_addr;
-	int	eeh_pe_config_addr; /* new-style partition endpoint address */
-	int	eeh_check_count;	/* # times driver ignored error */
-	int	eeh_freeze_count;	/* # times this device froze up. */
-	int	eeh_false_positives;	/* # times this device reported #ff's */
-	u32	config_space[16];	/* saved PCI config space */
+	struct eeh_dev *edev;		/* eeh device */
 #endif
 #endif
 #define IODA_INVALID_PE		(-1)
 #define IODA_INVALID_PE		(-1)
 #ifdef CONFIG_PPC_POWERNV
 #ifdef CONFIG_PPC_POWERNV
@@ -185,6 +178,13 @@ static inline int pci_device_from_OF_node(struct device_node *np,
 	return 0;
 	return 0;
 }
 }
 
 
+#if defined(CONFIG_EEH)
+static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
+{
+	return PCI_DN(dn)->edev;
+}
+#endif
+
 /** Find the bus corresponding to the indicated device node */
 /** Find the bus corresponding to the indicated device node */
 extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
 extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
 
 

+ 2 - 0
arch/powerpc/include/asm/perf_event_server.h

@@ -47,6 +47,8 @@ struct power_pmu {
  */
  */
 #define PPMU_LIMITED_PMC5_6	1	/* PMC5/6 have limited function */
 #define PPMU_LIMITED_PMC5_6	1	/* PMC5/6 have limited function */
 #define PPMU_ALT_SIPR		2	/* uses alternate posn for SIPR/HV */
 #define PPMU_ALT_SIPR		2	/* uses alternate posn for SIPR/HV */
+#define PPMU_NO_SIPR		4	/* no SIPR/HV in MMCRA at all */
+#define PPMU_NO_CONT_SAMPLING	8	/* no continuous sampling */
 
 
 /*
 /*
  * Values for flags to get_alternatives()
  * Values for flags to get_alternatives()

+ 33 - 1
arch/powerpc/include/asm/rtas.h

@@ -74,7 +74,6 @@ struct rtas_suspend_me_data {
 /* RTAS event classes */
 /* RTAS event classes */
 #define RTAS_INTERNAL_ERROR		0x80000000 /* set bit 0 */
 #define RTAS_INTERNAL_ERROR		0x80000000 /* set bit 0 */
 #define RTAS_EPOW_WARNING		0x40000000 /* set bit 1 */
 #define RTAS_EPOW_WARNING		0x40000000 /* set bit 1 */
-#define RTAS_POWERMGM_EVENTS		0x20000000 /* set bit 2 */
 #define RTAS_HOTPLUG_EVENTS		0x10000000 /* set bit 3 */
 #define RTAS_HOTPLUG_EVENTS		0x10000000 /* set bit 3 */
 #define RTAS_IO_EVENTS			0x08000000 /* set bit 4 */
 #define RTAS_IO_EVENTS			0x08000000 /* set bit 4 */
 #define RTAS_EVENT_SCAN_ALL_EVENTS	0xffffffff
 #define RTAS_EVENT_SCAN_ALL_EVENTS	0xffffffff
@@ -204,6 +203,39 @@ struct rtas_ext_event_log_v6 {
 					/* Variable length.		*/
 					/* Variable length.		*/
 };
 };
 
 
+/* 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_errorlog {
+	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	*/
+};
+
+struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
+					      uint16_t section_id);
+
 /*
 /*
  * This can be set by the rtas_flash module so that it can get called
  * This can be set by the rtas_flash module so that it can get called
  * as the absolutely last thing before the kernel terminates.
  * as the absolutely last thing before the kernel terminates.

+ 0 - 1
arch/powerpc/include/asm/smp.h

@@ -122,7 +122,6 @@ extern void smp_muxed_ipi_set_data(int cpu, unsigned long data);
 extern void smp_muxed_ipi_message_pass(int cpu, int msg);
 extern void smp_muxed_ipi_message_pass(int cpu, int msg);
 extern irqreturn_t smp_ipi_demux(void);
 extern irqreturn_t smp_ipi_demux(void);
 
 
-void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
 void smp_init_cell(void);
 void smp_init_celleb(void);
 void smp_init_celleb(void);

+ 0 - 1
arch/powerpc/include/asm/udbg.h

@@ -44,7 +44,6 @@ extern void __init udbg_init_debug_lpar_hvsi(void);
 extern void __init udbg_init_pmac_realmode(void);
 extern void __init udbg_init_pmac_realmode(void);
 extern void __init udbg_init_maple_realmode(void);
 extern void __init udbg_init_maple_realmode(void);
 extern void __init udbg_init_pas_realmode(void);
 extern void __init udbg_init_pas_realmode(void);
-extern void __init udbg_init_iseries(void);
 extern void __init udbg_init_rtas_panel(void);
 extern void __init udbg_init_rtas_panel(void);
 extern void __init udbg_init_rtas_console(void);
 extern void __init udbg_init_rtas_console(void);
 extern void __init udbg_init_debug_beat(void);
 extern void __init udbg_init_debug_beat(void);

+ 9 - 1
arch/powerpc/include/asm/vio.h

@@ -69,6 +69,7 @@ struct vio_dev {
 };
 };
 
 
 struct vio_driver {
 struct vio_driver {
+	const char *name;
 	const struct vio_device_id *id_table;
 	const struct vio_device_id *id_table;
 	int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
 	int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
 	int (*remove)(struct vio_dev *dev);
 	int (*remove)(struct vio_dev *dev);
@@ -76,10 +77,17 @@ struct vio_driver {
 	 * be loaded in a CMO environment if it uses DMA.
 	 * be loaded in a CMO environment if it uses DMA.
 	 */
 	 */
 	unsigned long (*get_desired_dma)(struct vio_dev *dev);
 	unsigned long (*get_desired_dma)(struct vio_dev *dev);
+	const struct dev_pm_ops *pm;
 	struct device_driver driver;
 	struct device_driver driver;
 };
 };
 
 
-extern int vio_register_driver(struct vio_driver *drv);
+extern int __vio_register_driver(struct vio_driver *drv, struct module *owner,
+				 const char *mod_name);
+/*
+ * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded
+ */
+#define vio_register_driver(driver)		\
+	__vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 extern void vio_unregister_driver(struct vio_driver *drv);
 extern void vio_unregister_driver(struct vio_driver *drv);
 
 
 extern int vio_cmo_entitlement_update(size_t);
 extern int vio_cmo_entitlement_update(size_t);

+ 4 - 4
arch/powerpc/kernel/irq.c

@@ -208,8 +208,8 @@ notrace void arch_local_irq_restore(unsigned long en)
 	 * we are checking the "new" CPU instead of the old one. This
 	 * we are checking the "new" CPU instead of the old one. This
 	 * is only a problem if an event happened on the "old" CPU.
 	 * is only a problem if an event happened on the "old" CPU.
 	 *
 	 *
-	 * External interrupt events on non-iseries will have caused
-	 * interrupts to be hard-disabled, so there is no problem, we
+	 * External interrupt events will have caused interrupts to
+	 * be hard-disabled, so there is no problem, we
 	 * cannot have preempted.
 	 * cannot have preempted.
 	 */
 	 */
 	irq_happened = get_irq_happened();
 	irq_happened = get_irq_happened();
@@ -445,9 +445,9 @@ void do_IRQ(struct pt_regs *regs)
 	may_hard_irq_enable();
 	may_hard_irq_enable();
 
 
 	/* And finally process it */
 	/* And finally process it */
-	if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
+	if (irq != NO_IRQ)
 		handle_one_irq(irq);
 		handle_one_irq(irq);
-	else if (irq != NO_IRQ_IGNORE)
+	else
 		__get_cpu_var(irq_stat).spurious_irqs++;
 		__get_cpu_var(irq_stat).spurious_irqs++;
 
 
 	irq_exit();
 	irq_exit();

+ 1 - 1
arch/powerpc/kernel/prom_init.c

@@ -447,7 +447,7 @@ static void __init __attribute__((noreturn)) prom_panic(const char *reason)
 	if (RELOC(of_platform) == PLATFORM_POWERMAC)
 	if (RELOC(of_platform) == PLATFORM_POWERMAC)
 		asm("trap\n");
 		asm("trap\n");
 
 
-	/* ToDo: should put up an SRC here on p/iSeries */
+	/* ToDo: should put up an SRC here on pSeries */
 	call_prom("exit", 0, 0);
 	call_prom("exit", 0, 0);
 
 
 	for (;;)			/* should never get here */
 	for (;;)			/* should never get here */

+ 34 - 0
arch/powerpc/kernel/rtas.c

@@ -868,6 +868,40 @@ int rtas_ibm_suspend_me(struct rtas_args *args)
 }
 }
 #endif
 #endif
 
 
+/**
+ * Find a specific pseries error log in an RTAS extended event log.
+ * @log: RTAS error/event log
+ * @section_id: two character section identifier
+ *
+ * Returns a pointer to the specified errorlog or NULL if not found.
+ */
+struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
+					      uint16_t section_id)
+{
+	struct rtas_ext_event_log_v6 *ext_log =
+		(struct rtas_ext_event_log_v6 *)log->buffer;
+	struct pseries_errorlog *sect;
+	unsigned char *p, *log_end;
+
+	/* Check that we understand the format */
+	if (log->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
+	    ext_log->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
+	    ext_log->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
+		return NULL;
+
+	log_end = log->buffer + log->extended_log_length;
+	p = ext_log->vendor_log;
+
+	while (p < log_end) {
+		sect = (struct pseries_errorlog *)p;
+		if (sect->id == section_id)
+			return sect;
+		p += sect->length;
+	}
+
+	return NULL;
+}
+
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 {
 {
 	struct rtas_args args;
 	struct rtas_args args;

+ 0 - 3
arch/powerpc/kernel/udbg.c

@@ -46,9 +46,6 @@ void __init udbg_early_init(void)
 #elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
 #elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
 	/* Maple real mode debug */
 	/* Maple real mode debug */
 	udbg_init_maple_realmode();
 	udbg_init_maple_realmode();
-#elif defined(CONFIG_PPC_EARLY_DEBUG_ISERIES)
-	/* For iSeries - hit Ctrl-x Ctrl-x to see the output */
-	udbg_init_iseries();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_BEAT)
 #elif defined(CONFIG_PPC_EARLY_DEBUG_BEAT)
 	udbg_init_debug_beat();
 	udbg_init_debug_beat();
 #elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
 #elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)

+ 2 - 2
arch/powerpc/kernel/vdso.c

@@ -721,10 +721,10 @@ static int __init vdso_init(void)
 	vdso_data->version.minor = SYSTEMCFG_MINOR;
 	vdso_data->version.minor = SYSTEMCFG_MINOR;
 	vdso_data->processor = mfspr(SPRN_PVR);
 	vdso_data->processor = mfspr(SPRN_PVR);
 	/*
 	/*
-	 * Fake the old platform number for pSeries and iSeries and add
+	 * Fake the old platform number for pSeries and add
 	 * in LPAR bit if necessary
 	 * in LPAR bit if necessary
 	 */
 	 */
-	vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100;
+	vdso_data->platform = 0x100;
 	if (firmware_has_feature(FW_FEATURE_LPAR))
 	if (firmware_has_feature(FW_FEATURE_LPAR))
 		vdso_data->platform |= 1;
 		vdso_data->platform |= 1;
 	vdso_data->physicalMemorySize = memblock_phys_mem_size();
 	vdso_data->physicalMemorySize = memblock_phys_mem_size();

+ 8 - 4
arch/powerpc/kernel/vio.c

@@ -1159,17 +1159,21 @@ static int vio_bus_remove(struct device *dev)
  * vio_register_driver: - Register a new vio driver
  * vio_register_driver: - Register a new vio driver
  * @drv:	The vio_driver structure to be registered.
  * @drv:	The vio_driver structure to be registered.
  */
  */
-int vio_register_driver(struct vio_driver *viodrv)
+int __vio_register_driver(struct vio_driver *viodrv, struct module *owner,
+			  const char *mod_name)
 {
 {
-	printk(KERN_DEBUG "%s: driver %s registering\n", __func__,
-		viodrv->driver.name);
+	pr_debug("%s: driver %s registering\n", __func__, viodrv->name);
 
 
 	/* fill in 'struct driver' fields */
 	/* fill in 'struct driver' fields */
+	viodrv->driver.name = viodrv->name;
+	viodrv->driver.pm = viodrv->pm;
 	viodrv->driver.bus = &vio_bus_type;
 	viodrv->driver.bus = &vio_bus_type;
+	viodrv->driver.owner = owner;
+	viodrv->driver.mod_name = mod_name;
 
 
 	return driver_register(&viodrv->driver);
 	return driver_register(&viodrv->driver);
 }
 }
-EXPORT_SYMBOL(vio_register_driver);
+EXPORT_SYMBOL(__vio_register_driver);
 
 
 /**
 /**
  * vio_unregister_driver - Remove registration of vio driver.
  * vio_unregister_driver - Remove registration of vio driver.

+ 41 - 5
arch/powerpc/perf/core-book3s.c

@@ -116,14 +116,45 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
 		*addrp = mfspr(SPRN_SDAR);
 		*addrp = mfspr(SPRN_SDAR);
 }
 }
 
 
+static inline u32 perf_flags_from_msr(struct pt_regs *regs)
+{
+	if (regs->msr & MSR_PR)
+		return PERF_RECORD_MISC_USER;
+	if ((regs->msr & MSR_HV) && freeze_events_kernel != MMCR0_FCHV)
+		return PERF_RECORD_MISC_HYPERVISOR;
+	return PERF_RECORD_MISC_KERNEL;
+}
+
 static inline u32 perf_get_misc_flags(struct pt_regs *regs)
 static inline u32 perf_get_misc_flags(struct pt_regs *regs)
 {
 {
 	unsigned long mmcra = regs->dsisr;
 	unsigned long mmcra = regs->dsisr;
 	unsigned long sihv = MMCRA_SIHV;
 	unsigned long sihv = MMCRA_SIHV;
 	unsigned long sipr = MMCRA_SIPR;
 	unsigned long sipr = MMCRA_SIPR;
 
 
+	/* Not a PMU interrupt: Make up flags from regs->msr */
 	if (TRAP(regs) != 0xf00)
 	if (TRAP(regs) != 0xf00)
-		return 0;	/* not a PMU interrupt */
+		return perf_flags_from_msr(regs);
+
+	/*
+	 * If we don't support continuous sampling and this
+	 * is not a marked event, same deal
+	 */
+	if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+	    !(mmcra & MMCRA_SAMPLE_ENABLE))
+		return perf_flags_from_msr(regs);
+
+	/*
+	 * If we don't have flags in MMCRA, rather than using
+	 * the MSR, we intuit the flags from the address in
+	 * SIAR which should give slightly more reliable
+	 * results
+	 */
+	if (ppmu->flags & PPMU_NO_SIPR) {
+		unsigned long siar = mfspr(SPRN_SIAR);
+		if (siar >= PAGE_OFFSET)
+			return PERF_RECORD_MISC_KERNEL;
+		return PERF_RECORD_MISC_USER;
+	}
 
 
 	if (ppmu->flags & PPMU_ALT_SIPR) {
 	if (ppmu->flags & PPMU_ALT_SIPR) {
 		sihv = POWER6_MMCRA_SIHV;
 		sihv = POWER6_MMCRA_SIHV;
@@ -1299,13 +1330,18 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
  */
  */
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
 {
-	unsigned long ip;
+	unsigned long mmcra = regs->dsisr;
 
 
+	/* Not a PMU interrupt */
 	if (TRAP(regs) != 0xf00)
 	if (TRAP(regs) != 0xf00)
-		return regs->nip;	/* not a PMU interrupt */
+		return regs->nip;
+
+	/* Processor doesn't support sampling non marked events */
+	if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) &&
+	    !(mmcra & MMCRA_SAMPLE_ENABLE))
+		return regs->nip;
 
 
-	ip = mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
-	return ip;
+	return mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
 }
 }
 
 
 static bool pmc_overflow(unsigned long val)
 static bool pmc_overflow(unsigned long val)

+ 1 - 0
arch/powerpc/perf/power4-pmu.c

@@ -607,6 +607,7 @@ static struct power_pmu power4_pmu = {
 	.n_generic		= ARRAY_SIZE(p4_generic_events),
 	.n_generic		= ARRAY_SIZE(p4_generic_events),
 	.generic_events		= p4_generic_events,
 	.generic_events		= p4_generic_events,
 	.cache_events		= &power4_cache_events,
 	.cache_events		= &power4_cache_events,
+	.flags			= PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
 };
 };
 
 
 static int __init init_power4_pmu(void)
 static int __init init_power4_pmu(void)

+ 1 - 0
arch/powerpc/perf/ppc970-pmu.c

@@ -487,6 +487,7 @@ static struct power_pmu ppc970_pmu = {
 	.n_generic		= ARRAY_SIZE(ppc970_generic_events),
 	.n_generic		= ARRAY_SIZE(ppc970_generic_events),
 	.generic_events		= ppc970_generic_events,
 	.generic_events		= ppc970_generic_events,
 	.cache_events		= &ppc970_cache_events,
 	.cache_events		= &ppc970_cache_events,
+	.flags			= PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
 };
 };
 
 
 static int __init init_ppc970_pmu(void)
 static int __init init_ppc970_pmu(void)

+ 0 - 2
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;
 	unsigned long lpar_rc;
 	u64 hpte_v, hpte_r, slot;
 	u64 hpte_v, hpte_r, slot;
 
 
-	/* same as iseries */
 	if (vflags & HPTE_V_SECONDARY)
 	if (vflags & HPTE_V_SECONDARY)
 		return -1;
 		return -1;
 
 
@@ -319,7 +318,6 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group,
 	unsigned long lpar_rc;
 	unsigned long lpar_rc;
 	u64 hpte_v, hpte_r, slot;
 	u64 hpte_v, hpte_r, slot;
 
 
-	/* same as iseries */
 	if (vflags & HPTE_V_SECONDARY)
 	if (vflags & HPTE_V_SECONDARY)
 		return -1;
 		return -1;
 
 

+ 5 - 14
arch/powerpc/platforms/pseries/eeh.c

@@ -984,7 +984,8 @@ int __exit eeh_ops_unregister(const char *name)
  */
  */
 void __init eeh_init(void)
 void __init eeh_init(void)
 {
 {
-	struct device_node *phb, *np;
+	struct pci_controller *hose, *tmp;
+	struct device_node *phb;
 	int ret;
 	int ret;
 
 
 	/* call platform initialization function */
 	/* call platform initialization function */
@@ -1000,19 +1001,9 @@ void __init eeh_init(void)
 
 
 	raw_spin_lock_init(&confirm_error_lock);
 	raw_spin_lock_init(&confirm_error_lock);
 
 
-	np = of_find_node_by_path("/rtas");
-	if (np == NULL)
-		return;
-
-	/* 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 || !of_node_to_eeh_dev(phb))
-			continue;
-
+	/* 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);
 		traverse_pci_devices(phb, eeh_early_enable, NULL);
 	}
 	}
 
 

+ 1 - 1
arch/powerpc/platforms/pseries/eeh_dev.c

@@ -62,7 +62,7 @@ void * __devinit eeh_dev_init(struct device_node *dn, void *data)
 	}
 	}
 
 
 	/* Associate EEH device with OF node */
 	/* Associate EEH device with OF node */
-	dn->edev  = edev;
+	PCI_DN(dn)->edev = edev;
 	edev->dn  = dn;
 	edev->dn  = dn;
 	edev->phb = phb;
 	edev->phb = phb;
 
 

+ 2 - 66
arch/powerpc/platforms/pseries/io_event_irq.c

@@ -63,72 +63,8 @@ EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list);
 
 
 static int ioei_check_exception_token;
 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;
 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.
  * Find the data portion of an IO Event section from event log.
  * @elog: RTAS error/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)
 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 should only ever get called for io-event interrupts, but if
 	 * we do get called for another type then something went wrong so
 	 * 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;
 		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)) {
 	if (unlikely(!sect)) {
 		printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
 		printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
 			    "log does not contain an IO Event section. "
 			    "log does not contain an IO Event section. "

+ 13 - 16
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,
 static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
 			struct ddw_query_response *query)
 			struct ddw_query_response *query)
 {
 {
-	struct device_node *dn;
-	struct pci_dn *pcidn;
+	struct eeh_dev *edev;
 	u32 cfg_addr;
 	u32 cfg_addr;
 	u64 buid;
 	u64 buid;
 	int ret;
 	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
 	 * Retrieve them from the pci device, not the node with the
 	 * dma-window property
 	 * 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,
 	ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query,
 		  cfg_addr, BUID_HI(buid), BUID_LO(buid));
 		  cfg_addr, BUID_HI(buid), BUID_LO(buid));
 	dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
 	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,
 			struct ddw_create_response *create, int page_shift,
 			int window_shift)
 			int window_shift)
 {
 {
-	struct device_node *dn;
-	struct pci_dn *pcidn;
+	struct eeh_dev *edev;
 	u32 cfg_addr;
 	u32 cfg_addr;
 	u64 buid;
 	u64 buid;
 	int ret;
 	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
 	 * Retrieve them from the pci device, not the node with the
 	 * dma-window property
 	 * 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 {
 	do {
 		/* extra outputs are LIOBN and dma-addr (hi, lo) */
 		/* extra outputs are LIOBN and dma-addr (hi, lo) */

+ 128 - 67
arch/powerpc/platforms/pseries/ras.c

@@ -16,37 +16,15 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  * 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/sched.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
-#include <linux/random.h>
-#include <linux/sysrq.h>
-#include <linux/bitops.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 <linux/of.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+
 #include <asm/machdep.h>
 #include <asm/machdep.h>
 #include <asm/rtas.h>
 #include <asm/rtas.h>
-#include <asm/udbg.h>
 #include <asm/firmware.h>
 #include <asm/firmware.h>
 
 
 #include "pseries.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 char global_mce_data_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_PER_CPU(__u64, mce_data_buf);
 static DEFINE_PER_CPU(__u64, mce_data_buf);
 
 
-static int ras_get_sensor_state_token;
 static int ras_check_exception_token;
 static int ras_check_exception_token;
 
 
 #define EPOW_SENSOR_TOKEN	9
 #define EPOW_SENSOR_TOKEN	9
@@ -75,7 +52,6 @@ static int __init init_ras_IRQ(void)
 {
 {
 	struct device_node *np;
 	struct device_node *np;
 
 
-	ras_get_sensor_state_token = rtas_token("get-sensor-state");
 	ras_check_exception_token = rtas_token("check-exception");
 	ras_check_exception_token = rtas_token("check-exception");
 
 
 	/* Internal Errors */
 	/* Internal Errors */
@@ -95,26 +71,126 @@ static int __init init_ras_IRQ(void)
 
 
 	return 0;
 	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)
 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
 {
 {
-	int status = 0xdeadbeef;
-	int state = 0;
+	int status;
+	int state;
 	int critical;
 	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)
 	if (state > 3)
-		critical = 1;  /* Time Critical */
+		critical = 1;		/* Time Critical */
 	else
 	else
 		critical = 0;
 		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,
 	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
 			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
 			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
 			   virq_to_hw(irq),
 			   virq_to_hw(irq),
-			   RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,
+			   RTAS_EPOW_WARNING,
 			   critical, __pa(&ras_log_buf),
 			   critical, __pa(&ras_log_buf),
 				rtas_get_error_log_max());
 				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);
 	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);
 	spin_unlock(&ras_log_buf_lock);
 	return IRQ_HANDLED;
 	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)
 static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
 {
 {
 	struct rtas_error_log *rtas_elog;
 	struct rtas_error_log *rtas_elog;
-	int status = 0xdeadbeef;
+	int status;
 	int fatal;
 	int fatal;
 
 
 	spin_lock(&ras_log_buf_lock);
 	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,
 	status = rtas_call(ras_check_exception_token, 6, 1, NULL,
 			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
 			   RTAS_VECTOR_EXTERNAL_INTERRUPT,
 			   virq_to_hw(irq),
 			   virq_to_hw(irq),
-			   RTAS_INTERNAL_ERROR, 1 /*Time Critical */,
+			   RTAS_INTERNAL_ERROR, 1 /* Time Critical */,
 			   __pa(&ras_log_buf),
 			   __pa(&ras_log_buf),
 				rtas_get_error_log_max());
 				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);
 	log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal);
 
 
 	if (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 {
 	} 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);
 	spin_unlock(&ras_log_buf_lock);

+ 8 - 1
arch/sparc/include/asm/vio.h

@@ -284,6 +284,7 @@ struct vio_dev {
 };
 };
 
 
 struct vio_driver {
 struct vio_driver {
+	const char			*name;
 	struct list_head		node;
 	struct list_head		node;
 	const struct vio_device_id	*id_table;
 	const struct vio_device_id	*id_table;
 	int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
 	int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
@@ -371,7 +372,13 @@ do {	if (vio->debug & VIO_DEBUG_##TYPE) \
 		       vio->vdev->channel_id, ## a); \
 		       vio->vdev->channel_id, ## a); \
 } while (0)
 } while (0)
 
 
-extern int vio_register_driver(struct vio_driver *drv);
+extern int __vio_register_driver(struct vio_driver *drv, struct module *owner,
+				 const char *mod_name);
+/*
+ * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded
+ */
+#define vio_register_driver(driver)		\
+	__vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 extern void vio_unregister_driver(struct vio_driver *drv);
 extern void vio_unregister_driver(struct vio_driver *drv);
 
 
 static inline struct vio_driver *to_vio_driver(struct device_driver *drv)
 static inline struct vio_driver *to_vio_driver(struct device_driver *drv)

+ 1 - 4
arch/sparc/kernel/ds.c

@@ -1244,10 +1244,7 @@ static struct vio_driver ds_driver = {
 	.id_table	= ds_match,
 	.id_table	= ds_match,
 	.probe		= ds_probe,
 	.probe		= ds_probe,
 	.remove		= ds_remove,
 	.remove		= ds_remove,
-	.driver		= {
-		.name	= "ds",
-		.owner	= THIS_MODULE,
-	}
+	.name		= "ds",
 };
 };
 
 
 static int __init ds_init(void)
 static int __init ds_init(void)

+ 6 - 2
arch/sparc/kernel/vio.c

@@ -119,13 +119,17 @@ static struct bus_type vio_bus_type = {
 	.remove		= vio_device_remove,
 	.remove		= vio_device_remove,
 };
 };
 
 
-int vio_register_driver(struct vio_driver *viodrv)
+int __vio_register_driver(struct vio_driver *viodrv, struct module *owner,
+			const char *mod_name)
 {
 {
 	viodrv->driver.bus = &vio_bus_type;
 	viodrv->driver.bus = &vio_bus_type;
+	viodrv->driver.name = viodrv->name;
+	viodrv->driver.owner = owner;
+	viodrv->driver.mod_name = mod_name;
 
 
 	return driver_register(&viodrv->driver);
 	return driver_register(&viodrv->driver);
 }
 }
-EXPORT_SYMBOL(vio_register_driver);
+EXPORT_SYMBOL(__vio_register_driver);
 
 
 void vio_unregister_driver(struct vio_driver *viodrv)
 void vio_unregister_driver(struct vio_driver *viodrv)
 {
 {

+ 1 - 4
drivers/block/sunvdc.c

@@ -839,10 +839,7 @@ static struct vio_driver vdc_port_driver = {
 	.id_table	= vdc_port_match,
 	.id_table	= vdc_port_match,
 	.probe		= vdc_port_probe,
 	.probe		= vdc_port_probe,
 	.remove		= vdc_port_remove,
 	.remove		= vdc_port_remove,
-	.driver		= {
-		.name	= "vdc_port",
-		.owner	= THIS_MODULE,
-	}
+	.name		= "vdc_port",
 };
 };
 
 
 static int __init vdc_init(void)
 static int __init vdc_init(void)

+ 2 - 5
drivers/net/ethernet/ibm/ibmveth.c

@@ -1616,11 +1616,8 @@ static struct vio_driver ibmveth_driver = {
 	.probe		= ibmveth_probe,
 	.probe		= ibmveth_probe,
 	.remove		= ibmveth_remove,
 	.remove		= ibmveth_remove,
 	.get_desired_dma = ibmveth_get_desired_dma,
 	.get_desired_dma = ibmveth_get_desired_dma,
-	.driver		= {
-		.name	= ibmveth_driver_name,
-		.owner	= THIS_MODULE,
-		.pm = &ibmveth_pm_ops,
-	}
+	.name		= ibmveth_driver_name,
+	.pm		= &ibmveth_pm_ops,
 };
 };
 
 
 static int __init ibmveth_module_init(void)
 static int __init ibmveth_module_init(void)

+ 1 - 4
drivers/net/ethernet/sun/sunvnet.c

@@ -1259,10 +1259,7 @@ static struct vio_driver vnet_port_driver = {
 	.id_table	= vnet_port_match,
 	.id_table	= vnet_port_match,
 	.probe		= vnet_port_probe,
 	.probe		= vnet_port_probe,
 	.remove		= vnet_port_remove,
 	.remove		= vnet_port_remove,
-	.driver		= {
-		.name	= "vnet_port",
-		.owner	= THIS_MODULE,
-	}
+	.name		= "vnet_port",
 };
 };
 
 
 static int __init vnet_init(void)
 static int __init vnet_init(void)

+ 2 - 5
drivers/scsi/ibmvscsi/ibmvfc.c

@@ -4890,11 +4890,8 @@ static struct vio_driver ibmvfc_driver = {
 	.probe = ibmvfc_probe,
 	.probe = ibmvfc_probe,
 	.remove = ibmvfc_remove,
 	.remove = ibmvfc_remove,
 	.get_desired_dma = ibmvfc_get_desired_dma,
 	.get_desired_dma = ibmvfc_get_desired_dma,
-	.driver = {
-		.name = IBMVFC_NAME,
-		.owner = THIS_MODULE,
-		.pm = &ibmvfc_pm_ops,
-	}
+	.name = IBMVFC_NAME,
+	.pm = &ibmvfc_pm_ops,
 };
 };
 
 
 static struct fc_function_template ibmvfc_transport_functions = {
 static struct fc_function_template ibmvfc_transport_functions = {

+ 2 - 5
drivers/scsi/ibmvscsi/ibmvscsi.c

@@ -2061,11 +2061,8 @@ static struct vio_driver ibmvscsi_driver = {
 	.probe = ibmvscsi_probe,
 	.probe = ibmvscsi_probe,
 	.remove = ibmvscsi_remove,
 	.remove = ibmvscsi_remove,
 	.get_desired_dma = ibmvscsi_get_desired_dma,
 	.get_desired_dma = ibmvscsi_get_desired_dma,
-	.driver = {
-		.name = "ibmvscsi",
-		.owner = THIS_MODULE,
-		.pm = &ibmvscsi_pm_ops,
-	}
+	.name = "ibmvscsi",
+	.pm = &ibmvscsi_pm_ops,
 };
 };
 
 
 static struct srp_function_template ibmvscsi_transport_functions = {
 static struct srp_function_template ibmvscsi_transport_functions = {

+ 1 - 4
drivers/scsi/ibmvscsi/ibmvstgt.c

@@ -918,10 +918,7 @@ static struct vio_driver ibmvstgt_driver = {
 	.id_table = ibmvstgt_device_table,
 	.id_table = ibmvstgt_device_table,
 	.probe = ibmvstgt_probe,
 	.probe = ibmvstgt_probe,
 	.remove = ibmvstgt_remove,
 	.remove = ibmvstgt_remove,
-	.driver = {
-		.name = "ibmvscsis",
-		.owner = THIS_MODULE,
-	}
+	.name = "ibmvscsis",
 };
 };
 
 
 static int get_system_info(void)
 static int get_system_info(void)

+ 2 - 5
drivers/tty/hvc/hvc_vio.c

@@ -310,11 +310,8 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev)
 static struct vio_driver hvc_vio_driver = {
 static struct vio_driver hvc_vio_driver = {
 	.id_table	= hvc_driver_table,
 	.id_table	= hvc_driver_table,
 	.probe		= hvc_vio_probe,
 	.probe		= hvc_vio_probe,
-	.remove		= __devexit_p(hvc_vio_remove),
-	.driver		= {
-		.name	= hvc_driver_name,
-		.owner	= THIS_MODULE,
-	}
+	.remove		= hvc_vio_remove,
+	.name		= hvc_driver_name,
 };
 };
 
 
 static int __init hvc_vio_init(void)
 static int __init hvc_vio_init(void)

+ 1 - 4
drivers/tty/hvc/hvcs.c

@@ -879,10 +879,7 @@ static struct vio_driver hvcs_vio_driver = {
 	.id_table	= hvcs_driver_table,
 	.id_table	= hvcs_driver_table,
 	.probe		= hvcs_probe,
 	.probe		= hvcs_probe,
 	.remove		= __devexit_p(hvcs_remove),
 	.remove		= __devexit_p(hvcs_remove),
-	.driver		= {
-		.name	= hvcs_driver_name,
-		.owner	= THIS_MODULE,
-	}
+	.name		= hvcs_driver_name,
 };
 };
 
 
 /* Only called from hvcs_get_pi please */
 /* Only called from hvcs_get_pi please */

+ 0 - 10
include/linux/of.h

@@ -58,9 +58,6 @@ struct device_node {
 	struct	kref kref;
 	struct	kref kref;
 	unsigned long _flags;
 	unsigned long _flags;
 	void	*data;
 	void	*data;
-#if defined(CONFIG_EEH)
-	struct eeh_dev *edev;
-#endif
 #if defined(CONFIG_SPARC)
 #if defined(CONFIG_SPARC)
 	char	*path_component_name;
 	char	*path_component_name;
 	unsigned int unique_id;
 	unsigned int unique_id;
@@ -75,13 +72,6 @@ struct of_phandle_args {
 	uint32_t args[MAX_PHANDLE_ARGS];
 	uint32_t args[MAX_PHANDLE_ARGS];
 };
 };
 
 
-#if defined(CONFIG_EEH)
-static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
-{
-	return dn->edev;
-}
-#endif
-
 #ifdef CONFIG_OF_DYNAMIC
 #ifdef CONFIG_OF_DYNAMIC
 extern struct device_node *of_node_get(struct device_node *node);
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
 extern void of_node_put(struct device_node *node);