diff mbox

[2/3] pci: pcie-designware: add support for external MSI controller

Message ID 1472561830-20932-3-git-send-email-thomas.petazzoni@free-electrons.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Thomas Petazzoni Aug. 30, 2016, 12:57 p.m. UTC
The Designware PCIe controllers have a built-in MSI controller, which is
already supported by the existing. However, in some situations, it might
be a better choice to use an external MSI controller, especially when it
provides a higher number of MSI interrupts than the built-in one.

Therefore, this commit extends the pcie-designware driver to support the
"msi-parent" DT property, already used by other drivers. It contains a
phandle pointing to the external MSI controller to be used.

Following this commit, the pcie-designware code supports three
possibilities, in this order:

 1. If msi-parent is provided, then the MSI controller pointed by this
    property is used.

 2. Otherwise, and if no ->msi_host_init() function is provided by the
    platform-specific "glue", then the built-in MSI controller of the
    Designware controller is used.

 3. Otherwise, the ->msi_host_init() function of the platform-specific
    "glue" is used to do some additional initialization, but it's still
    the built-in MSI controller that is used.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
 drivers/pci/host/pcie-designware.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

Comments

Andrew Lunn Aug. 30, 2016, 1:11 p.m. UTC | #1
On Tue, Aug 30, 2016 at 02:57:09PM +0200, Thomas Petazzoni wrote:
> The Designware PCIe controllers have a built-in MSI controller, which is
> already supported by the existing. However, in some situations, it might

                                   ^ driver.

> be a better choice to use an external MSI controller, especially when it
> provides a higher number of MSI interrupts than the built-in one.
> 
> Therefore, this commit extends the pcie-designware driver to support the
> "msi-parent" DT property, already used by other drivers. It contains a
> phandle pointing to the external MSI controller to be used.
> 
> Following this commit, the pcie-designware code supports three
> possibilities, in this order:
> 
>  1. If msi-parent is provided, then the MSI controller pointed by this

                                                                 ^ to  

>     property is used.

>  	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> -		if (!pp->ops->msi_host_init) {
> +		if (of_find_property(pp->dev->of_node, "msi-parent", NULL)) {
> +			struct device_node *msi_node;
> +
> +			msi_node = of_parse_phandle(pp->dev->of_node,
> +						    "msi-parent", 0);
> +			if (!msi_node)
> +				return -ENODEV;
> +
> +			msi = of_pci_find_msi_chip_by_node(msi_node);

By this point, device tree tells us the external MSI controller
should exist. So if we get a NULL here, should we not return
-EPROBE_DIFFERED?

	Andrew
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 12afce1..1e18a85 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -437,6 +437,7 @@  int dw_pcie_host_init(struct pcie_port *pp)
 	int i, ret;
 	LIST_HEAD(res);
 	struct resource_entry *win;
+	struct msi_controller *msi = NULL;
 
 	cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
 	if (cfg_res) {
@@ -525,10 +526,21 @@  int dw_pcie_host_init(struct pcie_port *pp)
 		pp->lanes = 0;
 
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
-		if (!pp->ops->msi_host_init) {
+		if (of_find_property(pp->dev->of_node, "msi-parent", NULL)) {
+			struct device_node *msi_node;
+
+			msi_node = of_parse_phandle(pp->dev->of_node,
+						    "msi-parent", 0);
+			if (!msi_node)
+				return -ENODEV;
+
+			msi = of_pci_find_msi_chip_by_node(msi_node);
+		} else if (!pp->ops->msi_host_init) {
+			msi = &dw_pcie_msi_chip;
+			msi->dev = pp->dev;
 			pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
 						MAX_MSI_IRQS, &msi_domain_ops,
-						&dw_pcie_msi_chip);
+						msi);
 			if (!pp->irq_domain) {
 				dev_err(pp->dev, "irq domain init failed\n");
 				ret = -ENXIO;
@@ -538,7 +550,9 @@  int dw_pcie_host_init(struct pcie_port *pp)
 			for (i = 0; i < MAX_MSI_IRQS; i++)
 				irq_create_mapping(pp->irq_domain, i);
 		} else {
-			ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
+			msi = &dw_pcie_msi_chip;
+			msi->dev = pp->dev;
+			ret = pp->ops->msi_host_init(pp, msi);
 			if (ret < 0)
 				goto error;
 		}
@@ -550,9 +564,7 @@  int dw_pcie_host_init(struct pcie_port *pp)
 	pp->root_bus_nr = pp->busn->start;
 	if (IS_ENABLED(CONFIG_PCI_MSI)) {
 		bus = pci_scan_root_bus_msi(pp->dev, pp->root_bus_nr,
-					    &dw_pcie_ops, pp, &res,
-					    &dw_pcie_msi_chip);
-		dw_pcie_msi_chip.dev = pp->dev;
+					    &dw_pcie_ops, pp, &res, msi);
 	} else
 		bus = pci_scan_root_bus(pp->dev, pp->root_bus_nr, &dw_pcie_ops,
 					pp, &res);