aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/pseries
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c46
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c19
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c28
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c14
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h5
-rw-r--r--arch/powerpc/platforms/pseries/smp.c3
-rw-r--r--arch/powerpc/platforms/pseries/xics.c59
-rw-r--r--arch/powerpc/platforms/pseries/xics.h3
8 files changed, 79 insertions, 98 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index fb3d636e088..9eb539ee5f9 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -29,6 +29,8 @@
#include <linux/rbtree.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
+#include <linux/of.h>
+
#include <asm/atomic.h>
#include <asm/eeh.h>
#include <asm/eeh_event.h>
@@ -169,7 +171,6 @@ static void rtas_slot_error_detail(struct pci_dn *pdn, int severity,
*/
static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
{
- struct device_node *dn;
struct pci_dev *dev = pdn->pcidev;
u32 cfg;
int cap, i;
@@ -243,12 +244,12 @@ 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) {
- dn = pdn->node->child;
- while (dn) {
+ struct device_node *dn;
+
+ for_each_child_of_node(pdn->node, dn) {
pdn = PCI_DN(dn);
if (pdn)
n += gather_pci_data(pdn, buf+n, len-n);
- dn = dn->sibling;
}
}
@@ -372,7 +373,7 @@ struct device_node * find_device_pe(struct device_node *dn)
return dn;
}
-/** Mark all devices that are peers of this device as failed.
+/** 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,
@@ -380,9 +381,11 @@ struct device_node * find_device_pe(struct device_node *dn)
* an interrupt context, which is bad.
*/
-static void __eeh_mark_slot (struct device_node *dn, int mode_flag)
+static void __eeh_mark_slot(struct device_node *parent, int mode_flag)
{
- while (dn) {
+ struct device_node *dn;
+
+ for_each_child_of_node(parent, dn) {
if (PCI_DN(dn)) {
/* Mark the pci device driver too */
struct pci_dev *dev = PCI_DN(dn)->pcidev;
@@ -392,10 +395,8 @@ static void __eeh_mark_slot (struct device_node *dn, int mode_flag)
if (dev && dev->driver)
dev->error_state = pci_channel_io_frozen;
- if (dn->child)
- __eeh_mark_slot (dn->child, mode_flag);
+ __eeh_mark_slot(dn, mode_flag);
}
- dn = dn->sibling;
}
}
@@ -415,19 +416,19 @@ void eeh_mark_slot (struct device_node *dn, int mode_flag)
if (dev)
dev->error_state = pci_channel_io_frozen;
- __eeh_mark_slot (dn->child, mode_flag);
+ __eeh_mark_slot(dn, mode_flag);
}
-static void __eeh_clear_slot (struct device_node *dn, int mode_flag)
+static void __eeh_clear_slot(struct device_node *parent, int mode_flag)
{
- while (dn) {
+ 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 (dn->child)
- __eeh_clear_slot (dn->child, mode_flag);
+ __eeh_clear_slot(dn, mode_flag);
}
- dn = dn->sibling;
}
}
@@ -444,7 +445,7 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag)
PCI_DN(dn)->eeh_mode &= ~mode_flag;
PCI_DN(dn)->eeh_check_count = 0;
- __eeh_clear_slot (dn->child, mode_flag);
+ __eeh_clear_slot(dn, mode_flag);
spin_unlock_irqrestore(&confirm_error_lock, flags);
}
@@ -480,6 +481,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
no_dn++;
return 0;
}
+ dn = find_device_pe(dn);
pdn = PCI_DN(dn);
/* Access to IO BARs might get this far and still not want checking. */
@@ -545,7 +547,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
/* Note that config-io to empty slots may fail;
* they are empty when they don't have children. */
- if ((rets[0] == 5) && (dn->child == NULL)) {
+ if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) {
false_positives++;
pdn->eeh_false_positives ++;
rc = 0;
@@ -848,11 +850,8 @@ void eeh_restore_bars(struct pci_dn *pdn)
if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code))
__restore_bars (pdn);
- dn = pdn->node->child;
- while (dn) {
+ for_each_child_of_node(pdn->node, dn)
eeh_restore_bars (PCI_DN(dn));
- dn = dn->sibling;
- }
}
/**
@@ -1130,7 +1129,8 @@ static void eeh_add_device_early(struct device_node *dn)
void eeh_add_device_tree_early(struct device_node *dn)
{
struct device_node *sib;
- for (sib = dn->child; sib; sib = sib->sibling)
+
+ for_each_child_of_node(dn, sib)
eeh_add_device_tree_early(sib);
eeh_add_device_early(dn);
}
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 57e025e84ab..68ea5eee39a 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -310,8 +310,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
const char *location, *pci_str, *drv_str;
frozen_dn = find_device_pe(event->dn);
- frozen_bus = pcibios_find_pci_bus(frozen_dn);
-
if (!frozen_dn) {
location = of_get_property(event->dn, "ibm,loc-code", NULL);
@@ -321,6 +319,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
location, pci_name(event->dev));
return NULL;
}
+
+ frozen_bus = pcibios_find_pci_bus(frozen_dn);
location = of_get_property(frozen_dn, "ibm,loc-code", NULL);
location = location ? location : "unknown";
@@ -354,13 +354,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
goto excess_failures;
- /* Get the current PCI slot state. */
- rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
- if (rc < 0) {
- printk(KERN_WARNING "EEH: Permanent failure\n");
- goto hard_fail;
- }
-
printk(KERN_WARNING
"EEH: This PCI device has failed %d times in the last hour:\n",
frozen_pdn->eeh_freeze_count);
@@ -376,6 +369,14 @@ 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) {
+ printk(KERN_WARNING "EEH: Permanent failure\n");
+ goto hard_fail;
+ }
+
/* Since rtas may enable MMIO when posting the error log,
* don't post the error log until after all dev drivers
* have been informed.
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index be17d239507..a65c7630820 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -251,7 +251,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
const unsigned long *basep;
const u32 *sizep;
- node = (struct device_node *)phb->arch_data;
+ node = phb->dn;
basep = of_get_property(node, "linux,tce-base", NULL);
sizep = of_get_property(node, "linux,tce-size", NULL);
@@ -296,11 +296,12 @@ static void iommu_table_setparms(struct pci_controller *phb,
static void iommu_table_setparms_lpar(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl,
- const void *dma_window)
+ const void *dma_window,
+ int bussubno)
{
unsigned long offset, size;
- tbl->it_busno = PCI_DN(dn)->bussubno;
+ tbl->it_busno = bussubno;
of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size);
tbl->it_base = 0;
@@ -420,17 +421,10 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
pdn->full_name, ppci->iommu_table);
if (!ppci->iommu_table) {
- /* Bussubno hasn't been copied yet.
- * Do it now because iommu_table_setparms_lpar needs it.
- */
-
- ppci->bussubno = bus->number;
-
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
ppci->phb->node);
-
- iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
-
+ iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window,
+ bus->number);
ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
DBG(" created table: %p\n", ppci->iommu_table);
}
@@ -523,14 +517,10 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
pci = PCI_DN(pdn);
if (!pci->iommu_table) {
- /* iommu_table_setparms_lpar needs bussubno. */
- pci->bussubno = pci->phb->bus->number;
-
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
pci->phb->node);
-
- iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
-
+ iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window,
+ pci->phb->bus->number);
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
DBG(" created table: %p\n", pci->iommu_table);
} else {
@@ -556,7 +546,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
case PSERIES_RECONFIG_REMOVE:
if (pci && pci->iommu_table &&
of_get_property(np, "ibm,dma-window", NULL))
- iommu_free_table(np);
+ iommu_free_table(pci->iommu_table, np->full_name);
break;
default:
err = NOTIFY_DONE;
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 47f0e0857f0..5a5a19e40bb 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -83,7 +83,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
/* Must be called before pci_bus_add_devices */
void
-pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
+pcibios_fixup_new_pci_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
@@ -98,8 +98,6 @@ pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
/* Fill device archdata and setup iommu table */
pcibios_setup_new_device(dev);
- if(fix_bus)
- pcibios_fixup_device_resources(dev, bus);
pci_read_irq_line(dev);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r = &dev->resource[i];
@@ -132,8 +130,8 @@ pcibios_pci_config_bridge(struct pci_dev *dev)
pci_scan_child_bus(child_bus);
- /* Fixup new pci devices without touching bus struct */
- pcibios_fixup_new_pci_devices(child_bus, 0);
+ /* Fixup new pci devices */
+ pcibios_fixup_new_pci_devices(child_bus);
/* Make the discovered devices available */
pci_bus_add_devices(child_bus);
@@ -169,7 +167,7 @@ pcibios_add_pci_devices(struct pci_bus * bus)
/* use ofdt-based probe */
of_scan_bus(dn, bus);
if (!list_empty(&bus->devices)) {
- pcibios_fixup_new_pci_devices(bus, 0);
+ pcibios_fixup_new_pci_devices(bus);
pci_bus_add_devices(bus);
eeh_add_device_tree_late(bus);
}
@@ -178,7 +176,7 @@ pcibios_add_pci_devices(struct pci_bus * bus)
slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
if (num) {
- pcibios_fixup_new_pci_devices(bus, 1);
+ pcibios_fixup_new_pci_devices(bus);
pci_bus_add_devices(bus);
eeh_add_device_tree_late(bus);
}
@@ -208,7 +206,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
eeh_add_device_tree_early(dn);
scan_phb(phb);
- pcibios_fixup_new_pci_devices(phb->bus, 0);
+ pcibios_fixup_new_pci_devices(phb->bus);
pci_bus_add_devices(phb->bus);
eeh_add_device_tree_late(phb->bus);
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index d003c80fa31..d8680b589dc 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -8,11 +8,6 @@ static inline long poll_pending(void)
return plpar_hcall_norets(H_POLL_PENDING);
}
-static inline long prod_processor(void)
-{
- return plpar_hcall_norets(H_PROD);
-}
-
static inline long cede_processor(void)
{
return plpar_hcall_norets(H_CEDE);
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 116305b22a2..ea4c65917a6 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -46,6 +46,7 @@
#include <asm/pSeries_reconfig.h>
#include <asm/mpic.h>
#include <asm/vdso_datapage.h>
+#include <asm/cputhreads.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -202,7 +203,7 @@ static int smp_pSeries_cpu_bootable(unsigned int nr)
*/
if (system_state < SYSTEM_RUNNING &&
cpu_has_feature(CPU_FTR_SMT) &&
- !smt_enabled_at_boot && nr % 2 != 0)
+ !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
return 1;
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 66e7d68ffeb..8f8dd9c3ca6 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -87,19 +87,25 @@ static int ibm_int_off;
/* Direct HW low level accessors */
-static inline unsigned int direct_xirr_info_get(int n_cpu)
+static inline unsigned int direct_xirr_info_get(void)
{
- return in_be32(&xics_per_cpu[n_cpu]->xirr.word);
+ int cpu = smp_processor_id();
+
+ return in_be32(&xics_per_cpu[cpu]->xirr.word);
}
-static inline void direct_xirr_info_set(int n_cpu, int value)
+static inline void direct_xirr_info_set(int value)
{
- out_be32(&xics_per_cpu[n_cpu]->xirr.word, value);
+ int cpu = smp_processor_id();
+
+ out_be32(&xics_per_cpu[cpu]->xirr.word, value);
}
-static inline void direct_cppr_info(int n_cpu, u8 value)
+static inline void direct_cppr_info(u8 value)
{
- out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value);
+ int cpu = smp_processor_id();
+
+ out_8(&xics_per_cpu[cpu]->xirr.bytes[0], value);
}
static inline void direct_qirr_info(int n_cpu, u8 value)
@@ -111,7 +117,7 @@ static inline void direct_qirr_info(int n_cpu, u8 value)
/* LPAR low level accessors */
-static inline unsigned int lpar_xirr_info_get(int n_cpu)
+static inline unsigned int lpar_xirr_info_get(void)
{
unsigned long lpar_rc;
unsigned long return_value;
@@ -122,7 +128,7 @@ static inline unsigned int lpar_xirr_info_get(int n_cpu)
return (unsigned int)return_value;
}
-static inline void lpar_xirr_info_set(int n_cpu, int value)
+static inline void lpar_xirr_info_set(int value)
{
unsigned long lpar_rc;
unsigned long val64 = value & 0xffffffff;
@@ -133,7 +139,7 @@ static inline void lpar_xirr_info_set(int n_cpu, int value)
val64);
}
-static inline void lpar_cppr_info(int n_cpu, u8 value)
+static inline void lpar_cppr_info(u8 value)
{
unsigned long lpar_rc;
@@ -275,21 +281,19 @@ static unsigned int xics_startup(unsigned int virq)
static void xics_eoi_direct(unsigned int virq)
{
- int cpu = smp_processor_id();
unsigned int irq = (unsigned int)irq_map[virq].hwirq;
iosync();
- direct_xirr_info_set(cpu, (0xff << 24) | irq);
+ direct_xirr_info_set((0xff << 24) | irq);
}
static void xics_eoi_lpar(unsigned int virq)
{
- int cpu = smp_processor_id();
unsigned int irq = (unsigned int)irq_map[virq].hwirq;
iosync();
- lpar_xirr_info_set(cpu, (0xff << 24) | irq);
+ lpar_xirr_info_set((0xff << 24) | irq);
}
static inline unsigned int xics_remap_irq(unsigned int vec)
@@ -312,16 +316,12 @@ static inline unsigned int xics_remap_irq(unsigned int vec)
static unsigned int xics_get_irq_direct(void)
{
- unsigned int cpu = smp_processor_id();
-
- return xics_remap_irq(direct_xirr_info_get(cpu));
+ return xics_remap_irq(direct_xirr_info_get());
}
static unsigned int xics_get_irq_lpar(void)
{
- unsigned int cpu = smp_processor_id();
-
- return xics_remap_irq(lpar_xirr_info_get(cpu));
+ return xics_remap_irq(lpar_xirr_info_get());
}
#ifdef CONFIG_SMP
@@ -387,12 +387,12 @@ void xics_cause_IPI(int cpu)
#endif /* CONFIG_SMP */
-static void xics_set_cpu_priority(int cpu, unsigned char cppr)
+static void xics_set_cpu_priority(unsigned char cppr)
{
if (firmware_has_feature(FW_FEATURE_LPAR))
- lpar_cppr_info(cpu, cppr);
+ lpar_cppr_info(cppr);
else
- direct_cppr_info(cpu, cppr);
+ direct_cppr_info(cppr);
iosync();
}
@@ -440,9 +440,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
void xics_setup_cpu(void)
{
- int cpu = smp_processor_id();
-
- xics_set_cpu_priority(cpu, 0xff);
+ xics_set_cpu_priority(0xff);
/*
* Put the calling processor into the GIQ. This is really only
@@ -783,7 +781,7 @@ void xics_teardown_cpu(int secondary)
unsigned int ipi;
struct irq_desc *desc;
- xics_set_cpu_priority(cpu, 0);
+ xics_set_cpu_priority(0);
/*
* Clear IPI
@@ -824,10 +822,11 @@ void xics_teardown_cpu(int secondary)
void xics_migrate_irqs_away(void)
{
int status;
- unsigned int irq, virq, cpu = smp_processor_id();
+ int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id();
+ unsigned int irq, virq;
/* Reject any interrupt that was queued to us... */
- xics_set_cpu_priority(cpu, 0);
+ xics_set_cpu_priority(0);
/* remove ourselves from the global interrupt queue */
status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
@@ -835,7 +834,7 @@ void xics_migrate_irqs_away(void)
WARN_ON(status < 0);
/* Allow IPIs again... */
- xics_set_cpu_priority(cpu, DEFAULT_PRIORITY);
+ xics_set_cpu_priority(DEFAULT_PRIORITY);
for_each_irq(virq) {
struct irq_desc *desc;
@@ -874,7 +873,7 @@ void xics_migrate_irqs_away(void)
* The irq has to be migrated only in the single cpu
* case.
*/
- if (xics_status[0] != get_hard_smp_processor_id(cpu))
+ if (xics_status[0] != hw_cpu)
goto unlock;
printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n",
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h
index db0ec3ba3ae..9ffd809d29e 100644
--- a/arch/powerpc/platforms/pseries/xics.h
+++ b/arch/powerpc/platforms/pseries/xics.h
@@ -21,9 +21,6 @@ extern void xics_cause_IPI(int cpu);
extern void xics_request_IPIs(void);
extern void xics_migrate_irqs_away(void);
-/* first argument is ignored for now*/
-void pSeriesLP_cppr_info(int n_cpu, u8 value);
-
struct xics_ipi_struct {
volatile unsigned long value;
} ____cacheline_aligned;