On Tue, Jun 10, 2014 at 2:56 AM, Wei Yang <weiyang@xxxxxxxxxxxxxxxxxx> wrote: > 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@xxxxxxxxxxxxxxxxxx> I don't think this is the right way to handle this. Unless it is a fixup to a buggy devicetree provided by firmware, I don't want to see any code modifying the devicetree to describe stuff that is able to be directly enumerated. Really the pci code should handle the lack of a device_node gracefully. If it cannot then it should be fixed. g. > --- > 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 > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@xxxxxxxxxxxxxxxx > https://lists.ozlabs.org/listinfo/linuxppc-dev -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html