* Re: [PATCH v2 1/6] powerpc/powernv: Enable M64 aperatus for PHB3
From: Gavin Shan @ 2014-07-17 4:40 UTC (permalink / raw)
To: Guo Chao; +Cc: linuxppc-dev, gwshan
In-Reply-To: <1405513475-24220-2-git-send-email-yan@linux.vnet.ibm.com>
On Wed, Jul 16, 2014 at 08:24:30PM +0800, Guo Chao wrote:
>This patch enables M64 aperatus for PHB3.
>
>We already had platform hook (ppc_md.pcibios_window_alignment) to affect
>the PCI resource assignment done in PCI core so that each PE's M32 resource
>was built on basis of M32 segment size. Similarly, we're using that for
>M64 assignment on basis of M64 segment size.
>
> * We're using last M64 BAR to cover M64 aperatus, and it's shared by all
> 256 PEs.
> * We don't support P7IOC yet. However, some function callbacks are added
> to (struct pnv_phb) so that we can reuse them on P7IOC in future.
> * PE, corresponding to PCI bus with large M64 BAR device attached, might
> span multiple M64 segments. We introduce "compound" PE to cover the case.
> The compound PE is a list of PEs and the master PE is used as before.
> The slave PEs are just for MMIO isolation.
>
>Signed-off-by: Guo Chao <yan@linux.vnet.ibm.com>
Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
It looks good to me except the PELTV bits (I told you before), which can be
fixed later. Without PELTV, we can rely software to maintain master/slave
business. However, it's worthy to have PELTV setup correctly so that inbound
ER errors can freeze multiple PEs (if applicable) by hardware.
Also, I run it on P7 box and no problem found there.
Thanks,
Gavin
>---
> arch/powerpc/include/asm/opal.h | 8 +-
> arch/powerpc/platforms/powernv/pci-ioda.c | 301 +++++++++++++++++++++++++++---
> arch/powerpc/platforms/powernv/pci.h | 20 ++
> 3 files changed, 307 insertions(+), 22 deletions(-)
>
>diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
>index 0da1dbd..ae885cc 100644
>--- a/arch/powerpc/include/asm/opal.h
>+++ b/arch/powerpc/include/asm/opal.h
>@@ -340,6 +340,12 @@ enum OpalMveEnableAction {
> OPAL_ENABLE_MVE = 1
> };
>
>+enum OpalM64EnableAction {
>+ OPAL_DISABLE_M64 = 0,
>+ OPAL_ENABLE_M64_SPLIT = 1,
>+ OPAL_ENABLE_M64_NON_SPLIT = 2
>+};
>+
> enum OpalPciResetScope {
> OPAL_PHB_COMPLETE = 1, OPAL_PCI_LINK = 2, OPAL_PHB_ERROR = 3,
> OPAL_PCI_HOT_RESET = 4, OPAL_PCI_FUNDAMENTAL_RESET = 5,
>@@ -768,7 +774,7 @@ int64_t opal_pci_set_phb_mem_window(uint64_t phb_id, uint16_t window_type,
> uint16_t window_num,
> uint64_t starting_real_address,
> uint64_t starting_pci_address,
>- uint16_t segment_size);
>+ uint64_t size);
> int64_t opal_pci_map_pe_mmio_window(uint64_t phb_id, uint16_t pe_number,
> uint16_t window_type, uint16_t window_num,
> uint16_t segment_num);
>diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
>index 93fd815..2b659d9 100644
>--- a/arch/powerpc/platforms/powernv/pci-ioda.c
>+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
>@@ -36,6 +36,7 @@
> #include <asm/tce.h>
> #include <asm/xics.h>
> #include <asm/debug.h>
>+#include <asm/firmware.h>
>
> #include "powernv.h"
> #include "pci.h"
>@@ -82,6 +83,12 @@ static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
> : : "r" (val), "r" (paddr) : "memory");
> }
>
>+static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)
>+{
>+ return ((flags & (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)) ==
>+ (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH));
>+}
>+
> static int pnv_ioda_alloc_pe(struct pnv_phb *phb)
> {
> unsigned long pe;
>@@ -106,6 +113,240 @@ static void pnv_ioda_free_pe(struct pnv_phb *phb, int pe)
> clear_bit(pe, phb->ioda.pe_alloc);
> }
>
>+/* The default M64 BAR is shared by all PEs */
>+static int pnv_ioda2_init_m64(struct pnv_phb *phb)
>+{
>+ const char *desc;
>+ struct resource *r;
>+ s64 rc;
>+
>+ /* Configure the default M64 BAR */
>+ rc = opal_pci_set_phb_mem_window(phb->opal_id,
>+ OPAL_M64_WINDOW_TYPE,
>+ phb->ioda.m64_bar_idx,
>+ phb->ioda.m64_base,
>+ 0, /* unused */
>+ phb->ioda.m64_size);
>+ if (rc != OPAL_SUCCESS) {
>+ desc = "configuring";
>+ goto fail;
>+ }
>+
>+ /* Enable the default M64 BAR */
>+ rc = opal_pci_phb_mmio_enable(phb->opal_id,
>+ OPAL_M64_WINDOW_TYPE,
>+ phb->ioda.m64_bar_idx,
>+ OPAL_ENABLE_M64_SPLIT);
>+ if (rc != OPAL_SUCCESS) {
>+ desc = "enabling";
>+ goto fail;
>+ }
>+
>+ /* Mark the M64 BAR assigned */
>+ set_bit(phb->ioda.m64_bar_idx, &phb->ioda.m64_bar_alloc);
>+
>+ /*
>+ * Strip off the segment used by the reserved PE, which is
>+ * expected to be 0 or last one of PE capabicity.
>+ */
>+ r = &phb->hose->mem_resources[1];
>+ if (phb->ioda.reserved_pe == 0)
>+ r->start += phb->ioda.m64_segsize;
>+ else if (phb->ioda.reserved_pe == (phb->ioda.total_pe - 1))
>+ r->end -= phb->ioda.m64_segsize;
>+ else
>+ pr_warn(" Cannot strip M64 segment for reserved PE#%d\n",
>+ phb->ioda.reserved_pe);
>+
>+ return 0;
>+
>+fail:
>+ pr_warn(" Failure %lld %s M64 BAR#%d\n",
>+ rc, desc, phb->ioda.m64_bar_idx);
>+ opal_pci_phb_mmio_enable(phb->opal_id,
>+ OPAL_M64_WINDOW_TYPE,
>+ phb->ioda.m64_bar_idx,
>+ OPAL_DISABLE_M64);
>+ return -EIO;
>+}
>+
>+static void pnv_ioda2_alloc_m64_pe(struct pnv_phb *phb)
>+{
>+ resource_size_t sgsz = phb->ioda.m64_segsize;
>+ struct pci_dev *pdev;
>+ struct resource *r;
>+ int base, step, i;
>+
>+ /*
>+ * Root bus always has full M64 range and root port has
>+ * M64 range used in reality. So we're checking root port
>+ * instead of root bus.
>+ */
>+ list_for_each_entry(pdev, &phb->hose->bus->devices, bus_list) {
>+ for (i = PCI_BRIDGE_RESOURCES;
>+ i <= PCI_BRIDGE_RESOURCE_END; i++) {
>+ r = &pdev->resource[i];
>+ if (!r->parent ||
>+ !pnv_pci_is_mem_pref_64(r->flags))
>+ continue;
>+
>+ base = (r->start - phb->ioda.m64_base) / sgsz;
>+ for (step = 0; step < resource_size(r) / sgsz; step++)
>+ set_bit(base + step, phb->ioda.pe_alloc);
>+ }
>+ }
>+}
>+
>+static int pnv_ioda2_pick_m64_pe(struct pnv_phb *phb,
>+ struct pci_bus *bus, int all)
>+{
>+ resource_size_t segsz = phb->ioda.m64_segsize;
>+ struct pci_dev *pdev;
>+ struct resource *r;
>+ struct pnv_ioda_pe *master_pe, *pe;
>+ unsigned long size, *pe_alloc;
>+ bool found;
>+ int start, i, j;
>+
>+ /* Root bus shouldn't use M64 */
>+ if (pci_is_root_bus(bus))
>+ return IODA_INVALID_PE;
>+
>+ /* We support only one M64 window on each bus */
>+ found = false;
>+ pci_bus_for_each_resource(bus, r, i) {
>+ if (r && r->parent &&
>+ pnv_pci_is_mem_pref_64(r->flags)) {
>+ found = true;
>+ break;
>+ }
>+ }
>+
>+ /* No M64 window found ? */
>+ if (!found)
>+ return IODA_INVALID_PE;
>+
>+ /* Allocate bitmap */
>+ size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long));
>+ pe_alloc = kzalloc(size, GFP_KERNEL);
>+ if (!pe_alloc) {
>+ pr_warn("%s: Out of memory !\n",
>+ __func__);
>+ return IODA_INVALID_PE;
>+ }
>+
>+ /*
>+ * Figure out reserved PE numbers by the PE
>+ * the its child PEs.
>+ */
>+ start = (r->start - phb->ioda.m64_base) / segsz;
>+ for (i = 0; i < resource_size(r) / segsz; i++)
>+ set_bit(start + i, pe_alloc);
>+
>+ if (all)
>+ goto done;
>+
>+ /*
>+ * If the PE doesn't cover all subordinate buses,
>+ * we need subtract from reserved PEs for children.
>+ */
>+ list_for_each_entry(pdev, &bus->devices, bus_list) {
>+ if (!pdev->subordinate)
>+ continue;
>+
>+ pci_bus_for_each_resource(pdev->subordinate, r, i) {
>+ if (!r || !r->parent ||
>+ !pnv_pci_is_mem_pref_64(r->flags))
>+ continue;
>+
>+ start = (r->start - phb->ioda.m64_base) / segsz;
>+ for (j = 0; j < resource_size(r) / segsz ; j++)
>+ clear_bit(start + j, pe_alloc);
>+ }
>+ }
>+
>+ /*
>+ * the current bus might not own M64 window and that's all
>+ * contributed by its child buses. For the case, we needn't
>+ * pick M64 dependent PE#.
>+ */
>+ if (bitmap_empty(pe_alloc, phb->ioda.total_pe)) {
>+ kfree(pe_alloc);
>+ return IODA_INVALID_PE;
>+ }
>+
>+ /*
>+ * Figure out the master PE and put all slave PEs to master
>+ * PE's list to form compound PE.
>+ */
>+done:
>+ master_pe = NULL;
>+ i = -1;
>+ while ((i = find_next_bit(pe_alloc, phb->ioda.total_pe, i + 1)) <
>+ phb->ioda.total_pe) {
>+ pe = &phb->ioda.pe_array[i];
>+ pe->phb = phb;
>+ pe->pe_number = i;
>+
>+ if (!master_pe) {
>+ pe->flags |= PNV_IODA_PE_MASTER;
>+ INIT_LIST_HEAD(&pe->slaves);
>+ master_pe = pe;
>+ } else {
>+ pe->flags |= PNV_IODA_PE_SLAVE;
>+ pe->master = master_pe;
>+ list_add_tail(&pe->list, &master_pe->slaves);
>+ }
>+ }
>+
>+ kfree(pe_alloc);
>+ return master_pe->pe_number;
>+}
>+
>+static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
>+{
>+ struct pci_controller *hose = phb->hose;
>+ struct device_node *dn = hose->dn;
>+ struct resource *res;
>+ const u32 *r;
>+ u64 pci_addr;
>+
>+ if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
>+ pr_info(" Firmware too old to support M64 window\n");
>+ return;
>+ }
>+
>+ r = of_get_property(dn, "ibm,opal-m64-window", NULL);
>+ if (!r) {
>+ pr_info(" No <ibm,opal-m64-window> on %s\n",
>+ dn->full_name);
>+ return;
>+ }
>+
>+ /* FIXME: Support M64 for P7IOC */
>+ if (phb->type != PNV_PHB_IODA2) {
>+ pr_info(" Not support M64 window\n");
>+ return;
>+ }
>+
>+ res = &hose->mem_resources[1];
>+ res->start = of_translate_address(dn, r + 2);
>+ res->end = res->start + of_read_number(r + 4, 2) - 1;
>+ res->flags = (IORESOURCE_MEM | IORESOURCE_MEM_64 | IORESOURCE_PREFETCH);
>+ pci_addr = of_read_number(r, 2);
>+ hose->mem_offset[1] = res->start - pci_addr;
>+
>+ phb->ioda.m64_size = resource_size(res);
>+ phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe;
>+ phb->ioda.m64_base = pci_addr;
>+
>+ /* Use last M64 BAR to cover M64 window */
>+ phb->ioda.m64_bar_idx = 15;
>+ phb->init_m64 = pnv_ioda2_init_m64;
>+ phb->alloc_m64_pe = pnv_ioda2_alloc_m64_pe;
>+ phb->pick_m64_pe = pnv_ioda2_pick_m64_pe;
>+}
>+
> /* Currently those 2 are only used when MSIs are enabled, this will change
> * but in the meantime, we need to protect them to avoid warnings
> */
>@@ -363,9 +604,16 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
> struct pci_controller *hose = pci_bus_to_host(bus);
> struct pnv_phb *phb = hose->private_data;
> struct pnv_ioda_pe *pe;
>- int pe_num;
>+ int pe_num = IODA_INVALID_PE;
>+
>+ /* Check if PE is determined by M64 */
>+ if (phb->pick_m64_pe)
>+ pe_num = phb->pick_m64_pe(phb, bus, all);
>+
>+ /* The PE number isn't pinned by M64 */
>+ if (pe_num == IODA_INVALID_PE)
>+ pe_num = pnv_ioda_alloc_pe(phb);
>
>- pe_num = pnv_ioda_alloc_pe(phb);
> if (pe_num == IODA_INVALID_PE) {
> pr_warning("%s: Not enough PE# available for PCI bus %04x:%02x\n",
> __func__, pci_domain_nr(bus), bus->number);
>@@ -373,7 +621,7 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
> }
>
> pe = &phb->ioda.pe_array[pe_num];
>- pe->flags = (all ? PNV_IODA_PE_BUS_ALL : PNV_IODA_PE_BUS);
>+ pe->flags |= (all ? PNV_IODA_PE_BUS_ALL : PNV_IODA_PE_BUS);
> pe->pbus = bus;
> pe->pdev = NULL;
> pe->tce32_seg = -1;
>@@ -441,8 +689,15 @@ static void pnv_ioda_setup_PEs(struct pci_bus *bus)
> static void pnv_pci_ioda_setup_PEs(void)
> {
> struct pci_controller *hose, *tmp;
>+ struct pnv_phb *phb;
>
> list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
>+ phb = hose->private_data;
>+
>+ /* M64 layout might affect PE allocation */
>+ if (phb->alloc_m64_pe)
>+ phb->alloc_m64_pe(phb);
>+
> pnv_ioda_setup_PEs(hose->bus);
> }
> }
>@@ -1067,9 +1322,6 @@ static void pnv_ioda_setup_pe_seg(struct pci_controller *hose,
> index++;
> }
> } else if (res->flags & IORESOURCE_MEM) {
>- /* WARNING: Assumes M32 is mem region 0 in PHB. We need to
>- * harden that algorithm when we start supporting M64
>- */
> region.start = res->start -
> hose->mem_offset[0] -
> phb->ioda.m32_pci_base;
>@@ -1190,7 +1442,10 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
> bridge = bridge->bus->self;
> }
>
>- /* We need support prefetchable memory window later */
>+ /* We fail back to M32 if M64 isn't supported */
>+ if (phb->ioda.m64_segsize &&
>+ pnv_pci_is_mem_pref_64(type))
>+ return phb->ioda.m64_segsize;
> if (type & IORESOURCE_MEM)
> return phb->ioda.m32_segsize;
>
>@@ -1311,6 +1566,10 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
> prop32 = of_get_property(np, "ibm,opal-reserved-pe", NULL);
> if (prop32)
> phb->ioda.reserved_pe = be32_to_cpup(prop32);
>+
>+ /* Parse 64-bit MMIO range */
>+ pnv_ioda_parse_m64_window(phb);
>+
> phb->ioda.m32_size = resource_size(&hose->mem_resources[0]);
> /* FW Has already off top 64k of M32 space (MSI space) */
> phb->ioda.m32_size += 0x10000;
>@@ -1346,14 +1605,6 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
> /* Calculate how many 32-bit TCE segments we have */
> phb->ioda.tce32_count = phb->ioda.m32_pci_base >> 28;
>
>- /* Clear unusable m64 */
>- hose->mem_resources[1].flags = 0;
>- hose->mem_resources[1].start = 0;
>- hose->mem_resources[1].end = 0;
>- hose->mem_resources[2].flags = 0;
>- hose->mem_resources[2].start = 0;
>- hose->mem_resources[2].end = 0;
>-
> #if 0 /* We should really do that ... */
> rc = opal_pci_set_phb_mem_window(opal->phb_id,
> window_type,
>@@ -1363,12 +1614,16 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
> segment_size);
> #endif
>
>- pr_info(" %d (%d) PE's M32: 0x%x [segment=0x%x]"
>- " IO: 0x%x [segment=0x%x]\n",
>- phb->ioda.total_pe,
>- phb->ioda.reserved_pe,
>- phb->ioda.m32_size, phb->ioda.m32_segsize,
>- phb->ioda.io_size, phb->ioda.io_segsize);
>+ pr_info(" %03d (%03d) PE's M32: 0x%x [segment=0x%x]\n",
>+ phb->ioda.total_pe, phb->ioda.reserved_pe,
>+ phb->ioda.m32_size, phb->ioda.m32_segsize);
>+ if (phb->ioda.m64_size)
>+ pr_info(" M64: 0x%lx [segment=0x%lx]\n",
>+ phb->ioda.m64_size, phb->ioda.m64_segsize);
>+ if (phb->ioda.io_size)
>+ pr_info(" IO: 0x%x [segment=0x%x]\n",
>+ phb->ioda.io_size, phb->ioda.io_segsize);
>+
>
> phb->hose->ops = &pnv_pci_ops;
> #ifdef CONFIG_EEH
>@@ -1416,6 +1671,10 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
> ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
> ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET);
> }
>+
>+ /* Configure M64 window */
>+ if (phb->init_m64 && phb->init_m64(phb))
>+ hose->mem_resources[1].flags = 0;
> }
>
> void __init pnv_pci_init_ioda2_phb(struct device_node *np)
>diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
>index 676232c..def7171 100644
>--- a/arch/powerpc/platforms/powernv/pci.h
>+++ b/arch/powerpc/platforms/powernv/pci.h
>@@ -21,6 +21,8 @@ enum pnv_phb_model {
> #define PNV_IODA_PE_DEV (1 << 0) /* PE has single PCI device */
> #define PNV_IODA_PE_BUS (1 << 1) /* PE has primary PCI bus */
> #define PNV_IODA_PE_BUS_ALL (1 << 2) /* PE has subordinate buses */
>+#define PNV_IODA_PE_MASTER (1 << 3) /* Master PE in compound case */
>+#define PNV_IODA_PE_SLAVE (1 << 4) /* Slave PE in compound case */
>
> /* Data associated with a PE, including IOMMU tracking etc.. */
> struct pnv_phb;
>@@ -64,6 +66,10 @@ struct pnv_ioda_pe {
> */
> int mve_number;
>
>+ /* PEs in compound case */
>+ struct pnv_ioda_pe *master;
>+ struct list_head slaves;
>+
> /* Link in list of PE#s */
> struct list_head dma_link;
> struct list_head list;
>@@ -119,6 +125,9 @@ struct pnv_phb {
> void (*fixup_phb)(struct pci_controller *hose);
> u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
> void (*shutdown)(struct pnv_phb *phb);
>+ int (*init_m64)(struct pnv_phb *phb);
>+ void (*alloc_m64_pe)(struct pnv_phb *phb);
>+ int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all);
>
> union {
> struct {
>@@ -129,9 +138,20 @@ struct pnv_phb {
> /* Global bridge info */
> unsigned int total_pe;
> unsigned int reserved_pe;
>+
>+ /* 32-bit MMIO window */
> unsigned int m32_size;
> unsigned int m32_segsize;
> unsigned int m32_pci_base;
>+
>+ /* 64-bit MMIO window */
>+ unsigned int m64_bar_idx;
>+ unsigned long m64_size;
>+ unsigned long m64_segsize;
>+ unsigned long m64_base;
>+ unsigned long m64_bar_alloc;
>+
>+ /* IO ports */
> unsigned int io_size;
> unsigned int io_segsize;
> unsigned int io_pci_base;
>--
>1.9.1
>
^ permalink raw reply
* [PATCH v2 2/6] powerpc/eeh: Selectively enable IO for error log
From: Gavin Shan @ 2014-07-17 4:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405572103-32152-1-git-send-email-gwshan@linux.vnet.ibm.com>
According to the experiment I did, PCI config access is blocked
on P7IOC frozen PE by hardware, but PHB3 doesn't do that. That
means we always get 0xFF's while dumping PCI config space of the
frozen PE on P7IOC. We don't have the problem on PHB3. So we have
to enable I/O prioir to collecting error log. Otherwise, meaningless
0xFF's are always returned.
The patch fixes it by EEH flag (EEH_ENABLE_IO_FOR_LOG), which is
selectively set to indicate the case for: P7IOC on PowerNV platform,
pSeries platform.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 9 +++++----
arch/powerpc/kernel/eeh.c | 2 +-
arch/powerpc/platforms/powernv/eeh-powernv.c | 16 ++++++++++++++++
arch/powerpc/platforms/pseries/eeh_pseries.c | 2 +-
4 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index ca8aada..494c3ff 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -34,10 +34,11 @@ struct device_node;
#ifdef CONFIG_EEH
/* EEH subsystem flags */
-#define EEH_ENABLED 0x1 /* EEH enabled */
-#define EEH_FORCE_DISABLED 0x2 /* EEH disabled */
-#define EEH_PROBE_MODE_DEV 0x4 /* From PCI device */
-#define EEH_PROBE_MODE_DEVTREE 0x8 /* From device tree */
+#define EEH_ENABLED 0x01 /* EEH enabled */
+#define EEH_FORCE_DISABLED 0x02 /* EEH disabled */
+#define EEH_PROBE_MODE_DEV 0x04 /* From PCI device */
+#define EEH_PROBE_MODE_DEVTREE 0x08 /* From device tree */
+#define EEH_ENABLE_IO_FOR_LOG 0x10 /* Enable IO for log */
/*
* Delay for PE reset, all in ms
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 65a163f..aa33656 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -252,7 +252,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
* 0xFF's is always returned from PCI config space.
*/
if (!(pe->type & EEH_PE_PHB)) {
- if (eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
+ if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG))
eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
eeh_ops->configure_bridge(pe);
eeh_pe_restore_bars(pe);
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index ba134ac..740c396 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -45,6 +45,9 @@
*/
static int powernv_eeh_init(void)
{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+
/* We require OPALv3 */
if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
pr_warning("%s: OPALv3 is required !\n", __func__);
@@ -54,6 +57,19 @@ static int powernv_eeh_init(void)
/* Set probe mode */
eeh_add_flag(EEH_PROBE_MODE_DEV);
+ /*
+ * P7IOC blocks PCI config access to frozen PE, but PHB3
+ * doesn't do that. So we have to selectively enable I/O
+ * prior to collecting error log.
+ */
+ list_for_each_entry(hose, &hose_list, list_node) {
+ phb = hose->private_data;
+
+ if (phb->model == PNV_PHB_MODEL_P7IOC)
+ eeh_add_flag(EEH_ENABLE_IO_FOR_LOG);
+ break;
+ }
+
return 0;
}
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index f173705..1e15cdd 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -128,7 +128,7 @@ static int pseries_eeh_init(void)
}
/* Set EEH probe mode */
- eeh_add_flag(EEH_PROBE_MODE_DEVTREE);
+ eeh_add_flag(EEH_PROBE_MODE_DEVTREE | EEH_ENABLE_IO_FOR_LOG);
return 0;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 0/6] EEH Cleanup
From: Gavin Shan @ 2014-07-17 4:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
The patchset is EEH cleanup and expected to be merged during 3.17
window. The the patchset is expected to be applied after:
| EEH support for guest
| 2 more bug fixes for EEH support for guest
| M64 related EEH changes
| 2 bug fixes from Mike Qiu
|
+-> The current patchset
Except the following 2 patches, all patches are for cleanup:
Refactoring EEH log, replacing pr_warning() with pr_warn(),
reducing length of EEH log dump etc:
PATCH[2/6]: We have to enable I/O path before collecting EEH log.
Otherwise, 0xFF is always returned from PCI config
of devices in frozen PE. the problem is only existing
on PHB3.
PATCH[6/6]: It's something related to EEH guest log retrieval.
Currently, all PEs in one specific PHB are sharing
diag-data blob for storing EEH log. It's possible
for diag-data blob overwritten before being collected
by guest. The patch introduce auxillary data for PE,
which is maintained by backend. On PowerNV, that's used
for EEH log.
Changelog
=========
v1 -> v2:
* Simplified condition to output buffer in PATCH[3/6].
Gavin Shan (6):
powerpc/eeh: Refactor EEH flag accessors
powerpc/eeh: Selectively enable IO for error log
powerpc/eeh: Reduce lines of log dump
powerpc/eeh: Replace pr_warning() with pr_warn()
powerpc/eeh: Make diag-data not endian dependent
powerpc/eeh: Aux PE data for error log
arch/powerpc/include/asm/eeh.h | 43 ++++-----
arch/powerpc/include/asm/opal.h | 128 +++++++++++++--------------
arch/powerpc/kernel/eeh.c | 74 +++++++++++-----
arch/powerpc/kernel/eeh_cache.c | 9 +-
arch/powerpc/kernel/eeh_dev.c | 3 +-
arch/powerpc/kernel/eeh_driver.c | 16 ++--
arch/powerpc/kernel/eeh_pe.c | 29 +++++-
arch/powerpc/platforms/powernv/eeh-ioda.c | 103 +++++++++++++--------
arch/powerpc/platforms/powernv/eeh-powernv.c | 32 +++++--
arch/powerpc/platforms/powernv/pci-ioda.c | 1 -
arch/powerpc/platforms/powernv/pci.c | 68 ++++++++------
arch/powerpc/platforms/pseries/eeh_pseries.c | 32 +++----
12 files changed, 325 insertions(+), 213 deletions(-)
--
1.8.3.2
^ permalink raw reply
* [PATCH v2 3/6] powerpc/eeh: Reduce lines of log dump
From: Gavin Shan @ 2014-07-17 4:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405572103-32152-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch prints 4 PCIE or AER config registers each line, which
is part of the EEH log so that it looks a bit more compact.
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
v2: Siplified condition to output buffer and renamed "i" to "l".
---
arch/powerpc/kernel/eeh.c | 38 +++++++++++++++++++++++++++++++++-----
1 file changed, 33 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index aa33656..afde505 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -157,12 +157,13 @@ __setup("eeh=", eeh_setup);
* This routine captures assorted PCI configuration space data,
* and puts them into a buffer for RTAS error logging.
*/
-static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
+static size_t eeh_gather_pci_data(struct eeh_dev *edev, char *buf, size_t len)
{
struct device_node *dn = eeh_dev_to_of_node(edev);
u32 cfg;
int cap, i;
- int n = 0;
+ int n = 0, l = 0;
+ char buffer[128];
n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
pr_warn("EEH: of node=%s\n", dn->full_name);
@@ -207,8 +208,22 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
for (i=0; i<=8; i++) {
eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
- pr_warn("EEH: PCI-E %02x: %08x\n", i, cfg);
+
+ if ((i % 4) == 0) {
+ if (i != 0)
+ pr_warn("%s\n", buffer);
+
+ l = scnprintf(buffer, sizeof(buffer),
+ "EEH: PCI-E %02x: %08x ",
+ 4*i, cfg);
+ } else {
+ l += scnprintf(buffer+l, sizeof(buffer)-l,
+ "%08x ", cfg);
+ }
+
}
+
+ pr_warn("%s\n", buffer);
}
/* If AER capable, dump it */
@@ -217,11 +232,24 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
n += scnprintf(buf+n, len-n, "pci-e AER:\n");
pr_warn("EEH: PCI-E AER capability register set follows:\n");
- for (i=0; i<14; i++) {
+ for (i=0; i<=13; i++) {
eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
- pr_warn("EEH: PCI-E AER %02x: %08x\n", i, cfg);
+
+ if ((i % 4) == 0) {
+ if (i != 0)
+ pr_warn("%s\n", buffer);
+
+ l = scnprintf(buffer, sizeof(buffer),
+ "EEH: PCI-E AER %02x: %08x ",
+ 4*i, cfg);
+ } else {
+ l += scnprintf(buffer+l, sizeof(buffer)-l,
+ "%08x ", cfg);
+ }
}
+
+ pr_warn("%s\n", buffer);
}
return n;
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 5/6] powerpc/eeh: Make diag-data not endian dependent
From: Gavin Shan @ 2014-07-17 4:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Guo Chao, Gavin Shan
In-Reply-To: <1405572103-32152-1-git-send-email-gwshan@linux.vnet.ibm.com>
It's followup of commit ddf0322a ("powerpc/powernv: Fix endianness
problems in EEH"). The patch helps to get non-endian-dependent
diag-data.
Cc: Guo Chao <yan@linux.vnet.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/opal.h | 128 +++++++++++++++---------------
arch/powerpc/platforms/powernv/eeh-ioda.c | 51 +++++++-----
arch/powerpc/platforms/powernv/pci.c | 68 ++++++++++------
3 files changed, 139 insertions(+), 108 deletions(-)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index edbfe1c..f0b5b40 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -520,40 +520,40 @@ enum {
};
struct OpalIoP7IOCErrorData {
- uint16_t type;
+ __be16 type;
/* GEM */
- uint64_t gemXfir;
- uint64_t gemRfir;
- uint64_t gemRirqfir;
- uint64_t gemMask;
- uint64_t gemRwof;
+ __be64 gemXfir;
+ __be64 gemRfir;
+ __be64 gemRirqfir;
+ __be64 gemMask;
+ __be64 gemRwof;
/* LEM */
- uint64_t lemFir;
- uint64_t lemErrMask;
- uint64_t lemAction0;
- uint64_t lemAction1;
- uint64_t lemWof;
+ __be64 lemFir;
+ __be64 lemErrMask;
+ __be64 lemAction0;
+ __be64 lemAction1;
+ __be64 lemWof;
union {
struct OpalIoP7IOCRgcErrorData {
- uint64_t rgcStatus; /* 3E1C10 */
- uint64_t rgcLdcp; /* 3E1C18 */
+ __be64 rgcStatus; /* 3E1C10 */
+ __be64 rgcLdcp; /* 3E1C18 */
}rgc;
struct OpalIoP7IOCBiErrorData {
- uint64_t biLdcp0; /* 3C0100, 3C0118 */
- uint64_t biLdcp1; /* 3C0108, 3C0120 */
- uint64_t biLdcp2; /* 3C0110, 3C0128 */
- uint64_t biFenceStatus; /* 3C0130, 3C0130 */
+ __be64 biLdcp0; /* 3C0100, 3C0118 */
+ __be64 biLdcp1; /* 3C0108, 3C0120 */
+ __be64 biLdcp2; /* 3C0110, 3C0128 */
+ __be64 biFenceStatus; /* 3C0130, 3C0130 */
- uint8_t biDownbound; /* BI Downbound or Upbound */
+ u8 biDownbound; /* BI Downbound or Upbound */
}bi;
struct OpalIoP7IOCCiErrorData {
- uint64_t ciPortStatus; /* 3Dn008 */
- uint64_t ciPortLdcp; /* 3Dn010 */
+ __be64 ciPortStatus; /* 3Dn008 */
+ __be64 ciPortLdcp; /* 3Dn010 */
- uint8_t ciPort; /* Index of CI port: 0/1 */
+ u8 ciPort; /* Index of CI port: 0/1 */
}ci;
};
};
@@ -585,60 +585,60 @@ struct OpalIoPhbErrorCommon {
struct OpalIoP7IOCPhbErrorData {
struct OpalIoPhbErrorCommon common;
- uint32_t brdgCtl;
+ __be32 brdgCtl;
// P7IOC utl regs
- uint32_t portStatusReg;
- uint32_t rootCmplxStatus;
- uint32_t busAgentStatus;
+ __be32 portStatusReg;
+ __be32 rootCmplxStatus;
+ __be32 busAgentStatus;
// P7IOC cfg regs
- uint32_t deviceStatus;
- uint32_t slotStatus;
- uint32_t linkStatus;
- uint32_t devCmdStatus;
- uint32_t devSecStatus;
+ __be32 deviceStatus;
+ __be32 slotStatus;
+ __be32 linkStatus;
+ __be32 devCmdStatus;
+ __be32 devSecStatus;
// cfg AER regs
- uint32_t rootErrorStatus;
- uint32_t uncorrErrorStatus;
- uint32_t corrErrorStatus;
- uint32_t tlpHdr1;
- uint32_t tlpHdr2;
- uint32_t tlpHdr3;
- uint32_t tlpHdr4;
- uint32_t sourceId;
+ __be32 rootErrorStatus;
+ __be32 uncorrErrorStatus;
+ __be32 corrErrorStatus;
+ __be32 tlpHdr1;
+ __be32 tlpHdr2;
+ __be32 tlpHdr3;
+ __be32 tlpHdr4;
+ __be32 sourceId;
- uint32_t rsv3;
+ __be32 rsv3;
// Record data about the call to allocate a buffer.
- uint64_t errorClass;
- uint64_t correlator;
+ __be64 errorClass;
+ __be64 correlator;
//P7IOC MMIO Error Regs
- uint64_t p7iocPlssr; // n120
- uint64_t p7iocCsr; // n110
- uint64_t lemFir; // nC00
- uint64_t lemErrorMask; // nC18
- uint64_t lemWOF; // nC40
- uint64_t phbErrorStatus; // nC80
- uint64_t phbFirstErrorStatus; // nC88
- uint64_t phbErrorLog0; // nCC0
- uint64_t phbErrorLog1; // nCC8
- uint64_t mmioErrorStatus; // nD00
- uint64_t mmioFirstErrorStatus; // nD08
- uint64_t mmioErrorLog0; // nD40
- uint64_t mmioErrorLog1; // nD48
- uint64_t dma0ErrorStatus; // nD80
- uint64_t dma0FirstErrorStatus; // nD88
- uint64_t dma0ErrorLog0; // nDC0
- uint64_t dma0ErrorLog1; // nDC8
- uint64_t dma1ErrorStatus; // nE00
- uint64_t dma1FirstErrorStatus; // nE08
- uint64_t dma1ErrorLog0; // nE40
- uint64_t dma1ErrorLog1; // nE48
- uint64_t pestA[OPAL_P7IOC_NUM_PEST_REGS];
- uint64_t pestB[OPAL_P7IOC_NUM_PEST_REGS];
+ __be64 p7iocPlssr; // n120
+ __be64 p7iocCsr; // n110
+ __be64 lemFir; // nC00
+ __be64 lemErrorMask; // nC18
+ __be64 lemWOF; // nC40
+ __be64 phbErrorStatus; // nC80
+ __be64 phbFirstErrorStatus; // nC88
+ __be64 phbErrorLog0; // nCC0
+ __be64 phbErrorLog1; // nCC8
+ __be64 mmioErrorStatus; // nD00
+ __be64 mmioFirstErrorStatus; // nD08
+ __be64 mmioErrorLog0; // nD40
+ __be64 mmioErrorLog1; // nD48
+ __be64 dma0ErrorStatus; // nD80
+ __be64 dma0FirstErrorStatus; // nD88
+ __be64 dma0ErrorLog0; // nDC0
+ __be64 dma0ErrorLog1; // nDC8
+ __be64 dma1ErrorStatus; // nE00
+ __be64 dma1FirstErrorStatus; // nE08
+ __be64 dma1ErrorLog0; // nE40
+ __be64 dma1ErrorLog1; // nE48
+ __be64 pestA[OPAL_P7IOC_NUM_PEST_REGS];
+ __be64 pestB[OPAL_P7IOC_NUM_PEST_REGS];
};
struct OpalIoPhb3ErrorData {
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index edec622..bccdf60 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -639,18 +639,24 @@ static int ioda_eeh_configure_bridge(struct eeh_pe *pe)
static void ioda_eeh_hub_diag_common(struct OpalIoP7IOCErrorData *data)
{
/* GEM */
- pr_info(" GEM XFIR: %016llx\n", data->gemXfir);
- pr_info(" GEM RFIR: %016llx\n", data->gemRfir);
- pr_info(" GEM RIRQFIR: %016llx\n", data->gemRirqfir);
- pr_info(" GEM Mask: %016llx\n", data->gemMask);
- pr_info(" GEM RWOF: %016llx\n", data->gemRwof);
+ if (data->gemXfir || data->gemRfir ||
+ data->gemRirqfir || data->gemMask || data->gemRwof)
+ pr_info(" GEM: %016llx %016llx %016llx %016llx %016llx\n",
+ be64_to_cpu(data->gemXfir),
+ be64_to_cpu(data->gemRfir),
+ be64_to_cpu(data->gemRirqfir),
+ be64_to_cpu(data->gemMask),
+ be64_to_cpu(data->gemRwof));
/* LEM */
- pr_info(" LEM FIR: %016llx\n", data->lemFir);
- pr_info(" LEM Error Mask: %016llx\n", data->lemErrMask);
- pr_info(" LEM Action 0: %016llx\n", data->lemAction0);
- pr_info(" LEM Action 1: %016llx\n", data->lemAction1);
- pr_info(" LEM WOF: %016llx\n", data->lemWof);
+ if (data->lemFir || data->lemErrMask ||
+ data->lemAction0 || data->lemAction1 || data->lemWof)
+ pr_info(" LEM: %016llx %016llx %016llx %016llx %016llx\n",
+ be64_to_cpu(data->lemFir),
+ be64_to_cpu(data->lemErrMask),
+ be64_to_cpu(data->lemAction0),
+ be64_to_cpu(data->lemAction1),
+ be64_to_cpu(data->lemWof));
}
static void ioda_eeh_hub_diag(struct pci_controller *hose)
@@ -670,24 +676,31 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
case OPAL_P7IOC_DIAG_TYPE_RGC:
pr_info("P7IOC diag-data for RGC\n\n");
ioda_eeh_hub_diag_common(data);
- pr_info(" RGC Status: %016llx\n", data->rgc.rgcStatus);
- pr_info(" RGC LDCP: %016llx\n", data->rgc.rgcLdcp);
+ if (data->rgc.rgcStatus || data->rgc.rgcLdcp)
+ pr_info(" RGC: %016llx %016llx\n",
+ be64_to_cpu(data->rgc.rgcStatus),
+ be64_to_cpu(data->rgc.rgcLdcp));
break;
case OPAL_P7IOC_DIAG_TYPE_BI:
pr_info("P7IOC diag-data for BI %s\n\n",
data->bi.biDownbound ? "Downbound" : "Upbound");
ioda_eeh_hub_diag_common(data);
- pr_info(" BI LDCP 0: %016llx\n", data->bi.biLdcp0);
- pr_info(" BI LDCP 1: %016llx\n", data->bi.biLdcp1);
- pr_info(" BI LDCP 2: %016llx\n", data->bi.biLdcp2);
- pr_info(" BI Fence Status: %016llx\n", data->bi.biFenceStatus);
+ if (data->bi.biLdcp0 || data->bi.biLdcp1 ||
+ data->bi.biLdcp2 || data->bi.biFenceStatus)
+ pr_info(" BI: %016llx %016llx %016llx %016llx\n",
+ be64_to_cpu(data->bi.biLdcp0),
+ be64_to_cpu(data->bi.biLdcp1),
+ be64_to_cpu(data->bi.biLdcp2),
+ be64_to_cpu(data->bi.biFenceStatus));
break;
case OPAL_P7IOC_DIAG_TYPE_CI:
- pr_info("P7IOC diag-data for CI Port %d\\nn",
+ pr_info("P7IOC diag-data for CI Port %d\n\n",
data->ci.ciPort);
ioda_eeh_hub_diag_common(data);
- pr_info(" CI Port Status: %016llx\n", data->ci.ciPortStatus);
- pr_info(" CI Port LDCP: %016llx\n", data->ci.ciPortLdcp);
+ if (data->ci.ciPortStatus || data->ci.ciPortLdcp)
+ pr_info(" CI: %016llx %016llx\n",
+ be64_to_cpu(data->ci.ciPortStatus),
+ be64_to_cpu(data->ci.ciPortLdcp));
break;
case OPAL_P7IOC_DIAG_TYPE_MISC:
pr_info("P7IOC diag-data for MISC\n\n");
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 353e35b..97f515c 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -132,61 +132,78 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
data = (struct OpalIoP7IOCPhbErrorData *)common;
pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n",
- hose->global_number, common->version);
+ hose->global_number, be32_to_cpu(common->version));
if (data->brdgCtl)
pr_info("brdgCtl: %08x\n",
- data->brdgCtl);
+ be32_to_cpu(data->brdgCtl));
if (data->portStatusReg || data->rootCmplxStatus ||
data->busAgentStatus)
pr_info("UtlSts: %08x %08x %08x\n",
- data->portStatusReg, data->rootCmplxStatus,
- data->busAgentStatus);
+ be32_to_cpu(data->portStatusReg),
+ be32_to_cpu(data->rootCmplxStatus),
+ be32_to_cpu(data->busAgentStatus));
if (data->deviceStatus || data->slotStatus ||
data->linkStatus || data->devCmdStatus ||
data->devSecStatus)
pr_info("RootSts: %08x %08x %08x %08x %08x\n",
- data->deviceStatus, data->slotStatus,
- data->linkStatus, data->devCmdStatus,
- data->devSecStatus);
+ be32_to_cpu(data->deviceStatus),
+ be32_to_cpu(data->slotStatus),
+ be32_to_cpu(data->linkStatus),
+ be32_to_cpu(data->devCmdStatus),
+ be32_to_cpu(data->devSecStatus));
if (data->rootErrorStatus || data->uncorrErrorStatus ||
data->corrErrorStatus)
pr_info("RootErrSts: %08x %08x %08x\n",
- data->rootErrorStatus, data->uncorrErrorStatus,
- data->corrErrorStatus);
+ be32_to_cpu(data->rootErrorStatus),
+ be32_to_cpu(data->uncorrErrorStatus),
+ be32_to_cpu(data->corrErrorStatus));
if (data->tlpHdr1 || data->tlpHdr2 ||
data->tlpHdr3 || data->tlpHdr4)
pr_info("RootErrLog: %08x %08x %08x %08x\n",
- data->tlpHdr1, data->tlpHdr2,
- data->tlpHdr3, data->tlpHdr4);
+ be32_to_cpu(data->tlpHdr1),
+ be32_to_cpu(data->tlpHdr2),
+ be32_to_cpu(data->tlpHdr3),
+ be32_to_cpu(data->tlpHdr4));
if (data->sourceId || data->errorClass ||
data->correlator)
pr_info("RootErrLog1: %08x %016llx %016llx\n",
- data->sourceId, data->errorClass,
- data->correlator);
+ be32_to_cpu(data->sourceId),
+ be64_to_cpu(data->errorClass),
+ be64_to_cpu(data->correlator));
if (data->p7iocPlssr || data->p7iocCsr)
pr_info("PhbSts: %016llx %016llx\n",
- data->p7iocPlssr, data->p7iocCsr);
+ be64_to_cpu(data->p7iocPlssr),
+ be64_to_cpu(data->p7iocCsr));
if (data->lemFir)
pr_info("Lem: %016llx %016llx %016llx\n",
- data->lemFir, data->lemErrorMask,
- data->lemWOF);
+ be64_to_cpu(data->lemFir),
+ be64_to_cpu(data->lemErrorMask),
+ be64_to_cpu(data->lemWOF));
if (data->phbErrorStatus)
pr_info("PhbErr: %016llx %016llx %016llx %016llx\n",
- data->phbErrorStatus, data->phbFirstErrorStatus,
- data->phbErrorLog0, data->phbErrorLog1);
+ be64_to_cpu(data->phbErrorStatus),
+ be64_to_cpu(data->phbFirstErrorStatus),
+ be64_to_cpu(data->phbErrorLog0),
+ be64_to_cpu(data->phbErrorLog1));
if (data->mmioErrorStatus)
pr_info("OutErr: %016llx %016llx %016llx %016llx\n",
- data->mmioErrorStatus, data->mmioFirstErrorStatus,
- data->mmioErrorLog0, data->mmioErrorLog1);
+ be64_to_cpu(data->mmioErrorStatus),
+ be64_to_cpu(data->mmioFirstErrorStatus),
+ be64_to_cpu(data->mmioErrorLog0),
+ be64_to_cpu(data->mmioErrorLog1));
if (data->dma0ErrorStatus)
pr_info("InAErr: %016llx %016llx %016llx %016llx\n",
- data->dma0ErrorStatus, data->dma0FirstErrorStatus,
- data->dma0ErrorLog0, data->dma0ErrorLog1);
+ be64_to_cpu(data->dma0ErrorStatus),
+ be64_to_cpu(data->dma0FirstErrorStatus),
+ be64_to_cpu(data->dma0ErrorLog0),
+ be64_to_cpu(data->dma0ErrorLog1));
if (data->dma1ErrorStatus)
pr_info("InBErr: %016llx %016llx %016llx %016llx\n",
- data->dma1ErrorStatus, data->dma1FirstErrorStatus,
- data->dma1ErrorLog0, data->dma1ErrorLog1);
+ be64_to_cpu(data->dma1ErrorStatus),
+ be64_to_cpu(data->dma1FirstErrorStatus),
+ be64_to_cpu(data->dma1ErrorLog0),
+ be64_to_cpu(data->dma1ErrorLog1));
for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
if ((data->pestA[i] >> 63) == 0 &&
@@ -194,7 +211,8 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
continue;
pr_info("PE[%3d] A/B: %016llx %016llx\n",
- i, data->pestA[i], data->pestB[i]);
+ i, be64_to_cpu(data->pestA[i]),
+ be64_to_cpu(data->pestB[i]));
}
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 1/6] powerpc/eeh: Refactor EEH flag accessors
From: Gavin Shan @ 2014-07-17 4:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405572103-32152-1-git-send-email-gwshan@linux.vnet.ibm.com>
There are multiple global EEH flags. Almost each flag has its own
accessor, which doesn't make sense. The patch refactors EEH flag
accessors so that they look unified:
eeh_add_flag(): Add EEH flag
eeh_clear_flag(): Clear EEH flag
eeh_has_flag(): Check if one specific flag has been set
eeh_enabled(): Check if EEH functionality has been enabled
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 32 ++++++++++------------------
arch/powerpc/kernel/eeh.c | 20 ++++++++---------
arch/powerpc/kernel/eeh_cache.c | 2 +-
arch/powerpc/platforms/powernv/eeh-powernv.c | 6 +++---
arch/powerpc/platforms/powernv/pci-ioda.c | 1 -
arch/powerpc/platforms/pseries/eeh_pseries.c | 4 ++--
6 files changed, 27 insertions(+), 38 deletions(-)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 6e47894..ca8aada 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -206,36 +206,28 @@ extern int eeh_subsystem_flags;
extern struct eeh_ops *eeh_ops;
extern raw_spinlock_t confirm_error_lock;
-static inline bool eeh_enabled(void)
+static inline void eeh_add_flag(int flag)
{
- if ((eeh_subsystem_flags & EEH_FORCE_DISABLED) ||
- !(eeh_subsystem_flags & EEH_ENABLED))
- return false;
-
- return true;
+ eeh_subsystem_flags |= flag;
}
-static inline void eeh_set_enable(bool mode)
+static inline void eeh_clear_flag(int flag)
{
- if (mode)
- eeh_subsystem_flags |= EEH_ENABLED;
- else
- eeh_subsystem_flags &= ~EEH_ENABLED;
+ eeh_subsystem_flags &= ~flag;
}
-static inline void eeh_probe_mode_set(int flag)
+static inline bool eeh_has_flag(int flag)
{
- eeh_subsystem_flags |= flag;
+ return !!(eeh_subsystem_flags & flag);
}
-static inline int eeh_probe_mode_devtree(void)
+static inline bool eeh_enabled(void)
{
- return (eeh_subsystem_flags & EEH_PROBE_MODE_DEVTREE);
-}
+ if (eeh_has_flag(EEH_FORCE_DISABLED) ||
+ !eeh_has_flag(EEH_ENABLED))
+ return false;
-static inline int eeh_probe_mode_dev(void)
-{
- return (eeh_subsystem_flags & EEH_PROBE_MODE_DEV);
+ return true;
}
static inline void eeh_serialize_lock(unsigned long *flags)
@@ -314,8 +306,6 @@ static inline bool eeh_enabled(void)
return false;
}
-static inline void eeh_set_enable(bool mode) { }
-
static inline int eeh_init(void)
{
return 0;
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 4de2103..65a163f 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -142,7 +142,7 @@ static struct eeh_stats eeh_stats;
static int __init eeh_setup(char *str)
{
if (!strcmp(str, "off"))
- eeh_subsystem_flags |= EEH_FORCE_DISABLED;
+ eeh_add_flag(EEH_FORCE_DISABLED);
return 1;
}
@@ -252,7 +252,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
* 0xFF's is always returned from PCI config space.
*/
if (!(pe->type & EEH_PE_PHB)) {
- if (eeh_probe_mode_devtree())
+ if (eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
eeh_ops->configure_bridge(pe);
eeh_pe_restore_bars(pe);
@@ -303,7 +303,7 @@ static int eeh_phb_check_failure(struct eeh_pe *pe)
unsigned long flags;
int ret;
- if (!eeh_probe_mode_dev())
+ if (!eeh_has_flag(EEH_PROBE_MODE_DEV))
return -EPERM;
/* Find the PHB PE */
@@ -801,7 +801,7 @@ int __exit eeh_ops_unregister(const char *name)
static int eeh_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *unused)
{
- eeh_set_enable(false);
+ eeh_clear_flag(EEH_ENABLED);
return NOTIFY_DONE;
}
@@ -865,13 +865,13 @@ int eeh_init(void)
return ret;
/* Enable EEH for all adapters */
- if (eeh_probe_mode_devtree()) {
+ if (eeh_has_flag(EEH_PROBE_MODE_DEVTREE)) {
list_for_each_entry_safe(hose, tmp,
&hose_list, list_node) {
phb = hose->dn;
traverse_pci_devices(phb, eeh_ops->of_probe, NULL);
}
- } else if (eeh_probe_mode_dev()) {
+ } else if (eeh_has_flag(EEH_PROBE_MODE_DEV)) {
list_for_each_entry_safe(hose, tmp,
&hose_list, list_node)
pci_walk_bus(hose->bus, eeh_ops->dev_probe, NULL);
@@ -923,7 +923,7 @@ void eeh_add_device_early(struct device_node *dn)
* would delay the probe until late stage because
* the PCI device isn't available this moment.
*/
- if (!eeh_probe_mode_devtree())
+ if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
return;
if (!of_node_to_eeh_dev(dn))
@@ -1009,7 +1009,7 @@ void eeh_add_device_late(struct pci_dev *dev)
* We have to do the EEH probe here because the PCI device
* hasn't been created yet in the early stage.
*/
- if (eeh_probe_mode_dev())
+ if (eeh_has_flag(EEH_PROBE_MODE_DEV))
eeh_ops->dev_probe(dev, NULL);
eeh_addr_cache_insert_dev(dev);
@@ -1430,9 +1430,9 @@ static const struct file_operations proc_eeh_operations = {
static int eeh_enable_dbgfs_set(void *data, u64 val)
{
if (val)
- eeh_subsystem_flags &= ~EEH_FORCE_DISABLED;
+ eeh_clear_flag(EEH_FORCE_DISABLED);
else
- eeh_subsystem_flags |= EEH_FORCE_DISABLED;
+ eeh_add_flag(EEH_FORCE_DISABLED);
/* Notify the backend */
if (eeh_ops->post_init)
diff --git a/arch/powerpc/kernel/eeh_cache.c b/arch/powerpc/kernel/eeh_cache.c
index e8c9fd5..3639bee 100644
--- a/arch/powerpc/kernel/eeh_cache.c
+++ b/arch/powerpc/kernel/eeh_cache.c
@@ -189,7 +189,7 @@ static void __eeh_addr_cache_insert_dev(struct pci_dev *dev)
}
/* Skip any devices for which EEH is not enabled. */
- if (!eeh_probe_mode_dev() && !edev->pe) {
+ if (!edev->pe) {
#ifdef DEBUG
pr_info("PCI: skip building address cache for=%s - %s\n",
pci_name(dev), dn->full_name);
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index 48eb223..ba134ac 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -51,8 +51,8 @@ static int powernv_eeh_init(void)
return -EINVAL;
}
- /* Set EEH probe mode */
- eeh_probe_mode_set(EEH_PROBE_MODE_DEV);
+ /* Set probe mode */
+ eeh_add_flag(EEH_PROBE_MODE_DEV);
return 0;
}
@@ -164,7 +164,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* Enable EEH explicitly so that we will do EEH check
* while accessing I/O stuff
*/
- eeh_set_enable(true);
+ eeh_add_flag(EEH_ENABLED);
/* Save memory bars */
eeh_save_bars(edev);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 91333ea..137e324 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1545,7 +1545,6 @@ static void pnv_pci_ioda_fixup(void)
pnv_pci_ioda_create_dbgfs();
#ifdef CONFIG_EEH
- eeh_probe_mode_set(EEH_PROBE_MODE_DEV);
eeh_init();
eeh_addr_cache_build();
#endif
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 0bec0c0..f173705 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -128,7 +128,7 @@ static int pseries_eeh_init(void)
}
/* Set EEH probe mode */
- eeh_probe_mode_set(EEH_PROBE_MODE_DEVTREE);
+ eeh_add_flag(EEH_PROBE_MODE_DEVTREE);
return 0;
}
@@ -297,7 +297,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
enable = 1;
if (enable) {
- eeh_set_enable(true);
+ eeh_add_flag(EEH_ENABLED);
eeh_add_to_parent_pe(edev);
pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n",
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 6/6] powerpc/eeh: Aux PE data for error log
From: Gavin Shan @ 2014-07-17 4:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405572103-32152-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch allows PE (struct eeh_pe) instance to have auxillary data,
whose size is configurable on basis of platform. For PowerNV, the
auxillary data will be used to cache PHB diag-data for that PE
(frozen PE or fenced PHB). In turn, we can retrieve the diag-data
at any later points.
It's useful for the case of VFIO PCI devices where the error log
should be cached, and then be retrieved by the guest at later point.
Also, it can avoid PHB diag-data overwritting if another frozen PE
reported and the previous diag-data isn't fetched by guest.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 2 ++
arch/powerpc/kernel/eeh_pe.c | 26 ++++++++++++++++-
arch/powerpc/platforms/powernv/eeh-ioda.c | 42 +++++++++++++++++++---------
arch/powerpc/platforms/powernv/eeh-powernv.c | 3 +-
4 files changed, 58 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 494c3ff..9983c3d 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -88,6 +88,7 @@ struct eeh_pe {
int false_positives; /* Times of reported #ff's */
atomic_t pass_dev_cnt; /* Count of passed through devs */
struct eeh_pe *parent; /* Parent PE */
+ void *data; /* PE auxillary data */
struct list_head child_list; /* Link PE to the child list */
struct list_head edevs; /* Link list of EEH devices */
struct list_head child; /* Child PEs */
@@ -248,6 +249,7 @@ static inline void eeh_serialize_unlock(unsigned long flags)
#define EEH_MAX_ALLOWED_FREEZES 5
typedef void *(*eeh_traverse_func)(void *data, void *flag);
+void eeh_set_pe_aux_size(int size);
int eeh_phb_pe_create(struct pci_controller *phb);
struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
struct eeh_pe *eeh_pe_get(struct eeh_dev *edev);
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index 77632ab..00e3844 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -32,9 +32,24 @@
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
+static int eeh_pe_aux_size = 0;
static LIST_HEAD(eeh_phb_pe);
/**
+ * eeh_set_pe_aux_size - Set PE auxillary data size
+ * @size: PE auxillary data size
+ *
+ * Set PE auxillary data size
+ */
+void eeh_set_pe_aux_size(int size)
+{
+ if (size < 0)
+ return;
+
+ eeh_pe_aux_size = size;
+}
+
+/**
* eeh_pe_alloc - Allocate PE
* @phb: PCI controller
* @type: PE type
@@ -44,9 +59,16 @@ static LIST_HEAD(eeh_phb_pe);
static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type)
{
struct eeh_pe *pe;
+ size_t alloc_size;
+
+ alloc_size = sizeof(struct eeh_pe);
+ if (eeh_pe_aux_size) {
+ alloc_size = ALIGN(alloc_size, cache_line_size());
+ alloc_size += eeh_pe_aux_size;
+ }
/* Allocate PHB PE */
- pe = kzalloc(sizeof(struct eeh_pe), GFP_KERNEL);
+ pe = kzalloc(alloc_size, GFP_KERNEL);
if (!pe) return NULL;
/* Initialize PHB PE */
@@ -56,6 +78,8 @@ static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type)
INIT_LIST_HEAD(&pe->child);
INIT_LIST_HEAD(&pe->edevs);
+ pe->data = (void *)pe + ALIGN(sizeof(struct eeh_pe),
+ cache_line_size());
return pe;
}
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index bccdf60..b4624cf 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -236,20 +236,16 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
return ret;
}
-static void ioda_eeh_phb_diag(struct pci_controller *hose)
+static void ioda_eeh_phb_diag(struct eeh_pe *pe)
{
- struct pnv_phb *phb = hose->private_data;
+ struct pnv_phb *phb = pe->phb->private_data;
long rc;
- rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+ rc = opal_pci_get_phb_diag_data2(phb->opal_id, pe->data,
PNV_PCI_DIAG_BUF_SIZE);
- if (rc != OPAL_SUCCESS) {
+ if (rc != OPAL_SUCCESS)
pr_warn("%s: Failed to get diag-data for PHB#%x (%ld)\n",
- __func__, hose->global_number, rc);
- return;
- }
-
- pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
+ __func__, pe->phb->global_number, rc);
}
static int ioda_eeh_get_phb_state(struct eeh_pe *pe)
@@ -282,7 +278,7 @@ static int ioda_eeh_get_phb_state(struct eeh_pe *pe)
EEH_STATE_DMA_ENABLED);
} else if (!(pe->state & EEH_PE_ISOLATED)) {
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
- ioda_eeh_phb_diag(phb->hose);
+ ioda_eeh_phb_diag(pe);
}
return result;
@@ -380,7 +376,7 @@ static int ioda_eeh_get_pe_state(struct eeh_pe *pe)
phb->freeze_pe(phb, pe->addr);
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
- ioda_eeh_phb_diag(phb->hose);
+ ioda_eeh_phb_diag(pe);
}
return result;
@@ -623,6 +619,24 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
}
/**
+ * ioda_eeh_get_log - Retrieve error log
+ * @pe: frozen PE
+ * @severity: permanent or temporary error
+ * @drv_log: device driver log
+ * @len: length of device driver log
+ *
+ * Retrieve error log, which contains log from device driver
+ * and firmware.
+ */
+int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
+ char *drv_log, unsigned long len)
+{
+ pnv_pci_dump_phb_diag_data(pe->phb, pe->data);
+
+ return 0;
+}
+
+/**
* ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
* @pe: EEH PE
*
@@ -860,7 +874,8 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
"detected, location: %s\n",
hose->global_number,
eeh_pe_loc_get(phb_pe));
- ioda_eeh_phb_diag(hose);
+ ioda_eeh_phb_diag(phb_pe);
+ pnv_pci_dump_phb_diag_data(hose, phb_pe->data);
ret = EEH_NEXT_ERR_NONE;
}
@@ -908,7 +923,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
ret == EEH_NEXT_ERR_FENCED_PHB) &&
!((*pe)->state & EEH_PE_ISOLATED)) {
eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
- ioda_eeh_phb_diag(hose);
+ ioda_eeh_phb_diag(*pe);
}
/*
@@ -954,6 +969,7 @@ struct pnv_eeh_ops ioda_eeh_ops = {
.set_option = ioda_eeh_set_option,
.get_state = ioda_eeh_get_state,
.reset = ioda_eeh_reset,
+ .get_log = ioda_eeh_get_log,
.configure_bridge = ioda_eeh_configure_bridge,
.next_error = ioda_eeh_next_error
};
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index f1f5d4b..f5bbc9f 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -326,7 +326,7 @@ static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait)
* Retrieve the temporary or permanent error from the PE.
*/
static int powernv_eeh_get_log(struct eeh_pe *pe, int severity,
- char *drv_log, unsigned long len)
+ char *drv_log, unsigned long len)
{
struct pci_controller *hose = pe->phb;
struct pnv_phb *phb = hose->private_data;
@@ -433,6 +433,7 @@ static int __init eeh_powernv_init(void)
if (!machine_is(powernv))
return ret;
+ eeh_set_pe_aux_size(PNV_PCI_DIAG_BUF_SIZE);
ret = eeh_ops_register(&powernv_eeh_ops);
if (!ret)
pr_info("EEH: PowerNV platform initialized\n");
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 4/6] powerpc/eeh: Replace pr_warning() with pr_warn()
From: Gavin Shan @ 2014-07-17 4:41 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405572103-32152-1-git-send-email-gwshan@linux.vnet.ibm.com>
pr_warn() is equal to pr_warning(), but the former is a bit more
formal according to commit fc62f2f ("kernel.h: add pr_warn for
symmetry to dev_warn, netdev_warn").
The patch replaces pr_warning() with pr_warn().
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh.c | 16 ++++++++--------
arch/powerpc/kernel/eeh_cache.c | 7 ++++---
arch/powerpc/kernel/eeh_dev.c | 3 ++-
arch/powerpc/kernel/eeh_driver.c | 16 ++++++++--------
arch/powerpc/kernel/eeh_pe.c | 3 ++-
arch/powerpc/platforms/powernv/eeh-ioda.c | 12 ++++++------
arch/powerpc/platforms/powernv/eeh-powernv.c | 7 ++++---
arch/powerpc/platforms/pseries/eeh_pseries.c | 28 ++++++++++++++--------------
8 files changed, 48 insertions(+), 44 deletions(-)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index afde505..02a6774 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -337,8 +337,8 @@ static int eeh_phb_check_failure(struct eeh_pe *pe)
/* Find the PHB PE */
phb_pe = eeh_phb_pe_get(pe->phb);
if (!phb_pe) {
- pr_warning("%s Can't find PE for PHB#%d\n",
- __func__, pe->phb->global_number);
+ pr_warn("%s Can't find PE for PHB#%d\n",
+ __func__, pe->phb->global_number);
return -EEXIST;
}
@@ -787,13 +787,13 @@ void eeh_save_bars(struct eeh_dev *edev)
int __init eeh_ops_register(struct eeh_ops *ops)
{
if (!ops->name) {
- pr_warning("%s: Invalid EEH ops name for %p\n",
+ pr_warn("%s: Invalid EEH ops name for %p\n",
__func__, ops);
return -EINVAL;
}
if (eeh_ops && eeh_ops != ops) {
- pr_warning("%s: EEH ops of platform %s already existing (%s)\n",
+ pr_warn("%s: EEH ops of platform %s already existing (%s)\n",
__func__, eeh_ops->name, ops->name);
return -EEXIST;
}
@@ -813,7 +813,7 @@ int __init eeh_ops_register(struct eeh_ops *ops)
int __exit eeh_ops_unregister(const char *name)
{
if (!name || !strlen(name)) {
- pr_warning("%s: Invalid EEH ops name\n",
+ pr_warn("%s: Invalid EEH ops name\n",
__func__);
return -EINVAL;
}
@@ -878,11 +878,11 @@ int eeh_init(void)
/* call platform initialization function */
if (!eeh_ops) {
- pr_warning("%s: Platform EEH operation not found\n",
+ pr_warn("%s: Platform EEH operation not found\n",
__func__);
return -EEXIST;
} else if ((ret = eeh_ops->init())) {
- pr_warning("%s: Failed to call platform init function (%d)\n",
+ pr_warn("%s: Failed to call platform init function (%d)\n",
__func__, ret);
return ret;
}
@@ -923,7 +923,7 @@ int eeh_init(void)
if (eeh_enabled())
pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
else
- pr_warning("EEH: No capable adapters found\n");
+ pr_warn("EEH: No capable adapters found\n");
return ret;
}
diff --git a/arch/powerpc/kernel/eeh_cache.c b/arch/powerpc/kernel/eeh_cache.c
index 3639bee..07d8a24 100644
--- a/arch/powerpc/kernel/eeh_cache.c
+++ b/arch/powerpc/kernel/eeh_cache.c
@@ -143,7 +143,7 @@ eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
} else {
if (dev != piar->pcidev ||
alo != piar->addr_lo || ahi != piar->addr_hi) {
- pr_warning("PIAR: overlapping address range\n");
+ pr_warn("PIAR: overlapping address range\n");
}
return piar;
}
@@ -177,13 +177,14 @@ static void __eeh_addr_cache_insert_dev(struct pci_dev *dev)
dn = pci_device_to_OF_node(dev);
if (!dn) {
- pr_warning("PCI: no pci dn found for dev=%s\n", pci_name(dev));
+ pr_warn("PCI: no pci dn found for dev=%s\n",
+ pci_name(dev));
return;
}
edev = of_node_to_eeh_dev(dn);
if (!edev) {
- pr_warning("PCI: no EEH dev found for dn=%s\n",
+ pr_warn("PCI: no EEH dev found for dn=%s\n",
dn->full_name);
return;
}
diff --git a/arch/powerpc/kernel/eeh_dev.c b/arch/powerpc/kernel/eeh_dev.c
index 1efa28f..e5274ee 100644
--- a/arch/powerpc/kernel/eeh_dev.c
+++ b/arch/powerpc/kernel/eeh_dev.c
@@ -57,7 +57,8 @@ void *eeh_dev_init(struct device_node *dn, void *data)
/* Allocate EEH device */
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
if (!edev) {
- pr_warning("%s: out of memory\n", __func__);
+ pr_warn("%s: out of memory\n",
+ __func__);
return NULL;
}
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 420da61..6a0dcee 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -599,7 +599,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
pe->freeze_count++;
if (pe->freeze_count > EEH_MAX_ALLOWED_FREEZES)
goto excess_failures;
- pr_warning("EEH: This PCI device has failed %d times in the last hour\n",
+ pr_warn("EEH: This PCI device has failed %d times in the last hour\n",
pe->freeze_count);
/* Walk the various device drivers attached to this slot through
@@ -616,7 +616,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
*/
rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000);
if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
- pr_warning("EEH: Permanent failure\n");
+ pr_warn("EEH: Permanent failure\n");
goto hard_fail;
}
@@ -635,8 +635,8 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
pr_info("EEH: Reset with hotplug activity\n");
rc = eeh_reset_device(pe, frozen_bus);
if (rc) {
- pr_warning("%s: Unable to reset, err=%d\n",
- __func__, rc);
+ pr_warn("%s: Unable to reset, err=%d\n",
+ __func__, rc);
goto hard_fail;
}
}
@@ -678,7 +678,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
/* If any device has a hard failure, then shut off everything. */
if (result == PCI_ERS_RESULT_DISCONNECT) {
- pr_warning("EEH: Device driver gave up\n");
+ pr_warn("EEH: Device driver gave up\n");
goto hard_fail;
}
@@ -687,8 +687,8 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
pr_info("EEH: Reset without hotplug activity\n");
rc = eeh_reset_device(pe, NULL);
if (rc) {
- pr_warning("%s: Cannot reset, err=%d\n",
- __func__, rc);
+ pr_warn("%s: Cannot reset, err=%d\n",
+ __func__, rc);
goto hard_fail;
}
@@ -701,7 +701,7 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
/* All devices should claim they have recovered by now. */
if ((result != PCI_ERS_RESULT_RECOVERED) &&
(result != PCI_ERS_RESULT_NONE)) {
- pr_warning("EEH: Not recovered\n");
+ pr_warn("EEH: Not recovered\n");
goto hard_fail;
}
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index 418d79c..77632ab 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -179,7 +179,8 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
void *ret;
if (!root) {
- pr_warning("%s: Invalid PE %p\n", __func__, root);
+ pr_warn("%s: Invalid PE %p\n",
+ __func__, root);
return NULL;
}
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 7f6bee1..edec622 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -244,8 +244,8 @@ static void ioda_eeh_phb_diag(struct pci_controller *hose)
rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
PNV_PCI_DIAG_BUF_SIZE);
if (rc != OPAL_SUCCESS) {
- pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
- __func__, hose->global_number, rc);
+ pr_warn("%s: Failed to get diag-data for PHB#%x (%ld)\n",
+ __func__, hose->global_number, rc);
return;
}
@@ -661,8 +661,8 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
rc = opal_pci_get_hub_diag_data(phb->hub_id, data, sizeof(*data));
if (rc != OPAL_SUCCESS) {
- pr_warning("%s: Failed to get HUB#%llx diag-data (%ld)\n",
- __func__, phb->hub_id, rc);
+ pr_warn("%s: Failed to get HUB#%llx diag-data (%ld)\n",
+ __func__, phb->hub_id, rc);
return;
}
@@ -698,8 +698,8 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
ioda_eeh_hub_diag_common(data);
break;
default:
- pr_warning("%s: Invalid type of HUB#%llx diag-data (%d)\n",
- __func__, phb->hub_id, data->type);
+ pr_warn("%s: Invalid type of HUB#%llx diag-data (%d)\n",
+ __func__, phb->hub_id, data->type);
}
}
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index 740c396..f1f5d4b 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -50,7 +50,8 @@ static int powernv_eeh_init(void)
/* We require OPALv3 */
if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
- pr_warning("%s: OPALv3 is required !\n", __func__);
+ pr_warn("%s: OPALv3 is required !\n",
+ __func__);
return -EINVAL;
}
@@ -304,8 +305,8 @@ static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait)
max_wait -= mwait;
if (max_wait <= 0) {
- pr_warning("%s: Timeout getting PE#%x's state (%d)\n",
- __func__, pe->addr, max_wait);
+ pr_warn("%s: Timeout getting PE#%x's state (%d)\n",
+ __func__, pe->addr, max_wait);
return EEH_STATE_NOT_SUPPORT;
}
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 1e15cdd..a81c063 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -89,26 +89,26 @@ static int pseries_eeh_init(void)
* of domain/bus/slot/function for EEH RTAS operations.
*/
if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) {
- pr_warning("%s: RTAS service <ibm,set-eeh-option> invalid\n",
+ pr_warn("%s: RTAS service <ibm,set-eeh-option> invalid\n",
__func__);
return -EINVAL;
} else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) {
- pr_warning("%s: RTAS service <ibm,set-slot-reset> invalid\n",
+ pr_warn("%s: RTAS service <ibm,set-slot-reset> invalid\n",
__func__);
return -EINVAL;
} else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE &&
ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) {
- pr_warning("%s: RTAS service <ibm,read-slot-reset-state2> and "
+ pr_warn("%s: RTAS service <ibm,read-slot-reset-state2> and "
"<ibm,read-slot-reset-state> invalid\n",
__func__);
return -EINVAL;
} else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) {
- pr_warning("%s: RTAS service <ibm,slot-error-detail> invalid\n",
+ pr_warn("%s: RTAS service <ibm,slot-error-detail> invalid\n",
__func__);
return -EINVAL;
} else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE &&
ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) {
- pr_warning("%s: RTAS service <ibm,configure-pe> and "
+ pr_warn("%s: RTAS service <ibm,configure-pe> and "
"<ibm,configure-bridge> invalid\n",
__func__);
return -EINVAL;
@@ -118,11 +118,11 @@ static int pseries_eeh_init(void)
spin_lock_init(&slot_errbuf_lock);
eeh_error_buf_size = rtas_token("rtas-error-log-max");
if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
- pr_warning("%s: unknown EEH error log size\n",
+ pr_warn("%s: unknown EEH error log size\n",
__func__);
eeh_error_buf_size = 1024;
} else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
- pr_warning("%s: EEH error log size %d exceeds the maximal %d\n",
+ pr_warn("%s: EEH error log size %d exceeds the maximal %d\n",
__func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
}
@@ -270,7 +270,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
/* Retrieve the device address */
regs = of_get_property(dn, "reg", NULL);
if (!regs) {
- pr_warning("%s: OF node property %s::reg not found\n",
+ pr_warn("%s: OF node property %s::reg not found\n",
__func__, dn->full_name);
return NULL;
}
@@ -398,7 +398,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe)
pe->config_addr, BUID_HI(pe->phb->buid),
BUID_LO(pe->phb->buid), 0);
if (ret) {
- pr_warning("%s: Failed to get address for PHB#%d-PE#%x\n",
+ pr_warn("%s: Failed to get address for PHB#%d-PE#%x\n",
__func__, pe->phb->global_number, pe->config_addr);
return 0;
}
@@ -411,7 +411,7 @@ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe)
pe->config_addr, BUID_HI(pe->phb->buid),
BUID_LO(pe->phb->buid), 0);
if (ret) {
- pr_warning("%s: Failed to get address for PHB#%d-PE#%x\n",
+ pr_warn("%s: Failed to get address for PHB#%d-PE#%x\n",
__func__, pe->phb->global_number, pe->config_addr);
return 0;
}
@@ -584,17 +584,17 @@ static int pseries_eeh_wait_state(struct eeh_pe *pe, int max_wait)
return ret;
if (max_wait <= 0) {
- pr_warning("%s: Timeout when getting PE's state (%d)\n",
+ pr_warn("%s: Timeout when getting PE's state (%d)\n",
__func__, max_wait);
return EEH_STATE_NOT_SUPPORT;
}
if (mwait <= 0) {
- pr_warning("%s: Firmware returned bad wait value %d\n",
+ pr_warn("%s: Firmware returned bad wait value %d\n",
__func__, mwait);
mwait = EEH_STATE_MIN_WAIT_TIME;
} else if (mwait > EEH_STATE_MAX_WAIT_TIME) {
- pr_warning("%s: Firmware returned too long wait value %d\n",
+ pr_warn("%s: Firmware returned too long wait value %d\n",
__func__, mwait);
mwait = EEH_STATE_MAX_WAIT_TIME;
}
@@ -675,7 +675,7 @@ static int pseries_eeh_configure_bridge(struct eeh_pe *pe)
}
if (ret)
- pr_warning("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n",
+ pr_warn("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n",
__func__, pe->phb->global_number, pe->addr, ret);
return ret;
--
1.8.3.2
^ permalink raw reply related
* [PATCH] powerpc: Document how we set AIL on guest kernels
From: Michael Ellerman @ 2014-07-17 5:29 UTC (permalink / raw)
To: linuxppc-dev
I spent ten minutes scratching my head, trying to work out where we
enabled relocation on interrupts for guest kernels. Expand the doco to
make it clear.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/kernel/setup_64.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index ee082d771178..d600b3fe5f5c 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -201,7 +201,11 @@ static void cpu_ready_for_interrupts(void)
/* Set IR and DR in PACA MSR */
get_paca()->kernel_msr = MSR_KERNEL;
- /* Enable AIL if supported */
+ /*
+ * Enable AIL if supported, and we are in hypervisor mode. If we are
+ * not in hypervisor mode, we enable relocation-on interrupts later
+ * in pSeries_setup_arch() using the H_SET_MODE hcall.
+ */
if (cpu_has_feature(CPU_FTR_HVMODE) &&
cpu_has_feature(CPU_FTR_ARCH_207S)) {
unsigned long lpcr = mfspr(SPRN_LPCR);
--
1.9.1
^ permalink raw reply related
* Re: Re: Re: [PATCH v5 2/2] [BUGFIX] kprobes: Fix "Failed to find blacklist" error on ia64 and ppc64
From: Masami Hiramatsu @ 2014-07-17 7:10 UTC (permalink / raw)
To: Ingo Molnar
Cc: Jeremy Fitzhardinge, linux-ia64, sparse,
Linux Kernel Mailing List, Paul Mackerras, H. Peter Anvin,
Thomas Gleixner, linux-tip-commits, anil.s.keshavamurthy,
Suzuki K. Poulose, Fenghua Yu, Arnd Bergmann, Rusty Russell,
Chris Wright, yrl.pp-manager.tt, akataria, Tony Luck, Kevin Hao,
Linus Torvalds, rdunlap, Tony Luck, dl9pf, Andrew Morton,
linuxppc-dev, David S. Miller
In-Reply-To: <20140716132838.GA18597@gmail.com>
(2014/07/16 22:28), Ingo Molnar wrote:
>
> * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> wrote:
>
>> (2014/07/15 16:16), Benjamin Herrenschmidt wrote:
>>> On Tue, 2014-07-15 at 13:19 +1000, Michael Ellerman wrote:
>>>
>>>>> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
>>>>> Reported-by: Tony Luck <tony.luck@gmail.com>
>>>>> Tested-by: Tony Luck <tony.luck@intel.com>
>>>>> Cc: Michael Ellerman <mpe@ellerman.id.au>
>>>>
>>>> Tested-by: Michael Ellerman <mpe@ellerman.id.au>
>>>> Acked-by: Michael Ellerman <mpe@ellerman.id.au> (for powerpc)
>>>>
>>>> Ben, can you take this in your tree?
>>>
>>> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>>
>>> That looks more like generic material. Do we have a kprobes maintainer ?
>>> Andrew, do you want to take this ?
>>
>> Yeah, I usually use Ingo's tip tree for kprobes maintenance.
>> Ingo, could you pull this as urgent-for-linus patch?
>
> Mind resending it in a separate thread with all acks added, etc?
OK, I'll resend that soon.
BTW, I missed Suzuki's Signed-off-by in this version,
I'd like to recover that since he made a big bugfix on this.
Thanks,
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com
^ permalink raw reply
* [RESEND PATCH v5] [BUGFIX] kprobes: Fix "Failed to find blacklist" error on ia64 and ppc64
From: Masami Hiramatsu @ 2014-07-17 7:11 UTC (permalink / raw)
To: Ingo Molnar
Cc: Jeremy Fitzhardinge, linux-ia64, sparse, Tony Luck,
Paul Mackerras, H. Peter Anvin, Thomas Gleixner,
linux-tip-commits, anil.s.keshavamurthy, Suzuki K. Poulose,
Fenghua Yu, Arnd Bergmann, Rusty Russell, Chris Wright,
yrl.pp-manager.tt, akataria, Tony Luck, Kevin Hao, Linus Torvalds,
rdunlap, Linux Kernel Mailing List, dl9pf, Andrew Morton,
linuxppc-dev, David S. Miller
On ia64 and ppc64, the function pointer does not point the
entry address of the function, but the address of function
discriptor (which contains the entry address and misc
data.) Since the kprobes passes the function pointer stored
by NOKPROBE_SYMBOL() to kallsyms_lookup_size_offset() for
initalizing its blacklist, it fails and reports many errors
as below.
Failed to find blacklist 0001013168300000
Failed to find blacklist 0001013000f0a000
Failed to find blacklist 000101315f70a000
Failed to find blacklist 000101324c80a000
Failed to find blacklist 0001013063f0a000
Failed to find blacklist 000101327800a000
Failed to find blacklist 0001013277f0a000
Failed to find blacklist 000101315a70a000
Failed to find blacklist 0001013277e0a000
Failed to find blacklist 000101305a20a000
Failed to find blacklist 0001013277d0a000
Failed to find blacklist 00010130bdc0a000
Failed to find blacklist 00010130dc20a000
Failed to find blacklist 000101309a00a000
Failed to find blacklist 0001013277c0a000
Failed to find blacklist 0001013277b0a000
Failed to find blacklist 0001013277a0a000
Failed to find blacklist 000101327790a000
Failed to find blacklist 000101303140a000
Failed to find blacklist 0001013a3280a000
To fix this bug, this introduces function_entry() macro to
retrieve the entry address from the given function pointer,
and uses for kallsyms_lookup_size_offset() while initializing
blacklist.
Changes in v5:
- Use arch_deref_entry_point() instead of function_entry().
Changes in v4:
- Add kernel_text_address() check for verifying the address.
- Moved on the latest linus tree.
Changes in v3:
- Fix a bug to get blacklist address based on function entry
instead of function descriptor. (Suzuki's work, Thanks!)
Changes in V2:
- Use function_entry() macro when lookin up symbols instead
of storing it.
- Update for the latest -next.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Reported-by: Tony Luck <tony.luck@gmail.com>
Tested-by: Tony Luck <tony.luck@intel.com>
Tested-by: Michael Ellerman <mpe@ellerman.id.au>
Acked-by: Michael Ellerman <mpe@ellerman.id.au> (for powerpc)
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Kevin Hao <haokexin@gmail.com>
Cc: linux-ia64@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
---
kernel/kprobes.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 3214289..ec370cc 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -32,6 +32,7 @@
* <prasanna@in.ibm.com> added function-return probes.
*/
#include <linux/kprobes.h>
+#include <linux/types.h>
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -2037,19 +2038,23 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
{
unsigned long *iter;
struct kprobe_blacklist_entry *ent;
- unsigned long offset = 0, size = 0;
+ unsigned long entry, offset = 0, size = 0;
for (iter = start; iter < end; iter++) {
- if (!kallsyms_lookup_size_offset(*iter, &size, &offset)) {
- pr_err("Failed to find blacklist %p\n", (void *)*iter);
+ entry = arch_deref_entry_point((void *)*iter);
+
+ if (!kernel_text_address(entry) ||
+ !kallsyms_lookup_size_offset(entry, &size, &offset)) {
+ pr_err("Failed to find blacklist at %p\n",
+ (void *)entry);
continue;
}
ent = kmalloc(sizeof(*ent), GFP_KERNEL);
if (!ent)
return -ENOMEM;
- ent->start_addr = *iter;
- ent->end_addr = *iter + size;
+ ent->start_addr = entry;
+ ent->end_addr = entry + size;
INIT_LIST_HEAD(&ent->list);
list_add_tail(&ent->list, &kprobe_blacklist);
}
^ permalink raw reply related
* Re: [PATCH v3] Use the POWER8 Micro Partition Prefetch Engine in KVM HV on POWER8
From: Alexander Graf @ 2014-07-17 7:55 UTC (permalink / raw)
To: Stewart Smith, linuxppc-dev, paulus, kvm-ppc
In-Reply-To: <1405567197-23333-1-git-send-email-stewart@linux.vnet.ibm.com>
On 17.07.14 05:19, Stewart Smith wrote:
> The POWER8 processor has a Micro Partition Prefetch Engine, which is
> a fancy way of saying "has way to store and load contents of L2 or
> L2+MRU way of L3 cache". We initiate the storing of the log (list of
> addresses) using the logmpp instruction and start restore by writing
> to a SPR.
>
> The logmpp instruction takes parameters in a single 64bit register:
> - starting address of the table to store log of L2/L2+L3 cache contents
> - 32kb for L2
> - 128kb for L2+L3
> - Aligned relative to maximum size of the table (32kb or 128kb)
> - Log control (no-op, L2 only, L2 and L3, abort logout)
>
> We should abort any ongoing logging before initiating one.
>
> To initiate restore, we write to the MPPR SPR. The format of what to write
> to the SPR is similar to the logmpp instruction parameter:
> - starting address of the table to read from (same alignment requirements)
> - table size (no data, until end of table)
> - prefetch rate (from fastest possible to slower. about every 8, 16, 24 or
> 32 cycles)
>
> The idea behind loading and storing the contents of L2/L3 cache is to
> reduce memory latency in a system that is frequently swapping vcores on
> a physical CPU.
>
> The best case scenario for doing this is when some vcores are doing very
> cache heavy workloads. The worst case is when they have about 0 cache hits,
> so we just generate needless memory operations.
>
> This implementation just does L2 store/load. In my benchmarks this proves
> to be useful.
>
> Benchmark 1:
> - 16 core POWER8
> - 3x Ubuntu 14.04LTS guests (LE) with 8 VCPUs each
> - No split core/SMT
> - two guests running sysbench memory test.
> sysbench --test=memory --num-threads=8 run
> - one guest running apache bench (of default HTML page)
> ab -n 490000 -c 400 http://localhost/
>
> This benchmark aims to measure performance of real world application (apache)
> where other guests are cache hot with their own workloads. The sysbench memory
> benchmark does pointer sized writes to a (small) memory buffer in a loop.
>
> In this benchmark with this patch I can see an improvement both in requests
> per second (~5%) and in mean and median response times (again, about 5%).
> The spread of minimum and maximum response times were largely unchanged.
>
> benchmark 2:
> - Same VM config as benchmark 1
> - all three guests running sysbench memory benchmark
>
> This benchmark aims to see if there is a positive or negative affect to this
> cache heavy benchmark. Although due to the nature of the benchmark (stores) we
> may not see a difference in performance, but rather hopefully an improvement
> in consistency of performance (when vcore switched in, don't have to wait
> many times for cachelines to be pulled in)
>
> The results of this benchmark are improvements in consistency of performance
> rather than performance itself. With this patch, the few outliers in duration
> go away and we get more consistent performance in each guest.
>
> benchmark 3:
> - same 3 guests and CPU configuration as benchmark 1 and 2.
> - two idle guests
> - 1 guest running STREAM benchmark
>
> This scenario also saw performance improvement with this patch. On Copy and
> Scale workloads from STREAM, I got 5-6% improvement with this patch. For
> Add and triad, it was around 10% (or more).
>
> benchmark 4:
> - same 3 guests as previous benchmarks
> - two guests running sysbench --memory, distinctly different cache heavy
> workload
> - one guest running STREAM benchmark.
>
> Similar improvements to benchmark 3.
>
> benchmark 5:
> - 1 guest, 8 VCPUs, Ubuntu 14.04
> - Host configured with split core (SMT8, subcores-per-core=4)
> - STREAM benchmark
>
> In this benchmark, we see a 10-20% performance improvement across the board
> of STREAM benchmark results with this patch.
>
> Based on preliminary investigation and microbenchmarks
> by Prerna Saxena <prerna@linux.vnet.ibm.com>
>
> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
A lot nicer :)
>
> --
> changes since v2:
> - based on feedback from Alexander Graf:
> - move save and restore of cache to separate functions
> - move allocation of mpp_buffer to vcore creation
> - get_free_pages() does actually allocate pages aligned to order
> (Mel Gorman confirms)
> - make SPR and logmpp parameters a bit less magic, especially around abort
>
> changes since v1:
> - s/mppe/mpp_buffer/
> - add MPP_BUFFER_ORDER define.
> ---
> arch/powerpc/include/asm/kvm_host.h | 2 +
> arch/powerpc/include/asm/ppc-opcode.h | 17 +++++++
> arch/powerpc/include/asm/reg.h | 1 +
> arch/powerpc/kvm/book3s_hv.c | 89 +++++++++++++++++++++++++++++----
> 4 files changed, 98 insertions(+), 11 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
> index 1eaea2d..5769497 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -305,6 +305,8 @@ struct kvmppc_vcore {
> u32 arch_compat;
> ulong pcr;
> ulong dpdes; /* doorbell state (POWER8) */
> + unsigned long mpp_buffer; /* Micro Partition Prefetch buffer */
Just make this a void*?
> + bool mpp_buffer_is_valid;
> };
>
> #define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff)
> diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
> index 3132bb9..c636841 100644
> --- a/arch/powerpc/include/asm/ppc-opcode.h
> +++ b/arch/powerpc/include/asm/ppc-opcode.h
> @@ -139,6 +139,7 @@
> #define PPC_INST_ISEL 0x7c00001e
> #define PPC_INST_ISEL_MASK 0xfc00003e
> #define PPC_INST_LDARX 0x7c0000a8
> +#define PPC_INST_LOGMPP 0x7c0007e4
> #define PPC_INST_LSWI 0x7c0004aa
> #define PPC_INST_LSWX 0x7c00042a
> #define PPC_INST_LWARX 0x7c000028
> @@ -275,6 +276,20 @@
> #define __PPC_EH(eh) 0
> #endif
>
> +/* POWER8 Micro Partition Prefetch (MPP) parameters */
> +/* Address mask is common for LOGMPP instruction and MPPR SPR */
> +#define PPC_MPPE_ADDRESS_MASK 0xffffffffc000
> +
> +/* Bits 60 and 61 of MPP SPR should be set to one of the following */
> +/* Aborting the fetch is indeed setting 00 in the table size bits */
> +#define PPC_MPPR_FETCH_ABORT (0x0ULL << 60)
> +#define PPC_MPPR_FETCH_WHOLE_TABLE (0x2ULL << 60)
> +
> +/* Bits 54 and 55 of register for LOGMPP instruction should be set to: */
> +#define PPC_LOGMPP_LOG_L2 (0x02ULL << 54)
> +#define PPC_LOGMPP_LOG_L2L3 (0x01ULL << 54)
> +#define PPC_LOGMPP_LOG_ABORT (0x03ULL << 54)
> +
> /* Deal with instructions that older assemblers aren't aware of */
> #define PPC_DCBAL(a, b) stringify_in_c(.long PPC_INST_DCBAL | \
> __PPC_RA(a) | __PPC_RB(b))
> @@ -283,6 +298,8 @@
> #define PPC_LDARX(t, a, b, eh) stringify_in_c(.long PPC_INST_LDARX | \
> ___PPC_RT(t) | ___PPC_RA(a) | \
> ___PPC_RB(b) | __PPC_EH(eh))
> +#define PPC_LOGMPP(b) stringify_in_c(.long PPC_INST_LOGMPP | \
> + __PPC_RB(b))
> #define PPC_LWARX(t, a, b, eh) stringify_in_c(.long PPC_INST_LWARX | \
> ___PPC_RT(t) | ___PPC_RA(a) | \
> ___PPC_RB(b) | __PPC_EH(eh))
> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
> index e5d2e0b..5164beb 100644
> --- a/arch/powerpc/include/asm/reg.h
> +++ b/arch/powerpc/include/asm/reg.h
> @@ -224,6 +224,7 @@
> #define CTRL_TE 0x00c00000 /* thread enable */
> #define CTRL_RUNLATCH 0x1
> #define SPRN_DAWR 0xB4
> +#define SPRN_MPPR 0xB8 /* Micro Partition Prefetch Register */
> #define SPRN_CIABR 0xBB
> #define CIABR_PRIV 0x3
> #define CIABR_PRIV_USER 1
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 8227dba..b5a8b11 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -67,6 +67,13 @@
> /* Used as a "null" value for timebase values */
> #define TB_NIL (~(u64)0)
>
> +#if defined(CONFIG_PPC_64K_PAGES)
> +#define MPP_BUFFER_ORDER 0
> +#elif defined(CONFIG_PPC_4K_PAGES)
> +#define MPP_BUFFER_ORDER 4
> +#endif
> +
> +
> static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
> static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
>
> @@ -1258,6 +1265,32 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
> return r;
> }
>
> +static struct kvmppc_vcore *kvmppc_vcore_create(struct kvm *kvm, int core)
> +{
> + struct kvmppc_vcore *vcore;
> +
> + vcore = kzalloc(sizeof(struct kvmppc_vcore), GFP_KERNEL);
> +
> + if (vcore == NULL)
> + return NULL;
> +
> + INIT_LIST_HEAD(&vcore->runnable_threads);
> + spin_lock_init(&vcore->lock);
> + init_waitqueue_head(&vcore->wq);
> + vcore->preempt_tb = TB_NIL;
> + vcore->lpcr = kvm->arch.lpcr;
> + vcore->first_vcpuid = core * threads_per_core;
> + vcore->kvm = kvm;
> +
> + vcore->mpp_buffer_is_valid = false;
> +
> + if (cpu_has_feature(CPU_FTR_ARCH_207S))
> + vcore->mpp_buffer = __get_free_pages(GFP_KERNEL|__GFP_ZERO,
> + MPP_BUFFER_ORDER);
> +
> + return vcore;
> +}
> +
> static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
> unsigned int id)
> {
> @@ -1298,16 +1331,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
> mutex_lock(&kvm->lock);
> vcore = kvm->arch.vcores[core];
> if (!vcore) {
> - vcore = kzalloc(sizeof(struct kvmppc_vcore), GFP_KERNEL);
> - if (vcore) {
> - INIT_LIST_HEAD(&vcore->runnable_threads);
> - spin_lock_init(&vcore->lock);
> - init_waitqueue_head(&vcore->wq);
> - vcore->preempt_tb = TB_NIL;
> - vcore->lpcr = kvm->arch.lpcr;
> - vcore->first_vcpuid = core * threads_per_core;
> - vcore->kvm = kvm;
> - }
> + vcore = kvmppc_vcore_create(kvm, core);
> kvm->arch.vcores[core] = vcore;
> kvm->arch.online_vcores++;
> }
> @@ -1516,6 +1540,37 @@ static int on_primary_thread(void)
> return 1;
> }
>
> +static void ppc_start_saving_l2_cache(struct kvmppc_vcore *vc)
Please use the "kvmppc" name space.
> +{
> + phys_addr_t phy_addr, tmp;
> +
> + phy_addr = (phys_addr_t)virt_to_phys((void *)vc->mpp_buffer);
> +
> + tmp = phy_addr & PPC_MPPE_ADDRESS_MASK;
I would prefer if you give the variable a more telling name.
> +
> + mtspr(SPRN_MPPR, tmp | PPC_MPPR_FETCH_ABORT);
> +
> + asm volatile(PPC_LOGMPP(R1) : : "r" (tmp | PPC_LOGMPP_LOG_L2));
Can you move this asm() into a static inline function in generic code
somewhere?
> +
> + vc->mpp_buffer_is_valid = true;
Where does this ever get unset? And what point does this variable make?
Can't you just check on if (vc->mpp_buffer)?
Also, a single whitespace line between every instruction you do looks
weird ;). When you have the feeling that the code flow is weird enough
that you need empty lines between every real line, there's probably
something wrong in the code flow :).
Alex
> +}
> +
> +static void ppc_start_restoring_l2_cache(const struct kvmppc_vcore *vc)
> +{
> + phys_addr_t phy_addr, tmp;
> +
> + phy_addr = virt_to_phys((void *)vc->mpp_buffer);
> +
> + tmp = phy_addr & PPC_MPPE_ADDRESS_MASK;
> +
> + /* We must abort any in-progress save operations to ensure
> + * the table is valid so that prefetch engine knows when to
> + * stop prefetching. */
> + asm volatile(PPC_LOGMPP(R1) : : "r" (tmp | PPC_LOGMPP_LOG_ABORT));
> +
> + mtspr(SPRN_MPPR, tmp | PPC_MPPR_FETCH_WHOLE_TABLE);
> +}
> +
> /*
> * Run a set of guest threads on a physical core.
> * Called with vc->lock held.
> @@ -1590,9 +1645,16 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
>
> srcu_idx = srcu_read_lock(&vc->kvm->srcu);
>
> + if (vc->mpp_buffer_is_valid)
> + ppc_start_restoring_l2_cache(vc);
> +
> __kvmppc_vcore_entry();
>
> spin_lock(&vc->lock);
> +
> + if (vc->mpp_buffer)
> + ppc_start_saving_l2_cache(vc);
> +
> /* disable sending of IPIs on virtual external irqs */
> list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
> vcpu->cpu = -1;
> @@ -2329,8 +2391,13 @@ static void kvmppc_free_vcores(struct kvm *kvm)
> {
> long int i;
>
> - for (i = 0; i < KVM_MAX_VCORES; ++i)
> + for (i = 0; i < KVM_MAX_VCORES; ++i) {
> + if (kvm->arch.vcores[i] && kvm->arch.vcores[i]->mpp_buffer) {
> + free_pages(kvm->arch.vcores[i]->mpp_buffer,
> + MPP_BUFFER_ORDER);
> + }
> kfree(kvm->arch.vcores[i]);
> + }
> kvm->arch.online_vcores = 0;
> }
>
^ permalink raw reply
* Re: [PATCH v3 -next 5/9] CMA: generalize CMA reserved area management functionality
From: Marek Szyprowski @ 2014-07-17 8:52 UTC (permalink / raw)
To: Joonsoo Kim, Andrew Morton, Aneesh Kumar K.V, Michal Nazarewicz
Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
Minchan Kim, Paul Mackerras, Paolo Bonzini, Zhang Yanfei,
linuxppc-dev, linux-arm-kernel
In-Reply-To: <1402897251-23639-6-git-send-email-iamjoonsoo.kim@lge.com>
Hello,
On 2014-06-16 07:40, Joonsoo Kim wrote:
> Currently, there are two users on CMA functionality, one is the DMA
> subsystem and the other is the KVM on powerpc. They have their own code
> to manage CMA reserved area even if they looks really similar.
> >From my guess, it is caused by some needs on bitmap management. KVM side
> wants to maintain bitmap not for 1 page, but for more size. Eventually it
> use bitmap where one bit represents 64 pages.
>
> When I implement CMA related patches, I should change those two places
> to apply my change and it seem to be painful to me. I want to change
> this situation and reduce future code management overhead through
> this patch.
>
> This change could also help developer who want to use CMA in their
> new feature development, since they can use CMA easily without
> copying & pasting this reserved area management code.
>
> In previous patches, we have prepared some features to generalize
> CMA reserved area management and now it's time to do it. This patch
> moves core functions to mm/cma.c and change DMA APIs to use
> these functions.
>
> There is no functional change in DMA APIs.
>
> v2: There is no big change from v1 in mm/cma.c. Mostly renaming.
> v3: remove log2.h in dma-contiguous.c (Minchan)
> add some accessor functions to pass aligned base and size to
> dma_contiguous_early_fixup() function
> move MAX_CMA_AREAS to cma.h
I've just noticed that MAX_CMA_AREAS is used also by
arch/arm/mm/dma-mapping.c,
so we need to provide correct definition if CMA is disabled in kconfig.
I will
send a fixup patch in a few minutes.
> Acked-by: Michal Nazarewicz <mina86@mina86.com>
> Acked-by: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
> Acked-by: Minchan Kim <minchan@kernel.org>
> Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
>
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index 4c88935..3116880 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -26,6 +26,7 @@
> #include <linux/io.h>
> #include <linux/vmalloc.h>
> #include <linux/sizes.h>
> +#include <linux/cma.h>
>
> #include <asm/memory.h>
> #include <asm/highmem.h>
> diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
> index 00e13ce..4eac559 100644
> --- a/drivers/base/Kconfig
> +++ b/drivers/base/Kconfig
> @@ -283,16 +283,6 @@ config CMA_ALIGNMENT
>
> If unsure, leave the default value "8".
>
> -config CMA_AREAS
> - int "Maximum count of the CMA device-private areas"
> - default 7
> - help
> - CMA allows to create CMA areas for particular devices. This parameter
> - sets the maximum number of such device private CMA areas in the
> - system.
> -
> - If unsure, leave the default value "7".
> -
> endif
>
> endmenu
> diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
> index c6eeb2c..0411c1c 100644
> --- a/drivers/base/dma-contiguous.c
> +++ b/drivers/base/dma-contiguous.c
> @@ -24,25 +24,9 @@
>
> #include <linux/memblock.h>
> #include <linux/err.h>
> -#include <linux/mm.h>
> -#include <linux/mutex.h>
> -#include <linux/page-isolation.h>
> #include <linux/sizes.h>
> -#include <linux/slab.h>
> -#include <linux/swap.h>
> -#include <linux/mm_types.h>
> #include <linux/dma-contiguous.h>
> -#include <linux/log2.h>
> -
> -struct cma {
> - unsigned long base_pfn;
> - unsigned long count;
> - unsigned long *bitmap;
> - unsigned int order_per_bit; /* Order of pages represented by one bit */
> - struct mutex lock;
> -};
> -
> -struct cma *dma_contiguous_default_area;
> +#include <linux/cma.h>
>
> #ifdef CONFIG_CMA_SIZE_MBYTES
> #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
> @@ -50,6 +34,8 @@ struct cma *dma_contiguous_default_area;
> #define CMA_SIZE_MBYTES 0
> #endif
>
> +struct cma *dma_contiguous_default_area;
> +
> /*
> * Default global CMA area size can be defined in kernel's .config.
> * This is useful mainly for distro maintainers to create a kernel
> @@ -156,169 +142,6 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
> }
> }
>
> -static DEFINE_MUTEX(cma_mutex);
> -
> -static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
> -{
> - return (1 << (align_order >> cma->order_per_bit)) - 1;
> -}
> -
> -static unsigned long cma_bitmap_maxno(struct cma *cma)
> -{
> - return cma->count >> cma->order_per_bit;
> -}
> -
> -static unsigned long cma_bitmap_pages_to_bits(struct cma *cma,
> - unsigned long pages)
> -{
> - return ALIGN(pages, 1 << cma->order_per_bit) >> cma->order_per_bit;
> -}
> -
> -static void cma_clear_bitmap(struct cma *cma, unsigned long pfn, int count)
> -{
> - unsigned long bitmap_no, bitmap_count;
> -
> - bitmap_no = (pfn - cma->base_pfn) >> cma->order_per_bit;
> - bitmap_count = cma_bitmap_pages_to_bits(cma, count);
> -
> - mutex_lock(&cma->lock);
> - bitmap_clear(cma->bitmap, bitmap_no, bitmap_count);
> - mutex_unlock(&cma->lock);
> -}
> -
> -static int __init cma_activate_area(struct cma *cma)
> -{
> - int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma)) * sizeof(long);
> - unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
> - unsigned i = cma->count >> pageblock_order;
> - struct zone *zone;
> -
> - cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
> -
> - if (!cma->bitmap)
> - return -ENOMEM;
> -
> - WARN_ON_ONCE(!pfn_valid(pfn));
> - zone = page_zone(pfn_to_page(pfn));
> -
> - do {
> - unsigned j;
> - base_pfn = pfn;
> - for (j = pageblock_nr_pages; j; --j, pfn++) {
> - WARN_ON_ONCE(!pfn_valid(pfn));
> - /*
> - * alloc_contig_range requires the pfn range
> - * specified to be in the same zone. Make this
> - * simple by forcing the entire CMA resv range
> - * to be in the same zone.
> - */
> - if (page_zone(pfn_to_page(pfn)) != zone)
> - goto err;
> - }
> - init_cma_reserved_pageblock(pfn_to_page(base_pfn));
> - } while (--i);
> -
> - mutex_init(&cma->lock);
> - return 0;
> -
> -err:
> - kfree(cma->bitmap);
> - return -EINVAL;
> -}
> -
> -static struct cma cma_areas[MAX_CMA_AREAS];
> -static unsigned cma_area_count;
> -
> -static int __init cma_init_reserved_areas(void)
> -{
> - int i;
> -
> - for (i = 0; i < cma_area_count; i++) {
> - int ret = cma_activate_area(&cma_areas[i]);
> - if (ret)
> - return ret;
> - }
> -
> - return 0;
> -}
> -core_initcall(cma_init_reserved_areas);
> -
> -static int __init __dma_contiguous_reserve_area(phys_addr_t size,
> - phys_addr_t base, phys_addr_t limit,
> - phys_addr_t alignment, unsigned int order_per_bit,
> - struct cma **res_cma, bool fixed)
> -{
> - struct cma *cma = &cma_areas[cma_area_count];
> - int ret = 0;
> -
> - pr_debug("%s(size %lx, base %08lx, limit %08lx alignment %08lx)\n",
> - __func__, (unsigned long)size, (unsigned long)base,
> - (unsigned long)limit, (unsigned long)alignment);
> -
> - if (cma_area_count == ARRAY_SIZE(cma_areas)) {
> - pr_err("Not enough slots for CMA reserved regions!\n");
> - return -ENOSPC;
> - }
> -
> - if (!size)
> - return -EINVAL;
> -
> - if (alignment && !is_power_of_2(alignment))
> - return -EINVAL;
> -
> - /*
> - * Sanitise input arguments.
> - * Pages both ends in CMA area could be merged into adjacent unmovable
> - * migratetype page by page allocator's buddy algorithm. In the case,
> - * you couldn't get a contiguous memory, which is not what we want.
> - */
> - alignment = max(alignment,
> - (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
> - base = ALIGN(base, alignment);
> - size = ALIGN(size, alignment);
> - limit &= ~(alignment - 1);
> -
> - /* size should be aligned with order_per_bit */
> - if (!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit))
> - return -EINVAL;
> -
> - /* Reserve memory */
> - if (base && fixed) {
> - if (memblock_is_region_reserved(base, size) ||
> - memblock_reserve(base, size) < 0) {
> - ret = -EBUSY;
> - goto err;
> - }
> - } else {
> - phys_addr_t addr = memblock_alloc_range(size, alignment, base,
> - limit);
> - if (!addr) {
> - ret = -ENOMEM;
> - goto err;
> - } else {
> - base = addr;
> - }
> - }
> -
> - /*
> - * Each reserved area must be initialised later, when more kernel
> - * subsystems (like slab allocator) are available.
> - */
> - cma->base_pfn = PFN_DOWN(base);
> - cma->count = size >> PAGE_SHIFT;
> - cma->order_per_bit = order_per_bit;
> - *res_cma = cma;
> - cma_area_count++;
> -
> - pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
> - (unsigned long)base);
> - return 0;
> -
> -err:
> - pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
> - return ret;
> -}
> -
> /**
> * dma_contiguous_reserve_area() - reserve custom contiguous area
> * @size: Size of the reserved area (in bytes),
> @@ -342,77 +165,17 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
> {
> int ret;
>
> - ret = __dma_contiguous_reserve_area(size, base, limit, 0, 0,
> - res_cma, fixed);
> + ret = cma_declare_contiguous(size, base, limit, 0, 0, res_cma, fixed);
> if (ret)
> return ret;
>
> /* Architecture specific contiguous memory fixup. */
> - dma_contiguous_early_fixup(PFN_PHYS((*res_cma)->base_pfn),
> - (*res_cma)->count << PAGE_SHIFT);
> + dma_contiguous_early_fixup(cma_get_base(*res_cma),
> + cma_get_size(*res_cma));
>
> return 0;
> }
>
> -static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
> - unsigned int align)
> -{
> - unsigned long mask, pfn, start = 0;
> - unsigned long bitmap_maxno, bitmap_no, bitmap_count;
> - struct page *page = NULL;
> - int ret;
> -
> - if (!cma || !cma->count)
> - return NULL;
> -
> - pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma,
> - count, align);
> -
> - if (!count)
> - return NULL;
> -
> - mask = cma_bitmap_aligned_mask(cma, align);
> - bitmap_maxno = cma_bitmap_maxno(cma);
> - bitmap_count = cma_bitmap_pages_to_bits(cma, count);
> -
> - for (;;) {
> - mutex_lock(&cma->lock);
> - bitmap_no = bitmap_find_next_zero_area(cma->bitmap,
> - bitmap_maxno, start, bitmap_count, mask);
> - if (bitmap_no >= bitmap_maxno) {
> - mutex_unlock(&cma->lock);
> - break;
> - }
> - bitmap_set(cma->bitmap, bitmap_no, bitmap_count);
> - /*
> - * It's safe to drop the lock here. We've marked this region for
> - * our exclusive use. If the migration fails we will take the
> - * lock again and unmark it.
> - */
> - mutex_unlock(&cma->lock);
> -
> - pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit);
> - mutex_lock(&cma_mutex);
> - ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
> - mutex_unlock(&cma_mutex);
> - if (ret == 0) {
> - page = pfn_to_page(pfn);
> - break;
> - } else if (ret != -EBUSY) {
> - cma_clear_bitmap(cma, pfn, count);
> - break;
> - }
> - cma_clear_bitmap(cma, pfn, count);
> - pr_debug("%s(): memory range at %p is busy, retrying\n",
> - __func__, pfn_to_page(pfn));
> - /* try again with a bit different memory target */
> - start = bitmap_no + mask + 1;
> - }
> -
> - pr_debug("%s(): returned %p\n", __func__, page);
> - return page;
> -}
> -
> /**
> * dma_alloc_from_contiguous() - allocate pages from contiguous area
> * @dev: Pointer to device for which the allocation is performed.
> @@ -427,35 +190,10 @@ static struct page *__dma_alloc_from_contiguous(struct cma *cma, int count,
> struct page *dma_alloc_from_contiguous(struct device *dev, int count,
> unsigned int align)
> {
> - struct cma *cma = dev_get_cma_area(dev);
> -
> if (align > CONFIG_CMA_ALIGNMENT)
> align = CONFIG_CMA_ALIGNMENT;
>
> - return __dma_alloc_from_contiguous(cma, count, align);
> -}
> -
> -static bool __dma_release_from_contiguous(struct cma *cma, struct page *pages,
> - int count)
> -{
> - unsigned long pfn;
> -
> - if (!cma || !pages)
> - return false;
> -
> - pr_debug("%s(page %p)\n", __func__, (void *)pages);
> -
> - pfn = page_to_pfn(pages);
> -
> - if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
> - return false;
> -
> - VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
> -
> - free_contig_range(pfn, count);
> - cma_clear_bitmap(cma, pfn, count);
> -
> - return true;
> + return cma_alloc(dev_get_cma_area(dev), count, align);
> }
>
> /**
> @@ -471,7 +209,5 @@ static bool __dma_release_from_contiguous(struct cma *cma, struct page *pages,
> bool dma_release_from_contiguous(struct device *dev, struct page *pages,
> int count)
> {
> - struct cma *cma = dev_get_cma_area(dev);
> -
> - return __dma_release_from_contiguous(cma, pages, count);
> + return cma_release(dev_get_cma_area(dev), pages, count);
> }
> diff --git a/include/linux/cma.h b/include/linux/cma.h
> new file mode 100644
> index 0000000..69d3726
> --- /dev/null
> +++ b/include/linux/cma.h
> @@ -0,0 +1,21 @@
> +#ifndef __CMA_H__
> +#define __CMA_H__
> +
> +/*
> + * There is always at least global CMA area and a few optional
> + * areas configured in kernel .config.
> + */
> +#define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS)
> +
> +struct cma;
> +
> +extern phys_addr_t cma_get_base(struct cma *cma);
> +extern unsigned long cma_get_size(struct cma *cma);
> +
> +extern int __init cma_declare_contiguous(phys_addr_t size,
> + phys_addr_t base, phys_addr_t limit,
> + phys_addr_t alignment, unsigned int order_per_bit,
> + struct cma **res_cma, bool fixed);
> +extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
> +extern bool cma_release(struct cma *cma, struct page *pages, int count);
> +#endif
> diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
> index 772eab5..569bbd0 100644
> --- a/include/linux/dma-contiguous.h
> +++ b/include/linux/dma-contiguous.h
> @@ -53,18 +53,13 @@
>
> #ifdef __KERNEL__
>
> +#include <linux/device.h>
> +
> struct cma;
> struct page;
> -struct device;
>
> #ifdef CONFIG_DMA_CMA
>
> -/*
> - * There is always at least global CMA area and a few optional device
> - * private areas configured in kernel .config.
> - */
> -#define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS)
> -
> extern struct cma *dma_contiguous_default_area;
>
> static inline struct cma *dev_get_cma_area(struct device *dev)
> @@ -123,8 +118,6 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
>
> #else
>
> -#define MAX_CMA_AREAS (0)
> -
> static inline struct cma *dev_get_cma_area(struct device *dev)
> {
> return NULL;
> diff --git a/mm/Kconfig b/mm/Kconfig
> index 3e9977a..f4899ec 100644
> --- a/mm/Kconfig
> +++ b/mm/Kconfig
> @@ -508,6 +508,17 @@ config CMA_DEBUG
> processing calls such as dma_alloc_from_contiguous().
> This option does not affect warning and error messages.
>
> +config CMA_AREAS
> + int "Maximum count of the CMA areas"
> + depends on CMA
> + default 7
> + help
> + CMA allows to create CMA areas for particular purpose, mainly,
> + used as device private area. This parameter sets the maximum
> + number of CMA area in the system.
> +
> + If unsure, leave the default value "7".
> +
> config ZBUD
> tristate
> default n
> diff --git a/mm/Makefile b/mm/Makefile
> index 1eaa70b..bc0422b 100644
> --- a/mm/Makefile
> +++ b/mm/Makefile
> @@ -62,3 +62,4 @@ obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
> obj-$(CONFIG_ZBUD) += zbud.o
> obj-$(CONFIG_ZSMALLOC) += zsmalloc.o
> obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o
> +obj-$(CONFIG_CMA) += cma.o
> diff --git a/mm/cma.c b/mm/cma.c
> new file mode 100644
> index 0000000..0cf50da
> --- /dev/null
> +++ b/mm/cma.c
> @@ -0,0 +1,333 @@
> +/*
> + * Contiguous Memory Allocator
> + *
> + * Copyright (c) 2010-2011 by Samsung Electronics.
> + * Copyright IBM Corporation, 2013
> + * Copyright LG Electronics Inc., 2014
> + * Written by:
> + * Marek Szyprowski <m.szyprowski@samsung.com>
> + * Michal Nazarewicz <mina86@mina86.com>
> + * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> + * Joonsoo Kim <iamjoonsoo.kim@lge.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of the
> + * License or (at your optional) any later version of the license.
> + */
> +
> +#define pr_fmt(fmt) "cma: " fmt
> +
> +#ifdef CONFIG_CMA_DEBUG
> +#ifndef DEBUG
> +# define DEBUG
> +#endif
> +#endif
> +
> +#include <linux/memblock.h>
> +#include <linux/err.h>
> +#include <linux/mm.h>
> +#include <linux/mutex.h>
> +#include <linux/sizes.h>
> +#include <linux/slab.h>
> +#include <linux/log2.h>
> +#include <linux/cma.h>
> +
> +struct cma {
> + unsigned long base_pfn;
> + unsigned long count;
> + unsigned long *bitmap;
> + unsigned int order_per_bit; /* Order of pages represented by one bit */
> + struct mutex lock;
> +};
> +
> +static struct cma cma_areas[MAX_CMA_AREAS];
> +static unsigned cma_area_count;
> +static DEFINE_MUTEX(cma_mutex);
> +
> +phys_addr_t cma_get_base(struct cma *cma)
> +{
> + return PFN_PHYS(cma->base_pfn);
> +}
> +
> +unsigned long cma_get_size(struct cma *cma)
> +{
> + return cma->count << PAGE_SHIFT;
> +}
> +
> +static unsigned long cma_bitmap_aligned_mask(struct cma *cma, int align_order)
> +{
> + return (1 << (align_order >> cma->order_per_bit)) - 1;
> +}
> +
> +static unsigned long cma_bitmap_maxno(struct cma *cma)
> +{
> + return cma->count >> cma->order_per_bit;
> +}
> +
> +static unsigned long cma_bitmap_pages_to_bits(struct cma *cma,
> + unsigned long pages)
> +{
> + return ALIGN(pages, 1 << cma->order_per_bit) >> cma->order_per_bit;
> +}
> +
> +static void cma_clear_bitmap(struct cma *cma, unsigned long pfn, int count)
> +{
> + unsigned long bitmap_no, bitmap_count;
> +
> + bitmap_no = (pfn - cma->base_pfn) >> cma->order_per_bit;
> + bitmap_count = cma_bitmap_pages_to_bits(cma, count);
> +
> + mutex_lock(&cma->lock);
> + bitmap_clear(cma->bitmap, bitmap_no, bitmap_count);
> + mutex_unlock(&cma->lock);
> +}
> +
> +static int __init cma_activate_area(struct cma *cma)
> +{
> + int bitmap_size = BITS_TO_LONGS(cma_bitmap_maxno(cma)) * sizeof(long);
> + unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
> + unsigned i = cma->count >> pageblock_order;
> + struct zone *zone;
> +
> + cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
> +
> + if (!cma->bitmap)
> + return -ENOMEM;
> +
> + WARN_ON_ONCE(!pfn_valid(pfn));
> + zone = page_zone(pfn_to_page(pfn));
> +
> + do {
> + unsigned j;
> +
> + base_pfn = pfn;
> + for (j = pageblock_nr_pages; j; --j, pfn++) {
> + WARN_ON_ONCE(!pfn_valid(pfn));
> + /*
> + * alloc_contig_range requires the pfn range
> + * specified to be in the same zone. Make this
> + * simple by forcing the entire CMA resv range
> + * to be in the same zone.
> + */
> + if (page_zone(pfn_to_page(pfn)) != zone)
> + goto err;
> + }
> + init_cma_reserved_pageblock(pfn_to_page(base_pfn));
> + } while (--i);
> +
> + mutex_init(&cma->lock);
> + return 0;
> +
> +err:
> + kfree(cma->bitmap);
> + return -EINVAL;
> +}
> +
> +static int __init cma_init_reserved_areas(void)
> +{
> + int i;
> +
> + for (i = 0; i < cma_area_count; i++) {
> + int ret = cma_activate_area(&cma_areas[i]);
> +
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +core_initcall(cma_init_reserved_areas);
> +
> +/**
> + * cma_declare_contiguous() - reserve custom contiguous area
> + * @size: Size of the reserved area (in bytes),
> + * @base: Base address of the reserved area optional, use 0 for any
> + * @limit: End address of the reserved memory (optional, 0 for any).
> + * @alignment: Alignment for the CMA area, should be power of 2 or zero
> + * @order_per_bit: Order of pages represented by one bit on bitmap.
> + * @res_cma: Pointer to store the created cma region.
> + * @fixed: hint about where to place the reserved area
> + *
> + * This function reserves memory from early allocator. It should be
> + * called by arch specific code once the early allocator (memblock or bootmem)
> + * has been activated and all other subsystems have already allocated/reserved
> + * memory. This function allows to create custom reserved areas.
> + *
> + * If @fixed is true, reserve contiguous area at exactly @base. If false,
> + * reserve in range from @base to @limit.
> + */
> +int __init cma_declare_contiguous(phys_addr_t size,
> + phys_addr_t base, phys_addr_t limit,
> + phys_addr_t alignment, unsigned int order_per_bit,
> + struct cma **res_cma, bool fixed)
> +{
> + struct cma *cma = &cma_areas[cma_area_count];
> + int ret = 0;
> +
> + pr_debug("%s(size %lx, base %08lx, limit %08lx alignment %08lx)\n",
> + __func__, (unsigned long)size, (unsigned long)base,
> + (unsigned long)limit, (unsigned long)alignment);
> +
> + if (cma_area_count == ARRAY_SIZE(cma_areas)) {
> + pr_err("Not enough slots for CMA reserved regions!\n");
> + return -ENOSPC;
> + }
> +
> + if (!size)
> + return -EINVAL;
> +
> + if (alignment && !is_power_of_2(alignment))
> + return -EINVAL;
> +
> + /*
> + * Sanitise input arguments.
> + * Pages both ends in CMA area could be merged into adjacent unmovable
> + * migratetype page by page allocator's buddy algorithm. In the case,
> + * you couldn't get a contiguous memory, which is not what we want.
> + */
> + alignment = max(alignment,
> + (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
> + base = ALIGN(base, alignment);
> + size = ALIGN(size, alignment);
> + limit &= ~(alignment - 1);
> +
> + /* size should be aligned with order_per_bit */
> + if (!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit))
> + return -EINVAL;
> +
> + /* Reserve memory */
> + if (base && fixed) {
> + if (memblock_is_region_reserved(base, size) ||
> + memblock_reserve(base, size) < 0) {
> + ret = -EBUSY;
> + goto err;
> + }
> + } else {
> + phys_addr_t addr = memblock_alloc_range(size, alignment, base,
> + limit);
> + if (!addr) {
> + ret = -ENOMEM;
> + goto err;
> + } else {
> + base = addr;
> + }
> + }
> +
> + /*
> + * Each reserved area must be initialised later, when more kernel
> + * subsystems (like slab allocator) are available.
> + */
> + cma->base_pfn = PFN_DOWN(base);
> + cma->count = size >> PAGE_SHIFT;
> + cma->order_per_bit = order_per_bit;
> + *res_cma = cma;
> + cma_area_count++;
> +
> + pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
> + (unsigned long)base);
> + return 0;
> +
> +err:
> + pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
> + return ret;
> +}
> +
> +/**
> + * cma_alloc() - allocate pages from contiguous area
> + * @cma: Contiguous memory region for which the allocation is performed.
> + * @count: Requested number of pages.
> + * @align: Requested alignment of pages (in PAGE_SIZE order).
> + *
> + * This function allocates part of contiguous memory on specific
> + * contiguous memory area.
> + */
> +struct page *cma_alloc(struct cma *cma, int count, unsigned int align)
> +{
> + unsigned long mask, pfn, start = 0;
> + unsigned long bitmap_maxno, bitmap_no, bitmap_count;
> + struct page *page = NULL;
> + int ret;
> +
> + if (!cma || !cma->count)
> + return NULL;
> +
> + pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma,
> + count, align);
> +
> + if (!count)
> + return NULL;
> +
> + mask = cma_bitmap_aligned_mask(cma, align);
> + bitmap_maxno = cma_bitmap_maxno(cma);
> + bitmap_count = cma_bitmap_pages_to_bits(cma, count);
> +
> + for (;;) {
> + mutex_lock(&cma->lock);
> + bitmap_no = bitmap_find_next_zero_area(cma->bitmap,
> + bitmap_maxno, start, bitmap_count, mask);
> + if (bitmap_no >= bitmap_maxno) {
> + mutex_unlock(&cma->lock);
> + break;
> + }
> + bitmap_set(cma->bitmap, bitmap_no, bitmap_count);
> + /*
> + * It's safe to drop the lock here. We've marked this region for
> + * our exclusive use. If the migration fails we will take the
> + * lock again and unmark it.
> + */
> + mutex_unlock(&cma->lock);
> +
> + pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit);
> + mutex_lock(&cma_mutex);
> + ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
> + mutex_unlock(&cma_mutex);
> + if (ret == 0) {
> + page = pfn_to_page(pfn);
> + break;
> + } else if (ret != -EBUSY) {
> + cma_clear_bitmap(cma, pfn, count);
> + break;
> + }
> + cma_clear_bitmap(cma, pfn, count);
> + pr_debug("%s(): memory range at %p is busy, retrying\n",
> + __func__, pfn_to_page(pfn));
> + /* try again with a bit different memory target */
> + start = bitmap_no + mask + 1;
> + }
> +
> + pr_debug("%s(): returned %p\n", __func__, page);
> + return page;
> +}
> +
> +/**
> + * cma_release() - release allocated pages
> + * @cma: Contiguous memory region for which the allocation is performed.
> + * @pages: Allocated pages.
> + * @count: Number of allocated pages.
> + *
> + * This function releases memory allocated by alloc_cma().
> + * It returns false when provided pages do not belong to contiguous area and
> + * true otherwise.
> + */
> +bool cma_release(struct cma *cma, struct page *pages, int count)
> +{
> + unsigned long pfn;
> +
> + if (!cma || !pages)
> + return false;
> +
> + pr_debug("%s(page %p)\n", __func__, (void *)pages);
> +
> + pfn = page_to_pfn(pages);
> +
> + if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
> + return false;
> +
> + VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
> +
> + free_contig_range(pfn, count);
> + cma_clear_bitmap(cma, pfn, count);
> +
> + return true;
> +}
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply
* spi, spi_fsl-spi.c not working?
From: Heiko Schocher @ 2014-07-17 9:11 UTC (permalink / raw)
To: linuxppc-dev
Cc: Andreas Larsson, linux-spi, linux-kernel@vger.kernel.org,
Mark Brown, Anton Vorontsov
Hello all,
I just tried a mpc83xx based board (similiar to the mpc8313erdb)
with linux v3.16-rc4 using the drivers/spi/spi-fsl-spi.c driver.
DT nodes for spi are the same as in arch/powerpc/boot/dts/mpc8313erdb.dts:
spi@7000 {
cell-index = <0>;
compatible = "fsl,spi";
reg = <0x7000 0x1000>;
interrupts = <16 0x8>;
interrupt-parent = <&ipic>;
mode = "cpu";
};
Bootlog shows:
[ 1.341411] fsl_spi f0007000.spi: master is unqueued, this is deprecated
[ 1.554405] ------------[ cut here ]------------
[ 1.559080] WARNING: at c023a958 [verbose debug info unavailable]
[ 1.565208] Modules linked in:
[ 1.568305] CPU: 0 PID: 1 Comm: swapper Not tainted 3.16.0-rc4-ids720-patch1-01642-g69ef753 #20
[ 1.577059] task: c782c000 ti: c781a000 task.ti: c781a000
[ 1.582493] NIP: c023a958 LR: c0238bfc CTR: c027884c
[ 1.587491] REGS: c781bb80 TRAP: 0700 Not tainted (3.16.0-rc4-ids720-patch1-01642-g69ef753)
[ 1.596149] MSR: 00029032 <EE,ME,IR,DR,RI> CR: 22002044 XER: 00000000
[ 1.602851]
GPR00: c0238bfc c781bc30 c782c000 c051421c c6c62a00 c6c62b06 c03e392c 00000002
GPR08: c03de53c 00000001 c6c62ab8 00001032 82002042 00000000 c0004158 00000000
GPR16: 00000000 00000000 00000000 00000000 c0495c54 c0495cbc c0495cc8 c0495cd4
GPR24: 00000000 00000000 00000000 c050c6a4 c051421c c0544aa8 c0540000 c6c62a00
[ 1.632952] NIP [c023a958] driver_probe_device+0x58/0x230
[ 1.638397] LR [c0238bfc] bus_for_each_drv+0x50/0xac
[ 1.643390] Call Trace:
[ 1.645865] [c781bc30] [c023abf0] __device_attach+0x0/0x70 (unreliable)
[ 1.652539] [c781bc50] [c0238bfc] bus_for_each_drv+0x50/0xac
[ 1.658247] [c781bc80] [c023a8bc] device_attach+0xb4/0xd8
[ 1.663693] [c781bca0] [c0239dd4] bus_probe_device+0xa0/0xc4
[ 1.669400] [c781bcc0] [c0237d68] device_add+0x384/0x520
[ 1.674762] [c781bd00] [c0279298] spi_add_device+0xb0/0x170
[ 1.680383] [c781bd20] [c027aac4] spi_register_master+0x500/0x75c
[ 1.686530] [c781bd70] [c027e138] of_fsl_spi_probe+0x494/0x594
[ 1.692413] [c781bdd0] [c023c1ac] platform_drv_probe+0x28/0x68
[ 1.698297] [c781bde0] [c023a98c] driver_probe_device+0x8c/0x230
[ 1.704353] [c781be00] [c023abec] __driver_attach+0xbc/0xc0
[ 1.709972] [c781be20] [c0238cb4] bus_for_each_dev+0x5c/0xa8
[ 1.715681] [c781be50] [c023a038] bus_add_driver+0xf4/0x1e4
[ 1.721300] [c781be70] [c023b394] driver_register+0x88/0x130
[ 1.727013] [c781be80] [c0003ad0] do_one_initcall+0x8c/0x210
[ 1.732732] [c781bef0] [c04d30ac] kernel_init_freeable+0x114/0x1c0
[ 1.738962] [c781bf30] [c0004170] kernel_init+0x18/0x108
[ 1.744331] [c781bf40] [c000e830] ret_from_kernel_thread+0x5c/0x64
[ 1.750549] Instruction dump:
Did someone detected such a problem with this driver?
Is it maybe the missing "support for the SPI subsystem's queue SPI messages"?
Any hints?
Thanks!
bye,
Heiko
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
^ permalink raw reply
* [PATCH] CMA: generalize CMA reserved area management functionality (fixup)
From: Marek Szyprowski @ 2014-07-17 9:36 UTC (permalink / raw)
To: Joonsoo Kim, Andrew Morton, Aneesh Kumar K.V, Michal Nazarewicz
Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
Minchan Kim, Paul Mackerras, Paolo Bonzini, Zhang Yanfei,
linuxppc-dev, linux-arm-kernel, Marek Szyprowski
In-Reply-To: <53C78ED7.7030002@samsung.com>
MAX_CMA_AREAS is used by other subsystems (i.e. arch/arm/mm/dma-mapping.c),
so we need to provide correct definition even if CMA is disabled.
This patch fixes this issue.
Reported-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
include/linux/cma.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/linux/cma.h b/include/linux/cma.h
index 9a18a2b1934c..c077635cad76 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -5,7 +5,11 @@
* There is always at least global CMA area and a few optional
* areas configured in kernel .config.
*/
+#ifdef CONFIG_CMA
#define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS)
+#else
+#define MAX_CMA_AREAS (0)
+#endif
struct cma;
--
1.9.2
^ permalink raw reply related
* Re: [RESEND PATCH v5] [BUGFIX] kprobes: Fix "Failed to find blacklist" error on ia64 and ppc64
From: Ingo Molnar @ 2014-07-17 9:38 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Jeremy Fitzhardinge, linux-ia64, sparse, Tony Luck,
Paul Mackerras, H. Peter Anvin, Thomas Gleixner,
linux-tip-commits, anil.s.keshavamurthy, Suzuki K. Poulose,
Fenghua Yu, Arnd Bergmann, Rusty Russell, Chris Wright,
yrl.pp-manager.tt, akataria, Tony Luck, Kevin Hao, Linus Torvalds,
rdunlap, Linux Kernel Mailing List, dl9pf, Andrew Morton,
linuxppc-dev, David S. Miller
In-Reply-To: <20140717071121.3130.86341.stgit@kbuild-fedora.novalocal>
* Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> wrote:
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Looks good, but this is not a valid SOB sequence: if Suzuki wrote the
patch then he should be the first SOB (and should have a From line as
well), if he acked it along the way then it should be an Acked-by - or
Reviewed-by.
This fix should be in v3.16 as well, right?
Thanks,
Ingo
^ permalink raw reply
* Re: Re: Re: [PATCH v5 2/2] [BUGFIX] kprobes: Fix "Failed to find blacklist" error on ia64 and ppc64
From: Ingo Molnar @ 2014-07-17 9:40 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Jeremy Fitzhardinge, linux-ia64, sparse,
Linux Kernel Mailing List, Paul Mackerras, H. Peter Anvin,
Thomas Gleixner, linux-tip-commits, anil.s.keshavamurthy,
Suzuki K. Poulose, Fenghua Yu, Arnd Bergmann, Rusty Russell,
Chris Wright, yrl.pp-manager.tt, akataria, Tony Luck, Kevin Hao,
Linus Torvalds, rdunlap, Tony Luck, dl9pf, Andrew Morton,
linuxppc-dev, David S. Miller
In-Reply-To: <53C776ED.3050001@hitachi.com>
* Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> wrote:
> (2014/07/16 22:28), Ingo Molnar wrote:
> >
> > * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> wrote:
> >
> >> (2014/07/15 16:16), Benjamin Herrenschmidt wrote:
> >>> On Tue, 2014-07-15 at 13:19 +1000, Michael Ellerman wrote:
> >>>
> >>>>> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> >>>>> Reported-by: Tony Luck <tony.luck@gmail.com>
> >>>>> Tested-by: Tony Luck <tony.luck@intel.com>
> >>>>> Cc: Michael Ellerman <mpe@ellerman.id.au>
> >>>>
> >>>> Tested-by: Michael Ellerman <mpe@ellerman.id.au>
> >>>> Acked-by: Michael Ellerman <mpe@ellerman.id.au> (for powerpc)
> >>>>
> >>>> Ben, can you take this in your tree?
> >>>
> >>> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> >>>
> >>> That looks more like generic material. Do we have a kprobes maintainer ?
> >>> Andrew, do you want to take this ?
> >>
> >> Yeah, I usually use Ingo's tip tree for kprobes maintenance.
> >> Ingo, could you pull this as urgent-for-linus patch?
> >
> > Mind resending it in a separate thread with all acks added, etc?
>
> OK, I'll resend that soon.
> BTW, I missed Suzuki's Signed-off-by in this version,
> I'd like to recover that since he made a big bugfix on this.
That kind of credit can be added as:
Fixed-by: Suzuki K. Poulose <suzuki@in.ibm.com>
and by also adding a sentence to the log message (outside of the
version changelogs which get stripped ususally).
Thanks,
Ingo
^ permalink raw reply
* Re: [PATCH 2/2] PCI/MSI: Remove arch_msi_check_device()
From: Alexander Gordeev @ 2014-07-17 10:22 UTC (permalink / raw)
To: Bjorn Helgaas; +Cc: linux-pci, linuxppc-dev, linux-kernel
In-Reply-To: <20140716222024.GE14366@google.com>
On Wed, Jul 16, 2014 at 04:20:24PM -0600, Bjorn Helgaas wrote:
> > @@ -809,22 +799,23 @@ out_free:
> > }
> >
> > /**
> > - * pci_msi_check_device - check whether MSI may be enabled on a device
> > + * msi_check_device - check whether MSI may be enabled on a device
> > * @dev: pointer to the pci_dev data structure of MSI device function
> > * @nvec: how many MSIs have been requested ?
> > - * @type: are we checking for MSI or MSI-X ?
> > *
> > * Look at global flags, the device itself, and its parent buses
> > * to determine if MSI/-X are supported for the device. If MSI/-X is
> > * supported return 0, else return an error code.
> > **/
> > -static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
> > +static int msi_check_device(struct pci_dev *dev, int nvec)
>
> I think "check_device" is a terrible name because it really doesn't
> give a clue about what it's doing or what the return value means.
> Since you're removing the external usage (arch_msi_check_device) and
> this one is static, this would be a good time to fix it. Maybe
> "pci_msi_supported()" or something?
What about pci_can_enable_msi() or pci_msi_can_enable() or msi_can_enable()?
> I *love* the idea of getting rid of this much code!
>
> Bjorn
--
Regards,
Alexander Gordeev
agordeev@redhat.com
^ permalink raw reply
* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
From: Anshuman Khandual @ 2014-07-17 10:27 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Michael Neuling, james.hogan, avagin, Paul.Clothier, peterz,
palves, linux-kernel, oleg, dhowells, linuxppc-dev, tglx, davej,
akpm, davem
In-Reply-To: <53996E41.4070309@linux.vnet.ibm.com>
On 06/12/2014 02:39 PM, Anshuman Khandual wrote:
> On 05/23/2014 08:45 PM, Anshuman Khandual wrote:
>> This patch series adds five new ELF core note sections which can be
>> used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
>> various transactional memory and miscellaneous register sets on PowerPC
>> platform. Please find a test program exploiting these new ELF core note
>> types on a POWER8 system.
>>
>> RFC: https://lkml.org/lkml/2014/4/1/292
>> V1: https://lkml.org/lkml/2014/4/2/43
>> V2: https://lkml.org/lkml/2014/5/5/88
>>
>> Changes in V3
>> =============
>> (1) Added two new error paths in every TM related get/set functions when regset
>> support is not present on the system (ENODEV) or when the process does not
>> have any transaction active (ENODATA) in the context
>>
>> (2) Installed the active hooks for all the newly added regset core note types
>>
>> Changes in V2
>> =============
>> (1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
>> elf core note types. Now all the register sets can be accessed from ptrace
>> through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
>> note type instead
>> (2) Fixed couple of attribute values for REGSET_TM_CGPR register set
>> (3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
>> (4) Fixed 32 bit checkpointed GPR support
>> (5) Changed commit messages accordingly
>>
>> Outstanding Issues
>> ==================
>> (1) Running DSCR register value inside a transaction does not seem to be saved
>> at thread.dscr when the process stops for ptrace examination.
>
> Hey Ben,
>
> Any updates on this patch series ?
Ben,
Any updates on this patch series ?
^ permalink raw reply
* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
From: Benjamin Herrenschmidt @ 2014-07-17 11:09 UTC (permalink / raw)
To: Anshuman Khandual
Cc: Michael Neuling, james.hogan, avagin, Paul.Clothier, peterz,
palves, linux-kernel, oleg, dhowells, linuxppc-dev, tglx, davej,
akpm, davem
In-Reply-To: <53C7A4FA.4030600@linux.vnet.ibm.com>
> >
> >> Outstanding Issues
> >> ==================
> >> (1) Running DSCR register value inside a transaction does not seem to be saved
> >> at thread.dscr when the process stops for ptrace examination.
> >
> > Hey Ben,
> >
> > Any updates on this patch series ?
>
> Ben,
>
> Any updates on this patch series ?
I haven't had a chance to review yet, I was hoping somebody else would..
Have you made any progress vs. the DSCR outstanding issue mentioned
above ?
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH V3 0/3] Add new PowerPC specific ELF core notes
From: Michael Neuling @ 2014-07-17 11:14 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: james.hogan, avagin, Paul.Clothier, Peter Zijlstra, Pedro Alves,
oleg, akpm, Linux Kernel Mailing List, dhowells, Linux PPC dev,
davej, tglx, David S. Miller, sam.bobroff, Anshuman Khandual
In-Reply-To: <1405595380.25310.21.camel@pasglop>
[-- Attachment #1: Type: text/plain, Size: 741 bytes --]
On Jul 17, 2014 9:11 PM, "Benjamin Herrenschmidt" <benh@kernel.crashing.org>
wrote:
>
> > >
> > >> Outstanding Issues
> > >> ==================
> > >> (1) Running DSCR register value inside a transaction does not seem
to be saved
> > >> at thread.dscr when the process stops for ptrace examination.
> > >
> > > Hey Ben,
> > >
> > > Any updates on this patch series ?
> >
> > Ben,
> >
> > Any updates on this patch series ?
>
> I haven't had a chance to review yet, I was hoping somebody else would..
>
> Have you made any progress vs. the DSCR outstanding issue mentioned
> above ?
The DSCR issue should be resolved with Sam Bobroff's recent DSCR fixes.
I've not tested them though.
Actually... Sam did you review this series?
Mikey
[-- Attachment #2: Type: text/html, Size: 1132 bytes --]
^ permalink raw reply
* Re: [RESEND PATCH v5] [BUGFIX] kprobes: Fix "Failed to find blacklist" error on ia64 and ppc64
From: Masami Hiramatsu @ 2014-07-17 11:17 UTC (permalink / raw)
To: Ingo Molnar
Cc: Jeremy Fitzhardinge, linux-ia64, sparse, Tony Luck,
Paul Mackerras, H. Peter Anvin, Thomas Gleixner,
linux-tip-commits, anil.s.keshavamurthy, Suzuki K. Poulose,
Fenghua Yu, Arnd Bergmann, Rusty Russell, Chris Wright,
yrl.pp-manager.tt, akataria, Tony Luck, Kevin Hao, Linus Torvalds,
rdunlap, Linux Kernel Mailing List, dl9pf, Andrew Morton,
linuxppc-dev, David S. Miller
In-Reply-To: <20140717093832.GB4232@gmail.com>
(2014/07/17 18:38), Ingo Molnar wrote:
>
> * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> wrote:
>
>> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
>> Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
>
> Looks good, but this is not a valid SOB sequence: if Suzuki wrote the
> patch then he should be the first SOB (and should have a From line as
> well), if he acked it along the way then it should be an Acked-by - or
> Reviewed-by.
Ah, OK, so I'll add his name as Fixed-by:.
>
> This fix should be in v3.16 as well, right?
Right, it should be.
Thank you,
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com
^ permalink raw reply
* [PATCH] selftests/powerpc: Add test of L3 bank handling
From: Michael Ellerman @ 2014-07-17 11:18 UTC (permalink / raw)
To: linuxppc-dev
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
tools/testing/selftests/powerpc/pmu/Makefile | 2 +-
tools/testing/selftests/powerpc/pmu/l3_bank_test.c | 48 ++++++++++++++++++++++
2 files changed, 49 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/powerpc/pmu/l3_bank_test.c
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index b9ff0db42c79..8f1aca38c055 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -1,7 +1,7 @@
noarg:
$(MAKE) -C ../
-PROGS := count_instructions
+PROGS := count_instructions l3_bank_test
EXTRA_SOURCES := ../harness.c event.c
all: $(PROGS) sub_all
diff --git a/tools/testing/selftests/powerpc/pmu/l3_bank_test.c b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
new file mode 100644
index 000000000000..77472f31441e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "event.h"
+#include "utils.h"
+
+#define MALLOC_SIZE (0x10000 * 10) /* Ought to be enough .. */
+
+/*
+ * Tests that the L3 bank handling is correct. We fixed it in commit e9aaac1.
+ */
+static int l3_bank_test(void)
+{
+ struct event event;
+ char *p;
+ int i;
+
+ p = malloc(MALLOC_SIZE);
+ FAIL_IF(!p);
+
+ event_init(&event, 0x84918F);
+
+ FAIL_IF(event_open(&event));
+
+ for (i = 0; i < MALLOC_SIZE; i += 0x10000)
+ p[i] = i;
+
+ event_read(&event);
+ event_report(&event);
+
+ FAIL_IF(event.result.running == 0);
+ FAIL_IF(event.result.enabled == 0);
+
+ event_close(&event);
+ free(p);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(l3_bank_test, "l3_bank_test");
+}
--
1.9.1
^ permalink raw reply related
* [PATCH v5 0/5] Read guest last instruction from kvmppc_get_last_inst()
From: Mihai Caraman @ 2014-07-17 11:22 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
Read guest last instruction from kvmppc_get_last_inst() allowing the function
to fail in order to emulate again. On bookehv architecture search for
the physical address and kmap it, instead of using Load External PID (lwepx)
instruction. This fixes an infinite loop caused by lwepx's data TLB miss
exception handled in the host and the TODO for execute-but-not-read entries
and TLB eviction.
Mihai Caraman (5):
KVM: PPC: e500mc: Revert "add load inst fixup"
KVM: PPC: Book3e: Add TLBSEL/TSIZE defines for MAS0/1
KVM: PPC: Book3s: Remove kvmppc_read_inst() function
KVM: PPC: Alow kvmppc_get_last_inst() to fail
KVM: PPC: Bookehv: Get vcpu's last instruction for emulation
arch/powerpc/include/asm/kvm_book3s.h | 26 -------
arch/powerpc/include/asm/kvm_booke.h | 5 --
arch/powerpc/include/asm/kvm_ppc.h | 25 +++++++
arch/powerpc/include/asm/mmu-book3e.h | 9 ++-
arch/powerpc/kvm/book3s.c | 17 +++++
arch/powerpc/kvm/book3s_64_mmu_hv.c | 17 ++---
arch/powerpc/kvm/book3s_paired_singles.c | 38 +++++++----
arch/powerpc/kvm/book3s_pr.c | 114 ++++++++++++++++---------------
arch/powerpc/kvm/booke.c | 47 +++++++++++++
arch/powerpc/kvm/bookehv_interrupts.S | 55 ++-------------
arch/powerpc/kvm/e500_mmu_host.c | 98 ++++++++++++++++++++++++++
arch/powerpc/kvm/emulate.c | 18 +++--
arch/powerpc/kvm/powerpc.c | 11 ++-
13 files changed, 309 insertions(+), 171 deletions(-)
--
1.7.11.7
^ permalink raw reply
* [PATCH v5 1/5] KVM: PPC: e500mc: Revert "add load inst fixup"
From: Mihai Caraman @ 2014-07-17 11:22 UTC (permalink / raw)
To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1405596148-1507-1-git-send-email-mihai.caraman@freescale.com>
The commit 1d628af7 "add load inst fixup" made an attempt to handle
failures generated by reading the guest current instruction. The fixup
code that was added works by chance hiding the real issue.
Load external pid (lwepx) instruction, used by KVM to read guest
instructions, is executed in a subsituted guest translation context
(EPLC[EGS] = 1). In consequence lwepx's TLB error and data storage
interrupts need to be handled by KVM, even though these interrupts
are generated from host context (MSR[GS] = 0) where lwepx is executed.
Currently, KVM hooks only interrupts generated from guest context
(MSR[GS] = 1), doing minimal checks on the fast path to avoid host
performance degradation. As a result, the host kernel handles lwepx
faults searching the faulting guest data address (loaded in DEAR) in
its own Logical Partition ID (LPID) 0 context. In case a host translation
is found the execution returns to the lwepx instruction instead of the
fixup, the host ending up in an infinite loop.
Revert the commit "add load inst fixup". lwepx issue will be addressed
in a subsequent patch without needing fixup code.
Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v5-v2:
- no change
arch/powerpc/kvm/bookehv_interrupts.S | 26 +-------------------------
1 file changed, 1 insertion(+), 25 deletions(-)
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index a1712b8..6ff4480 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -29,7 +29,6 @@
#include <asm/asm-compat.h>
#include <asm/asm-offsets.h>
#include <asm/bitsperlong.h>
-#include <asm/thread_info.h>
#ifdef CONFIG_64BIT
#include <asm/exception-64e.h>
@@ -164,32 +163,9 @@
PPC_STL r30, VCPU_GPR(R30)(r4)
PPC_STL r31, VCPU_GPR(R31)(r4)
mtspr SPRN_EPLC, r8
-
- /* disable preemption, so we are sure we hit the fixup handler */
- CURRENT_THREAD_INFO(r8, r1)
- li r7, 1
- stw r7, TI_PREEMPT(r8)
-
isync
-
- /*
- * In case the read goes wrong, we catch it and write an invalid value
- * in LAST_INST instead.
- */
-1: lwepx r9, 0, r5
-2:
-.section .fixup, "ax"
-3: li r9, KVM_INST_FETCH_FAILED
- b 2b
-.previous
-.section __ex_table,"a"
- PPC_LONG_ALIGN
- PPC_LONG 1b,3b
-.previous
-
+ lwepx r9, 0, r5
mtspr SPRN_EPLC, r3
- li r7, 0
- stw r7, TI_PREEMPT(r8)
stw r9, VCPU_LAST_INST(r4)
.endif
--
1.7.11.7
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox