Commit 47b816ff authored by Linus Torvalds's avatar Linus Torvalds

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
parents 2e7580b0 1ce447b9
......@@ -27,7 +27,6 @@ zImage.bin.*
zImage.chrp
zImage.coff
zImage.holly
zImage.iseries
zImage.*lds
zImage.miboot
zImage.pmac
......
......@@ -112,7 +112,6 @@ extern void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
struct dma_attrs *attrs);
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_pasemi(void);
......
......@@ -27,12 +27,6 @@ extern atomic_t ppc_n_lost_interrupts;
/* This number is used when no interrupt has been assigned */
#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 */
#define NR_IRQS CONFIG_NR_IRQS
......
......@@ -99,9 +99,7 @@ struct machdep_calls {
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);
/* PCI stuff */
......
......@@ -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_lpar(void);
extern void hpte_init_iSeries(void);
extern void hpte_init_beat(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
* implementations in slb_allocate (slb_low.S), do_stab_bolted
* (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 */
......@@ -484,14 +480,6 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea,
| (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 /* _ASM_POWERPC_MMU_HASH64_H_ */
......@@ -155,14 +155,7 @@ struct pci_dn {
struct pci_dev *pcidev; /* back-pointer to the pci device */
#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
#define IODA_INVALID_PE (-1)
#ifdef CONFIG_PPC_POWERNV
......@@ -185,6 +178,13 @@ static inline int pci_device_from_OF_node(struct device_node *np,
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 */
extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
......
......@@ -47,6 +47,8 @@ struct power_pmu {
*/
#define PPMU_LIMITED_PMC5_6 1 /* PMC5/6 have limited function */
#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()
......
......@@ -74,7 +74,6 @@ struct rtas_suspend_me_data {
/* RTAS event classes */
#define RTAS_INTERNAL_ERROR 0x80000000 /* set bit 0 */
#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_IO_EVENTS 0x08000000 /* set bit 4 */
#define RTAS_EVENT_SCAN_ALL_EVENTS 0xffffffff
......@@ -204,6 +203,39 @@ struct rtas_ext_event_log_v6 {
/* 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
* as the absolutely last thing before the kernel terminates.
......
......@@ -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 irqreturn_t smp_ipi_demux(void);
void smp_init_iSeries(void);
void smp_init_pSeries(void);
void smp_init_cell(void);
void smp_init_celleb(void);
......
......@@ -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_maple_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_console(void);
extern void __init udbg_init_debug_beat(void);
......
......@@ -69,6 +69,7 @@ struct vio_dev {
};
struct vio_driver {
const char *name;
const struct vio_device_id *id_table;
int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
int (*remove)(struct vio_dev *dev);
......@@ -76,10 +77,17 @@ struct vio_driver {
* be loaded in a CMO environment if it uses DMA.
*/
unsigned long (*get_desired_dma)(struct vio_dev *dev);
const struct dev_pm_ops *pm;
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 int vio_cmo_entitlement_update(size_t);
......
......@@ -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
* 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.
*/
irq_happened = get_irq_happened();
......@@ -445,9 +445,9 @@ void do_IRQ(struct pt_regs *regs)
may_hard_irq_enable();
/* And finally process it */
if (irq != NO_IRQ && irq != NO_IRQ_IGNORE)
if (irq != NO_IRQ)
handle_one_irq(irq);
else if (irq != NO_IRQ_IGNORE)
else
__get_cpu_var(irq_stat).spurious_irqs++;
irq_exit();
......
......@@ -447,7 +447,7 @@ static void __init __attribute__((noreturn)) prom_panic(const char *reason)
if (RELOC(of_platform) == PLATFORM_POWERMAC)
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);
for (;;) /* should never get here */
......
......@@ -868,6 +868,40 @@ int rtas_ibm_suspend_me(struct rtas_args *args)
}
#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)
{
struct rtas_args args;
......
......@@ -46,9 +46,6 @@ void __init udbg_early_init(void)
#elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE)
/* Maple real mode debug */
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)
udbg_init_debug_beat();
#elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
......
......@@ -721,10 +721,10 @@ static int __init vdso_init(void)
vdso_data->version.minor = SYSTEMCFG_MINOR;
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
*/
vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100;
vdso_data->platform = 0x100;
if (firmware_has_feature(FW_FEATURE_LPAR))
vdso_data->platform |= 1;
vdso_data->physicalMemorySize = memblock_phys_mem_size();
......
......@@ -1159,17 +1159,21 @@ static int vio_bus_remove(struct device *dev)
* vio_register_driver: - Register a new vio driver
* @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 */
viodrv->driver.name = viodrv->name;
viodrv->driver.pm = viodrv->pm;
viodrv->driver.bus = &vio_bus_type;
viodrv->driver.owner = owner;
viodrv->driver.mod_name = mod_name;
return driver_register(&viodrv->driver);
}
EXPORT_SYMBOL(vio_register_driver);
EXPORT_SYMBOL(__vio_register_driver);
/**
* vio_unregister_driver - Remove registration of vio driver.
......
......@@ -116,14 +116,45 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
*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)
{
unsigned long mmcra = regs->dsisr;
unsigned long sihv = MMCRA_SIHV;
unsigned long sipr = MMCRA_SIPR;
/* Not a PMU interrupt: Make up flags from regs->msr */
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) {
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 ip;
unsigned long mmcra = regs->dsisr;
/* Not a PMU interrupt */
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)
......
......@@ -607,6 +607,7 @@ static struct power_pmu power4_pmu = {
.n_generic = ARRAY_SIZE(p4_generic_events),
.generic_events = p4_generic_events,
.cache_events = &power4_cache_events,
.flags = PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
};
static int __init init_power4_pmu(void)
......
......@@ -487,6 +487,7 @@ static struct power_pmu ppc970_pmu = {
.n_generic = ARRAY_SIZE(ppc970_generic_events),
.generic_events = ppc970_generic_events,
.cache_events = &ppc970_cache_events,
.flags = PPMU_NO_SIPR | PPMU_NO_CONT_SAMPLING,
};
static int __init init_ppc970_pmu(void)
......
......@@ -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;
......
......@@ -984,7 +984,8 @@ int __exit eeh_ops_unregister(const char *name)
*/
void __init eeh_init(void)
{
struct device_node *phb, *np;
struct pci_controller *hose, *tmp;
struct device_node *phb;
int ret;
/* call platform initialization function */
......@@ -1000,19 +1001,9 @@ void __init eeh_init(void)
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);
}
......
......@@ -62,7 +62,7 @@ void * __devinit eeh_dev_init(struct device_node *dn, void *data)
}
/* Associate EEH device with OF node */
dn->edev = edev;
PCI_DN(dn)->edev = edev;
edev->dn = dn;
edev->phb = phb;
......
......@@ -63,72 +63,8 @@ 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. "
......
......@@ -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) */
......
......@@ -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 <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/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);
......
......@@ -284,6 +284,7 @@ struct vio_dev {
};
struct vio_driver {
const char *name;
struct list_head node;
const struct vio_device_id *id_table;
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); \
} 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);
static inline struct vio_driver *to_vio_driver(struct device_driver *drv)
......
......@@ -1244,10 +1244,7 @@ static struct vio_driver ds_driver = {
.id_table = ds_match,
.probe = ds_probe,
.remove = ds_remove,
.driver = {
.name = "ds",
.owner = THIS_MODULE,
}
.name = "ds",
};
static int __init ds_init(void)
......
......@@ -119,13 +119,17 @@ static struct bus_type vio_bus_type = {
.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.name = viodrv->name;
viodrv->driver.owner = owner;
viodrv->driver.mod_name = mod_name;
return driver_register(&viodrv->driver);
}
EXPORT_SYMBOL(vio_register_driver);
EXPORT_SYMBOL(__vio_register_driver);
void vio_unregister_driver(struct vio_driver *viodrv)
{
......
......@@ -839,10 +839,7 @@ static struct vio_driver vdc_port_driver = {
.id_table = vdc_port_match,
.probe = vdc_port_probe,
.remove = vdc_port_remove,
.driver = {
.name = "vdc_port",
.owner = THIS_MODULE,
}
.name = "vdc_port",
};
static int __init vdc_init(void)
......
......@@ -1616,11 +1616,8 @@ static struct vio_driver ibmveth_driver = {
.probe = ibmveth_probe,
.remove = ibmveth_remove,
.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)
......
......@@ -1259,10 +1259,7 @@ static struct vio_driver vnet_port_driver = {
.id_table = vnet_port_match,
.probe = vnet_port_probe,
.remove = vnet_port_remove,
.driver = {
.name = "vnet_port",
.owner = THIS_MODULE,
}
.name = "vnet_port",
};
static int __init vnet_init(void)
......
......@@ -4890,11 +4890,8 @@ static struct vio_driver ibmvfc_driver = {
.probe = ibmvfc_probe,
.remove = ibmvfc_remove,
.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 = {
......
......@@ -2061,11 +2061,8 @@ static struct vio_driver ibmvscsi_driver = {
.probe = ibmvscsi_probe,
.remove = ibmvscsi_remove,
.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 = {
......
......@@ -918,10 +918,7 @@ static struct vio_driver ibmvstgt_driver = {
.id_table = ibmvstgt_device_table,
.probe = ibmvstgt_probe,
.remove = ibmvstgt_remove,
.driver = {
.name = "ibmvscsis",
.owner = THIS_MODULE,
}
.name = "ibmvscsis",
};
static int get_system_info(void)
......
......@@ -310,11 +310,8 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev)
static struct vio_driver hvc_vio_driver = {
.id_table = hvc_driver_table,
.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)
......
......@@ -879,10 +879,7 @@ static struct vio_driver hvcs_vio_driver = {
.id_table = hvcs_driver_table,
.probe = hvcs_probe,
.remove = __devexit_p(hvcs_remove),
.driver = {
.name = hvcs_driver_name,
.owner = THIS_MODULE,
}
.name = hvcs_driver_name,
};
/* Only called from hvcs_get_pi please */
......
......@@ -58,9 +58,6 @@ struct device_node {
struct kref kref;
unsigned long _flags;
void *data;
#if defined(CONFIG_EEH)
struct eeh_dev *edev;
#endif
#if defined(CONFIG_SPARC)
char *path_component_name;
unsigned int unique_id;
......@@ -75,13 +72,6 @@ struct of_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
extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment