summaryrefslogtreecommitdiffstats
path: root/kernel/arch/powerpc/platforms/pseries
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/arch/powerpc/platforms/pseries
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/arch/powerpc/platforms/pseries')
-rw-r--r--kernel/arch/powerpc/platforms/pseries/Kconfig7
-rw-r--r--kernel/arch/powerpc/platforms/pseries/Makefile7
-rw-r--r--kernel/arch/powerpc/platforms/pseries/dlpar.c38
-rw-r--r--kernel/arch/powerpc/platforms/pseries/eeh_pseries.c62
-rw-r--r--kernel/arch/powerpc/platforms/pseries/hotplug-memory.c3
-rw-r--r--kernel/arch/powerpc/platforms/pseries/hvcserver.c2
-rw-r--r--kernel/arch/powerpc/platforms/pseries/iommu.c192
-rw-r--r--kernel/arch/powerpc/platforms/pseries/msi.c22
-rw-r--r--kernel/arch/powerpc/platforms/pseries/of_helpers.c38
-rw-r--r--kernel/arch/powerpc/platforms/pseries/of_helpers.h8
-rw-r--r--kernel/arch/powerpc/platforms/pseries/reconfig.c34
-rw-r--r--kernel/arch/powerpc/platforms/pseries/rng.c2
-rw-r--r--kernel/arch/powerpc/platforms/pseries/setup.c44
13 files changed, 253 insertions, 206 deletions
diff --git a/kernel/arch/powerpc/platforms/pseries/Kconfig b/kernel/arch/powerpc/platforms/pseries/Kconfig
index 54c87d5d3..bec90fb30 100644
--- a/kernel/arch/powerpc/platforms/pseries/Kconfig
+++ b/kernel/arch/powerpc/platforms/pseries/Kconfig
@@ -4,6 +4,7 @@ config PPC_PSERIES
select HAVE_PCSPKR_PLATFORM
select MPIC
select OF_DYNAMIC
+ select PCI
select PCI_MSI
select PPC_XICS
select PPC_ICP_NATIVE
@@ -15,7 +16,6 @@ config PPC_PSERIES
select RTAS_ERROR_LOGGING
select PPC_UDBG_16550
select PPC_NATIVE
- select PPC_PCI_CHOICE if EXPERT
select PPC_DOORBELL
select HAVE_CONTEXT_TRACKING
select HOTPLUG_CPU if SMP
@@ -43,11 +43,6 @@ config DTL
Say N if you are unsure.
-config PSERIES_MSI
- bool
- depends on PCI_MSI && PPC_PSERIES && EEH
- default y
-
config PSERIES_ENERGY
tristate "pSeries energy management capabilities driver"
depends on PPC_PSERIES
diff --git a/kernel/arch/powerpc/platforms/pseries/Makefile b/kernel/arch/powerpc/platforms/pseries/Makefile
index 03480796a..fedc2ccf0 100644
--- a/kernel/arch/powerpc/platforms/pseries/Makefile
+++ b/kernel/arch/powerpc/platforms/pseries/Makefile
@@ -2,14 +2,13 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG
obj-y := lpar.o hvCall.o nvram.o reconfig.o \
+ of_helpers.o \
setup.o iommu.o event_sources.o ras.o \
- firmware.o power.o dlpar.o mobility.o rng.o
+ firmware.o power.o dlpar.o mobility.o rng.o \
+ pci.o pci_dlpar.o eeh_pseries.o msi.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SCANLOG) += scanlog.o
-obj-$(CONFIG_EEH) += eeh_pseries.o
obj-$(CONFIG_KEXEC) += kexec.o
-obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
-obj-$(CONFIG_PSERIES_MSI) += msi.o
obj-$(CONFIG_PSERIES_ENERGY) += pseries_energy.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
diff --git a/kernel/arch/powerpc/platforms/pseries/dlpar.c b/kernel/arch/powerpc/platforms/pseries/dlpar.c
index 019d34aaf..f244dcb4f 100644
--- a/kernel/arch/powerpc/platforms/pseries/dlpar.c
+++ b/kernel/arch/powerpc/platforms/pseries/dlpar.c
@@ -18,6 +18,8 @@
#include <linux/cpu.h>
#include <linux/slab.h>
#include <linux/of.h>
+
+#include "of_helpers.h"
#include "offline_states.h"
#include "pseries.h"
@@ -244,36 +246,13 @@ cc_error:
return first_dn;
}
-static struct device_node *derive_parent(const char *path)
-{
- struct device_node *parent;
- char *last_slash;
-
- last_slash = strrchr(path, '/');
- if (last_slash == path) {
- parent = of_find_node_by_path("/");
- } else {
- char *parent_path;
- int parent_path_len = last_slash - path + 1;
- parent_path = kmalloc(parent_path_len, GFP_KERNEL);
- if (!parent_path)
- return NULL;
-
- strlcpy(parent_path, path, parent_path_len);
- parent = of_find_node_by_path(parent_path);
- kfree(parent_path);
- }
-
- return parent;
-}
-
int dlpar_attach_node(struct device_node *dn)
{
int rc;
- dn->parent = derive_parent(dn->full_name);
- if (!dn->parent)
- return -ENOMEM;
+ dn->parent = pseries_of_derive_parent(dn->full_name);
+ if (IS_ERR(dn->parent))
+ return PTR_ERR(dn->parent);
rc = of_attach_node(dn);
if (rc) {
@@ -421,10 +400,11 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
return -ENODEV;
dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
- if (!dn)
- return -EINVAL;
-
of_node_put(parent);
+ if (!dn) {
+ dlpar_release_drc(drc_index);
+ return -EINVAL;
+ }
rc = dlpar_attach_node(dn);
if (rc) {
diff --git a/kernel/arch/powerpc/platforms/pseries/eeh_pseries.c b/kernel/arch/powerpc/platforms/pseries/eeh_pseries.c
index 2039397cc..ac3ffd97e 100644
--- a/kernel/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/kernel/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -433,42 +433,34 @@ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state)
return ret;
/* Parse the result out */
- result = 0;
- if (rets[1]) {
- switch(rets[0]) {
- case 0:
- result &= ~EEH_STATE_RESET_ACTIVE;
- result |= EEH_STATE_MMIO_ACTIVE;
- result |= EEH_STATE_DMA_ACTIVE;
- break;
- case 1:
- result |= EEH_STATE_RESET_ACTIVE;
- result |= EEH_STATE_MMIO_ACTIVE;
- result |= EEH_STATE_DMA_ACTIVE;
- break;
- case 2:
- result &= ~EEH_STATE_RESET_ACTIVE;
- result &= ~EEH_STATE_MMIO_ACTIVE;
- result &= ~EEH_STATE_DMA_ACTIVE;
- break;
- case 4:
- result &= ~EEH_STATE_RESET_ACTIVE;
- result &= ~EEH_STATE_MMIO_ACTIVE;
- result &= ~EEH_STATE_DMA_ACTIVE;
- result |= EEH_STATE_MMIO_ENABLED;
- break;
- case 5:
- if (rets[2]) {
- if (state) *state = rets[2];
- result = EEH_STATE_UNAVAILABLE;
- } else {
- result = EEH_STATE_NOT_SUPPORT;
- }
- break;
- default:
+ if (!rets[1])
+ return EEH_STATE_NOT_SUPPORT;
+
+ switch(rets[0]) {
+ case 0:
+ result = EEH_STATE_MMIO_ACTIVE |
+ EEH_STATE_DMA_ACTIVE;
+ break;
+ case 1:
+ result = EEH_STATE_RESET_ACTIVE |
+ EEH_STATE_MMIO_ACTIVE |
+ EEH_STATE_DMA_ACTIVE;
+ break;
+ case 2:
+ result = 0;
+ break;
+ case 4:
+ result = EEH_STATE_MMIO_ENABLED;
+ break;
+ case 5:
+ if (rets[2]) {
+ if (state) *state = rets[2];
+ result = EEH_STATE_UNAVAILABLE;
+ } else {
result = EEH_STATE_NOT_SUPPORT;
}
- } else {
+ break;
+ default:
result = EEH_STATE_NOT_SUPPORT;
}
@@ -519,7 +511,7 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option)
/**
* pseries_eeh_wait_state - Wait for PE state
* @pe: EEH PE
- * @max_wait: maximal period in microsecond
+ * @max_wait: maximal period in millisecond
*
* Wait for the state of associated PE. It might take some time
* to retrieve the PE's state.
diff --git a/kernel/arch/powerpc/platforms/pseries/hotplug-memory.c b/kernel/arch/powerpc/platforms/pseries/hotplug-memory.c
index 0ced387e1..e9ff44cd5 100644
--- a/kernel/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/kernel/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -92,13 +92,12 @@ static struct property *dlpar_clone_drconf_property(struct device_node *dn)
return NULL;
new_prop->name = kstrdup(prop->name, GFP_KERNEL);
- new_prop->value = kmalloc(prop->length, GFP_KERNEL);
+ new_prop->value = kmemdup(prop->value, prop->length, GFP_KERNEL);
if (!new_prop->name || !new_prop->value) {
dlpar_free_drconf_property(new_prop);
return NULL;
}
- memcpy(new_prop->value, prop->value, prop->length);
new_prop->length = prop->length;
/* Convert the property to cpu endian-ness */
diff --git a/kernel/arch/powerpc/platforms/pseries/hvcserver.c b/kernel/arch/powerpc/platforms/pseries/hvcserver.c
index eedb64594..94a6e5612 100644
--- a/kernel/arch/powerpc/platforms/pseries/hvcserver.c
+++ b/kernel/arch/powerpc/platforms/pseries/hvcserver.c
@@ -142,11 +142,11 @@ int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head,
int more = 1;
int retval;
- memset(pi_buff, 0x00, PAGE_SIZE);
/* invalid parameters */
if (!head || !pi_buff)
return -EINVAL;
+ memset(pi_buff, 0x00, PAGE_SIZE);
last_p_partition_ID = last_p_unit_address = ~0UL;
INIT_LIST_HEAD(head);
diff --git a/kernel/arch/powerpc/platforms/pseries/iommu.c b/kernel/arch/powerpc/platforms/pseries/iommu.c
index 61d5a17f4..bd98ce2be 100644
--- a/kernel/arch/powerpc/platforms/pseries/iommu.c
+++ b/kernel/arch/powerpc/platforms/pseries/iommu.c
@@ -36,6 +36,8 @@
#include <linux/crash_dump.h>
#include <linux/memory.h>
#include <linux/of.h>
+#include <linux/iommu.h>
+#include <linux/rculist.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -51,6 +53,73 @@
#include "pseries.h"
+static struct iommu_table_group *iommu_pseries_alloc_group(int node)
+{
+ struct iommu_table_group *table_group = NULL;
+ struct iommu_table *tbl = NULL;
+ struct iommu_table_group_link *tgl = NULL;
+
+ table_group = kzalloc_node(sizeof(struct iommu_table_group), GFP_KERNEL,
+ node);
+ if (!table_group)
+ goto fail_exit;
+
+ tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, node);
+ if (!tbl)
+ goto fail_exit;
+
+ tgl = kzalloc_node(sizeof(struct iommu_table_group_link), GFP_KERNEL,
+ node);
+ if (!tgl)
+ goto fail_exit;
+
+ INIT_LIST_HEAD_RCU(&tbl->it_group_list);
+ tgl->table_group = table_group;
+ list_add_rcu(&tgl->next, &tbl->it_group_list);
+
+ table_group->tables[0] = tbl;
+
+ return table_group;
+
+fail_exit:
+ kfree(tgl);
+ kfree(table_group);
+ kfree(tbl);
+
+ return NULL;
+}
+
+static void iommu_pseries_free_group(struct iommu_table_group *table_group,
+ const char *node_name)
+{
+ struct iommu_table *tbl;
+#ifdef CONFIG_IOMMU_API
+ struct iommu_table_group_link *tgl;
+#endif
+
+ if (!table_group)
+ return;
+
+ tbl = table_group->tables[0];
+#ifdef CONFIG_IOMMU_API
+ tgl = list_first_entry_or_null(&tbl->it_group_list,
+ struct iommu_table_group_link, next);
+
+ WARN_ON_ONCE(!tgl);
+ if (tgl) {
+ list_del_rcu(&tgl->next);
+ kfree(tgl);
+ }
+ if (table_group->group) {
+ iommu_group_put(table_group->group);
+ BUG_ON(table_group->group);
+ }
+#endif
+ iommu_free_table(tbl, node_name);
+
+ kfree(table_group);
+}
+
static void tce_invalidate_pSeries_sw(struct iommu_table *tbl,
__be64 *startp, __be64 *endp)
{
@@ -193,7 +262,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
int ret = 0;
unsigned long flags;
- if (npages == 1) {
+ if ((npages == 1) || !firmware_has_feature(FW_FEATURE_MULTITCE)) {
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
direction, attrs);
}
@@ -285,6 +354,9 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
{
u64 rc;
+ if (!firmware_has_feature(FW_FEATURE_MULTITCE))
+ return tce_free_pSeriesLP(tbl, tcenum, npages);
+
rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
if (rc && printk_ratelimit()) {
@@ -460,8 +532,6 @@ static int tce_setrange_multi_pSeriesLP_walk(unsigned long start_pfn,
return tce_setrange_multi_pSeriesLP(start_pfn, num_pfn, arg);
}
-
-#ifdef CONFIG_PCI
static void iommu_table_setparms(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl)
@@ -546,6 +616,12 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
tbl->it_size = size >> tbl->it_page_shift;
}
+struct iommu_table_ops iommu_table_pseries_ops = {
+ .set = tce_build_pSeries,
+ .clear = tce_free_pSeries,
+ .get = tce_get_pseries
+};
+
static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
{
struct device_node *dn;
@@ -610,12 +686,13 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
pci->phb->dma_window_size = 0x8000000ul;
pci->phb->dma_window_base_cur = 0x8000000ul;
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- pci->phb->node);
+ pci->table_group = iommu_pseries_alloc_group(pci->phb->node);
+ tbl = pci->table_group->tables[0];
iommu_table_setparms(pci->phb, dn, tbl);
- pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
- iommu_register_group(tbl, pci_domain_nr(bus), 0);
+ tbl->it_ops = &iommu_table_pseries_ops;
+ iommu_init_table(tbl, pci->phb->node);
+ iommu_register_group(pci->table_group, pci_domain_nr(bus), 0);
/* Divide the rest (1.75GB) among the children */
pci->phb->dma_window_size = 0x80000000ul;
@@ -625,6 +702,11 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
pr_debug("ISA/IDE, window size is 0x%llx\n", pci->phb->dma_window_size);
}
+struct iommu_table_ops iommu_table_lpar_multi_ops = {
+ .set = tce_buildmulti_pSeriesLP,
+ .clear = tce_freemulti_pSeriesLP,
+ .get = tce_get_pSeriesLP
+};
static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
{
@@ -653,15 +735,17 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
ppci = PCI_DN(pdn);
pr_debug(" parent is %s, iommu_table: 0x%p\n",
- pdn->full_name, ppci->iommu_table);
+ pdn->full_name, ppci->table_group);
- if (!ppci->iommu_table) {
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- ppci->phb->node);
+ if (!ppci->table_group) {
+ ppci->table_group = iommu_pseries_alloc_group(ppci->phb->node);
+ tbl = ppci->table_group->tables[0];
iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
- ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
- iommu_register_group(tbl, pci_domain_nr(bus), 0);
- pr_debug(" created table: %p\n", ppci->iommu_table);
+ tbl->it_ops = &iommu_table_lpar_multi_ops;
+ iommu_init_table(tbl, ppci->phb->node);
+ iommu_register_group(ppci->table_group,
+ pci_domain_nr(bus), 0);
+ pr_debug(" created table: %p\n", ppci->table_group);
}
}
@@ -683,13 +767,15 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
struct pci_controller *phb = PCI_DN(dn)->phb;
pr_debug(" --> first child, no bridge. Allocating iommu table.\n");
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- phb->node);
+ PCI_DN(dn)->table_group = iommu_pseries_alloc_group(phb->node);
+ tbl = PCI_DN(dn)->table_group->tables[0];
iommu_table_setparms(phb, dn, tbl);
- PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node);
- iommu_register_group(tbl, pci_domain_nr(phb->bus), 0);
- set_iommu_table_base_and_group(&dev->dev,
- PCI_DN(dn)->iommu_table);
+ tbl->it_ops = &iommu_table_pseries_ops;
+ iommu_init_table(tbl, phb->node);
+ iommu_register_group(PCI_DN(dn)->table_group,
+ pci_domain_nr(phb->bus), 0);
+ set_iommu_table_base(&dev->dev, tbl);
+ iommu_add_device(&dev->dev);
return;
}
@@ -697,13 +783,14 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
* an already allocated iommu table is found and use that.
*/
- while (dn && PCI_DN(dn) && PCI_DN(dn)->iommu_table == NULL)
+ while (dn && PCI_DN(dn) && PCI_DN(dn)->table_group == NULL)
dn = dn->parent;
- if (dn && PCI_DN(dn))
- set_iommu_table_base_and_group(&dev->dev,
- PCI_DN(dn)->iommu_table);
- else
+ if (dn && PCI_DN(dn)) {
+ set_iommu_table_base(&dev->dev,
+ PCI_DN(dn)->table_group->tables[0]);
+ iommu_add_device(&dev->dev);
+ } else
printk(KERN_WARNING "iommu: Device %s has no iommu table\n",
pci_name(dev));
}
@@ -1088,7 +1175,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
dn = pci_device_to_OF_node(dev);
pr_debug(" node is %s\n", dn->full_name);
- for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->table_group;
pdn = pdn->parent) {
dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
if (dma_window)
@@ -1104,18 +1191,21 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
pr_debug(" parent is %s\n", pdn->full_name);
pci = PCI_DN(pdn);
- if (!pci->iommu_table) {
- tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
- pci->phb->node);
+ if (!pci->table_group) {
+ pci->table_group = iommu_pseries_alloc_group(pci->phb->node);
+ tbl = pci->table_group->tables[0];
iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
- pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
- iommu_register_group(tbl, pci_domain_nr(pci->phb->bus), 0);
- pr_debug(" created table: %p\n", pci->iommu_table);
+ tbl->it_ops = &iommu_table_lpar_multi_ops;
+ iommu_init_table(tbl, pci->phb->node);
+ iommu_register_group(pci->table_group,
+ pci_domain_nr(pci->phb->bus), 0);
+ pr_debug(" created table: %p\n", pci->table_group);
} else {
- pr_debug(" found DMA window, table: %p\n", pci->iommu_table);
+ pr_debug(" found DMA window, table: %p\n", pci->table_group);
}
- set_iommu_table_base_and_group(&dev->dev, pci->iommu_table);
+ set_iommu_table_base(&dev->dev, pci->table_group->tables[0]);
+ iommu_add_device(&dev->dev);
}
static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
@@ -1145,7 +1235,7 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
* search upwards in the tree until we either hit a dma-window
* property, OR find a parent with a table already allocated.
*/
- for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->table_group;
pdn = pdn->parent) {
dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
if (dma_window)
@@ -1162,11 +1252,10 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
}
}
- /* fall back on iommu ops, restore table pointer with ops */
+ /* fall back on iommu ops */
if (!ddw_enabled && get_dma_ops(dev) != &dma_iommu_ops) {
dev_info(dev, "Restoring 32-bit DMA via iommu\n");
set_dma_ops(dev, &dma_iommu_ops);
- pci_dma_dev_setup_pSeriesLP(pdev);
}
check_mask:
@@ -1189,7 +1278,7 @@ static u64 dma_get_required_mask_pSeriesLP(struct device *dev)
dn = pci_device_to_OF_node(pdev);
/* search upwards for ibm,dma-window */
- for (; dn && PCI_DN(dn) && !PCI_DN(dn)->iommu_table;
+ for (; dn && PCI_DN(dn) && !PCI_DN(dn)->table_group;
dn = dn->parent)
if (of_get_property(dn, "ibm,dma-window", NULL))
break;
@@ -1202,15 +1291,6 @@ static u64 dma_get_required_mask_pSeriesLP(struct device *dev)
return dma_iommu_ops.get_required_mask(dev);
}
-#else /* CONFIG_PCI */
-#define pci_dma_bus_setup_pSeries NULL
-#define pci_dma_dev_setup_pSeries NULL
-#define pci_dma_bus_setup_pSeriesLP NULL
-#define pci_dma_dev_setup_pSeriesLP NULL
-#define dma_set_mask_pSeriesLP NULL
-#define dma_get_required_mask_pSeriesLP NULL
-#endif /* !CONFIG_PCI */
-
static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action,
void *data)
{
@@ -1269,8 +1349,9 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
* the device node.
*/
remove_ddw(np, false);
- if (pci && pci->iommu_table)
- iommu_free_table(pci->iommu_table, np->full_name);
+ if (pci && pci->table_group)
+ iommu_pseries_free_group(pci->table_group,
+ np->full_name);
spin_lock(&direct_window_list_lock);
list_for_each_entry(window, &direct_window_list, list) {
@@ -1300,22 +1381,11 @@ void iommu_init_early_pSeries(void)
return;
if (firmware_has_feature(FW_FEATURE_LPAR)) {
- if (firmware_has_feature(FW_FEATURE_MULTITCE)) {
- ppc_md.tce_build = tce_buildmulti_pSeriesLP;
- ppc_md.tce_free = tce_freemulti_pSeriesLP;
- } else {
- ppc_md.tce_build = tce_build_pSeriesLP;
- ppc_md.tce_free = tce_free_pSeriesLP;
- }
- ppc_md.tce_get = tce_get_pSeriesLP;
pseries_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pSeriesLP;
pseries_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pSeriesLP;
ppc_md.dma_set_mask = dma_set_mask_pSeriesLP;
ppc_md.dma_get_required_mask = dma_get_required_mask_pSeriesLP;
} else {
- ppc_md.tce_build = tce_build_pSeries;
- ppc_md.tce_free = tce_free_pSeries;
- ppc_md.tce_get = tce_get_pseries;
pseries_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pSeries;
pseries_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pSeries;
}
@@ -1333,8 +1403,6 @@ static int __init disable_multitce(char *str)
firmware_has_feature(FW_FEATURE_LPAR) &&
firmware_has_feature(FW_FEATURE_MULTITCE)) {
printk(KERN_INFO "Disabling MULTITCE firmware feature\n");
- ppc_md.tce_build = tce_build_pSeriesLP;
- ppc_md.tce_free = tce_free_pSeriesLP;
powerpc_firmware_features &= ~FW_FEATURE_MULTITCE;
}
return 1;
diff --git a/kernel/arch/powerpc/platforms/pseries/msi.c b/kernel/arch/powerpc/platforms/pseries/msi.c
index c8d24f9a6..272e9ec1a 100644
--- a/kernel/arch/powerpc/platforms/pseries/msi.c
+++ b/kernel/arch/powerpc/platforms/pseries/msi.c
@@ -18,6 +18,8 @@
#include <asm/ppc-pci.h>
#include <asm/machdep.h>
+#include "pseries.h"
+
static int query_token, change_token;
#define RTAS_QUERY_FN 0
@@ -116,7 +118,7 @@ static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
- list_for_each_entry(entry, &pdev->msi_list, list) {
+ for_each_pci_msi_entry(entry, pdev) {
if (entry->irq == NO_IRQ)
continue;
@@ -348,7 +350,7 @@ static int check_msix_entries(struct pci_dev *pdev)
* So we must reject such requests. */
expected = 0;
- list_for_each_entry(entry, &pdev->msi_list, list) {
+ for_each_pci_msi_entry(entry, pdev) {
if (entry->msi_attrib.entry_nr != expected) {
pr_debug("rtas_msi: bad MSI-X entries.\n");
return -EINVAL;
@@ -460,7 +462,7 @@ again:
}
i = 0;
- list_for_each_entry(entry, &pdev->msi_list, list) {
+ for_each_pci_msi_entry(entry, pdev) {
hwirq = rtas_query_irq_number(pdn, i++);
if (hwirq < 0) {
pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);
@@ -505,6 +507,8 @@ static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
static int rtas_msi_init(void)
{
+ struct pci_controller *phb;
+
query_token = rtas_token("ibm,query-interrupt-source-number");
change_token = rtas_token("ibm,change-msi");
@@ -516,9 +520,15 @@ static int rtas_msi_init(void)
pr_debug("rtas_msi: Registering RTAS MSI callbacks.\n");
- WARN_ON(ppc_md.setup_msi_irqs);
- ppc_md.setup_msi_irqs = rtas_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs;
+ WARN_ON(pseries_pci_controller_ops.setup_msi_irqs);
+ pseries_pci_controller_ops.setup_msi_irqs = rtas_setup_msi_irqs;
+ pseries_pci_controller_ops.teardown_msi_irqs = rtas_teardown_msi_irqs;
+
+ list_for_each_entry(phb, &hose_list, list_node) {
+ WARN_ON(phb->controller_ops.setup_msi_irqs);
+ phb->controller_ops.setup_msi_irqs = rtas_setup_msi_irqs;
+ phb->controller_ops.teardown_msi_irqs = rtas_teardown_msi_irqs;
+ }
WARN_ON(ppc_md.pci_irq_fixup);
ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup;
diff --git a/kernel/arch/powerpc/platforms/pseries/of_helpers.c b/kernel/arch/powerpc/platforms/pseries/of_helpers.c
new file mode 100644
index 000000000..2798933c0
--- /dev/null
+++ b/kernel/arch/powerpc/platforms/pseries/of_helpers.c
@@ -0,0 +1,38 @@
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "of_helpers.h"
+
+/**
+ * pseries_of_derive_parent - basically like dirname(1)
+ * @path: the full_name of a node to be added to the tree
+ *
+ * Returns the node which should be the parent of the node
+ * described by path. E.g., for path = "/foo/bar", returns
+ * the node with full_name = "/foo".
+ */
+struct device_node *pseries_of_derive_parent(const char *path)
+{
+ struct device_node *parent;
+ char *parent_path = "/";
+ const char *tail;
+
+ /* We do not want the trailing '/' character */
+ tail = kbasename(path) - 1;
+
+ /* reject if path is "/" */
+ if (!strcmp(path, "/"))
+ return ERR_PTR(-EINVAL);
+
+ if (tail > path) {
+ parent_path = kstrndup(path, tail - path, GFP_KERNEL);
+ if (!parent_path)
+ return ERR_PTR(-ENOMEM);
+ }
+ parent = of_find_node_by_path(parent_path);
+ if (strcmp(parent_path, "/"))
+ kfree(parent_path);
+ return parent ? parent : ERR_PTR(-EINVAL);
+}
diff --git a/kernel/arch/powerpc/platforms/pseries/of_helpers.h b/kernel/arch/powerpc/platforms/pseries/of_helpers.h
new file mode 100644
index 000000000..bb83d39ae
--- /dev/null
+++ b/kernel/arch/powerpc/platforms/pseries/of_helpers.h
@@ -0,0 +1,8 @@
+#ifndef _PSERIES_OF_HELPERS_H
+#define _PSERIES_OF_HELPERS_H
+
+#include <linux/of.h>
+
+struct device_node *pseries_of_derive_parent(const char *path);
+
+#endif /* _PSERIES_OF_HELPERS_H */
diff --git a/kernel/arch/powerpc/platforms/pseries/reconfig.c b/kernel/arch/powerpc/platforms/pseries/reconfig.c
index 0f319521e..7c7fcc042 100644
--- a/kernel/arch/powerpc/platforms/pseries/reconfig.c
+++ b/kernel/arch/powerpc/platforms/pseries/reconfig.c
@@ -22,37 +22,7 @@
#include <asm/uaccess.h>
#include <asm/mmu.h>
-/**
- * derive_parent - basically like dirname(1)
- * @path: the full_name of a node to be added to the tree
- *
- * Returns the node which should be the parent of the node
- * described by path. E.g., for path = "/foo/bar", returns
- * the node with full_name = "/foo".
- */
-static struct device_node *derive_parent(const char *path)
-{
- struct device_node *parent = NULL;
- char *parent_path = "/";
- size_t parent_path_len = strrchr(path, '/') - path + 1;
-
- /* reject if path is "/" */
- if (!strcmp(path, "/"))
- return ERR_PTR(-EINVAL);
-
- if (strrchr(path, '/') != path) {
- parent_path = kmalloc(parent_path_len, GFP_KERNEL);
- if (!parent_path)
- return ERR_PTR(-ENOMEM);
- strlcpy(parent_path, path, parent_path_len);
- }
- parent = of_find_node_by_path(parent_path);
- if (!parent)
- return ERR_PTR(-EINVAL);
- if (strcmp(parent_path, "/"))
- kfree(parent_path);
- return parent;
-}
+#include "of_helpers.h"
static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
{
@@ -71,7 +41,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
of_node_set_flag(np, OF_DYNAMIC);
of_node_init(np);
- np->parent = derive_parent(path);
+ np->parent = pseries_of_derive_parent(path);
if (IS_ERR(np->parent)) {
err = PTR_ERR(np->parent);
goto out_err;
diff --git a/kernel/arch/powerpc/platforms/pseries/rng.c b/kernel/arch/powerpc/platforms/pseries/rng.c
index e09608770..31ca557af 100644
--- a/kernel/arch/powerpc/platforms/pseries/rng.c
+++ b/kernel/arch/powerpc/platforms/pseries/rng.c
@@ -38,7 +38,7 @@ static __init int rng_init(void)
pr_info("Registering arch random hook.\n");
- ppc_md.get_random_long = pseries_get_random_long;
+ ppc_md.get_random_seed = pseries_get_random_long;
return 0;
}
diff --git a/kernel/arch/powerpc/platforms/pseries/setup.c b/kernel/arch/powerpc/platforms/pseries/setup.c
index e6e8b241d..36df46eab 100644
--- a/kernel/arch/powerpc/platforms/pseries/setup.c
+++ b/kernel/arch/powerpc/platforms/pseries/setup.c
@@ -40,6 +40,7 @@
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/of.h>
+#include <linux/of_pci.h>
#include <linux/kexec.h>
#include <asm/mmu.h>
@@ -111,7 +112,7 @@ static void __init fwnmi_init(void)
fwnmi_active = 1;
}
-static void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc)
+static void pseries_8259_cascade(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = i8259_irq();
@@ -254,24 +255,26 @@ static void __init pseries_discover_pic(void)
static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *data)
{
struct of_reconfig_data *rd = data;
- struct device_node *np = rd->dn;
- struct pci_dn *pci = NULL;
+ struct device_node *parent, *np = rd->dn;
+ struct pci_dn *pdn;
int err = NOTIFY_OK;
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
- pci = np->parent->data;
- if (pci) {
- update_dn_pci_info(np, pci->phb);
-
- /* Create EEH device for the OF node */
- eeh_dev_init(PCI_DN(np), pci->phb);
+ parent = of_get_parent(np);
+ pdn = parent ? PCI_DN(parent) : NULL;
+ if (pdn) {
+ /* Create pdn and EEH device */
+ update_dn_pci_info(np, pdn->phb);
+ eeh_dev_init(PCI_DN(np), pdn->phb);
}
+
+ of_node_put(parent);
break;
case OF_RECONFIG_DETACH_NODE:
- pci = PCI_DN(np);
- if (pci)
- list_del(&pci->list);
+ pdn = PCI_DN(np);
+ if (pdn)
+ list_del(&pdn->list);
break;
default:
err = NOTIFY_DONE;
@@ -493,18 +496,7 @@ static void __init find_and_init_phbs(void)
* PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties
* in chosen.
*/
- if (of_chosen) {
- const int *prop;
-
- prop = of_get_property(of_chosen,
- "linux,pci-probe-only", NULL);
- if (prop) {
- if (*prop)
- pci_add_flags(PCI_PROBE_ONLY);
- else
- pci_clear_flags(PCI_PROBE_ONLY);
- }
- }
+ of_pci_check_probe_only();
}
static void __init pSeries_setup_arch(void)
@@ -835,10 +827,6 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus)
return PCI_PROBE_NORMAL;
}
-#ifndef CONFIG_PCI
-void pSeries_final_fixup(void) { }
-#endif
-
struct pci_controller_ops pseries_pci_controller_ops = {
.probe_mode = pSeries_pci_probe_mode,
};