Skip to content

Commit 407d1a5

Browse files
houlz0507robherring
authored andcommitted
PCI: Create device tree node for bridge
The PCI endpoint device such as Xilinx Alveo PCI card maps the register spaces from multiple hardware peripherals to its PCI BAR. Normally, the PCI core discovers devices and BARs using the PCI enumeration process. There is no infrastructure to discover the hardware peripherals that are present in a PCI device, and which can be accessed through the PCI BARs. Apparently, the device tree framework requires a device tree node for the PCI device. Thus, it can generate the device tree nodes for hardware peripherals underneath. Because PCI is self discoverable bus, there might not be a device tree node created for PCI devices. Furthermore, if the PCI device is hot pluggable, when it is plugged in, the device tree nodes for its parent bridges are required. Add support to generate device tree node for PCI bridges. Add an of_pci_make_dev_node() interface that can be used to create device tree node for PCI devices. Add a PCI_DYNAMIC_OF_NODES config option. When the option is turned on, the kernel will generate device tree nodes for PCI bridges unconditionally. Initially, add the basic properties for the dynamically generated device tree nodes which include #address-cells, #size-cells, device_type, compatible, ranges, reg. Acked-by: Bjorn Helgaas <[email protected]> Signed-off-by: Lizhi Hou <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Rob Herring <[email protected]>
1 parent b544fc2 commit 407d1a5

File tree

7 files changed

+462
-0
lines changed

7 files changed

+462
-0
lines changed

drivers/pci/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ config PCI_HYPERV
194194
The PCI device frontend driver allows the kernel to import arbitrary
195195
PCI devices from a PCI backend to support PCI driver domains.
196196

197+
config PCI_DYNAMIC_OF_NODES
198+
bool "Create Device tree nodes for PCI devices"
199+
depends on OF
200+
select OF_DYNAMIC
201+
help
202+
This option enables support for generating device tree nodes for some
203+
PCI devices. Thus, the driver of this kind can load and overlay
204+
flattened device tree for its downstream devices.
205+
206+
Once this option is selected, the device tree nodes will be generated
207+
for all PCI bridges.
208+
197209
choice
198210
prompt "PCI Express hierarchy optimization setting"
199211
default PCIE_BUS_DEFAULT

drivers/pci/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o
3232
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
3333
obj-$(CONFIG_VGA_ARB) += vgaarb.o
3434
obj-$(CONFIG_PCI_DOE) += doe.o
35+
obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o
3536

3637
# Endpoint library must be initialized before its users
3738
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/

drivers/pci/bus.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ void pci_bus_add_device(struct pci_dev *dev)
340340
*/
341341
pcibios_bus_add_device(dev);
342342
pci_fixup_device(pci_fixup_final, dev);
343+
if (pci_is_bridge(dev))
344+
of_pci_make_dev_node(dev);
343345
pci_create_sysfs_dev_files(dev);
344346
pci_proc_attach_device(dev);
345347
pci_bridge_d3_update(dev);

drivers/pci/of.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,85 @@ int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge)
611611
return pci_parse_request_of_pci_ranges(dev, bridge);
612612
}
613613

614+
#ifdef CONFIG_PCI_DYNAMIC_OF_NODES
615+
616+
void of_pci_remove_node(struct pci_dev *pdev)
617+
{
618+
struct device_node *np;
619+
620+
np = pci_device_to_OF_node(pdev);
621+
if (!np || !of_node_check_flag(np, OF_DYNAMIC))
622+
return;
623+
pdev->dev.of_node = NULL;
624+
625+
of_changeset_revert(np->data);
626+
of_changeset_destroy(np->data);
627+
of_node_put(np);
628+
}
629+
630+
void of_pci_make_dev_node(struct pci_dev *pdev)
631+
{
632+
struct device_node *ppnode, *np = NULL;
633+
const char *pci_type;
634+
struct of_changeset *cset;
635+
const char *name;
636+
int ret;
637+
638+
/*
639+
* If there is already a device tree node linked to this device,
640+
* return immediately.
641+
*/
642+
if (pci_device_to_OF_node(pdev))
643+
return;
644+
645+
/* Check if there is device tree node for parent device */
646+
if (!pdev->bus->self)
647+
ppnode = pdev->bus->dev.of_node;
648+
else
649+
ppnode = pdev->bus->self->dev.of_node;
650+
if (!ppnode)
651+
return;
652+
653+
if (pci_is_bridge(pdev))
654+
pci_type = "pci";
655+
else
656+
pci_type = "dev";
657+
658+
name = kasprintf(GFP_KERNEL, "%s@%x,%x", pci_type,
659+
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
660+
if (!name)
661+
return;
662+
663+
cset = kmalloc(sizeof(*cset), GFP_KERNEL);
664+
if (!cset)
665+
goto failed;
666+
of_changeset_init(cset);
667+
668+
np = of_changeset_create_node(cset, ppnode, name);
669+
if (!np)
670+
goto failed;
671+
np->data = cset;
672+
673+
ret = of_pci_add_properties(pdev, cset, np);
674+
if (ret)
675+
goto failed;
676+
677+
ret = of_changeset_apply(cset);
678+
if (ret)
679+
goto failed;
680+
681+
pdev->dev.of_node = np;
682+
kfree(name);
683+
684+
return;
685+
686+
failed:
687+
if (np)
688+
of_node_put(np);
689+
kfree(name);
690+
}
691+
#endif
692+
614693
#endif /* CONFIG_PCI */
615694

616695
/**

0 commit comments

Comments
 (0)