From: Gavin Shan <gwshan@linux.vnet.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: linux-pci@vger.kernel.org, devicetree@vger.kernel.org,
benh@kernel.crashing.org, bhelgaas@google.com, aik@ozlabs.ru,
panto@antoniou-consulting.com, robherring2@gmail.com,
grant.likely@linaro.org, Gavin Shan <gwshan@linux.vnet.ibm.com>
Subject: [PATCH v5 24/42] powerpc/powernv: Release PEs dynamically
Date: Thu, 4 Jun 2015 16:41:53 +1000 [thread overview]
Message-ID: <1433400131-18429-25-git-send-email-gwshan@linux.vnet.ibm.com> (raw)
In-Reply-To: <1433400131-18429-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch adds refcount to PE, which counts number of PCI devices
included in the PE. When last device leaves from the PE, the PE
together with its consumed resources (IO, DMA, PELTM/PELTV) are
released, in order to support PCI hotplug.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
v5:
* Derived from PATCH[v4 07/21]
---
arch/powerpc/include/asm/pci-bridge.h | 1 +
arch/powerpc/kernel/pci-hotplug.c | 5 +
arch/powerpc/platforms/powernv/pci-ioda.c | 181 +++++++++++++++++++++++++++++-
arch/powerpc/platforms/powernv/pci.h | 2 +
4 files changed, 183 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 1f39ca7..9a83cdb 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -26,6 +26,7 @@ struct pci_controller_ops {
/* Called when pci_enable_device() is called. Returns true to
* allow assignment/enabling of the device. */
bool (*enable_device_hook)(struct pci_dev *);
+ void (*release_device)(struct pci_dev *);
/* Called during PCI resource reassignment */
resource_size_t (*window_alignment)(struct pci_bus *, unsigned long);
diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c
index 98f84ed..21973e7 100644
--- a/arch/powerpc/kernel/pci-hotplug.c
+++ b/arch/powerpc/kernel/pci-hotplug.c
@@ -29,6 +29,11 @@
*/
void pcibios_release_device(struct pci_dev *dev)
{
+ struct pci_controller *hose = pci_bus_to_host(dev->bus);
+
+ if (hose->controller_ops.release_device)
+ hose->controller_ops.release_device(dev);
+
eeh_remove_device(dev);
}
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 2e31472..17ba55c 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -132,6 +132,50 @@ static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)
(IORESOURCE_MEM_64 | IORESOURCE_PREFETCH));
}
+static void pnv_pci_ioda_release_pe_dma(struct pnv_ioda_pe *pe)
+{
+ struct pnv_phb *phb = pe->phb;
+ struct iommu_table *tbl;
+ int seg;
+ int64_t rc;
+
+ /* No DMA32 segments allocated */
+ if (pe->dma32_seg < 0 ||
+ pe->dma32_segcount <= 0)
+ return;
+
+ /* Unlink IOMMU table from group */
+ tbl = pe->table_group.tables[0];
+ pnv_pci_unlink_table_and_group(tbl, &pe->table_group);
+ if (pe->table_group.group) {
+ iommu_group_put(pe->table_group.group);
+ BUG_ON(pe->table_group.group);
+ }
+
+ /* Release IOMMU table */
+ free_pages(tbl->it_base,
+ get_order(TCE32_TABLE_SIZE * pe->dma32_segcount));
+ iommu_free_table(tbl,
+ of_node_full_name(pci_bus_to_OF_node(pe->pbus)));
+
+ /* Disable TVE */
+ for (seg = pe->dma32_seg;
+ seg < pe->dma32_seg + pe->dma32_segcount;
+ seg++) {
+ rc = opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number,
+ seg, 0, 0ul, 0ul, 0ul);
+ if (rc)
+ pe_warn(pe, "Error %ld unmapping DMA32 seg#%d\n",
+ rc, seg);
+ }
+
+ /* Free the DMA32 segments */
+ bitmap_clear(phb->ioda.dma32_segmap,
+ pe->dma32_seg, pe->dma32_segcount);
+ pe->dma32_seg = -1;
+ pe->dma32_segcount = 0;
+}
+
static inline void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_ioda_pe *pe)
{
/* 01xb - invalidate TCEs that match the specified PE# */
@@ -203,6 +247,10 @@ static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
struct device_node *dn;
int64_t rc;
+ if (pe->dma32_seg < 0 ||
+ pe->dma32_segcount <= 0)
+ return;
+
tbl = pe->table_group.tables[0];
rc = pnv_pci_ioda2_unset_window(&pe->table_group, 0);
if (rc)
@@ -227,6 +275,61 @@ static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
pnv_pci_ioda2_table_free_pages(tbl);
iommu_free_table(tbl, of_node_full_name(dn));
+ pe->dma32_seg = -1;
+ pe->dma32_segcount = 0;
+}
+
+static void pnv_ioda_release_pe_dma(struct pnv_ioda_pe *pe)
+{
+ struct pnv_phb *phb = pe->phb;
+
+ if (phb->type == PNV_PHB_IODA1)
+ pnv_pci_ioda_release_pe_dma(pe);
+ else if (phb->type == PNV_PHB_IODA2)
+ pnv_pci_ioda2_release_pe_dma(pe);
+}
+
+static void pnv_ioda_release_pe_seg(struct pnv_ioda_pe *pe)
+{
+ struct pnv_phb *phb = pe->phb;
+ unsigned long *segmap = NULL;
+ unsigned long *pe_segmap = NULL;
+ uint16_t win;
+ int segno;
+
+ for (win = OPAL_M32_WINDOW_TYPE; win <= OPAL_IO_WINDOW_TYPE; win++) {
+ switch (win) {
+ case OPAL_IO_WINDOW_TYPE:
+ segmap = phb->ioda.io_segmap;
+ pe_segmap = pe->io_segmap;
+ break;
+ case OPAL_M32_WINDOW_TYPE:
+ segmap = phb->ioda.m32_segmap;
+ pe_segmap = pe->m32_segmap;
+ break;
+ case OPAL_M64_WINDOW_TYPE:
+ segmap = phb->ioda.m64_segmap;
+ pe_segmap = pe->m64_segmap;
+ break;
+ }
+
+ segno = -1;
+ while ((segno = find_next_bit(pe_segmap,
+ phb->ioda.total_pe, segno + 1))
+ < phb->ioda.total_pe) {
+ if (win == OPAL_IO_WINDOW_TYPE ||
+ win == OPAL_M32_WINDOW_TYPE)
+ opal_pci_map_pe_mmio_window(phb->opal_id,
+ phb->ioda.reserved_pe, win, 0, segno);
+ else if (phb->type == PNV_PHB_IODA1)
+ opal_pci_map_pe_mmio_window(phb->opal_id,
+ phb->ioda.reserved_pe, win,
+ segno / 8, segno % 8);
+
+ clear_bit(segno, pe_segmap);
+ clear_bit(segno, segmap);
+ }
+ }
}
static int pnv_ioda_set_one_peltv(struct pnv_phb *phb,
@@ -333,7 +436,6 @@ static int pnv_ioda_set_peltv(struct pnv_phb *phb,
return 0;
}
-#ifdef CONFIG_PCI_IOV
static int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
{
struct pci_dev *parent;
@@ -421,7 +523,74 @@ static int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
return 0;
}
-#endif /* CONFIG_PCI_IOV */
+
+static void pnv_ioda_release_pe(struct pnv_ioda_pe *pe)
+{
+ struct pnv_phb *phb = pe->phb;
+ struct pnv_ioda_pe *tmp, *slave;
+
+ /* Release slave PEs in compound PE */
+ if (pe->flags & PNV_IODA_PE_MASTER) {
+ list_for_each_entry_safe(slave, tmp, &pe->slaves, list)
+ pnv_ioda_release_pe(pe);
+ }
+
+ /* Remove the PE from the list */
+ list_del(&pe->list);
+
+ /* Release resources */
+ pnv_ioda_release_pe_dma(pe);
+ pnv_ioda_release_pe_seg(pe);
+ pnv_ioda_deconfigure_pe(pe->phb, pe);
+
+ /* Release PE number */
+ clear_bit(pe->pe_number, phb->ioda.pe_alloc);
+}
+
+static void pnv_ioda_destroy_pe(struct kref *kref)
+{
+ struct pnv_ioda_pe *pe = container_of(kref, struct pnv_ioda_pe, kref);
+
+ pnv_ioda_release_pe(pe);
+}
+
+static inline struct pnv_ioda_pe *pnv_ioda_get_pe(struct pnv_ioda_pe *pe)
+{
+ if (!pe)
+ return NULL;
+
+ if (!pe->kref_init) {
+ pe->kref_init = true;
+ kref_init(&pe->kref);
+ } else {
+ kref_get(&pe->kref);
+ }
+
+ return pe;
+}
+
+static inline void pnv_ioda_put_pe(struct pnv_ioda_pe *pe)
+{
+ if (pe)
+ kref_put(&pe->kref, pnv_ioda_destroy_pe);
+}
+
+static void pnv_pci_release_device(struct pci_dev *pdev)
+{
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+ struct pnv_phb *phb = hose->private_data;
+ struct pci_dn *pdn = pci_get_pdn(pdev);
+ struct pnv_ioda_pe *pe;
+
+ if (pdev->is_virtfn)
+ return;
+
+ if (!pdn || pdn->pe_number == IODA_INVALID_PE)
+ return;
+
+ pe = &phb->ioda.pe_array[pdn->pe_number];
+ pnv_ioda_put_pe(pe);
+}
static struct pnv_ioda_pe *pnv_ioda_init_pe(struct pnv_phb *phb, int pe_no)
{
@@ -429,6 +598,7 @@ static struct pnv_ioda_pe *pnv_ioda_init_pe(struct pnv_phb *phb, int pe_no)
pe->phb = phb;
pe->pe_number = pe_no;
+ pe->kref_init = false;
INIT_LIST_HEAD(&pe->list);
return pe;
@@ -1233,6 +1403,7 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)
if (pdn->pe_number != IODA_INVALID_PE)
continue;
+ pnv_ioda_get_pe(pe);
pdn->pe_number = pe->pe_number;
pe->dma32_weight += pnv_ioda_dev_dma_weight(dev);
if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
@@ -1301,10 +1472,7 @@ static struct pnv_ioda_pe *pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
bus->busn_res.start, 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->pbus = NULL;
+ pnv_ioda_release_pe(pe);
return NULL;
}
@@ -3403,6 +3571,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
*/
ppc_md.pcibios_fixup = pnv_pci_ioda_fixup;
pnv_pci_controller_ops.enable_device_hook = pnv_pci_enable_device_hook;
+ pnv_pci_controller_ops.release_device = pnv_pci_release_device;
pnv_pci_controller_ops.window_alignment = pnv_pci_window_alignment;
pnv_pci_controller_ops.setup_bridge = pnv_pci_setup_bridge;
pnv_pci_controller_ops.reset_secondary_bus = pnv_pci_reset_secondary_bus;
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index bf63481..f68e036 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -30,6 +30,8 @@ struct pnv_phb;
struct pnv_ioda_pe {
unsigned long flags;
struct pnv_phb *phb;
+ struct kref kref;
+ bool kref_init;
/* A PE can be associated with a single device or an
* entire bus (& children). In the former case, pdev
--
2.1.0
next prev parent reply other threads:[~2015-06-04 6:44 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-04 6:41 [PATCH v5 00/42] PowerPC/PowerNV: PCI Slot Management Gavin Shan
2015-06-04 6:41 ` [PATCH v5 01/42] PCI: Add pcibios_setup_bridge() Gavin Shan
2015-06-05 19:44 ` Bjorn Helgaas
2015-06-09 5:49 ` Gavin Shan
2015-06-04 6:41 ` [PATCH v5 02/42] powerpc/powernv: Enable M64 on P7IOC Gavin Shan
2015-06-04 6:41 ` [PATCH v5 03/42] powerpc/powernv: M64 support improvement Gavin Shan
2015-06-04 6:41 ` [PATCH v5 04/42] powerpc/powernv: Trace consumed IO and M32 segments by PE Gavin Shan
2015-06-04 6:41 ` [PATCH v5 05/42] powerpc/powernv: Simplify pnv_ioda_setup_pe_seg() Gavin Shan
2015-06-04 6:41 ` [PATCH v5 06/42] powerpc/powernv: Improve IO and M32 mapping Gavin Shan
2015-06-04 6:41 ` [PATCH v5 07/42] powerpc/powernv: Calculate PHB's DMA weight dynamically Gavin Shan
2015-06-04 6:41 ` [PATCH v5 08/42] powerpc/powernv: DMA32 cleanup Gavin Shan
2015-06-10 4:17 ` Alexey Kardashevskiy
2015-06-10 6:12 ` Gavin Shan
2015-06-04 6:41 ` [PATCH v5 09/42] powerpc/powernv: pnv_ioda_setup_dma() configure one PE only Gavin Shan
2015-06-04 6:41 ` [PATCH v5 10/42] powerpc/powernv: Trace DMA32 segments consumed by PE Gavin Shan
2015-06-04 6:41 ` [PATCH v5 11/42] powerpc/powernv: Increase PE# capacity Gavin Shan
2015-06-10 4:41 ` Alexey Kardashevskiy
2015-06-10 6:18 ` Gavin Shan
2015-06-04 6:41 ` [PATCH v5 12/42] powerpc/pci: Cleanup on pci_controller_ops Gavin Shan
2015-06-10 4:43 ` Alexey Kardashevskiy
2015-06-10 6:20 ` Gavin Shan
2015-06-04 6:41 ` [PATCH v5 13/42] powerpc/pci: Override pcibios_setup_bridge() Gavin Shan
2015-06-04 6:41 ` [PATCH v5 14/42] powerpc/powernv: Allocate PE# in deasending order Gavin Shan
2015-06-04 6:41 ` [PATCH v5 15/42] powerpc/powernv: Reserve PE# for root bus Gavin Shan
2015-06-04 6:41 ` [PATCH v5 16/42] powerpc/powernv: Create PEs dynamically Gavin Shan
2015-06-04 6:41 ` [PATCH v5 17/42] powerpc/powernv: PE oriented during configuration Gavin Shan
2015-06-04 6:41 ` [PATCH v5 18/42] powerpc/powernv: Helper function pnv_ioda_init_pe() Gavin Shan
2015-06-04 6:41 ` [PATCH v5 19/42] powerpc/powernv: Remove DMA32 list of PEs Gavin Shan
2015-06-04 6:41 ` [PATCH v5 20/42] powerpc/powernv: Rename pnv_ioda_get_pe() to pnv_ioda_dev_to_pe() Gavin Shan
2015-06-04 6:41 ` [PATCH v5 21/42] powerpc/powernv: Drop pnv_ioda_setup_dev_PE() Gavin Shan
2015-06-04 6:41 ` [PATCH v5 22/42] powerpc/powernv: Move functions around Gavin Shan
2015-06-04 6:41 ` [PATCH v5 23/42] powerpc/powernv: Cleanup on pnv_pci_ioda2_release_dma_pe() Gavin Shan
2015-06-04 6:41 ` Gavin Shan [this message]
2015-06-04 6:41 ` [PATCH v5 25/42] powerpc/powernv: Supports slot ID Gavin Shan
2015-06-04 6:41 ` [PATCH v5 26/42] powerpc/powernv: Use PCI slot reset infrastructure Gavin Shan
2015-06-04 6:41 ` [PATCH v5 27/42] powerpc/powernv: Simplify pnv_eeh_reset() Gavin Shan
2015-06-04 6:41 ` [PATCH v5 28/42] powerpc/powernv: Don't cover root bus in pnv_pci_reset_secondary_bus() Gavin Shan
2015-06-04 6:41 ` [PATCH v5 29/42] powerpc/powernv: Issue fundamental reset " Gavin Shan
2015-06-04 6:41 ` [PATCH v5 30/42] powerpc/pci: Don't scan empty slot Gavin Shan
2015-06-04 6:42 ` [PATCH v5 31/42] powerpc/pci: Move pcibios_find_pci_bus() around Gavin Shan
2015-06-05 19:47 ` Bjorn Helgaas
2015-06-09 6:10 ` Gavin Shan
2015-06-04 6:42 ` [PATCH v5 32/42] powerpc/powernv: Introduce pnv_pci_poll() Gavin Shan
2015-06-04 6:42 ` [PATCH v5 33/42] powerpc/powernv: Functions to get/reset PCI slot status Gavin Shan
2015-06-04 6:42 ` [PATCH v5 34/42] powerpc/pci: Delay creating pci_dn Gavin Shan
2015-06-04 6:42 ` [PATCH v5 35/42] powerpc/pci: Create eeh_dev while " Gavin Shan
2015-06-04 6:42 ` [PATCH v5 36/42] powerpc/pci: Export traverse_pci_device_nodes() Gavin Shan
2015-06-04 6:42 ` [PATCH v5 37/42] powerpc/pci: Update bridge windows on PCI plugging Gavin Shan
2015-06-04 6:42 ` [PATCH v5 38/42] powerpc/powernv: Select OF_OVERLAY Gavin Shan
2015-06-04 6:42 ` [PATCH v5 39/42] drivers/of: Unflatten nodes equal or deeper than specified level Gavin Shan
2015-06-30 17:47 ` Grant Likely
2015-06-04 6:42 ` [PATCH v5 40/42] drivers/of: Allow to specify root node in of_fdt_unflatten_tree() Gavin Shan
2015-06-30 18:06 ` Grant Likely
2015-06-30 21:46 ` Benjamin Herrenschmidt
2015-06-04 6:42 ` [PATCH v5 41/42] drivers/of: Return allocated memory chunk from of_fdt_unflatten_tree() Gavin Shan
2015-06-04 6:42 ` [PATCH v5 42/42] pci/hotplug: PowerPC PowerNV PCI hotplug driver Gavin Shan
2015-06-05 20:11 ` Bjorn Helgaas
2015-06-05 20:18 ` Benjamin Herrenschmidt
2015-06-09 6:10 ` Gavin Shan
2015-06-09 6:08 ` Gavin Shan
2015-06-30 18:18 ` Grant Likely
2015-07-01 0:51 ` Gavin Shan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1433400131-18429-25-git-send-email-gwshan@linux.vnet.ibm.com \
--to=gwshan@linux.vnet.ibm.com \
--cc=aik@ozlabs.ru \
--cc=benh@kernel.crashing.org \
--cc=bhelgaas@google.com \
--cc=devicetree@vger.kernel.org \
--cc=grant.likely@linaro.org \
--cc=linux-pci@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=panto@antoniou-consulting.com \
--cc=robherring2@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).