* [RFC PATCH V3 03/17] ppc/pci: don't unset pci resources for VFs
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
When the PCI_REASSIGN_ALL_RSRC is set, each resource for a pci_dev will be
unset. which means the pci core will reassign those resources.
While this behavior will clean up the resources information for VFs, whose
value is calculated in virtfn_add.
This patch adds a condition. If the pci_dev is a VF, skip the resource
unset process.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/kernel/pci-common.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index d9476c1..c449a26 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -824,6 +824,12 @@ static void pcibios_fixup_resources(struct pci_dev *dev)
pci_name(dev));
return;
}
+
+#ifdef CONFIG_PCI_IOV
+ if (dev->is_virtfn)
+ return;
+#endif
+
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
struct resource *res = dev->resource + i;
struct pci_bus_region reg;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 05/17] ppc/pnv: user macro to define the TCE size
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
During the initialization of the TVT/TCE, it uses digits to specify the TCE IO
Page Size, TCE Table Size, TCE Entry Size, etc.
This patch replaces those digits with macros, which will be more meaningful and
easy to read.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/tce.h | 3 ++-
arch/powerpc/platforms/powernv/pci-ioda.c | 25 +++++++++++--------------
arch/powerpc/platforms/powernv/pci.c | 2 +-
arch/powerpc/platforms/powernv/pci.h | 5 +++++
4 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/tce.h b/arch/powerpc/include/asm/tce.h
index 743f36b..28a1d06 100644
--- a/arch/powerpc/include/asm/tce.h
+++ b/arch/powerpc/include/asm/tce.h
@@ -40,7 +40,8 @@
#define TCE_SHIFT 12
#define TCE_PAGE_SIZE (1 << TCE_SHIFT)
-#define TCE_ENTRY_SIZE 8 /* each TCE is 64 bits */
+#define TCE_ENTRY_SHIFT 3
+#define TCE_ENTRY_SIZE (1 << TCE_ENTRY_SHIFT) /* each TCE is 64 bits */
#define TCE_RPN_MASK 0xfffffffffful /* 40-bit RPN (4K pages) */
#define TCE_RPN_SHIFT 12
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 8ae09cf..9715351 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -820,9 +820,6 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
int64_t rc;
void *addr;
- /* 256M DMA window, 4K TCE pages, 8 bytes TCE */
-#define TCE32_TABLE_SIZE ((0x10000000 / 0x1000) * 8)
-
/* XXX FIXME: Handle 64-bit only DMA devices */
/* XXX FIXME: Provide 64-bit DMA facilities & non-4K TCE tables etc.. */
/* XXX FIXME: Allocate multi-level tables on PHB3 */
@@ -834,7 +831,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
/* Grab a 32-bit TCE table */
pe->tce32_seg = base;
pe_info(pe, " Setting up 32-bit TCE table at %08x..%08x\n",
- (base << 28), ((base + segs) << 28) - 1);
+ (base << PNV_TCE32_SEG_SHIFT), ((base + segs) << PNV_TCE32_SEG_SHIFT) - 1);
/* XXX Currently, we allocate one big contiguous table for the
* TCEs. We only really need one chunk per 256M of TCE space
@@ -842,21 +839,21 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
* requires some added smarts with our get/put_tce implementation
*/
tce_mem = alloc_pages_node(phb->hose->node, GFP_KERNEL,
- get_order(TCE32_TABLE_SIZE * segs));
+ get_order(PNV_TCE32_TAB_SIZE * segs));
if (!tce_mem) {
pe_err(pe, " Failed to allocate a 32-bit TCE memory\n");
goto fail;
}
addr = page_address(tce_mem);
- memset(addr, 0, TCE32_TABLE_SIZE * segs);
+ memset(addr, 0, PNV_TCE32_TAB_SIZE * segs);
/* Configure HW */
for (i = 0; i < segs; i++) {
rc = opal_pci_map_pe_dma_window(phb->opal_id,
pe->pe_number,
base + i, 1,
- __pa(addr) + TCE32_TABLE_SIZE * i,
- TCE32_TABLE_SIZE, 0x1000);
+ __pa(addr) + PNV_TCE32_TAB_SIZE * i,
+ PNV_TCE32_TAB_SIZE, TCE_PAGE_SIZE);
if (rc) {
pe_err(pe, " Failed to configure 32-bit TCE table,"
" err %ld\n", rc);
@@ -866,8 +863,8 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
/* Setup linux iommu table */
tbl = &pe->tce32_table;
- pnv_pci_setup_iommu_table(tbl, addr, TCE32_TABLE_SIZE * segs,
- base << 28);
+ pnv_pci_setup_iommu_table(tbl, addr, PNV_TCE32_TAB_SIZE * segs,
+ base << PNV_TCE32_SEG_SHIFT);
/* OPAL variant of P7IOC SW invalidated TCEs */
swinvp = of_get_property(phb->hose->dn, "ibm,opal-tce-kill", NULL);
@@ -898,7 +895,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
if (pe->tce32_seg >= 0)
pe->tce32_seg = -1;
if (tce_mem)
- __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs));
+ __free_pages(tce_mem, get_order(PNV_TCE32_TAB_SIZE * segs));
}
static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
@@ -968,7 +965,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
/* The PE will reserve all possible 32-bits space */
pe->tce32_seg = 0;
end = (1 << ilog2(phb->ioda.m32_pci_base));
- tce_table_size = (end / 0x1000) * 8;
+ tce_table_size = (end / TCE_PAGE_SIZE) * TCE_ENTRY_SIZE;
pe_info(pe, "Setting up 32-bit TCE table at 0..%08x\n",
end);
@@ -988,7 +985,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
*/
rc = opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number,
pe->pe_number << 1, 1, __pa(addr),
- tce_table_size, 0x1000);
+ tce_table_size, TCE_PAGE_SIZE);
if (rc) {
pe_err(pe, "Failed to configure 32-bit TCE table,"
" err %ld\n", rc);
@@ -1573,7 +1570,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
INIT_LIST_HEAD(&phb->ioda.pe_list);
/* Calculate how many 32-bit TCE segments we have */
- phb->ioda.tce32_count = phb->ioda.m32_pci_base >> 28;
+ phb->ioda.tce32_count = phb->ioda.m32_pci_base >> PNV_TCE32_SEG_SHIFT;
#if 0 /* We should really do that ... */
rc = opal_pci_set_phb_mem_window(opal->phb_id,
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 8518817..687a068 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -597,7 +597,7 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
tbl->it_offset = dma_offset >> tbl->it_page_shift;
tbl->it_index = 0;
- tbl->it_size = tce_size >> 3;
+ tbl->it_size = tce_size >> TCE_ENTRY_SHIFT;
tbl->it_busno = 0;
tbl->it_type = TCE_PCI;
}
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 3e5f5a1..90f6da4 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -227,4 +227,9 @@ extern void pnv_pci_init_ioda2_phb(struct device_node *np);
extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
__be64 *startp, __be64 *endp, bool rm);
+#define PNV_TCE32_SEG_SHIFT 28
+#define PNV_TCE32_SEG_SIZE (1UL << PNV_TCE32_SEG_SHIFT)
+/* 256M DMA window, 4K TCE pages, 8 bytes TCE */
+#define PNV_TCE32_TAB_SIZE ((PNV_TCE32_SEG_SIZE / TCE_PAGE_SIZE) * TCE_ENTRY_SIZE)
+
#endif /* __POWERNV_PCI_H */
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 06/17] ppc/pnv: allocate pe->iommu_table dynamically
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
Current iommu_table of a PE is a static field. This will have a problem when
iommu_free_table is called.
This patch allocate iommu_table dynamically.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/iommu.h | 3 +++
arch/powerpc/platforms/powernv/pci-ioda.c | 24 +++++++++++++-----------
arch/powerpc/platforms/powernv/pci.h | 2 +-
3 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 42632c7..0fedacb 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -78,6 +78,9 @@ struct iommu_table {
struct iommu_group *it_group;
#endif
void (*set_bypass)(struct iommu_table *tbl, bool enable);
+#ifdef CONFIG_PPC_POWERNV
+ void *data;
+#endif
};
/* Pure 2^n version of get_order */
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 9715351..8ca3926 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -608,6 +608,10 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
return;
}
+ pe->tce32_table = kzalloc_node(sizeof(struct iommu_table),
+ GFP_KERNEL, hose->node);
+ pe->tce32_table->data = pe;
+
/* Associate it with all child devices */
pnv_ioda_setup_same_PE(bus, pe);
@@ -675,7 +679,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
pe = &phb->ioda.pe_array[pdn->pe_number];
WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
- set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
+ set_iommu_table_base_and_group(&pdev->dev, pe->tce32_table);
}
static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
@@ -702,7 +706,7 @@ static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
} else {
dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n");
set_dma_ops(&pdev->dev, &dma_iommu_ops);
- set_iommu_table_base(&pdev->dev, &pe->tce32_table);
+ set_iommu_table_base(&pdev->dev, pe->tce32_table);
}
return 0;
}
@@ -712,7 +716,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
- set_iommu_table_base_and_group(&dev->dev, &pe->tce32_table);
+ set_iommu_table_base_and_group(&dev->dev, pe->tce32_table);
if (dev->subordinate)
pnv_ioda_setup_bus_dma(pe, dev->subordinate);
}
@@ -798,8 +802,7 @@ static void pnv_pci_ioda2_tce_invalidate(struct pnv_ioda_pe *pe,
void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
__be64 *startp, __be64 *endp, bool rm)
{
- struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe,
- tce32_table);
+ struct pnv_ioda_pe *pe = tbl->data;
struct pnv_phb *phb = pe->phb;
if (phb->type == PNV_PHB_IODA1)
@@ -862,7 +865,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
}
/* Setup linux iommu table */
- tbl = &pe->tce32_table;
+ tbl = pe->tce32_table;
pnv_pci_setup_iommu_table(tbl, addr, PNV_TCE32_TAB_SIZE * segs,
base << PNV_TCE32_SEG_SHIFT);
@@ -900,8 +903,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
{
- struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe,
- tce32_table);
+ struct pnv_ioda_pe *pe = tbl->data;
uint16_t window_id = (pe->pe_number << 1 ) + 1;
int64_t rc;
@@ -942,10 +944,10 @@ static void pnv_pci_ioda2_setup_bypass_pe(struct pnv_phb *phb,
pe->tce_bypass_base = 1ull << 59;
/* Install set_bypass callback for VFIO */
- pe->tce32_table.set_bypass = pnv_pci_ioda2_set_bypass;
+ pe->tce32_table->set_bypass = pnv_pci_ioda2_set_bypass;
/* Enable bypass by default */
- pnv_pci_ioda2_set_bypass(&pe->tce32_table, true);
+ pnv_pci_ioda2_set_bypass(pe->tce32_table, true);
}
static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
@@ -993,7 +995,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
}
/* Setup linux iommu table */
- tbl = &pe->tce32_table;
+ tbl = pe->tce32_table;
pnv_pci_setup_iommu_table(tbl, addr, tce_table_size, 0);
/* OPAL variant of PHB3 invalidated TCEs */
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 90f6da4..9fbf7c0 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -60,7 +60,7 @@ struct pnv_ioda_pe {
/* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */
int tce32_seg;
int tce32_segcount;
- struct iommu_table tce32_table;
+ struct iommu_table *tce32_table;
phys_addr_t tce_inval_reg_phys;
/* 64-bit TCE bypass region */
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 07/17] ppc/pnv: Add function to deconfig a PE
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
On PowerNV platform, it will support dynamic PE allocation and deallocation.
This patch adds a function to release those resources related to a PE.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 77 +++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 8ca3926..87cb3089 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -330,6 +330,83 @@ static struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev)
}
#endif /* CONFIG_PCI_MSI */
+static int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
+{
+ struct pci_dev *parent;
+ uint8_t bcomp, dcomp, fcomp;
+ int64_t rc;
+ long rid_end, rid;
+ if (pe->pbus) {
+ int count;
+
+ dcomp = OPAL_IGNORE_RID_DEVICE_NUMBER;
+ fcomp = OPAL_IGNORE_RID_FUNCTION_NUMBER;
+ parent = pe->pbus->self;
+ if (pe->flags & PNV_IODA_PE_BUS_ALL)
+ count = pe->pbus->busn_res.end - pe->pbus->busn_res.start + 1;
+ else
+ count = 1;
+
+ switch(count) {
+ case 1: bcomp = OpalPciBusAll; break;
+ case 2: bcomp = OpalPciBus7Bits; break;
+ case 4: bcomp = OpalPciBus6Bits; break;
+ case 8: bcomp = OpalPciBus5Bits; break;
+ case 16: bcomp = OpalPciBus4Bits; break;
+ case 32: bcomp = OpalPciBus3Bits; break;
+ default:
+ pr_err("%s: Number of subordinate busses %d"
+ " unsupported\n",
+ pci_name(pe->pbus->self), count);
+ /* Do an exact match only */
+ bcomp = OpalPciBusAll;
+ }
+ rid_end = pe->rid + (count << 8);
+ }else {
+ parent = pe->pdev->bus->self;
+ bcomp = OpalPciBusAll;
+ dcomp = OPAL_COMPARE_RID_DEVICE_NUMBER;
+ fcomp = OPAL_COMPARE_RID_FUNCTION_NUMBER;
+ rid_end = pe->rid + 1;
+ }
+
+ /* Disable MVT on IODA1 */
+ if (phb->type == PNV_PHB_IODA1) {
+ rc = opal_pci_set_mve_enable(phb->opal_id,
+ pe->mve_number, OPAL_DISABLE_MVE);
+ if (rc) {
+ pe_err(pe, "OPAL error %ld enabling MVE %d\n",
+ rc, pe->mve_number);
+ pe->mve_number = -1;
+ }
+ }
+ /* Clear the reverse map */
+ for (rid = pe->rid; rid < rid_end; rid++)
+ phb->ioda.pe_rmap[rid] = 0;
+
+ /* Release from all parents PELT-V */
+ while (parent) {
+ struct pci_dn *pdn = pci_get_pdn(parent);
+ if (pdn && pdn->pe_number != IODA_INVALID_PE) {
+ rc = opal_pci_set_peltv(phb->opal_id, pdn->pe_number,
+ pe->pe_number, OPAL_REMOVE_PE_FROM_DOMAIN);
+ /* XXX What to do in case of error ? */
+ }
+ parent = parent->bus->self;
+ }
+
+ /* Dissociate PE in PELT */
+ rc = opal_pci_set_pe(phb->opal_id, pe->pe_number, pe->rid,
+ bcomp, dcomp, fcomp, OPAL_UNMAP_PE);
+ if (rc)
+ pe_err(pe, "OPAL error %ld trying to setup PELT table\n", rc);
+
+ pe->pbus = NULL;
+ pe->pdev = NULL;
+
+ return 0;
+}
+
static int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
{
struct pci_dev *parent;
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 08/17] PCI: Add weak pcibios_sriov_resource_size() interface
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
When retrieving sriov resource size in pci_sriov_resource_size(), it will
divide the total IOV resource size with the totalVF number. This is true for
most cases, while may not be correct on some specific platform.
For example on powernv platform, in order to fix the IOV BAR into a hardware
alignment, the IOV resource size would be expended. This means the original
method couldn't work.
This patch introduces a weak pcibios_sriov_resource_size() interface, which
gives platform a chance to implement specific method to calculate the sriov
resource size.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
drivers/pci/iov.c | 27 +++++++++++++++++++++++++--
include/linux/pci.h | 3 +++
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index cc87773..9fd4648 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -45,6 +45,30 @@ static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus)
pci_remove_bus(virtbus);
}
+resource_size_t __weak pcibios_sriov_resource_size(struct pci_dev *dev, int resno)
+{
+ return 0;
+}
+
+resource_size_t pci_sriov_resource_size(struct pci_dev *dev, int resno)
+{
+ u64 size;
+ struct pci_sriov *iov;
+
+ if (!dev->is_physfn)
+ return 0;
+
+ size = pcibios_sriov_resource_size(dev, resno);
+ if (size != 0)
+ return size;
+
+ iov = dev->sriov;
+ size = resource_size(dev->resource + resno);
+ do_div(size, iov->total_VFs);
+
+ return size;
+}
+
static int virtfn_add(struct pci_dev *dev, int id, int reset)
{
int i;
@@ -81,8 +105,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
continue;
virtfn->resource[i].name = pci_name(virtfn);
virtfn->resource[i].flags = res->flags;
- size = resource_size(res);
- do_div(size, iov->total_VFs);
+ size = pci_sriov_resource_size(dev, i + PCI_IOV_RESOURCES);
virtfn->resource[i].start = res->start + size * id;
virtfn->resource[i].end = virtfn->resource[i].start + size - 1;
rc = request_resource(res, &virtfn->resource[i]);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index ddb1ca0..315c150 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1637,6 +1637,7 @@ int pci_num_vf(struct pci_dev *dev);
int pci_vfs_assigned(struct pci_dev *dev);
int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
int pci_sriov_get_totalvfs(struct pci_dev *dev);
+resource_size_t pci_sriov_resource_size(struct pci_dev *dev, int resno);
#else
static inline int pci_iov_virtfn_bus(struct pci_dev *dev, int id)
{
@@ -1658,6 +1659,8 @@ static inline int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
{ return 0; }
static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
{ return 0; }
+static inline resource_size_t pci_sriov_resource_size(struct pci_dev *dev, int resno)
+{ return -1; }
#endif
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 09/17] PCI: Add weak pcibios_sriov_resource_alignment() interface
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
The sriov resource alignment is designed to be the individual size of a sriov
resource. This works fine for many platforms, but on powernv platform it needs
some change.
The original alignment works, since at sizing and assigning stage the
requirement is from an individual VF's resource size instead of the big IOV
BAR. This is the reason for the original code to just retrieve the individual
sriov size as the alignment.
On powernv platform, it is required to align the whole IOV BAR to a hardware
aperture. Based on this fact, the alignment of sriov resource should be the
total size of the IOV BAR.
This patch introduces a weak pcibios_sriov_resource_alignment() interface, which
gives platform a chance to implement specific method to calculate the sriov
resource alignment.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
drivers/pci/iov.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 9fd4648..dd7fc42 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -628,6 +628,12 @@ int pci_iov_resource_bar(struct pci_dev *dev, int resno,
4 * (resno - PCI_IOV_RESOURCES);
}
+resource_size_t __weak pcibios_sriov_resource_alignment(struct pci_dev *dev,
+ int resno, resource_size_t align)
+{
+ return align;
+}
+
/**
* pci_sriov_resource_alignment - get resource alignment for VF BAR
* @dev: the PCI device
@@ -642,13 +648,16 @@ resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
{
struct resource tmp;
enum pci_bar_type type;
+ resource_size_t align;
int reg = pci_iov_resource_bar(dev, resno, &type);
if (!reg)
return 0;
__pci_read_base(dev, type, &tmp, reg);
- return resource_alignment(&tmp);
+ align = resource_alignment(&tmp);
+
+ return pcibios_sriov_resource_alignment(dev, resno, align);
}
/**
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 10/17] PCI: take additional IOV BAR alignment in sizing and assigning
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
At resource sizing/assigning stage, resources are divided into two lists,
requested list and additional list, while the alignement of the additional
IOV BAR is not taken into the sizeing and assigning procedure.
This is reasonable in the original implementation, since IOV BAR's alignment is
mostly the size of a PF BAR alignemt. This means the alignment is already taken
into consideration. While this rule may be violated on some platform.
This patch take the additional IOV BAR alignment in sizing and assigning stage
explicitly.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
drivers/pci/setup-bus.c | 66 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 59 insertions(+), 7 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 9509ffa..0c3b3a5 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -120,6 +120,28 @@ static resource_size_t get_res_add_size(struct list_head *head,
return 0;
}
+static resource_size_t get_res_add_align(struct list_head *head,
+ struct resource *res)
+{
+ struct pci_dev_resource *dev_res;
+
+ list_for_each_entry(dev_res, head, list) {
+ if (dev_res->res == res) {
+ int idx = res - &dev_res->dev->resource[0];
+
+ dev_printk(KERN_DEBUG, &dev_res->dev->dev,
+ "res[%d]=%pR get_res_add_align min_align %llx\n",
+ idx, dev_res->res,
+ (unsigned long long)dev_res->min_align);
+
+ return dev_res->min_align;
+ }
+ }
+
+ return 0;
+}
+
+
/* Sort resources by alignment */
static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
{
@@ -369,8 +391,9 @@ static void __assign_resources_sorted(struct list_head *head,
LIST_HEAD(save_head);
LIST_HEAD(local_fail_head);
struct pci_dev_resource *save_res;
- struct pci_dev_resource *dev_res, *tmp_res;
+ struct pci_dev_resource *dev_res, *tmp_res, *dev_res2;
unsigned long fail_type;
+ resource_size_t add_align, align;
/* Check if optional add_size is there */
if (!realloc_head || list_empty(realloc_head))
@@ -385,10 +408,31 @@ static void __assign_resources_sorted(struct list_head *head,
}
/* Update res in head list with add_size in realloc_head list */
- list_for_each_entry(dev_res, head, list)
+ list_for_each_entry_safe(dev_res, tmp_res, head, list) {
dev_res->res->end += get_res_add_size(realloc_head,
dev_res->res);
+ if (!(dev_res->res->flags & IORESOURCE_STARTALIGN))
+ continue;
+
+ add_align = get_res_add_align(realloc_head, dev_res->res);
+
+ if (add_align > dev_res->res->start) {
+ dev_res->res->start = add_align;
+ dev_res->res->end = add_align +
+ resource_size(dev_res->res);
+
+ list_for_each_entry(dev_res2, head, list) {
+ align = pci_resource_alignment(dev_res2->dev,
+ dev_res2->res);
+ if (add_align > align)
+ list_move_tail(&dev_res->list,
+ &dev_res2->list);
+ }
+ }
+
+ }
+
/* Try updated head list with add_size added */
assign_requested_resources_sorted(head, &local_fail_head);
@@ -928,6 +972,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
mask | IORESOURCE_PREFETCH, type);
unsigned int mem64_mask = 0;
resource_size_t children_add_size = 0;
+ resource_size_t children_add_align = 0;
+ resource_size_t add_align = 0;
if (!b_res)
return 0;
@@ -955,6 +1001,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
/* put SRIOV requested res to the optional list */
if (realloc_head && i >= PCI_IOV_RESOURCES &&
i <= PCI_IOV_RESOURCE_END) {
+ add_align = max(pci_resource_alignment(dev, r), add_align);
r->end = r->start - 1;
add_to_list(realloc_head, dev, r, r_size, 0/* don't care */);
children_add_size += r_size;
@@ -982,8 +1029,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
max_order = order;
mem64_mask &= r->flags & IORESOURCE_MEM_64;
- if (realloc_head)
+ if (realloc_head) {
children_add_size += get_res_add_size(realloc_head, r);
+ children_add_align = get_res_add_align(realloc_head, r);
+ add_align = max(add_align, children_add_align);
+ }
}
}
@@ -994,7 +1044,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
add_size = children_add_size;
size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
calculate_memsize(size, min_size, add_size,
- resource_size(b_res), min_align);
+ resource_size(b_res), max(min_align, add_align));
if (!size0 && !size1) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
@@ -1007,10 +1057,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
b_res->end = size0 + min_align - 1;
b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
if (size1 > size0 && realloc_head) {
- add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
+ add_to_list(realloc_head, bus->self, b_res, size1-size0,
+ max(min_align, add_align));
dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
- "%pR to %pR add_size %llx\n", b_res,
- &bus->busn_res, (unsigned long long)size1-size0);
+ "%pR to %pR add_size %llx add_align %llx\n", b_res,
+ &bus->busn_res, (unsigned long long)size1-size0,
+ max(min_align, add_align));
}
return 1;
}
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 12/17] powerpc/powernv: implement pcibios_sriov_resource_alignment on powernv
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
This patch implements the pcibios_sriov_resource_alignment() on powernv
platform.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/machdep.h | 1 +
arch/powerpc/kernel/pci-common.c | 8 ++++++++
arch/powerpc/platforms/powernv/pci-ioda.c | 17 +++++++++++++++++
3 files changed, 26 insertions(+)
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 2f2e770..3bbc55f 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -242,6 +242,7 @@ struct machdep_calls {
resource_size_t (*pcibios_window_alignment)(struct pci_bus *, unsigned long type);
#ifdef CONFIG_PCI_IOV
resource_size_t (*__pci_sriov_resource_size)(struct pci_dev *, int resno);
+ resource_size_t (*__pci_sriov_resource_alignment)(struct pci_dev *, int resno, resource_size_t align);
#endif /* CONFIG_PCI_IOV */
/* Called to shutdown machine specific hardware not already controlled
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index c4e2e92..35345ac 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -128,6 +128,14 @@ resource_size_t pcibios_sriov_resource_size(struct pci_dev *pdev, int resno)
return 0;
}
+
+resource_size_t pcibios_sriov_resource_alignment(struct pci_dev *pdev, int resno, resource_size_t align)
+{
+ if (ppc_md.__pci_sriov_resource_alignment)
+ return ppc_md.__pci_sriov_resource_alignment(pdev, resno, align);
+
+ return 0;
+}
#endif /* CONFIG_PCI_IOV */
static resource_size_t pcibios_io_size(const struct pci_controller *hose)
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 7dfad6a..b0ac851 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1573,6 +1573,22 @@ static resource_size_t __pnv_pci_sriov_resource_size(struct pci_dev *pdev, int r
return size;
}
+
+static resource_size_t __pnv_pci_sriov_resource_alignment(struct pci_dev *pdev, int resno,
+ resource_size_t align)
+{
+ struct pci_dn *pdn = pci_get_pdn(pdev);
+ resource_size_t iov_align;
+
+ iov_align = resource_size(&pdev->resource[resno]);
+ if (iov_align)
+ return iov_align;
+
+ if (pdn->vfs)
+ return pdn->vfs * align;
+
+ return align;
+}
#endif /* CONFIG_PCI_IOV */
/* Prevent enabling devices for which we couldn't properly
@@ -1777,6 +1793,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
ppc_md.pcibios_window_alignment = pnv_pci_window_alignment;
#ifdef CONFIG_PCI_IOV
ppc_md.__pci_sriov_resource_size = __pnv_pci_sriov_resource_size;
+ ppc_md.__pci_sriov_resource_alignment = __pnv_pci_sriov_resource_alignment;
#endif /* CONFIG_PCI_IOV */
pci_add_flags(PCI_REASSIGN_ALL_RSRC);
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 11/17] ppc/pnv: Expand VF resources according to the number of total_pe
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
On PHB3, VF resources will be covered by M64 BAR to have better PE isolation.
Mostly the total_pe number is different from the total_VFs, which will lead to
a conflict between MMIO space and the PE number.
This patch expands the VF resource size to reserve total_pe number of VFs'
resource, which prevents the conflict.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/machdep.h | 6 +++
arch/powerpc/include/asm/pci-bridge.h | 3 ++
arch/powerpc/kernel/pci-common.c | 15 ++++++
arch/powerpc/platforms/powernv/pci-ioda.c | 83 +++++++++++++++++++++++++++++
4 files changed, 107 insertions(+)
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index ad3025d..2f2e770 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -234,9 +234,15 @@ struct machdep_calls {
/* Called after scan and before resource survey */
void (*pcibios_fixup_phb)(struct pci_controller *hose);
+#ifdef CONFIG_PCI_IOV
+ void (*pcibios_fixup_sriov)(struct pci_bus *bus);
+#endif /* CONFIG_PCI_IOV */
/* Called during PCI resource reassignment */
resource_size_t (*pcibios_window_alignment)(struct pci_bus *, unsigned long type);
+#ifdef CONFIG_PCI_IOV
+ resource_size_t (*__pci_sriov_resource_size)(struct pci_dev *, int resno);
+#endif /* CONFIG_PCI_IOV */
/* Called to shutdown machine specific hardware not already controlled
* by other drivers.
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 4ca90a3..8c849d8 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -168,6 +168,9 @@ struct pci_dn {
#define IODA_INVALID_PE (-1)
#ifdef CONFIG_PPC_POWERNV
int pe_number;
+#ifdef CONFIG_PCI_IOV
+ u16 vfs;
+#endif /* CONFIG_PCI_IOV */
#endif
};
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index c449a26..c4e2e92 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -120,6 +120,16 @@ resource_size_t pcibios_window_alignment(struct pci_bus *bus,
return 1;
}
+#ifdef CONFIG_PCI_IOV
+resource_size_t pcibios_sriov_resource_size(struct pci_dev *pdev, int resno)
+{
+ if (ppc_md.__pci_sriov_resource_size)
+ return ppc_md.__pci_sriov_resource_size(pdev, resno);
+
+ return 0;
+}
+#endif /* CONFIG_PCI_IOV */
+
static resource_size_t pcibios_io_size(const struct pci_controller *hose)
{
#ifdef CONFIG_PPC64
@@ -1675,6 +1685,11 @@ void pcibios_scan_phb(struct pci_controller *hose)
if (ppc_md.pcibios_fixup_phb)
ppc_md.pcibios_fixup_phb(hose);
+#ifdef CONFIG_PCI_IOV
+ if (ppc_md.pcibios_fixup_sriov)
+ ppc_md.pcibios_fixup_sriov(bus);
+#endif /* CONFIG_PCI_IOV */
+
/* Configure PCI Express settings */
if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
struct pci_bus *child;
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 87cb3089..7dfad6a 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1298,6 +1298,67 @@ static void pnv_pci_init_ioda_msis(struct pnv_phb *phb)
static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { }
#endif /* CONFIG_PCI_MSI */
+#ifdef CONFIG_PCI_IOV
+static void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct resource *res;
+ int i;
+ resource_size_t size;
+ struct pci_dn *pdn;
+
+ if (!pdev->is_physfn || pdev->is_added)
+ return;
+
+ hose = pci_bus_to_host(pdev->bus);
+ if (!hose) {
+ dev_err(&pdev->dev, "%s: NULL pci_controller\n", __func__);
+ return;
+ }
+
+ phb = hose->private_data;
+ if (!phb) {
+ dev_err(&pdev->dev, "%s: NULL PHB\n", __func__);
+ return;
+ }
+
+ pdn = pci_get_pdn(pdev);
+ pdn->vfs = 0;
+
+ for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
+ res = &pdev->resource[i];
+ if (!res->flags || res->parent)
+ continue;
+
+ if (!is_mem_pref_64_type(res->flags))
+ continue;
+
+ dev_info(&pdev->dev, "PowerNV: Fixing VF BAR[%d] %pR to\n",
+ i, res);
+ size = pci_sriov_resource_size(pdev, i);
+ res->end = res->start + size * phb->ioda.total_pe - 1;
+ dev_info(&pdev->dev, " %pR\n", res);
+ }
+ pdn->vfs = phb->ioda.total_pe;
+}
+
+static void pnv_pci_ioda_fixup_sriov(struct pci_bus *bus)
+{
+ struct pci_dev *pdev;
+ struct pci_bus *b;
+
+ list_for_each_entry(pdev, &bus->devices, bus_list) {
+ b = pdev->subordinate;
+
+ if (b)
+ pnv_pci_ioda_fixup_sriov(b);
+
+ pnv_pci_ioda_fixup_iov_resources(pdev);
+ }
+}
+#endif /* CONFIG_PCI_IOV */
+
/*
* This function is supposed to be called on basis of PE from top
* to bottom style. So the the I/O or MMIO segment assigned to
@@ -1498,6 +1559,22 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
return phb->ioda.io_segsize;
}
+#ifdef CONFIG_PCI_IOV
+static resource_size_t __pnv_pci_sriov_resource_size(struct pci_dev *pdev, int resno)
+{
+ struct pci_dn *pdn = pci_get_pdn(pdev);
+ u64 size = 0;
+
+ if (!pdn->vfs)
+ return size;
+
+ size = resource_size(pdev->resource + resno);
+ do_div(size, pdn->vfs);
+
+ return size;
+}
+#endif /* CONFIG_PCI_IOV */
+
/* Prevent enabling devices for which we couldn't properly
* assign a PE
*/
@@ -1692,9 +1769,15 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
* for the P2P bridge bars so that each PCI bus (excluding
* the child P2P bridges) can form individual PE.
*/
+#ifdef CONFIG_PCI_IOV
+ ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_sriov;
+#endif /* CONFIG_PCI_IOV */
ppc_md.pcibios_fixup = pnv_pci_ioda_fixup;
ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
ppc_md.pcibios_window_alignment = pnv_pci_window_alignment;
+#ifdef CONFIG_PCI_IOV
+ ppc_md.__pci_sriov_resource_size = __pnv_pci_sriov_resource_size;
+#endif /* CONFIG_PCI_IOV */
pci_add_flags(PCI_REASSIGN_ALL_RSRC);
/* Reset IODA tables to a clean state */
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 13/17] powerpc/powernv: shift VF resource with an offset
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
On powrnv platform, resource position in M64 implies the PE# the resource
belongs to. In some particular case, adjustment of a resource is necessary to
locate it to a correct position in M64.
This patch introduce a function to shift the 'real' VF BAR address according to
an offset.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 30 +++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index b0ac851..e46c5bf 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/pci_regs.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/string.h>
@@ -544,6 +545,35 @@ static unsigned int pnv_ioda_dma_weight(struct pci_dev *dev)
return 10;
}
+#ifdef CONFIG_PCI_IOV
+static void pnv_pci_vf_resource_shift(struct pci_dev *dev, int offset)
+{
+ struct pci_dn *pdn = pci_get_pdn(dev);
+ int i;
+ struct resource *res;
+ resource_size_t size;
+
+ if (dev->is_physfn) {
+ for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+ res = dev->resource + PCI_IOV_RESOURCES + i;
+ if (!res->flags || !res->parent)
+ continue;
+
+ if (!is_mem_pref_64_type(res->flags))
+ continue;
+
+ dev_info(&dev->dev, "PowerNV: Shifting VF BAR %pR to\n", res);
+ size = pci_sriov_resource_size(dev, PCI_IOV_RESOURCES + i);
+ res->start += size*offset;
+
+ dev_info(&dev->dev, " %pR\n", res);
+ pci_update_resource(dev, PCI_IOV_RESOURCES + i);
+ }
+ pdn->vfs -= offset;
+ }
+}
+#endif /* CONFIG_PCI_IOV */
+
#if 0
static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
{
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 14/17] ppc/pci: create/release dev-tree node for VFs
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
Currently, powernv platform is not aware of VFs. This means no dev-node
represents a VF. Also, VF PCI device is created when PF driver want to enable
it. This leads to the pdn->pdev and pdn->pe_number an invalid value.
This patch create/release dev-node for VF and fixs this when a VF's pci_dev
is created.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/Kconfig | 1 +
arch/powerpc/platforms/powernv/pci-ioda.c | 103 +++++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/pci.c | 20 ++++++
3 files changed, 124 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
index 895e8a2..0dd331b 100644
--- a/arch/powerpc/platforms/powernv/Kconfig
+++ b/arch/powerpc/platforms/powernv/Kconfig
@@ -11,6 +11,7 @@ config PPC_POWERNV
select PPC_UDBG_16550
select PPC_SCOM
select ARCH_RANDOM
+ select OF_DYNAMIC
default y
config PPC_POWERNV_RTAS
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index e46c5bf..9ace027 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <linux/msi.h>
#include <linux/memblock.h>
+#include <linux/of_pci.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -771,6 +772,108 @@ static void pnv_pci_ioda_setup_PEs(void)
}
}
+#ifdef CONFIG_PCI_IOV
+static void pnv_pci_create_vf_node(struct pci_dev *dev, u16 vf_num)
+{
+ struct device_node *dn, *p_dn;
+ struct pci_dn *pdn;
+ struct pci_controller *hose;
+ struct property *pp;
+ void* value;
+ u16 id;
+
+ hose = pci_bus_to_host(dev->bus);
+
+ /* Create dev-tree node for VFs if this is a PF */
+ p_dn = pci_bus_to_OF_node(dev->bus);
+ if (p_dn == NULL) {
+ dev_err(&dev->dev, "SRIOV: VF bus NULL device node\n");
+ return;
+ }
+
+ for (id = 0; id < vf_num; id++) {
+ dn = kzalloc(sizeof(*dn), GFP_KERNEL);
+ pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ value = kzalloc(sizeof(u32), GFP_KERNEL);
+
+ if (!dn || !pdn || !pp || !value) {
+ kfree(dn);
+ kfree(pdn);
+ kfree(pp);
+ kfree(value);
+ dev_warn(&dev->dev, "%s: failed to create"
+ "dev-tree node for idx(%d)\n",
+ __func__, id);
+
+ break;
+ }
+
+ pp->value = value;
+ pdn->node = dn;
+ pdn->devfn = pci_iov_virtfn_devfn(dev, id);
+ pdn->busno = dev->bus->number;
+ pdn->pe_number = IODA_INVALID_PE;
+ pdn->phb = hose;
+
+ dn->data = pdn;
+ kref_init(&dn->kref);
+ dn->full_name = dn->name =
+ kasprintf(GFP_KERNEL, "%s/vf%d",
+ p_dn->full_name, pdn->devfn);
+ dn->parent = p_dn;
+
+ pp->name = kasprintf(GFP_KERNEL, "reg");
+ pp->length = 5 * sizeof(__be32);
+ *(u32*)pp->value = cpu_to_be32(pdn->devfn) << 8;
+ dn->properties = pp;
+
+ of_attach_node(dn);
+ }
+}
+
+static void pnv_pci_release_vf_node(struct pci_dev *dev, u16 vf_num)
+{
+ struct device_node *dn;
+ struct property *pp;
+ u16 id;
+
+ for (id = 0; id < vf_num; id++) {
+ dn = of_pci_find_child_device(dev->bus->dev.of_node,
+ pci_iov_virtfn_devfn(dev, id));
+ if (!dn)
+ continue;
+
+ of_detach_node(dn);
+ pp = dn->properties;
+ kfree(pp->name);
+ kfree(pp->value);
+ kfree(pp);
+ kfree(dn->data);
+ kfree(dn);
+ }
+}
+
+int pcibios_sriov_disable(struct pci_dev *pdev)
+{
+ struct pci_sriov *iov;
+ u16 vf_num;
+
+ iov = pdev->sriov;
+ vf_num = iov->num_VFs;
+ pnv_pci_release_vf_node(pdev, vf_num);
+
+ return 0;
+}
+
+int pcibios_sriov_enable(struct pci_dev *pdev, u16 vf_num)
+{
+ pnv_pci_create_vf_node(pdev, vf_num);
+
+ return 0;
+}
+#endif /* CONFIG_PCI_IOV */
+
static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev)
{
struct pci_dn *pdn = pci_get_pdn(pdev);
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 687a068..43fcc73 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -654,6 +654,26 @@ static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
struct pnv_phb *phb = hose->private_data;
+#ifdef CONFIG_PCI_IOV
+ struct pnv_ioda_pe *pe;
+ struct pci_dn *pdn;
+
+ /* Fix the VF pdn PE number */
+ if (pdev->is_virtfn) {
+ pdn = pci_get_pdn(pdev);
+ if (pdn->pcidev == NULL || pdn->pe_number == IODA_INVALID_PE) {
+ list_for_each_entry(pe, &phb->ioda.pe_list, list) {
+ if (pe->rid ==
+ ((pdev->bus->number << 8) | (pdev->devfn & 0xff))) {
+ pdn->pcidev = pdev;
+ pdn->pe_number = pe->pe_number;
+ pe->pdev = pdev;
+ break;
+ }
+ }
+ }
+ }
+#endif /* CONFIG_PCI_IOV */
/* If we have no phb structure, try to setup a fallback based on
* the device-tree (RTAS PCI for example)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 16/17] ppc/pci: Expanding IOV BAR, with m64_per_iov supported
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
M64 aperture size is limited on PHB3. When the IOV BAR is too big, this will
exceed the limitation and failed to be assigned.
This patch introduce a different expanding based on the IOV BAR size:
IOV BAR size is smaller than 64M, expand to total_pe.
IOV BAR size is bigger than 64M, roundup power2.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/pci-bridge.h | 2 ++
arch/powerpc/platforms/powernv/pci-ioda.c | 28 ++++++++++++++++++++++++++--
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 72f0af5..36b88e4 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -171,6 +171,8 @@ struct pci_dn {
#ifdef CONFIG_PCI_IOV
u16 vfs;
int offset;
+#define M64_PER_IOV 4
+ int m64_per_iov;
int m64_wins[PCI_SRIOV_NUM_BARS];
#endif /* CONFIG_PCI_IOV */
#endif
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index fb2c2c6..98fc163 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1756,6 +1756,7 @@ static void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev)
int i;
resource_size_t size;
struct pci_dn *pdn;
+ int mul, total_vfs;
if (!pdev->is_physfn || pdev->is_added)
return;
@@ -1775,6 +1776,10 @@ static void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev)
pdn = pci_get_pdn(pdev);
pdn->vfs = 0;
+ total_vfs = pci_sriov_get_totalvfs(pdev);
+ pdn->m64_per_iov = 1;
+ mul = phb->ioda.total_pe;
+
for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
res = &pdev->resource[i];
if (!res->flags || res->parent)
@@ -1783,13 +1788,32 @@ static void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev)
if (!is_mem_pref_64_type(res->flags))
continue;
+ size = pci_sriov_resource_size(pdev, i);
+
+ /* bigger than 64M */
+ if (size > (1 << 26)) {
+ dev_info(&pdev->dev, "PowerNV: VF BAR[%d] size "
+ "is bigger than 64M, roundup power2\n", i);
+ pdn->m64_per_iov = M64_PER_IOV;
+ mul = __roundup_pow_of_two(total_vfs);
+ break;
+ }
+ }
+
+ for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
+ res = &pdev->resource[i];
+ if (!res->flags || res->parent)
+ continue;
+ if (!is_mem_pref_64_type(res->flags))
+ continue;
+
dev_info(&pdev->dev, "PowerNV: Fixing VF BAR[%d] %pR to\n",
i, res);
size = pci_sriov_resource_size(pdev, i);
- res->end = res->start + size * phb->ioda.total_pe - 1;
+ res->end = res->start + size * mul - 1;
dev_info(&pdev->dev, " %pR\n", res);
}
- pdn->vfs = phb->ioda.total_pe;
+ pdn->vfs = mul;
}
static void pnv_pci_ioda_fixup_sriov(struct pci_bus *bus)
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 15/17] powerpc/powernv: allocate VF PE
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
VFs are created, when driver intends to enable sriov.
This patch assign related resources and allocate PEs for VF at this moment.
This patch allocate enough M64 for IOV BAR and shift the VF resource to meet
the PE# indicated by M64.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/pci-bridge.h | 2 +
arch/powerpc/platforms/powernv/pci-ioda.c | 340 ++++++++++++++++++++++++++++-
arch/powerpc/platforms/powernv/pci.h | 10 +-
3 files changed, 339 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 8c849d8..72f0af5 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -170,6 +170,8 @@ struct pci_dn {
int pe_number;
#ifdef CONFIG_PCI_IOV
u16 vfs;
+ int offset;
+ int m64_wins[PCI_SRIOV_NUM_BARS];
#endif /* CONFIG_PCI_IOV */
#endif
};
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 9ace027..fb2c2c6 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -42,6 +42,17 @@
#include "powernv.h"
#include "pci.h"
+#ifdef CONFIG_PCI_IOV
+#define VF_PE_LOG \
+ else if (pe->flags & PNV_IODA_PE_VF) \
+ sprintf(pfix, "%04x:%02x:%2x.%d", \
+ pci_domain_nr(pe->parent_dev->bus), \
+ (pe->rid & 0xff00) >> 8, \
+ PCI_SLOT(pe->rid), PCI_FUNC(pe->rid));
+#else /* CONFIG_PCI_IOV*/
+#define VF_PE_LOG
+#endif /* CONFIG_PCI_IOV*/
+
#define define_pe_printk_level(func, kern_level) \
static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
{ \
@@ -55,13 +66,14 @@ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...) \
vaf.fmt = fmt; \
vaf.va = &args; \
\
- if (pe->pdev) \
+ if (pe->flags & PNV_IODA_PE_DEV) \
strlcpy(pfix, dev_name(&pe->pdev->dev), \
sizeof(pfix)); \
- else \
+ else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) \
sprintf(pfix, "%04x:%02x ", \
pci_domain_nr(pe->pbus), \
pe->pbus->number); \
+ VF_PE_LOG \
r = printk(kern_level "pci %s: [PE# %.3d] %pV", \
pfix, pe->pe_number, &vaf); \
\
@@ -365,7 +377,12 @@ static int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
}
rid_end = pe->rid + (count << 8);
}else {
- parent = pe->pdev->bus->self;
+#ifdef CONFIG_PCI_IOV
+ if (pe->flags & PNV_IODA_PE_VF)
+ parent = pe->parent_dev;
+ else
+#endif /* CONFIG_PCI_IOV */
+ parent = pe->pdev->bus->self;
bcomp = OpalPciBusAll;
dcomp = OPAL_COMPARE_RID_DEVICE_NUMBER;
fcomp = OPAL_COMPARE_RID_FUNCTION_NUMBER;
@@ -405,6 +422,9 @@ static int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
pe->pbus = NULL;
pe->pdev = NULL;
+#ifdef CONFIG_PCI_IOV
+ pe->parent_dev = NULL;
+#endif /* CONFIG_PCI_IOV */
return 0;
}
@@ -443,7 +463,12 @@ static int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
}
rid_end = pe->rid + (count << 8);
} else {
- parent = pe->pdev->bus->self;
+#ifdef CONFIG_PCI_IOV
+ if (pe->flags & PNV_IODA_PE_VF)
+ parent = pe->parent_dev;
+ else
+#endif /* CONFIG_PCI_IOV */
+ parent = pe->pdev->bus->self;
bcomp = OpalPciBusAll;
dcomp = OPAL_COMPARE_RID_DEVICE_NUMBER;
fcomp = OPAL_COMPARE_RID_FUNCTION_NUMBER;
@@ -773,6 +798,114 @@ static void pnv_pci_ioda_setup_PEs(void)
}
#ifdef CONFIG_PCI_IOV
+static int pnv_pci_vf_release_m64(struct pci_dev *pdev)
+{
+ struct pci_bus *bus;
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct pci_dn *pdn;
+ int i;
+
+ bus = pdev->bus;
+ hose = pci_bus_to_host(bus);
+ phb = hose->private_data;
+ pdn = pci_get_pdn(pdev);
+
+ for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+ if (pdn->m64_wins[i] == -1)
+ continue;
+ opal_pci_phb_mmio_enable(phb->opal_id,
+ OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i], 0);
+ clear_bit(pdn->m64_wins[i], &phb->ioda.m64win_alloc);
+ pdn->m64_wins[i] = -1;
+ }
+
+ return 0;
+}
+
+static int pnv_pci_vf_assign_m64(struct pci_dev *pdev)
+{
+ struct pci_bus *bus;
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct pci_dn *pdn;
+ unsigned int win;
+ struct resource *res;
+ int i;
+ int64_t rc;
+
+ bus = pdev->bus;
+ hose = pci_bus_to_host(bus);
+ phb = hose->private_data;
+ pdn = pci_get_pdn(pdev);
+
+ /* Initialize the m64_wins to -1 */
+ for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
+ pdn->m64_wins[i] = -1;
+
+ for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+ res = pdev->resource + PCI_IOV_RESOURCES + i;
+ if (!res->flags || !res->parent)
+ continue;
+
+ if (!is_mem_pref_64_type(res->flags))
+ continue;
+
+ do {
+ win = find_next_zero_bit(&phb->ioda.m64win_alloc,
+ phb->ioda.m64_bars, 0);
+
+ if (win >= phb->ioda.m64_bars)
+ goto m64_failed;
+ } while (test_and_set_bit(win, &phb->ioda.m64win_alloc));
+
+ pdn->m64_wins[i] = win;
+
+ /* Map the M64 here */
+ rc = opal_pci_set_phb_mem_window(phb->opal_id,
+ OPAL_M64_WINDOW_TYPE,
+ pdn->m64_wins[i],
+ res->start,
+ 0, /* unused */
+ resource_size(res));
+ if (rc != OPAL_SUCCESS) {
+ pr_err("Failed to map M64 BAR #%d: %lld\n", win, rc);
+ goto m64_failed;
+ }
+
+ rc = opal_pci_phb_mmio_enable(phb->opal_id,
+ OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i], 1);
+ if (rc != OPAL_SUCCESS) {
+ pr_err("Failed to enable M64 BAR #%d: %llx\n", win, rc);
+ goto m64_failed;
+ }
+ }
+ return 0;
+
+m64_failed:
+ pnv_pci_vf_release_m64(pdev);
+ return -EBUSY;
+}
+
+static void pnv_pci_release_dev_dma(struct pci_dev *dev, struct pnv_ioda_pe *pe)
+{
+ struct pci_bus *bus;
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct iommu_table *tbl;
+ unsigned long addr;
+
+ bus = dev->bus;
+ hose = pci_bus_to_host(bus);
+ phb = hose->private_data;
+ tbl = pe->tce32_table;
+ addr = tbl->it_base;
+
+ iommu_free_table(tbl, of_node_full_name(dev->dev.of_node));
+ free_pages(addr, get_order(PNV_TCE32_TAB_SIZE));
+ pe->tce32_table = NULL;
+}
+
static void pnv_pci_create_vf_node(struct pci_dev *dev, u16 vf_num)
{
struct device_node *dn, *p_dn;
@@ -854,23 +987,186 @@ static void pnv_pci_release_vf_node(struct pci_dev *dev, u16 vf_num)
}
}
+static void pnv_ioda_release_vf_PE(struct pci_dev *pdev)
+{
+ struct pci_bus *bus;
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct pnv_ioda_pe *pe, *pe_n;
+ struct pci_dn *pdn;
+
+ bus = pdev->bus;
+ hose = pci_bus_to_host(bus);
+ phb = hose->private_data;
+
+ if (!pdev->is_physfn)
+ return;
+
+ pdn = pci_get_pdn(pdev);
+ list_for_each_entry_safe(pe, pe_n, &phb->ioda.pe_list, list) {
+ if (pe->parent_dev != pdev)
+ continue;
+
+ pnv_pci_release_dev_dma(pdev, pe);
+
+ /* Remove from list */
+ mutex_lock(&phb->ioda.pe_list_mutex);
+ list_del(&pe->list);
+ mutex_unlock(&phb->ioda.pe_list_mutex);
+
+ pnv_ioda_deconfigure_pe(phb, pe);
+
+ pnv_ioda_free_pe(phb, pe->pe_number);
+ }
+}
+
int pcibios_sriov_disable(struct pci_dev *pdev)
{
- struct pci_sriov *iov;
+ struct pci_bus *bus;
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct pci_dn *pdn;
+ struct pci_sriov *iov;
u16 vf_num;
+ bus = pdev->bus;
+ hose = pci_bus_to_host(bus);
+ phb = hose->private_data;
+ pdn = pci_get_pdn(pdev);
iov = pdev->sriov;
vf_num = iov->num_VFs;
+
+ /* Release VF PEs */
+ pnv_ioda_release_vf_PE(pdev);
pnv_pci_release_vf_node(pdev, vf_num);
+ if (phb->type == PNV_PHB_IODA2) {
+ pnv_pci_vf_resource_shift(pdev, -pdn->offset);
+
+ /* Release M64 BARs */
+ pnv_pci_vf_release_m64(pdev);
+
+ /* Release PE numbers */
+ bitmap_clear(phb->ioda.pe_alloc, pdn->offset, vf_num);
+ pdn->offset = 0;
+ }
+
return 0;
}
+static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
+ struct pnv_ioda_pe *pe);
+static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 vf_num)
+{
+ struct pci_bus *bus;
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct pnv_ioda_pe *pe;
+ int pe_num;
+ u16 vf_index;
+ struct pci_dn *pdn;
+
+ bus = pdev->bus;
+ hose = pci_bus_to_host(bus);
+ phb = hose->private_data;
+ pdn = pci_get_pdn(pdev);
+
+ if (!pdev->is_physfn)
+ return;
+
+ /* Reserve PE for each VF */
+ for (vf_index = 0; vf_index < vf_num; vf_index++) {
+ pe_num = pdn->offset + vf_index;
+
+ pe = &phb->ioda.pe_array[pe_num];
+ pe->pe_number = pe_num;
+ pe->phb = phb;
+ pe->flags = PNV_IODA_PE_VF;
+ pe->pbus = NULL;
+ pe->parent_dev = pdev;
+ pe->tce32_seg = -1;
+ pe->mve_number = -1;
+ pe->rid = (pci_iov_virtfn_bus(pdev, vf_index) << 8) |
+ pci_iov_virtfn_devfn(pdev, vf_index);
+
+ pe_info(pe, "VF %04d:%02d:%02d.%d associated with PE#%d\n",
+ hose->global_number, pdev->bus->number,
+ PCI_SLOT(pci_iov_virtfn_devfn(pdev, vf_index)),
+ PCI_FUNC(pci_iov_virtfn_devfn(pdev, vf_index)), pe_num);
+
+ if (pnv_ioda_configure_pe(phb, pe)) {
+ /* XXX What do we do here ? */
+ if (pe_num)
+ pnv_ioda_free_pe(phb, pe_num);
+ pe->pdev = NULL;
+ continue;
+ }
+
+ pe->tce32_table = kzalloc_node(sizeof(struct iommu_table),
+ GFP_KERNEL, hose->node);
+ pe->tce32_table->data = pe;
+
+ /* Put PE to the list */
+ mutex_lock(&phb->ioda.pe_list_mutex);
+ list_add_tail(&pe->list, &phb->ioda.pe_list);
+ mutex_unlock(&phb->ioda.pe_list_mutex);
+
+ pnv_pci_ioda2_setup_dma_pe(phb, pe);
+
+ }
+}
+
int pcibios_sriov_enable(struct pci_dev *pdev, u16 vf_num)
{
+ struct pci_bus *bus;
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct pci_dn *pdn;
+ int ret;
+
+ bus = pdev->bus;
+ hose = pci_bus_to_host(bus);
+ phb = hose->private_data;
+ pdn = pci_get_pdn(pdev);
+
+ if (phb->type == PNV_PHB_IODA2) {
+ /* Calculate available PE for required VFs */
+ mutex_lock(&phb->ioda.pe_alloc_mutex);
+ pdn->offset = bitmap_find_next_zero_area(
+ phb->ioda.pe_alloc, phb->ioda.total_pe,
+ 0, vf_num, 0);
+ if (pdn->offset >= phb->ioda.total_pe) {
+ mutex_unlock(&phb->ioda.pe_alloc_mutex);
+ pr_info("Failed to enable %d VFs, reduce VF number"
+ " and try again\n", vf_num);
+ pdn->offset = 0;
+ return -EBUSY;
+ }
+ bitmap_set(phb->ioda.pe_alloc, pdn->offset, vf_num);
+ mutex_unlock(&phb->ioda.pe_alloc_mutex);
+
+ /* Assign M64 BAR accordingly */
+ ret = pnv_pci_vf_assign_m64(pdev);
+ if (ret) {
+ pr_info("No enough M64 resource\n");
+ goto m64_failed;
+ }
+
+ /* Do some magic shift */
+ pnv_pci_vf_resource_shift(pdev, pdn->offset);
+ }
+
+ /* Setup VF PEs */
pnv_pci_create_vf_node(pdev, vf_num);
+ pnv_ioda_setup_vf_PE(pdev, vf_num);
return 0;
+
+m64_failed:
+ bitmap_clear(phb->ioda.pe_alloc, pdn->offset, vf_num);
+ pdn->offset = 0;
+
+ return ret;
}
#endif /* CONFIG_PCI_IOV */
@@ -1095,12 +1391,22 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
TCE_PCI_SWINV_PAIR;
}
iommu_init_table(tbl, phb->hose->node);
- iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
- if (pe->pdev)
+ if (pe->flags & PNV_IODA_PE_DEV) {
+ iommu_register_group(tbl, pci_domain_nr(pe->pdev->bus),
+ pe->pe_number);
set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
- else
+ }
+ else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) {
+ iommu_register_group(tbl, pci_domain_nr(pe->pbus),
+ pe->pe_number);
pnv_ioda_setup_bus_dma(pe, pe->pbus);
+ }
+#ifdef CONFIG_PCI_IOV
+ else if (pe->flags & PNV_IODA_PE_VF)
+ iommu_register_group(tbl, pci_domain_nr(pe->parent_dev->bus),
+ pe->pe_number);
+#endif /* CONFIG_PCI_IOV */
return;
fail:
@@ -1223,12 +1529,22 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
tbl->it_type = TCE_PCI_SWINV_CREATE | TCE_PCI_SWINV_FREE;
}
iommu_init_table(tbl, phb->hose->node);
- iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
- if (pe->pdev)
+ if (pe->flags & PNV_IODA_PE_DEV) {
+ iommu_register_group(tbl, pci_domain_nr(pe->pdev->bus),
+ pe->pe_number);
set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
- else
+ }
+ else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) {
+ iommu_register_group(tbl, pci_domain_nr(pe->pbus),
+ pe->pe_number);
pnv_ioda_setup_bus_dma(pe, pe->pbus);
+ }
+#ifdef CONFIG_PCI_IOV
+ else if (pe->flags & PNV_IODA_PE_VF)
+ iommu_register_group(tbl, pci_domain_nr(pe->parent_dev->bus),
+ pe->pe_number);
+#endif /* CONFIG_PCI_IOV */
/* Also create a bypass window */
pnv_pci_ioda2_setup_bypass_pe(phb, pe);
@@ -1813,6 +2129,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
phb->hub_id = hub_id;
phb->opal_id = phb_id;
phb->type = ioda_type;
+ mutex_init(&phb->ioda.pe_alloc_mutex);
/* Detect specific models for error handling */
if (of_device_is_compatible(np, "ibm,p7ioc-pciex"))
@@ -1873,6 +2190,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
INIT_LIST_HEAD(&phb->ioda.pe_dma_list);
INIT_LIST_HEAD(&phb->ioda.pe_list);
+ mutex_init(&phb->ioda.pe_list_mutex);
/* Calculate how many 32-bit TCE segments we have */
phb->ioda.tce32_count = phb->ioda.m32_pci_base >> PNV_TCE32_SEG_SHIFT;
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 9fbf7c0..e3ca524 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -28,8 +28,9 @@ static inline bool is_mem_pref_64_type(unsigned long flags)
#define PNV_PCI_DIAG_BUF_SIZE 8192
#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_VF (1 << 1) /* PE for one VF */
+#define PNV_IODA_PE_BUS (1 << 2) /* PE has primary PCI bus */
+#define PNV_IODA_PE_BUS_ALL (1 << 3) /* PE has subordinate buses */
/* Data associated with a PE, including IOMMU tracking etc.. */
struct pnv_phb;
@@ -41,6 +42,9 @@ struct pnv_ioda_pe {
* entire bus (& children). In the former case, pdev
* is populated, in the later case, pbus is.
*/
+#ifdef CONFIG_PCI_IOV
+ struct pci_dev *parent_dev;
+#endif
struct pci_dev *pdev;
struct pci_bus *pbus;
@@ -156,6 +160,7 @@ struct pnv_phb {
/* PE allocation bitmap */
unsigned long *pe_alloc;
+ struct mutex pe_alloc_mutex;
/* M64 window allocation bitmap */
unsigned long m64win_alloc;
@@ -174,6 +179,7 @@ struct pnv_phb {
* on the sequence of creation
*/
struct list_head pe_list;
+ struct mutex pe_list_mutex;
/* Reverse map of PEs, will have to extend if
* we are to support more than 256 PEs, indexed
--
1.7.9.5
^ permalink raw reply related
* [RFC PATCH V3 17/17] ppc/pnv: Group VF PE when IOV BAR is big on PHB3
From: Wei Yang @ 2014-06-10 1:56 UTC (permalink / raw)
To: benh; +Cc: Wei Yang, linux-pci, gwshan, qiudayu, bhelgaas, yan, linuxppc-dev
In-Reply-To: <1402365399-5121-1-git-send-email-weiyang@linux.vnet.ibm.com>
When IOV BAR is big, each of it is covered by 4 M64 window. This leads to
several VF PE sits in one PE in terms of M64.
This patch group VF PEs according to the M64 allocation.
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/pci-bridge.h | 2 +-
arch/powerpc/platforms/powernv/pci-ioda.c | 183 +++++++++++++++++++++++------
2 files changed, 145 insertions(+), 40 deletions(-)
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 36b88e4..f0a21f5 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -173,7 +173,7 @@ struct pci_dn {
int offset;
#define M64_PER_IOV 4
int m64_per_iov;
- int m64_wins[PCI_SRIOV_NUM_BARS];
+ int m64_wins[PCI_SRIOV_NUM_BARS][M64_PER_IOV];
#endif /* CONFIG_PCI_IOV */
#endif
};
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 98fc163..86688cd 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -804,26 +804,27 @@ static int pnv_pci_vf_release_m64(struct pci_dev *pdev)
struct pci_controller *hose;
struct pnv_phb *phb;
struct pci_dn *pdn;
- int i;
+ int i, j;
bus = pdev->bus;
hose = pci_bus_to_host(bus);
phb = hose->private_data;
pdn = pci_get_pdn(pdev);
- for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
- if (pdn->m64_wins[i] == -1)
- continue;
- opal_pci_phb_mmio_enable(phb->opal_id,
- OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i], 0);
- clear_bit(pdn->m64_wins[i], &phb->ioda.m64win_alloc);
- pdn->m64_wins[i] = -1;
- }
+ for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
+ for (j = 0; j < M64_PER_IOV; j++) {
+ if (pdn->m64_wins[i][j] == -1)
+ continue;
+ opal_pci_phb_mmio_enable(phb->opal_id,
+ OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i][j], 0);
+ clear_bit(pdn->m64_wins[i][j], &phb->ioda.m64win_alloc);
+ pdn->m64_wins[i][j] = -1;
+ }
return 0;
}
-static int pnv_pci_vf_assign_m64(struct pci_dev *pdev)
+static int pnv_pci_vf_assign_m64(struct pci_dev *pdev, u16 vf_num)
{
struct pci_bus *bus;
struct pci_controller *hose;
@@ -831,17 +832,33 @@ static int pnv_pci_vf_assign_m64(struct pci_dev *pdev)
struct pci_dn *pdn;
unsigned int win;
struct resource *res;
- int i;
+ int i, j;
int64_t rc;
+ int total_vfs;
+ resource_size_t size, start;
+ int pe_num;
+ int vf_groups;
+ int vf_per_group;
bus = pdev->bus;
hose = pci_bus_to_host(bus);
phb = hose->private_data;
pdn = pci_get_pdn(pdev);
+ total_vfs = pci_sriov_get_totalvfs(pdev);
/* Initialize the m64_wins to -1 */
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++)
- pdn->m64_wins[i] = -1;
+ for (j = 0; j < 4; j++)
+ pdn->m64_wins[i][j] = -1;
+
+ if (pdn->m64_per_iov == M64_PER_IOV) {
+ vf_groups = (vf_num <= M64_PER_IOV) ? vf_num: M64_PER_IOV;
+ vf_per_group = (vf_num <= M64_PER_IOV)? 1:
+ __roundup_pow_of_two(vf_num) / pdn->m64_per_iov;
+ } else {
+ vf_groups = 1;
+ vf_per_group = 1;
+ }
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
res = pdev->resource + PCI_IOV_RESOURCES + i;
@@ -851,33 +868,61 @@ static int pnv_pci_vf_assign_m64(struct pci_dev *pdev)
if (!is_mem_pref_64_type(res->flags))
continue;
- do {
- win = find_next_zero_bit(&phb->ioda.m64win_alloc,
- phb->ioda.m64_bars, 0);
-
- if (win >= phb->ioda.m64_bars)
- goto m64_failed;
- } while (test_and_set_bit(win, &phb->ioda.m64win_alloc));
+ for (j = 0; j < vf_groups; j++) {
+ do {
+ win = find_next_zero_bit(&phb->ioda.m64win_alloc,
+ phb->ioda.m64_bars, 0);
+
+ if (win >= phb->ioda.m64_bars)
+ goto m64_failed;
+ } while (test_and_set_bit(win, &phb->ioda.m64win_alloc));
+
+ pdn->m64_wins[i][j] = win;
+
+ if (pdn->m64_per_iov == M64_PER_IOV) {
+ size = pci_sriov_resource_size(pdev,
+ PCI_IOV_RESOURCES + i);
+ size = size * vf_per_group;
+ start = res->start + size * j;
+ } else {
+ size = resource_size(res);
+ start = res->start;
+ }
- pdn->m64_wins[i] = win;
+ /* Map the M64 here */
+ if (pdn->m64_per_iov == M64_PER_IOV) {
+ pe_num = pdn->offset + j;
+ rc = opal_pci_map_pe_mmio_window(phb->opal_id,
+ pe_num, OPAL_M64_WINDOW_TYPE,
+ pdn->m64_wins[i][j], 0);
+ }
- /* Map the M64 here */
- rc = opal_pci_set_phb_mem_window(phb->opal_id,
+ rc = opal_pci_set_phb_mem_window(phb->opal_id,
OPAL_M64_WINDOW_TYPE,
- pdn->m64_wins[i],
- res->start,
+ pdn->m64_wins[i][j],
+ start,
0, /* unused */
- resource_size(res));
- if (rc != OPAL_SUCCESS) {
- pr_err("Failed to map M64 BAR #%d: %lld\n", win, rc);
- goto m64_failed;
- }
+ size);
- rc = opal_pci_phb_mmio_enable(phb->opal_id,
- OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i], 1);
- if (rc != OPAL_SUCCESS) {
- pr_err("Failed to enable M64 BAR #%d: %llx\n", win, rc);
- goto m64_failed;
+
+ if (rc != OPAL_SUCCESS) {
+ pr_err("Failed to set M64 BAR #%d: %lld\n",
+ win, rc);
+ goto m64_failed;
+ }
+
+ if (pdn->m64_per_iov == M64_PER_IOV)
+ rc = opal_pci_phb_mmio_enable(phb->opal_id,
+ OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i][j], 2);
+ else
+ rc = opal_pci_phb_mmio_enable(phb->opal_id,
+ OPAL_M64_WINDOW_TYPE, pdn->m64_wins[i][j], 1);
+
+ if (rc != OPAL_SUCCESS) {
+ pr_err("Failed to enable M64 BAR #%d: %llx\n",
+ win, rc);
+ goto m64_failed;
+ }
}
}
return 0;
@@ -987,21 +1032,51 @@ static void pnv_pci_release_vf_node(struct pci_dev *dev, u16 vf_num)
}
}
-static void pnv_ioda_release_vf_PE(struct pci_dev *pdev)
+static void pnv_ioda_release_vf_PE(struct pci_dev *pdev, u16 vf_num)
{
struct pci_bus *bus;
struct pci_controller *hose;
struct pnv_phb *phb;
struct pnv_ioda_pe *pe, *pe_n;
struct pci_dn *pdn;
+ u16 vf_index;
+ int64_t rc;
bus = pdev->bus;
hose = pci_bus_to_host(bus);
phb = hose->private_data;
+ pdn = pci_get_pdn(pdev);
if (!pdev->is_physfn)
return;
+ if (pdn->m64_per_iov == M64_PER_IOV && vf_num > M64_PER_IOV) {
+ int vf_group;
+ int vf_per_group;
+ int vf_index1;
+
+ vf_per_group = __roundup_pow_of_two(vf_num) / pdn->m64_per_iov;
+
+ for (vf_group = 0; vf_group < M64_PER_IOV; vf_group++)
+ for (vf_index = vf_group * vf_per_group;
+ vf_index < (vf_group + 1) * vf_per_group;
+ vf_index++)
+ for (vf_index1 = vf_group * vf_per_group;
+ vf_index1 < (vf_group + 1) * vf_per_group;
+ vf_index1++){
+
+ rc = opal_pci_set_peltv(phb->opal_id,
+ pdn->offset + vf_index,
+ pdn->offset + vf_index1,
+ OPAL_REMOVE_PE_FROM_DOMAIN);
+
+ if (rc)
+ pr_warn("%s: Failed to unlink same"
+ " group PE#%d(%lld)\n", __func__,
+ pdn->offset + vf_index1, rc);
+ }
+ }
+
pdn = pci_get_pdn(pdev);
list_for_each_entry_safe(pe, pe_n, &phb->ioda.pe_list, list) {
if (pe->parent_dev != pdev)
@@ -1037,11 +1112,12 @@ int pcibios_sriov_disable(struct pci_dev *pdev)
vf_num = iov->num_VFs;
/* Release VF PEs */
- pnv_ioda_release_vf_PE(pdev);
+ pnv_ioda_release_vf_PE(pdev, vf_num);
pnv_pci_release_vf_node(pdev, vf_num);
if (phb->type == PNV_PHB_IODA2) {
- pnv_pci_vf_resource_shift(pdev, -pdn->offset);
+ if (pdn->m64_per_iov == 1)
+ pnv_pci_vf_resource_shift(pdev, -pdn->offset);
/* Release M64 BARs */
pnv_pci_vf_release_m64(pdev);
@@ -1065,6 +1141,7 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 vf_num)
int pe_num;
u16 vf_index;
struct pci_dn *pdn;
+ int64_t rc;
bus = pdev->bus;
hose = pci_bus_to_host(bus);
@@ -1112,7 +1189,34 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 vf_num)
mutex_unlock(&phb->ioda.pe_list_mutex);
pnv_pci_ioda2_setup_dma_pe(phb, pe);
+ }
+ if (pdn->m64_per_iov == M64_PER_IOV && vf_num > M64_PER_IOV) {
+ int vf_group;
+ int vf_per_group;
+ int vf_index1;
+
+ vf_per_group = __roundup_pow_of_two(vf_num) / pdn->m64_per_iov;
+
+ for (vf_group = 0; vf_group < M64_PER_IOV; vf_group++)
+ for (vf_index = vf_group * vf_per_group;
+ vf_index < (vf_group + 1) * vf_per_group;
+ vf_index++)
+ for (vf_index1 = vf_group * vf_per_group;
+ vf_index1 < (vf_group + 1) * vf_per_group;
+ vf_index1++) {
+
+ rc = opal_pci_set_peltv(phb->opal_id,
+ pdn->offset + vf_index,
+ pdn->offset + vf_index1,
+ OPAL_ADD_PE_TO_DOMAIN);
+
+ if (rc)
+ pr_warn("%s: Failed to link same "
+ "group PE#%d(%lld)\n",
+ __func__,
+ pdn->offset + vf_index1, rc);
+ }
}
}
@@ -1146,14 +1250,15 @@ int pcibios_sriov_enable(struct pci_dev *pdev, u16 vf_num)
mutex_unlock(&phb->ioda.pe_alloc_mutex);
/* Assign M64 BAR accordingly */
- ret = pnv_pci_vf_assign_m64(pdev);
+ ret = pnv_pci_vf_assign_m64(pdev, vf_num);
if (ret) {
pr_info("No enough M64 resource\n");
goto m64_failed;
}
/* Do some magic shift */
- pnv_pci_vf_resource_shift(pdev, pdn->offset);
+ if (pdn->m64_per_iov == 1)
+ pnv_pci_vf_resource_shift(pdev, pdn->offset);
}
/* Setup VF PEs */
--
1.7.9.5
^ permalink raw reply related
* Re: [RFC PATCH 1/3] CMA: generalize CMA reserved area management functionality
From: Joonsoo Kim @ 2014-06-10 2:41 UTC (permalink / raw)
To: 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, Aneesh Kumar K.V, Paolo Bonzini,
Andrew Morton, linuxppc-dev, linux-arm-kernel, Marek Szyprowski
In-Reply-To: <xa1tzjhujxbz.fsf@mina86.com>
On Tue, Jun 03, 2014 at 08:56:00AM +0200, Michal Nazarewicz wrote:
> On Tue, Jun 03 2014, 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.
> >
> > Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
>
> Some small comments below, but in general
>
> Acked-by: Michal Nazarewicz <mina86@mina86.com>
Hello, Michal.
Thanks!
>
> >
> > diff --git a/include/linux/cma.h b/include/linux/cma.h
> > new file mode 100644
> > index 0000000..60ba06f
> > --- /dev/null
> > +++ b/include/linux/cma.h
> > @@ -0,0 +1,28 @@
> > +/*
> > + * Contiguous Memory Allocator
> > + *
> > + * Copyright LG Electronics Inc., 2014
> > + * Written by:
> > + * 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.
> > + *
>
> Superfluous empty comment line.
>
> Also, I'm not certain whether this copyright notice is appropriate here,
> but that's another story.
Yeah, I will remove copyright notice in .h file.
>
> > + */
> > +
> > +#ifndef __CMA_H__
> > +#define __CMA_H__
> > +
> > +struct cma;
> > +
> > +extern struct page *cma_alloc(struct cma *cma, unsigned long count,
> > + unsigned long align);
> > +extern bool cma_release(struct cma *cma, struct page *pages,
> > + unsigned long count);
> > +extern int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base,
> > + phys_addr_t limit, phys_addr_t alignment,
> > + unsigned long bitmap_shift, bool fixed,
> > + struct cma **res_cma);
> > +#endif
>
> > diff --git a/mm/cma.c b/mm/cma.c
> > new file mode 100644
> > index 0000000..0dae88d
> > --- /dev/null
> > +++ b/mm/cma.c
> > @@ -0,0 +1,329 @@
>
> > +static int __init cma_activate_area(struct cma *cma)
> > +{
> > + int max_bitmapno = cma_bitmap_max_no(cma);
> > + int bitmap_size = BITS_TO_LONGS(max_bitmapno) * sizeof(long);
> > + unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
> > + unsigned i = cma->count >> pageblock_order;
> > + struct zone *zone;
> > +
> > + pr_debug("%s()\n", __func__);
> > + if (!cma->count)
> > + return 0;
>
> Alternatively:
>
> + if (!i)
> + return 0;
I prefer cma->count than i, since it represents what it does itself.
> > +
> > + 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;
> > +}
>
> Or even:
>
> static int __init cma_init_reserved_areas(void)
> {
> int i, ret = 0;
> for (i = 0; !ret && i < cma_area_count; ++i)
> ret = cma_activate_area(&cma_areas[i]);
> return ret;
> }
I think that originial implementation is better, since it seems
more readable to me.
> > +int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base,
> > + phys_addr_t limit, phys_addr_t alignment,
> > + unsigned long bitmap_shift, bool fixed,
> > + struct cma **res_cma)
> > +{
> > + struct cma *cma = &cma_areas[cma_area_count];
>
> Perhaps it would make sense to move this initialisation to the far end
> of this function?
Yes, I will move it down.
> > + 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);
> > +
> > + /* Sanity checks */
> > + if (cma_area_count == ARRAY_SIZE(cma_areas)) {
> > + pr_err("Not enough slots for CMA reserved regions!\n");
> > + return -ENOSPC;
> > + }
> > +
> > + if (!size)
> > + return -EINVAL;
> > +
> > + /*
> > + * Sanitise input arguments.
> > + * CMA area should be at least MAX_ORDER - 1 aligned. Otherwise,
> > + * CMA area could be merged into other MIGRATE_TYPE by buddy mechanism
> > + * and CMA property will be broken.
> > + */
> > + alignment >>= PAGE_SHIFT;
> > + alignment = PAGE_SIZE << max3(MAX_ORDER - 1, pageblock_order,
> > + (int)alignment);
> > + base = ALIGN(base, alignment);
> > + size = ALIGN(size, alignment);
> > + limit &= ~(alignment - 1);
> > + /* size should be aligned with bitmap_shift */
> > + BUG_ON(!IS_ALIGNED(size >> PAGE_SHIFT, 1 << cma->bitmap_shift));
>
> cma->bitmap_shift is not yet initialised thus the above line should be:
>
> BUG_ON(!IS_ALIGNED(size >> PAGE_SHIFT, 1 << bitmap_shift));
Yes, I will fix it.
> > +
> > + /* 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->bitmap_shift = bitmap_shift;
> > + *res_cma = cma;
> > + cma_area_count++;
> > +
> > + pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
> > + (unsigned long)base);
>
> Doesn't this message end up being: “cma: CMA: reserved …”? pr_fmt adds
> “cma:” at the beginning, doesn't it? So we should probably drop “CMA:”
> here.
Okay. Will do.
Thanks.
^ permalink raw reply
* Re: [RFC PATCH 2/3] DMA, CMA: use general CMA reserved area management framework
From: Joonsoo Kim @ 2014-06-10 2:49 UTC (permalink / raw)
To: 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, Aneesh Kumar K.V, Paolo Bonzini,
Andrew Morton, linuxppc-dev, linux-arm-kernel, Marek Szyprowski
In-Reply-To: <xa1twqcyjx3z.fsf@mina86.com>
On Tue, Jun 03, 2014 at 09:00:48AM +0200, Michal Nazarewicz wrote:
> On Tue, Jun 03 2014, Joonsoo Kim wrote:
> > Now, we have general CMA reserved area management framework,
> > so use it for future maintainabilty. There is no functional change.
> >
> > Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
>
> Acked-by: Michal Nazarewicz <mina86@mina86.com>
>
> > diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
> > index dfb1dc9..ecb85ac 100644
> > --- a/include/linux/dma-contiguous.h
> > +++ b/include/linux/dma-contiguous.h
> > @@ -53,9 +53,10 @@
> >
> > #ifdef __KERNEL__
> >
> > +#include <linux/device.h>
> > +
>
> Why is this suddenly required?
>
> > struct cma;
> > struct page;
> > -struct device;
> >
> > #ifdef CONFIG_DMA_CMA
>
Without including device.h, build failure occurs.
In dma-contiguous.h, we try to access to dev->cma_area, so we need
device.h. In the past, we included it luckily by swap.h in
drivers/base/dma-contiguous.c. Swap.h includes node.h and then node.h
includes device.h, so we were happy. But, in this patch, I remove
'include <linux/swap.h>' so we need to include device.h explicitly.
Thanks.
^ permalink raw reply
* Re: [RFC PATCH 1/3] CMA: generalize CMA reserved area management functionality
From: Joonsoo Kim @ 2014-06-10 3:01 UTC (permalink / raw)
To: Aneesh Kumar K.V
Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
Greg Kroah-Hartman, Alexander Graf, Michal Nazarewicz,
linux-kernel, Minchan Kim, Paul Mackerras, kvm-ppc, Paolo Bonzini,
Andrew Morton, linuxppc-dev, linux-arm-kernel, Marek Szyprowski
In-Reply-To: <87zjhrtfwm.fsf@linux.vnet.ibm.com>
On Thu, Jun 05, 2014 at 11:09:05PM +0530, Aneesh Kumar K.V wrote:
> Joonsoo Kim <iamjoonsoo.kim@lge.com> writes:
>
> > 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.
> >
> > Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
>
>
> The way patches are split makes it difficult to review. Will it be
> possible to make changes against one implementation and them move that
> to generic code. That helps in finding out what exactly changed.
>
Hello,
You are right! I will respin this patchset as the form you
recommended.
> >
> > diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
> > index 00e13ce..b3fe1cc 100644
> > --- a/drivers/base/Kconfig
> > +++ b/drivers/base/Kconfig
> > @@ -283,7 +283,7 @@ config CMA_ALIGNMENT
> >
> > If unsure, leave the default value "8".
> >
> > -config CMA_AREAS
> > +config DMA_CMA_AREAS
> > int "Maximum count of the CMA device-private areas"
> > default 7
> > help
>
> for ex: The above can be a seperate patch along with further DMA related
> cleanups .
Okay.
>
> > diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
> > index 83969f8..48cdac8 100644
> > --- a/drivers/base/dma-contiguous.c
> > +++ b/drivers/base/dma-contiguous.c
> > @@ -186,7 +186,7 @@ static int __init cma_activate_area(struct cma *cma)
> > return 0;
> > }
> >
> > -static struct cma cma_areas[MAX_CMA_AREAS];
> > +static struct cma cma_areas[MAX_DMA_CMA_AREAS];
> > static unsigned cma_area_count;
> >
> > static int __init cma_init_reserved_areas(void)
> > diff --git a/include/linux/cma.h b/include/linux/cma.h
> > new file mode 100644
> > index 0000000..60ba06f
> > --- /dev/null
> > +++ b/include/linux/cma.h
> > @@ -0,0 +1,28 @@
> > +/*
> > + * Contiguous Memory Allocator
> > + *
> > + * Copyright LG Electronics Inc., 2014
> > + * Written by:
> > + * 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.
> > + *
> > + */
> > +
> > +#ifndef __CMA_H__
> > +#define __CMA_H__
> > +
> > +struct cma;
> > +
> > +extern struct page *cma_alloc(struct cma *cma, unsigned long count,
> > + unsigned long align);
> > +extern bool cma_release(struct cma *cma, struct page *pages,
> > + unsigned long count);
> > +extern int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base,
> > + phys_addr_t limit, phys_addr_t alignment,
> > + unsigned long bitmap_shift, bool fixed,
> > + struct cma **res_cma);
> > +#endif
> > diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
> > index 772eab5..dfb1dc9 100644
> > --- a/include/linux/dma-contiguous.h
> > +++ b/include/linux/dma-contiguous.h
> > @@ -63,7 +63,7 @@ struct device;
> > * 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)
> > +#define MAX_DMA_CMA_AREAS (1 + CONFIG_DMA_CMA_AREAS)
> >
> > extern struct cma *dma_contiguous_default_area;
> >
> > @@ -123,7 +123,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
> >
> > #else
> >
> > -#define MAX_CMA_AREAS (0)
> > +#define MAX_DMA_CMA_AREAS (0)
> >
> > static inline struct cma *dev_get_cma_area(struct device *dev)
> > {
> > diff --git a/mm/Kconfig b/mm/Kconfig
> > index 7511b4a..0877ddc 100644
> > --- a/mm/Kconfig
> > +++ b/mm/Kconfig
> > @@ -515,6 +515,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".
> > +
>
> If we have 7 declare continugous request, a kvm cma allocation request will fail ?
Yes. If you need more, you can increase it. :)
> > 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..0dae88d
> > --- /dev/null
> > +++ b/mm/cma.c
> > @@ -0,0 +1,329 @@
> > +/*
> > + * 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>
> > +
> > +struct cma {
> > + unsigned long base_pfn;
> > + unsigned long count;
> > + unsigned long *bitmap;
> > + unsigned long bitmap_shift;
>
> I guess this is added to accommodate the kvm specific alloc chunks. May
> be you should do this as a patch against kvm implementation and then
> move the code to generic ?
Yes, this is for kvm specific alloc chunks. I will consider which one
is better for the base implementation and makes patches against it.
Thanks.
^ permalink raw reply
* [PATCH] powerpc: Add AT_HWCAP2 to indicate V.CRYPTO category support
From: Benjamin Herrenschmidt @ 2014-06-10 5:04 UTC (permalink / raw)
To: linuxppc-dev
Cc: Diane Brent, Adhemerval Zanella, Jeffrey Scheel, Steve Munroe,
Hanns-Joachim Uhl
The Vector Crypto category instructions are supported by current POWER8
chips, advertise them to userspace using a specific bit to properly
differentiate with chips of the same architecture level that might not
have them.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: <stable@vger.kernel.org> [v3.10+]
--
diff --git a/arch/powerpc/include/uapi/asm/cputable.h b/arch/powerpc/include/uapi/asm/cputable.h
index 5b76579..de2c0e4 100644
--- a/arch/powerpc/include/uapi/asm/cputable.h
+++ b/arch/powerpc/include/uapi/asm/cputable.h
@@ -41,5 +41,6 @@
#define PPC_FEATURE2_EBB 0x10000000
#define PPC_FEATURE2_ISEL 0x08000000
#define PPC_FEATURE2_TAR 0x04000000
+#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
#endif /* _UAPI__ASM_POWERPC_CPUTABLE_H */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index c1faade..11da04a 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -109,7 +109,8 @@ extern void __restore_cpu_e6500(void);
PPC_FEATURE_PSERIES_PERFMON_COMPAT)
#define COMMON_USER2_POWER8 (PPC_FEATURE2_ARCH_2_07 | \
PPC_FEATURE2_HTM_COMP | PPC_FEATURE2_DSCR | \
- PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR)
+ PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | \
+ PPC_FEATURE2_VEC_CRYPTO)
#define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\
PPC_FEATURE_TRUE_LE | \
PPC_FEATURE_HAS_ALTIVEC_COMP)
^ permalink raw reply related
* [PATCH] powerpc/powernv: Fix reading of OPAL msglog
From: Joel Stanley @ 2014-06-10 6:03 UTC (permalink / raw)
To: benh; +Cc: michael, linuxppc-dev
memory_return_from_buffer returns a signed value, so ret should be
ssize_t.
Fixes the following issue reported by David Binderman:
[linux-3.15/arch/powerpc/platforms/powernv/opal-msglog.c:65]: (style)
Checking if unsigned variable 'ret' is less than zero.
[linux-3.15/arch/powerpc/platforms/powernv/opal-msglog.c:82]: (style)
Checking if unsigned variable 'ret' is less than zero.
Local variable "ret" is of type size_t. This is always unsigned,
so it is pointless to check if it is less than zero.
https://bugzilla.kernel.org/show_bug.cgi?id=77551
Fixing this exposes a real bug for the case where the entire count
bytes is successfully read from the POS_WRAP case. The second
memory_read_from_buffer will return EINVAL, causing the entire read to
return EINVAL to userspace, despite the data being copied correctly. The
fix is to test for the case where the data has been read and return
early.
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
arch/powerpc/platforms/powernv/opal-msglog.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/powernv/opal-msglog.c b/arch/powerpc/platforms/powernv/opal-msglog.c
index 1bb25b9..44ed78a 100644
--- a/arch/powerpc/platforms/powernv/opal-msglog.c
+++ b/arch/powerpc/platforms/powernv/opal-msglog.c
@@ -37,7 +37,8 @@ static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj,
{
struct memcons *mc = bin_attr->private;
const char *conbuf;
- size_t ret, first_read = 0;
+ ssize_t ret;
+ size_t first_read = 0;
uint32_t out_pos, avail;
if (!mc)
@@ -69,6 +70,9 @@ static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj,
to += first_read;
count -= first_read;
pos -= avail;
+
+ if (count <= 0)
+ goto out;
}
/* Sanity check. The firmware should not do this to us. */
--
2.0.0
^ permalink raw reply related
* [PATCH] powerpc/perf: Ensure all EBB register state is cleared on fork()
From: Michael Ellerman @ 2014-06-10 6:46 UTC (permalink / raw)
To: linuxppc-dev
In commit 330a1eb "Core EBB support for 64-bit book3s" I messed up
clear_task_ebb(). It clears some but not all of the task's Event Based
Branch (EBB) registers when we duplicate a task struct.
That allows a child task to observe the EBBHR & EBBRR of its parent,
which it should not be able to do.
Fix it by clearing EBBHR & EBBRR.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Cc: stable@vger.kernel.org
---
arch/powerpc/include/asm/switch_to.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 0e83e7d..b5fad8a 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -84,6 +84,8 @@ static inline void clear_task_ebb(struct task_struct *t)
{
#ifdef CONFIG_PPC_BOOK3S_64
/* EBB perf events are not inherited, so clear all EBB state. */
+ t->thread.ebbrr = 0;
+ t->thread.ebbhr = 0;
t->thread.bescr = 0;
t->thread.mmcr2 = 0;
t->thread.mmcr0 = 0;
--
1.9.1
^ permalink raw reply related
* [PATCH 1/1] powerpc/iommu: Handling null return of kzalloc_node
From: Zhouyi Zhou @ 2014-06-10 7:32 UTC (permalink / raw)
To: benh, paulus, aik, anton, nacc, alistair, deepthi, linuxppc-dev,
linux-kernel
Cc: Zhouyi Zhou, Zhouyi Zhou
NULL return of kzalloc_node should be handled
Signed-off-by: Zhouyi Zhou <yizhouzhou@ict.ac.cn>
---
arch/powerpc/platforms/pseries/iommu.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 33b552f..593cd3d 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -613,7 +613,11 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
pci->phb->node);
-
+ if (!tbl) {
+ pr_debug(" out of memory, can't create iommu_table !\n");
+ return;
+ }
+
iommu_table_setparms(pci->phb, dn, tbl);
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
iommu_register_group(tbl, pci_domain_nr(bus), 0);
@@ -659,6 +663,10 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
if (!ppci->iommu_table) {
tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
ppci->phb->node);
+ if (!tbl) {
+ pr_debug(" out of memory, can't create iommu_table !\n");
+ return;
+ }
iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
iommu_register_group(tbl, pci_domain_nr(bus), 0);
@@ -686,6 +694,11 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
pr_debug(" --> first child, no bridge. Allocating iommu table.\n");
tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
phb->node);
+ if (!tbl) {
+ pr_debug(" out of memory, can't create iommu_table !\n");
+ return;
+ }
+
iommu_table_setparms(phb, dn, tbl);
PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node);
iommu_register_group(tbl, pci_domain_nr(phb->bus), 0);
@@ -1102,6 +1116,10 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
if (!pci->iommu_table) {
tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
pci->phb->node);
+ if (!tbl) {
+ pr_debug(" out of memory, can't create iommu_table !\n");
+ return;
+ }
iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
iommu_register_group(tbl, pci_domain_nr(pci->phb->bus), 0);
--
1.7.10.4
^ permalink raw reply related
* Re: [patch] powerpc/spufs: remove duplicate SPUFS_CNTL_MAP_SIZE define
From: Arnd Bergmann @ 2014-06-10 7:55 UTC (permalink / raw)
To: linuxppc-dev
Cc: cbe-oss-dev, Paul Mackerras, kernel-janitors, Jeremy Kerr,
Dan Carpenter
In-Reply-To: <20140609151917.GM9600@mwanda>
On Monday 09 June 2014 18:19:17 Dan Carpenter wrote:
> The SPUFS_CNTL_MAP_SIZE define is cut and pasted twice so we can delete
> the second instance.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply
* Kernel 3.15: Boot problems with a PA6T board
From: Christian Zigotzky @ 2014-06-10 10:58 UTC (permalink / raw)
To: Michael Ellerman, linuxppc-dev
In-Reply-To: <538A58D4.5090602@xenosoft.de>
Hi Michael,
I have two times bisected with git. It seems the commit "PCI: Remove
pci_find_parent_resource() use for allocation" is the problem. I have
removed this patch from the kernel source code but unfortunately the
kernel doesn't boot. Have you another tip for me, please?
Cheers,
Christian
Am 01.06.14 00:33, schrieb Christian Zigotzky:
> On 31.05.2014 13:01, Christian Zigotzky wrote:
>> On 31.05.2014 12:28, Christian Zigotzky wrote:
>>> On 29.05.2014 04:48, Michael Ellerman wrote:
>>>> On Wed, 2014-05-28 at 13:25 +0200, Christian Zigotzky wrote:
>>>>> On 28.05.2014 10:53, Christian Zigotzky wrote:
>>>>>> Hi Michael,
>>>>>>
>>>>>> Thank you for your answer and thank you for your help. :-)
>>>>>>
>>>>>> On 28.05.2014 06:23, Michael Ellerman wrote:
>>>>>>> On Wed, 2014-05-28 at 01:08 +0200, Christian Zigotzky wrote:
>>>>>>>
>>>>>>> I'm going to guess that cd427485357c0c4b99f69719251baacf25946e11 is
>>>>>>> BAD. Can
>>>>>>> you please confirm or deny that?
>>>>>> It's not BAD. It boots.
>>>> Hmm, interesting.
>>>>
>>>>>>> If cd42748 is *good*, then you'll need to do a bigger bisect from
>>>>>>> d8ff9cd to
>>>>>>> 18a1a7a.
>>>>> OK :-)
>>>>>
>>>>> -> git clone
>>>>> git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
>>>>> linux2-git
>>>>> -> git bisect start
>>>>> -> git bisect good d8ff9cdf68fd119d491f3de90e1a612afc2f3b2b
>>>>> -> git bisect bad 18a1a7a1d862ae0794a0179473d08a414dd49234
>>>>>
>>>>> Output:
>>>>> Bisecting: 5900 revisions left to test after this (roughly 13 steps)
>>>>> [cb1595563880a81dab6eab9a5ecb4520d2e76077] Merge tag
>>>>> 'tty-3.15-rc1' of
>>>>> git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
>>>>>
>>>>> Unfortunately it doesn't boot. :-(
>>>> OK. So you do:
>>>>
>>>> $ git bisect bad
>>>>
>>>> And it will pick a new commit for you to test. Repeat that ~13
>>>> times and you
>>>> should have identified the bad commit.
>>> OK :-)
>>>
>>> git bisect bad
>>> Bisecting: 2902 revisions left to test after this (roughly 12 steps)
>>> [b22f136071b1a797e96b3ee6fb0dc32625bd152e] staging: rtl8821ae: Fix
>>> quoted string split across lines <- Kernel boots :-)
>>>
>>> What shall I do next?
>> OK, I know it: git bisect good
>>
>> -- Christian
>>
> git bisect good
> Bisecting: 1494 revisions left to test after this (roughly 11 steps)
> [3786075b5ebc8c4eaefd9e3ebf72883934fb64b3] Merge tag 'regulator-v3.15'
> of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator <-
> Kernel boots
>
> git bisect good
> Bisecting: 797 revisions left to test after this (roughly 10 steps)
> [69dd89fd2b9406603d218cab8996cfb232d5b8b9] Merge tag 'asoc-v3.15-4' of
> git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into
> for-linus <- Kernel boots
>
> git bisect good
> Bisecting: 372 revisions left to test after this (roughly 9 steps)
> [4b1779c2cf030c68aefe939d946475e4136c1895] Merge tag
> 'pci-v3.15-changes' of
> git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci <- Doesn't boot
>
> git bisect bad
> Bisecting: 212 revisions left to test after this (roughly 8 steps)
> [45b15d98a96ffdb3c608bdad952f51930c151420] Merge remote-tracking
> branches 'spi/topic/xilinx' and 'spi/topic/xtfpga' into spi-next <-
> Kernel boots
>
> git bisect good
> Bisecting: 118 revisions left to test after this (roughly 7 steps)
> [91b4adc983d8e9975bc677c2b8395631edf7b92d] Merge branch 'pci/misc'
> into next <- Kernel boots
>
> git bisect good
> Bisecting: 41 revisions left to test after this (roughly 6 steps)
> [26f31fb936042459d481557a83bda7a3f4d61906] Merge tag 'hwmon-for-linus'
> of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
> <- Kernel boots
>
> git bisect good
> Bisecting: 20 revisions left to test after this (roughly 4 steps)
> [e20fa6609a0076def469aeb799b1c25558e70042] PCI: Don't check
> resource_size() in pci_bus_alloc_resource() <- Doesn't boot
>
> git bisect bad
> Bisecting: 10 revisions left to test after this (roughly 3 steps)
> [cd8a4d3657c3f2cf9ce3780707be1debb8fea6e2] PCI: Check IORESOURCE_UNSET
> before updating BAR <- Doesn't boot
>
> git bisect bad
> Bisecting: 4 revisions left to test after this (roughly 2 steps)
> [5edb93b89f6cc3089ee283656555e7a9ad36a8a0] resource: Add
> resource_contains() <- Kernel boots
>
> git bisect good
> Bisecting: 2 revisions left to test after this (roughly 1 step)
> [f44116ae881868ab72274df1eff48fdbde9898af] PCI: Remove
> pci_find_parent_resource() use for allocation <- Doesn't boot
>
> git bisect bad
> Bisecting: 0 revisions left to test after this (roughly 0 steps)
> [d19cb803a2ff85d1b64b9628e1aec2aa76a9260b] vsprintf: Add support for
> IORESOURCE_UNSET in %pR <- Kernel boots
>
> git bisect good
> f44116ae881868ab72274df1eff48fdbde9898af is the first bad commit
> commit f44116ae881868ab72274df1eff48fdbde9898af
> Author: Bjorn Helgaas <bhelgaas@google.com>
> Date: Wed Feb 26 11:25:58 2014 -0700
>
> PCI: Remove pci_find_parent_resource() use for allocation
>
> If the resource hasn't been allocated yet,
> pci_find_parent_resource() is
> documented as returning the region "where it should be allocated
> from."
> This is impossible in general because there may be several
> candidates: a
> prefetchable BAR can be put in either a prefetchable or
> non-prefetchable
> window, a transparent bridge may have overlapping positively- and
> subtractively-decoded windows, and a root bus may have several
> windows of
> the same type.
>
> Allocation should be done by pci_bus_alloc_resource(), which iterates
> through all bus resources and looks for the best match, e.g., one
> with the
> desired prefetchability attributes, and falls back to less-desired
> possibilities.
>
> The only valid use of pci_find_parent_resource() is to find the
> parent of
> an already-allocated resource so we can claim it via
> request_resource(),
> and all we need for that is a bus region of the correct type that
> contains
> the resource.
>
> Note that like 8c8def26bfaa ("PCI: allow matching of prefetchable
> resources
> to non-prefetchable windows"), this depends on
> pci_bus_for_each_resource()
> iterating through positively-decoded regions before
> subtractively-decoded
> ones. We prefer not to return a subtractively-decoded region because
> requesting from it will likely conflict with the overlapping
> positively-
> decoded window (see Launchpad report below).
>
> Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/424142
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> CC: Linus Torvalds <torvalds@linux-foundation.org>
>
> :040000 040000 d9f2e04d3a635126a3c42406400b156aea3d2e30
> 43278454117307fa7e155fb241b16b1863ea45d0 M drivers
>
>
^ permalink raw reply
* [PATCH 1/4] selftests/powerpc: Fix instruction loop for ABIv2 (LE)
From: Michael Ellerman @ 2014-06-10 12:23 UTC (permalink / raw)
To: linuxppc-dev; +Cc: sam.bobroff
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
tools/testing/selftests/powerpc/pmu/loop.S | 73 ++++++++++++++----------------
1 file changed, 35 insertions(+), 38 deletions(-)
diff --git a/tools/testing/selftests/powerpc/pmu/loop.S b/tools/testing/selftests/powerpc/pmu/loop.S
index 8820e3d..20c1f08 100644
--- a/tools/testing/selftests/powerpc/pmu/loop.S
+++ b/tools/testing/selftests/powerpc/pmu/loop.S
@@ -3,44 +3,41 @@
* Licensed under GPLv2.
*/
+#include <ppc-asm.h>
+
.text
- .global thirty_two_instruction_loop
- .type .thirty_two_instruction_loop,@function
- .section ".opd","aw",@progbits
-thirty_two_instruction_loop:
- .quad .thirty_two_instruction_loop, .TOC.@tocbase, 0
- .previous
-.thirty_two_instruction_loop:
- cmpwi %r3,0
+FUNC_START(thirty_two_instruction_loop)
+ cmpdi r3,0
beqlr
- addi %r4,%r3,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1
- addi %r4,%r4,1 # 28 addi's
- subi %r3,%r3,1
- b .thirty_two_instruction_loop
+ addi r4,r3,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1
+ addi r4,r4,1 # 28 addi's
+ subi r3,r3,1
+ b FUNC_NAME(thirty_two_instruction_loop)
+FUNC_END(thirty_two_instruction_loop)
--
1.9.1
^ permalink raw reply related
* [PATCH 2/4] selftests/powerpc: Put the test in a separate process group
From: Michael Ellerman @ 2014-06-10 12:23 UTC (permalink / raw)
To: linuxppc-dev; +Cc: sam.bobroff
In-Reply-To: <1402402990-31925-1-git-send-email-mpe@ellerman.id.au>
Allows us to kill the test and any children it has spawned.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
tools/testing/selftests/powerpc/harness.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
index e80c42a..532ddff 100644
--- a/tools/testing/selftests/powerpc/harness.c
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -30,12 +30,15 @@ int run_test(int (test_function)(void), char *name)
pid = fork();
if (pid == 0) {
+ setpgid(0, 0);
exit(test_function());
} else if (pid == -1) {
perror("fork");
return 1;
}
+ setpgid(pid, pid);
+
/* Wake us up in timeout seconds */
alarm(TIMEOUT);
terminated = false;
@@ -50,17 +53,20 @@ wait:
if (terminated) {
printf("!! force killing %s\n", name);
- kill(pid, SIGKILL);
+ kill(-pid, SIGKILL);
return 1;
} else {
printf("!! killing %s\n", name);
- kill(pid, SIGTERM);
+ kill(-pid, SIGTERM);
terminated = true;
alarm(KILL_TIMEOUT);
goto wait;
}
}
+ /* Kill anything else in the process group that is still running */
+ kill(-pid, SIGTERM);
+
if (WIFEXITED(status))
status = WEXITSTATUS(status);
else {
--
1.9.1
^ 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