diff options
Diffstat (limited to 'drivers/pci/host/pci-keystone.c')
| -rw-r--r-- | drivers/pci/host/pci-keystone.c | 52 | 
1 files changed, 43 insertions, 9 deletions
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index b71f55bb0315..6b8301ef21ca 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -15,6 +15,7 @@  #include <linux/irqchip/chained_irq.h>  #include <linux/clk.h>  #include <linux/delay.h> +#include <linux/interrupt.h>  #include <linux/irqdomain.h>  #include <linux/module.h>  #include <linux/msi.h> @@ -159,7 +160,7 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)  static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,  					   char *controller, int *num_irqs)  { -	int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL; +	int temp, max_host_irqs, legacy = 1, *host_irqs;  	struct device *dev = ks_pcie->pp.dev;  	struct device_node *np_pcie = dev->of_node, **np_temp; @@ -180,11 +181,15 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,  	*np_temp = of_find_node_by_name(np_pcie, controller);  	if (!(*np_temp)) {  		dev_err(dev, "Node for %s is absent\n", controller); -		goto out; +		return -EINVAL;  	} +  	temp = of_irq_count(*np_temp); -	if (!temp) -		goto out; +	if (!temp) { +		dev_err(dev, "No IRQ entries in %s\n", controller); +		return -EINVAL; +	} +  	if (temp > max_host_irqs)  		dev_warn(dev, "Too many %s interrupts defined %u\n",  			(legacy ? "legacy" : "MSI"), temp); @@ -198,12 +203,13 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,  		if (!host_irqs[temp])  			break;  	} +  	if (temp) {  		*num_irqs = temp; -		ret = 0; +		return 0;  	} -out: -	return ret; + +	return -EINVAL;  }  static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) @@ -226,6 +232,9 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)  							 ks_pcie);  		}  	} + +	if (ks_pcie->error_irq > 0) +		ks_dw_pcie_enable_error_irq(ks_pcie->va_app_base);  }  /* @@ -289,6 +298,14 @@ static struct pcie_host_ops keystone_pcie_host_ops = {  	.scan_bus = ks_dw_pcie_v3_65_scan_bus,  }; +static irqreturn_t pcie_err_irq_handler(int irq, void *priv) +{ +	struct keystone_pcie *ks_pcie = priv; + +	return ks_dw_pcie_handle_error_irq(ks_pcie->pp.dev, +					   ks_pcie->va_app_base); +} +  static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,  			 struct platform_device *pdev)  { @@ -309,6 +326,22 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,  			return ret;  	} +	/* +	 * Index 0 is the platform interrupt for error interrupt +	 * from RC.  This is optional. +	 */ +	ks_pcie->error_irq = irq_of_parse_and_map(ks_pcie->np, 0); +	if (ks_pcie->error_irq <= 0) +		dev_info(&pdev->dev, "no error IRQ defined\n"); +	else { +		if (request_irq(ks_pcie->error_irq, pcie_err_irq_handler, +				IRQF_SHARED, "pcie-error-irq", ks_pcie) < 0) { +			dev_err(&pdev->dev, "failed to request error IRQ %d\n", +				ks_pcie->error_irq); +			return ret; +		} +	} +  	pp->root_bus_nr = -1;  	pp->ops = &keystone_pcie_host_ops;  	ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np); @@ -317,7 +350,7 @@ static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,  		return ret;  	} -	return ret; +	return 0;  }  static const struct of_device_id ks_pcie_of_match[] = { @@ -346,7 +379,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)  	struct resource *res;  	void __iomem *reg_p;  	struct phy *phy; -	int ret = 0; +	int ret;  	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),  				GFP_KERNEL); @@ -376,6 +409,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)  	devm_release_mem_region(dev, res->start, resource_size(res));  	pp->dev = dev; +	ks_pcie->np = dev->of_node;  	platform_set_drvdata(pdev, ks_pcie);  	ks_pcie->clk = devm_clk_get(dev, "pcie");  	if (IS_ERR(ks_pcie->clk)) {  | 
