Re: [PATCH 07/15] powerpc/powerpc: Add new PCIe functions for allocating cxl interrupts
> >+struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) > >+{ > >+struct device_node *np; > >+struct property *prop = NULL; > >+ > >+np = of_node_get(pci_device_to_OF_node(dev)); > >+ > >+/* Scan up the tree looking for the PHB node */ > >+while (np) { > >+if ((prop = of_find_property(np, "ibm,opal-phbid", NULL))) > >+break; > >+np = of_get_next_parent(np); > >+} > >+ > >+if (!prop) { > >+of_node_put(np); > >+return NULL; > >+} > >+ > >+return np; > >+} > >+EXPORT_SYMBOL(pnv_pci_to_phb_node); > > Nitpick: I'm not sure it's better way. "struct pci_controller::dn" should > always have valid "ibm,opal-phbid", so I guess the code could be like this > way: > > struct pci_controller *hose = pci_bus_to_host(dev->bus); > > return hose->dn; Nice.. that makes it much simpler. I'll update. > >+ > >+#ifdef CONFIG_CXL_BASE > >+int pnv_phb_to_cxl(struct pci_dev *dev) > >+{ > >+struct device_node *np; > >+struct pnv_ioda_pe *pe; > >+const u64 *prop64; > >+u64 phb_id; > >+int rc; > >+ > >+dev_info(>dev, "switch PHB to CXL\n"); > >+ > >+if (!(np = pnv_pci_to_phb_node(dev))) > >+return -ENODEV; > >+ > >+prop64 = of_get_property(np, "ibm,opal-phbid", NULL); > >+ > >+phb_id = be64_to_cpup(prop64); > >+dev_info(>dev, "PHB-ID : 0x%016llx\n", phb_id); > >+ > > The PHB ID would have been there: struct pnv_phb::opal_id. So > I guess we needn't grab it from device-tree again :) Nice, I'll update. > >+if (!(pe = pnv_ioda_get_pe(dev))) { > >+rc = -ENODEV; > >+goto out; > >+} > >+dev_info(>dev, " pe : %i\n", pe->pe_number); > > Perhaps you can reuse pe_info() here. Yep, will do. > >+#ifdef CONFIG_CXL_BASE > >+int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, > >+ unsigned int virq) > >+{ > >+struct pci_controller *hose = pci_bus_to_host(dev->bus); > >+struct pnv_phb *phb = hose->private_data; > >+unsigned int xive_num = hwirq - phb->msi_base; > >+struct pnv_ioda_pe *pe; > >+int rc; > >+ > >+if (!(pe = pnv_ioda_get_pe(dev))) > >+return -ENODEV; > >+ > >+/* Assign XIVE to PE */ > >+rc = opal_pci_set_xive_pe(phb->opal_id, pe->pe_number, xive_num); > >+if (rc) { > >+pr_warn("%s: OPAL error %d setting msi_base 0x%x hwirq 0x%x > >XIVE 0x%x PE\n", > >+pci_name(dev), rc, phb->msi_base, hwirq, xive_num); > >+return -EIO; > >+} > > It seems current firmware doesn't support the OPAL API for PHB3. The current public version of skiboot seems to be doing something here in hw/phb3.c in phb3_set_ive_pe(): https://github.com/open-power/skiboot/blob/c34c4ef8c660e3e439365c8f5c06143ff00bc6bc/hw/phb3.c#L1096 I think we still need this. Thanks again! Mikey -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 07/15] powerpc/powerpc: Add new PCIe functions for allocating cxl interrupts
snip +struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) +{ +struct device_node *np; +struct property *prop = NULL; + +np = of_node_get(pci_device_to_OF_node(dev)); + +/* Scan up the tree looking for the PHB node */ +while (np) { +if ((prop = of_find_property(np, ibm,opal-phbid, NULL))) +break; +np = of_get_next_parent(np); +} + +if (!prop) { +of_node_put(np); +return NULL; +} + +return np; +} +EXPORT_SYMBOL(pnv_pci_to_phb_node); Nitpick: I'm not sure it's better way. struct pci_controller::dn should always have valid ibm,opal-phbid, so I guess the code could be like this way: struct pci_controller *hose = pci_bus_to_host(dev-bus); return hose-dn; Nice.. that makes it much simpler. I'll update. snip + +#ifdef CONFIG_CXL_BASE +int pnv_phb_to_cxl(struct pci_dev *dev) +{ +struct device_node *np; +struct pnv_ioda_pe *pe; +const u64 *prop64; +u64 phb_id; +int rc; + +dev_info(dev-dev, switch PHB to CXL\n); + +if (!(np = pnv_pci_to_phb_node(dev))) +return -ENODEV; + +prop64 = of_get_property(np, ibm,opal-phbid, NULL); + +phb_id = be64_to_cpup(prop64); +dev_info(dev-dev, PHB-ID : 0x%016llx\n, phb_id); + The PHB ID would have been there: struct pnv_phb::opal_id. So I guess we needn't grab it from device-tree again :) Nice, I'll update. +if (!(pe = pnv_ioda_get_pe(dev))) { +rc = -ENODEV; +goto out; +} +dev_info(dev-dev, pe : %i\n, pe-pe_number); Perhaps you can reuse pe_info() here. Yep, will do. snip +#ifdef CONFIG_CXL_BASE +int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, + unsigned int virq) +{ +struct pci_controller *hose = pci_bus_to_host(dev-bus); +struct pnv_phb *phb = hose-private_data; +unsigned int xive_num = hwirq - phb-msi_base; +struct pnv_ioda_pe *pe; +int rc; + +if (!(pe = pnv_ioda_get_pe(dev))) +return -ENODEV; + +/* Assign XIVE to PE */ +rc = opal_pci_set_xive_pe(phb-opal_id, pe-pe_number, xive_num); +if (rc) { +pr_warn(%s: OPAL error %d setting msi_base 0x%x hwirq 0x%x XIVE 0x%x PE\n, +pci_name(dev), rc, phb-msi_base, hwirq, xive_num); +return -EIO; +} It seems current firmware doesn't support the OPAL API for PHB3. The current public version of skiboot seems to be doing something here in hw/phb3.c in phb3_set_ive_pe(): https://github.com/open-power/skiboot/blob/c34c4ef8c660e3e439365c8f5c06143ff00bc6bc/hw/phb3.c#L1096 I think we still need this. Thanks again! Mikey -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 07/15] powerpc/powerpc: Add new PCIe functions for allocating cxl interrupts
On Thu, Sep 18, 2014 at 06:26:52PM +1000, Michael Neuling wrote: >From: Ian Munsie > >This adds a number of functions for allocating IRQs under powernv PCIe for cxl. > >Signed-off-by: Ian Munsie >Signed-off-by: Michael Neuling >--- > arch/powerpc/include/asm/pnv-pci.h| 27 + > arch/powerpc/platforms/powernv/pci-ioda.c | 186 ++ > 2 files changed, 213 insertions(+) > create mode 100644 arch/powerpc/include/asm/pnv-pci.h > >diff --git a/arch/powerpc/include/asm/pnv-pci.h >b/arch/powerpc/include/asm/pnv-pci.h >new file mode 100644 >index 000..71717b5 >--- /dev/null >+++ b/arch/powerpc/include/asm/pnv-pci.h >@@ -0,0 +1,27 @@ >+/* >+ * Copyright 2014 IBM Corp. >+ * >+ * 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 option) any later version. >+ */ >+ >+#ifndef _ASM_PNV_PCI_H >+#define _ASM_PNV_PCI_H >+ >+#include >+#include >+ >+int pnv_phb_to_cxl(struct pci_dev *dev); >+int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, >+ unsigned int virq); >+int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num); >+void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num); >+int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, >+ struct pci_dev *dev, int num); >+void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs, >+struct pci_dev *dev); >+int pnv_cxl_get_irq_count(struct pci_dev *dev); >+ >+#endif >diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c >b/arch/powerpc/platforms/powernv/pci-ioda.c >index 194f90a..80919f8 100644 >--- a/arch/powerpc/platforms/powernv/pci-ioda.c >+++ b/arch/powerpc/platforms/powernv/pci-ioda.c >@@ -38,6 +38,8 @@ > #include > #include > >+#include >+ > #include "powernv.h" > #include "pci.h" > >@@ -503,6 +505,163 @@ static struct pnv_ioda_pe *pnv_ioda_get_pe(struct >pci_dev *dev) > return NULL; > return >ioda.pe_array[pdn->pe_number]; > } >+ >+struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) >+{ >+ struct device_node *np; >+ struct property *prop = NULL; >+ >+ np = of_node_get(pci_device_to_OF_node(dev)); >+ >+ /* Scan up the tree looking for the PHB node */ >+ while (np) { >+ if ((prop = of_find_property(np, "ibm,opal-phbid", NULL))) >+ break; >+ np = of_get_next_parent(np); >+ } >+ >+ if (!prop) { >+ of_node_put(np); >+ return NULL; >+ } >+ >+ return np; >+} >+EXPORT_SYMBOL(pnv_pci_to_phb_node); Nitpick: I'm not sure it's better way. "struct pci_controller::dn" should always have valid "ibm,opal-phbid", so I guess the code could be like this way: struct pci_controller *hose = pci_bus_to_host(dev->bus); return hose->dn; >+ >+#ifdef CONFIG_CXL_BASE >+int pnv_phb_to_cxl(struct pci_dev *dev) >+{ >+ struct device_node *np; >+ struct pnv_ioda_pe *pe; >+ const u64 *prop64; >+ u64 phb_id; >+ int rc; >+ >+ dev_info(>dev, "switch PHB to CXL\n"); >+ >+ if (!(np = pnv_pci_to_phb_node(dev))) >+ return -ENODEV; >+ >+ prop64 = of_get_property(np, "ibm,opal-phbid", NULL); >+ >+ phb_id = be64_to_cpup(prop64); >+ dev_info(>dev, "PHB-ID : 0x%016llx\n", phb_id); >+ The PHB ID would have been there: struct pnv_phb::opal_id. So I guess we needn't grab it from device-tree again :) >+ if (!(pe = pnv_ioda_get_pe(dev))) { >+ rc = -ENODEV; >+ goto out; >+ } >+ dev_info(>dev, " pe : %i\n", pe->pe_number); Perhaps you can reuse pe_info() here. >+ >+ if ((rc = opal_pci_set_phb_cxl_mode(phb_id, 1, pe->pe_number))) >+ dev_err(>dev, "opal_pci_set_phb_cxl_mode failed: %i\n", >rc); >+ >+out: >+ of_node_put(np); >+ return rc; >+} >+EXPORT_SYMBOL(pnv_phb_to_cxl); >+ >+int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num) >+{ >+ struct pci_controller *hose = pci_bus_to_host(dev->bus); >+ struct pnv_phb *phb = hose->private_data; >+ int hwirq = msi_bitmap_alloc_hwirqs(>msi_bmp, num); >+ >+ if (hwirq < 0) { >+ dev_warn(>dev, "Failed to find a free MSI\n"); >+ return -ENOSPC; >+ } >+ >+ return phb->msi_base + hwirq; >+} >+EXPORT_SYMBOL(pnv_cxl_alloc_hwirqs); >+ >+void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num) >+{ >+ struct pci_controller *hose = pci_bus_to_host(dev->bus); >+ struct pnv_phb *phb = hose->private_data; >+ >+ msi_bitmap_free_hwirqs(>msi_bmp, hwirq - phb->msi_base, num); >+} >+EXPORT_SYMBOL(pnv_cxl_release_hwirqs); >+ >+ >+int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, >+ struct pci_dev *dev, int num) >+{ >+ struct
Re: [PATCH 07/15] powerpc/powerpc: Add new PCIe functions for allocating cxl interrupts
On Thu, Sep 18, 2014 at 06:26:52PM +1000, Michael Neuling wrote: From: Ian Munsie imun...@au1.ibm.com This adds a number of functions for allocating IRQs under powernv PCIe for cxl. Signed-off-by: Ian Munsie imun...@au1.ibm.com Signed-off-by: Michael Neuling mi...@neuling.org --- arch/powerpc/include/asm/pnv-pci.h| 27 + arch/powerpc/platforms/powernv/pci-ioda.c | 186 ++ 2 files changed, 213 insertions(+) create mode 100644 arch/powerpc/include/asm/pnv-pci.h diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h new file mode 100644 index 000..71717b5 --- /dev/null +++ b/arch/powerpc/include/asm/pnv-pci.h @@ -0,0 +1,27 @@ +/* + * Copyright 2014 IBM Corp. + * + * 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 option) any later version. + */ + +#ifndef _ASM_PNV_PCI_H +#define _ASM_PNV_PCI_H + +#include linux/pci.h +#include misc/cxl.h + +int pnv_phb_to_cxl(struct pci_dev *dev); +int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, + unsigned int virq); +int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num); +void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num); +int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev, int num); +void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs, +struct pci_dev *dev); +int pnv_cxl_get_irq_count(struct pci_dev *dev); + +#endif diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 194f90a..80919f8 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -38,6 +38,8 @@ #include asm/debug.h #include asm/firmware.h +#include misc/cxl.h + #include powernv.h #include pci.h @@ -503,6 +505,163 @@ static struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev) return NULL; return phb-ioda.pe_array[pdn-pe_number]; } + +struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) +{ + struct device_node *np; + struct property *prop = NULL; + + np = of_node_get(pci_device_to_OF_node(dev)); + + /* Scan up the tree looking for the PHB node */ + while (np) { + if ((prop = of_find_property(np, ibm,opal-phbid, NULL))) + break; + np = of_get_next_parent(np); + } + + if (!prop) { + of_node_put(np); + return NULL; + } + + return np; +} +EXPORT_SYMBOL(pnv_pci_to_phb_node); Nitpick: I'm not sure it's better way. struct pci_controller::dn should always have valid ibm,opal-phbid, so I guess the code could be like this way: struct pci_controller *hose = pci_bus_to_host(dev-bus); return hose-dn; + +#ifdef CONFIG_CXL_BASE +int pnv_phb_to_cxl(struct pci_dev *dev) +{ + struct device_node *np; + struct pnv_ioda_pe *pe; + const u64 *prop64; + u64 phb_id; + int rc; + + dev_info(dev-dev, switch PHB to CXL\n); + + if (!(np = pnv_pci_to_phb_node(dev))) + return -ENODEV; + + prop64 = of_get_property(np, ibm,opal-phbid, NULL); + + phb_id = be64_to_cpup(prop64); + dev_info(dev-dev, PHB-ID : 0x%016llx\n, phb_id); + The PHB ID would have been there: struct pnv_phb::opal_id. So I guess we needn't grab it from device-tree again :) + if (!(pe = pnv_ioda_get_pe(dev))) { + rc = -ENODEV; + goto out; + } + dev_info(dev-dev, pe : %i\n, pe-pe_number); Perhaps you can reuse pe_info() here. + + if ((rc = opal_pci_set_phb_cxl_mode(phb_id, 1, pe-pe_number))) + dev_err(dev-dev, opal_pci_set_phb_cxl_mode failed: %i\n, rc); + +out: + of_node_put(np); + return rc; +} +EXPORT_SYMBOL(pnv_phb_to_cxl); + +int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev-bus); + struct pnv_phb *phb = hose-private_data; + int hwirq = msi_bitmap_alloc_hwirqs(phb-msi_bmp, num); + + if (hwirq 0) { + dev_warn(dev-dev, Failed to find a free MSI\n); + return -ENOSPC; + } + + return phb-msi_base + hwirq; +} +EXPORT_SYMBOL(pnv_cxl_alloc_hwirqs); + +void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev-bus); + struct pnv_phb *phb = hose-private_data; + + msi_bitmap_free_hwirqs(phb-msi_bmp, hwirq - phb-msi_base, num); +} +EXPORT_SYMBOL(pnv_cxl_release_hwirqs); + + +int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev-bus); +
[PATCH 07/15] powerpc/powerpc: Add new PCIe functions for allocating cxl interrupts
From: Ian Munsie This adds a number of functions for allocating IRQs under powernv PCIe for cxl. Signed-off-by: Ian Munsie Signed-off-by: Michael Neuling --- arch/powerpc/include/asm/pnv-pci.h| 27 + arch/powerpc/platforms/powernv/pci-ioda.c | 186 ++ 2 files changed, 213 insertions(+) create mode 100644 arch/powerpc/include/asm/pnv-pci.h diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h new file mode 100644 index 000..71717b5 --- /dev/null +++ b/arch/powerpc/include/asm/pnv-pci.h @@ -0,0 +1,27 @@ +/* + * Copyright 2014 IBM Corp. + * + * 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 option) any later version. + */ + +#ifndef _ASM_PNV_PCI_H +#define _ASM_PNV_PCI_H + +#include +#include + +int pnv_phb_to_cxl(struct pci_dev *dev); +int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, + unsigned int virq); +int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num); +void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num); +int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev, int num); +void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev); +int pnv_cxl_get_irq_count(struct pci_dev *dev); + +#endif diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 194f90a..80919f8 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -38,6 +38,8 @@ #include #include +#include + #include "powernv.h" #include "pci.h" @@ -503,6 +505,163 @@ static struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev) return NULL; return >ioda.pe_array[pdn->pe_number]; } + +struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) +{ + struct device_node *np; + struct property *prop = NULL; + + np = of_node_get(pci_device_to_OF_node(dev)); + + /* Scan up the tree looking for the PHB node */ + while (np) { + if ((prop = of_find_property(np, "ibm,opal-phbid", NULL))) + break; + np = of_get_next_parent(np); + } + + if (!prop) { + of_node_put(np); + return NULL; + } + + return np; +} +EXPORT_SYMBOL(pnv_pci_to_phb_node); + +#ifdef CONFIG_CXL_BASE +int pnv_phb_to_cxl(struct pci_dev *dev) +{ + struct device_node *np; + struct pnv_ioda_pe *pe; + const u64 *prop64; + u64 phb_id; + int rc; + + dev_info(>dev, "switch PHB to CXL\n"); + + if (!(np = pnv_pci_to_phb_node(dev))) + return -ENODEV; + + prop64 = of_get_property(np, "ibm,opal-phbid", NULL); + + phb_id = be64_to_cpup(prop64); + dev_info(>dev, "PHB-ID : 0x%016llx\n", phb_id); + + if (!(pe = pnv_ioda_get_pe(dev))) { + rc = -ENODEV; + goto out; + } + dev_info(>dev, " pe : %i\n", pe->pe_number); + + if ((rc = opal_pci_set_phb_cxl_mode(phb_id, 1, pe->pe_number))) + dev_err(>dev, "opal_pci_set_phb_cxl_mode failed: %i\n", rc); + +out: + of_node_put(np); + return rc; +} +EXPORT_SYMBOL(pnv_phb_to_cxl); + +int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + int hwirq = msi_bitmap_alloc_hwirqs(>msi_bmp, num); + + if (hwirq < 0) { + dev_warn(>dev, "Failed to find a free MSI\n"); + return -ENOSPC; + } + + return phb->msi_base + hwirq; +} +EXPORT_SYMBOL(pnv_cxl_alloc_hwirqs); + +void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + + msi_bitmap_free_hwirqs(>msi_bmp, hwirq - phb->msi_base, num); +} +EXPORT_SYMBOL(pnv_cxl_release_hwirqs); + + +int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + int range = 0; + int hwirq; + int try; + + memset(irqs, 0, sizeof(struct cxl_irq_ranges)); + + for (range = 1; range < CXL_IRQ_RANGES && num; range++) { + try = num; + while (try) { + hwirq = msi_bitmap_alloc_hwirqs(>msi_bmp, try); + if (hwirq >= 0) + break; + try /= 2; + } + if (!try) +
[PATCH 07/15] powerpc/powerpc: Add new PCIe functions for allocating cxl interrupts
From: Ian Munsie imun...@au1.ibm.com This adds a number of functions for allocating IRQs under powernv PCIe for cxl. Signed-off-by: Ian Munsie imun...@au1.ibm.com Signed-off-by: Michael Neuling mi...@neuling.org --- arch/powerpc/include/asm/pnv-pci.h| 27 + arch/powerpc/platforms/powernv/pci-ioda.c | 186 ++ 2 files changed, 213 insertions(+) create mode 100644 arch/powerpc/include/asm/pnv-pci.h diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h new file mode 100644 index 000..71717b5 --- /dev/null +++ b/arch/powerpc/include/asm/pnv-pci.h @@ -0,0 +1,27 @@ +/* + * Copyright 2014 IBM Corp. + * + * 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 option) any later version. + */ + +#ifndef _ASM_PNV_PCI_H +#define _ASM_PNV_PCI_H + +#include linux/pci.h +#include misc/cxl.h + +int pnv_phb_to_cxl(struct pci_dev *dev); +int pnv_cxl_ioda_msi_setup(struct pci_dev *dev, unsigned int hwirq, + unsigned int virq); +int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num); +void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num); +int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev, int num); +void pnv_cxl_release_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev); +int pnv_cxl_get_irq_count(struct pci_dev *dev); + +#endif diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 194f90a..80919f8 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -38,6 +38,8 @@ #include asm/debug.h #include asm/firmware.h +#include misc/cxl.h + #include powernv.h #include pci.h @@ -503,6 +505,163 @@ static struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev) return NULL; return phb-ioda.pe_array[pdn-pe_number]; } + +struct device_node *pnv_pci_to_phb_node(struct pci_dev *dev) +{ + struct device_node *np; + struct property *prop = NULL; + + np = of_node_get(pci_device_to_OF_node(dev)); + + /* Scan up the tree looking for the PHB node */ + while (np) { + if ((prop = of_find_property(np, ibm,opal-phbid, NULL))) + break; + np = of_get_next_parent(np); + } + + if (!prop) { + of_node_put(np); + return NULL; + } + + return np; +} +EXPORT_SYMBOL(pnv_pci_to_phb_node); + +#ifdef CONFIG_CXL_BASE +int pnv_phb_to_cxl(struct pci_dev *dev) +{ + struct device_node *np; + struct pnv_ioda_pe *pe; + const u64 *prop64; + u64 phb_id; + int rc; + + dev_info(dev-dev, switch PHB to CXL\n); + + if (!(np = pnv_pci_to_phb_node(dev))) + return -ENODEV; + + prop64 = of_get_property(np, ibm,opal-phbid, NULL); + + phb_id = be64_to_cpup(prop64); + dev_info(dev-dev, PHB-ID : 0x%016llx\n, phb_id); + + if (!(pe = pnv_ioda_get_pe(dev))) { + rc = -ENODEV; + goto out; + } + dev_info(dev-dev, pe : %i\n, pe-pe_number); + + if ((rc = opal_pci_set_phb_cxl_mode(phb_id, 1, pe-pe_number))) + dev_err(dev-dev, opal_pci_set_phb_cxl_mode failed: %i\n, rc); + +out: + of_node_put(np); + return rc; +} +EXPORT_SYMBOL(pnv_phb_to_cxl); + +int pnv_cxl_alloc_hwirqs(struct pci_dev *dev, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev-bus); + struct pnv_phb *phb = hose-private_data; + int hwirq = msi_bitmap_alloc_hwirqs(phb-msi_bmp, num); + + if (hwirq 0) { + dev_warn(dev-dev, Failed to find a free MSI\n); + return -ENOSPC; + } + + return phb-msi_base + hwirq; +} +EXPORT_SYMBOL(pnv_cxl_alloc_hwirqs); + +void pnv_cxl_release_hwirqs(struct pci_dev *dev, int hwirq, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev-bus); + struct pnv_phb *phb = hose-private_data; + + msi_bitmap_free_hwirqs(phb-msi_bmp, hwirq - phb-msi_base, num); +} +EXPORT_SYMBOL(pnv_cxl_release_hwirqs); + + +int pnv_cxl_alloc_hwirq_ranges(struct cxl_irq_ranges *irqs, + struct pci_dev *dev, int num) +{ + struct pci_controller *hose = pci_bus_to_host(dev-bus); + struct pnv_phb *phb = hose-private_data; + int range = 0; + int hwirq; + int try; + + memset(irqs, 0, sizeof(struct cxl_irq_ranges)); + + for (range = 1; range CXL_IRQ_RANGES num; range++) { + try = num; + while (try) { + hwirq = msi_bitmap_alloc_hwirqs(phb-msi_bmp, try); + if (hwirq = 0) +