From fc2786545395e0ca69f245e5617fee0639ff0d25 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 21 Mar 2019 14:39:24 -0500 Subject: PCI/MSI: Remove unused mask_msi_irq() and unmask_msi_irq() Change pcie-xilinx-nwl.c to use pci_msi_mask_irq() and pci_msi_unmask_irq() like all other PCI host controller drivers. Remove the now-unused mask_msi_irq() and unmask_msi_irq(). Signed-off-by: Bjorn Helgaas CC: Michal Simek CC: linux-arm-kernel@lists.infradead.org --- drivers/pci/controller/pcie-xilinx-nwl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c index 81538d77f790..3b031f00a94a 100644 --- a/drivers/pci/controller/pcie-xilinx-nwl.c +++ b/drivers/pci/controller/pcie-xilinx-nwl.c @@ -438,11 +438,10 @@ static const struct irq_domain_ops legacy_domain_ops = { #ifdef CONFIG_PCI_MSI static struct irq_chip nwl_msi_irq_chip = { .name = "nwl_pcie:msi", - .irq_enable = unmask_msi_irq, - .irq_disable = mask_msi_irq, - .irq_mask = mask_msi_irq, - .irq_unmask = unmask_msi_irq, - + .irq_enable = pci_msi_unmask_irq, + .irq_disable = pci_msi_mask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, }; static struct msi_domain_info nwl_msi_domain_info = { -- cgit v1.2.3 From be20bbcb0a8cb5597cc62b3e28d275919f3431df Mon Sep 17 00:00:00 2001 From: Kazufumi Ikeda Date: Mon, 25 Mar 2019 20:43:19 +0100 Subject: PCI: rcar: Add the initialization of PCIe link in resume_noirq() Reestablish the PCIe link very early in the resume process in case it went down to prevent PCI accesses from hanging the bus. Such accesses can happen early in the PCI resume process, as early as the SUSPEND_RESUME_NOIRQ step, thus the link must be reestablished in the driver resume_noirq() callback. Fixes: e015f88c368d ("PCI: rcar: Add support for R-Car H3 to pcie-rcar") Signed-off-by: Kazufumi Ikeda Signed-off-by: Gaku Inami Signed-off-by: Marek Vasut [lorenzo.pieralisi@arm.com: reformatted commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Acked-by: Wolfram Sang Cc: stable@vger.kernel.org Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index c8febb009454..6a4e435bd35f 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -46,6 +46,7 @@ /* Transfer control */ #define PCIETCTLR 0x02000 +#define DL_DOWN BIT(3) #define CFINIT 1 #define PCIETSTR 0x02004 #define DATA_LINK_ACTIVE 1 @@ -94,6 +95,7 @@ #define MACCTLR 0x011058 #define SPEED_CHANGE BIT(24) #define SCRAMBLE_DISABLE BIT(27) +#define PMSR 0x01105c #define MACS2R 0x011078 #define MACCGSPSETR 0x011084 #define SPCNGRSN BIT(31) @@ -1130,6 +1132,7 @@ static int rcar_pcie_probe(struct platform_device *pdev) pcie = pci_host_bridge_priv(bridge); pcie->dev = dev; + platform_set_drvdata(pdev, pcie); err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL); if (err) @@ -1221,10 +1224,28 @@ err_free_bridge: return err; } +static int rcar_pcie_resume_noirq(struct device *dev) +{ + struct rcar_pcie *pcie = dev_get_drvdata(dev); + + if (rcar_pci_read_reg(pcie, PMSR) && + !(rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN)) + return 0; + + /* Re-establish the PCIe link */ + rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR); + return rcar_pcie_wait_for_dl(pcie); +} + +static const struct dev_pm_ops rcar_pcie_pm_ops = { + .resume_noirq = rcar_pcie_resume_noirq, +}; + static struct platform_driver rcar_pcie_driver = { .driver = { .name = "rcar-pcie", .of_match_table = rcar_pcie_of_match, + .pm = &rcar_pcie_pm_ops, .suppress_bind_attrs = true, }, .probe = rcar_pcie_probe, -- cgit v1.2.3 From 05f151a73ec2b23ffbff706e5203e729a995cdc2 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 4 Mar 2019 21:34:48 +0000 Subject: PCI: hv: Fix a memory leak in hv_eject_device_work() When a device is created in new_pcichild_device(), hpdev->refs is set to 2 (i.e. the initial value of 1 plus the get_pcichild()). When we hot remove the device from the host, in a Linux VM we first call hv_pci_eject_device(), which increases hpdev->refs by get_pcichild() and then schedules a work of hv_eject_device_work(), so hpdev->refs becomes 3 (let's ignore the paired get/put_pcichild() in other places). But in hv_eject_device_work(), currently we only call put_pcichild() twice, meaning the 'hpdev' struct can't be freed in put_pcichild(). Add one put_pcichild() to fix the memory leak. The device can also be removed when we run "rmmod pci-hyperv". On this path (hv_pci_remove() -> hv_pci_bus_exit() -> hv_pci_devices_present()), hpdev->refs is 2, and we do correctly call put_pcichild() twice in pci_devices_present_work(). Fixes: 4daace0d8ce8 ("PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs") Signed-off-by: Dexuan Cui [lorenzo.pieralisi@arm.com: commit log rework] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Stephen Hemminger Reviewed-by: Michael Kelley Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-hyperv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 95441a35eceb..30f16b882746 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1900,6 +1900,9 @@ static void hv_eject_device_work(struct work_struct *work) sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt, VM_PKT_DATA_INBAND, 0); + /* For the get_pcichild() in hv_pci_eject_device() */ + put_pcichild(hpdev); + /* For the two refs got in new_pcichild_device() */ put_pcichild(hpdev); put_pcichild(hpdev); put_hvpcibus(hpdev->hbus); -- cgit v1.2.3 From 15becc2b56c6eda3d9bf5ae993bafd5661c1fad1 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 4 Mar 2019 21:34:48 +0000 Subject: PCI: hv: Add hv_pci_remove_slots() when we unload the driver When we unload the pci-hyperv host controller driver, the host does not send us a PCI_EJECT message. In this case we also need to make sure the sysfs PCI slot directory is removed, otherwise a command on a slot file eg: "cat /sys/bus/pci/slots/2/address" will trigger a "BUG: unable to handle kernel paging request" and, if we unload/reload the driver several times we would end up with stale slot entries in PCI slot directories in /sys/bus/pci/slots/ root@localhost:~# ls -rtl /sys/bus/pci/slots/ total 0 drwxr-xr-x 2 root root 0 Feb 7 10:49 2 drwxr-xr-x 2 root root 0 Feb 7 10:49 2-1 drwxr-xr-x 2 root root 0 Feb 7 10:51 2-2 Add the missing code to remove the PCI slot and fix the current behaviour. Fixes: a15f2c08c708 ("PCI: hv: support reporting serial number as slot information") Signed-off-by: Dexuan Cui [lorenzo.pieralisi@arm.com: reformatted the log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Stephen Hemminger Reviewed-by: Michael Kelley Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-hyperv.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 30f16b882746..b489412e3502 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1486,6 +1486,21 @@ static void hv_pci_assign_slots(struct hv_pcibus_device *hbus) } } +/* + * Remove entries in sysfs pci slot directory. + */ +static void hv_pci_remove_slots(struct hv_pcibus_device *hbus) +{ + struct hv_pci_dev *hpdev; + + list_for_each_entry(hpdev, &hbus->children, list_entry) { + if (!hpdev->pci_slot) + continue; + pci_destroy_slot(hpdev->pci_slot); + hpdev->pci_slot = NULL; + } +} + /** * create_root_hv_pci_bus() - Expose a new root PCI bus * @hbus: Root PCI bus, as understood by this driver @@ -2680,6 +2695,7 @@ static int hv_pci_remove(struct hv_device *hdev) pci_lock_rescan_remove(); pci_stop_root_bus(hbus->pci_bus); pci_remove_root_bus(hbus->pci_bus); + hv_pci_remove_slots(hbus); pci_unlock_rescan_remove(); hbus->state = hv_pcibus_removed; } -- cgit v1.2.3 From 340d455699400f2c2c0f9b3f703ade3085cdb501 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 4 Mar 2019 21:34:49 +0000 Subject: PCI: hv: Add pci_destroy_slot() in pci_devices_present_work(), if necessary When we hot-remove a device, usually the host sends us a PCI_EJECT message, and a PCI_BUS_RELATIONS message with bus_rel->device_count == 0. When we execute the quick hot-add/hot-remove test, the host may not send us the PCI_EJECT message if the guest has not fully finished the initialization by sending the PCI_RESOURCES_ASSIGNED* message to the host, so it's potentially unsafe to only depend on the pci_destroy_slot() in hv_eject_device_work() because the code path create_root_hv_pci_bus() -> hv_pci_assign_slots() is not called in this case. Note: in this case, the host still sends the guest a PCI_BUS_RELATIONS message with bus_rel->device_count == 0. In the quick hot-add/hot-remove test, we can have such a race before the code path pci_devices_present_work() -> new_pcichild_device() adds the new device into the hbus->children list, we may have already received the PCI_EJECT message, and since the tasklet handler hv_pci_onchannelcallback() may fail to find the "hpdev" by calling get_pcichild_wslot(hbus, dev_message->wslot.slot) hv_pci_eject_device() is not called; Later, by continuing execution create_root_hv_pci_bus() -> hv_pci_assign_slots() creates the slot and the PCI_BUS_RELATIONS message with bus_rel->device_count == 0 removes the device from hbus->children, and we end up being unable to remove the slot in hv_pci_remove() -> hv_pci_remove_slots() Remove the slot in pci_devices_present_work() when the device is removed to address this race. pci_devices_present_work() and hv_eject_device_work() run in the singled-threaded hbus->wq, so there is not a double-remove issue for the slot. We cannot offload hv_pci_eject_device() from hv_pci_onchannelcallback() to the workqueue, because we need the hv_pci_onchannelcallback() synchronously call hv_pci_eject_device() to poll the channel ringbuffer to work around the "hangs in hv_compose_msi_msg()" issue fixed in commit de0aa7b2f97d ("PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()") Fixes: a15f2c08c708 ("PCI: hv: support reporting serial number as slot information") Signed-off-by: Dexuan Cui [lorenzo.pieralisi@arm.com: rewritten commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Stephen Hemminger Reviewed-by: Michael Kelley Cc: stable@vger.kernel.org --- drivers/pci/controller/pci-hyperv.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index b489412e3502..82acd6155adf 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1776,6 +1776,10 @@ static void pci_devices_present_work(struct work_struct *work) hpdev = list_first_entry(&removed, struct hv_pci_dev, list_entry); list_del(&hpdev->list_entry); + + if (hpdev->pci_slot) + pci_destroy_slot(hpdev->pci_slot); + put_pcichild(hpdev); } -- cgit v1.2.3 From 699ca30162686bf305cdf94861be02eb0cf9bda2 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Mon, 25 Mar 2019 17:19:09 -0500 Subject: PCI: xilinx: Check for __get_free_pages() failure If __get_free_pages() fails, return -ENOMEM to avoid a NULL pointer dereference. Signed-off-by: Kangjie Lu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Steven Price Reviewed-by: Mukesh Ojha --- drivers/pci/controller/pcie-xilinx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c index 9bd1a35cd5d8..5bf3af3b28e6 100644 --- a/drivers/pci/controller/pcie-xilinx.c +++ b/drivers/pci/controller/pcie-xilinx.c @@ -336,14 +336,19 @@ static const struct irq_domain_ops msi_domain_ops = { * xilinx_pcie_enable_msi - Enable MSI support * @port: PCIe port information */ -static void xilinx_pcie_enable_msi(struct xilinx_pcie_port *port) +static int xilinx_pcie_enable_msi(struct xilinx_pcie_port *port) { phys_addr_t msg_addr; port->msi_pages = __get_free_pages(GFP_KERNEL, 0); + if (!port->msi_pages) + return -ENOMEM; + msg_addr = virt_to_phys((void *)port->msi_pages); pcie_write(port, 0x0, XILINX_PCIE_REG_MSIBASE1); pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2); + + return 0; } /* INTx Functions */ @@ -498,6 +503,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port) struct device *dev = port->dev; struct device_node *node = dev->of_node; struct device_node *pcie_intc_node; + int ret; /* Setup INTx */ pcie_intc_node = of_get_next_child(node, NULL); @@ -526,7 +532,9 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port) return -ENODEV; } - xilinx_pcie_enable_msi(port); + ret = xilinx_pcie_enable_msi(port); + if (ret) + return ret; } return 0; -- cgit v1.2.3 From 91e0a58e663ffdae2c96a27541794ab5a6fefb22 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:36 +0800 Subject: PCI: dwc: pci-dra7xx: Fix a leaked reference by adding missing of_node_put() The call to of_get_next_child() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/dwc/pci-dra7xx.c:252:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 241, but without a corresponding object release within this function. ./drivers/pci/controller/dwc/pci-dra7xx.c:255:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 241, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Kishon Vijay Abraham I Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linux-omap@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/dwc/pci-dra7xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index ae84a69ae63a..627c91da5701 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -247,6 +247,7 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) dra7xx->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &intx_domain_ops, pp); + of_node_put(pcie_intc_node); if (!dra7xx->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); return -ENODEV; -- cgit v1.2.3 From e12bfa013c0972dd94c2f849e05c87f5e1913e96 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:37 +0800 Subject: PCI: uniphier: Fix a leaked reference by adding missing of_node_put() The call to of_get_child_by_name() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/dwc/pcie-uniphier.c:283:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 274, but without a corresponding object release within this function. ./drivers/pci/controller/dwc/pcie-uniphier.c:290:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 274, but without a corresponding object release within this function. ./drivers/pci/controller/dwc/pcie-uniphier.c:296:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 274, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Kunihiko Hayashi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Masahiro Yamada Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/dwc/pcie-uniphier.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index d5dc40289cce..3f30ee4a00b3 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -270,6 +270,7 @@ static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp) struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci); struct device_node *np = pci->dev->of_node; struct device_node *np_intc; + int ret = 0; np_intc = of_get_child_by_name(np, "legacy-interrupt-controller"); if (!np_intc) { @@ -280,20 +281,24 @@ static int uniphier_pcie_config_legacy_irq(struct pcie_port *pp) pp->irq = irq_of_parse_and_map(np_intc, 0); if (!pp->irq) { dev_err(pci->dev, "Failed to get an IRQ entry in legacy-interrupt-controller\n"); - return -EINVAL; + ret = -EINVAL; + goto out_put_node; } priv->legacy_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX, &uniphier_intx_domain_ops, pp); if (!priv->legacy_irq_domain) { dev_err(pci->dev, "Failed to get INTx domain\n"); - return -ENODEV; + ret = -ENODEV; + goto out_put_node; } irq_set_chained_handler_and_data(pp->irq, uniphier_pcie_irq_handler, pp); - return 0; +out_put_node: + of_node_put(np_intc); + return ret; } static int uniphier_pcie_host_init(struct pcie_port *pp) -- cgit v1.2.3 From b35c0e4543945fe9b21e6ed9ab72cdb5efb30718 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:38 +0800 Subject: PCI: dwc: layerscape: Fix a leaked reference by adding missing of_node_put() The call to of_parse_phandle() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. Detected by coccinelle with the following warnings: ./drivers/pci/controller/dwc/pci-layerscape.c:204:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 198, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Minghuan Lian Cc: Mingkai Hu Cc: Roy Zang Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/dwc/pci-layerscape.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index ce45bde29bf8..3a5fa26d5e56 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -201,6 +201,7 @@ static int ls_pcie_msi_host_init(struct pcie_port *pp) return -EINVAL; } + of_node_put(msi_node); return 0; } -- cgit v1.2.3 From 69adea738eb2be70b4753dbb60eb1de9abbfb4dc Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:39 +0800 Subject: PCI: rockchip: Fix a leaked reference by adding missing of_node_put() The call to of_get_child_by_name() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pcie-rockchip-host.c:729:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 718, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-rockchip-host.c:732:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 718, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Shawn Lin Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Heiko Stuebner Cc: linux-pci@vger.kernel.org Cc: linux-rockchip@lists.infradead.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/pcie-rockchip-host.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 1372d270764f..8d20f1793a61 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -724,6 +724,7 @@ static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, &intx_domain_ops, rockchip); + of_node_put(intc); if (!rockchip->irq_domain) { dev_err(dev, "failed to get a INTx IRQ domain\n"); return -EINVAL; -- cgit v1.2.3 From 3842f5166bf1ef286fe7a39f262b5c9581308366 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:40 +0800 Subject: PCI: aardvark: Fix a leaked reference by adding missing of_node_put() The call to of_get_next_child() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pci-aardvark.c:826:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 798, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Thomas Petazzoni Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/pci-aardvark.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index eb58dfdaba1b..134e0306ff00 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -794,6 +794,7 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) struct device_node *node = dev->of_node; struct device_node *pcie_intc_node; struct irq_chip *irq_chip; + int ret = 0; pcie_intc_node = of_get_next_child(node, NULL); if (!pcie_intc_node) { @@ -806,8 +807,8 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq", dev_name(dev)); if (!irq_chip->name) { - of_node_put(pcie_intc_node); - return -ENOMEM; + ret = -ENOMEM; + goto out_put_node; } irq_chip->irq_mask = advk_pcie_irq_mask; @@ -819,11 +820,13 @@ static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) &advk_pcie_irq_domain_ops, pcie); if (!pcie->irq_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); - of_node_put(pcie_intc_node); - return -ENOMEM; + ret = -ENOMEM; + goto out_put_node; } - return 0; +out_put_node: + of_node_put(pcie_intc_node); + return ret; } static void advk_pcie_remove_irq_domain(struct advk_pcie *pcie) -- cgit v1.2.3 From 8956388d3670c5050825a6410761843ffd7e4848 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:41 +0800 Subject: PCI: iproc: Fix a leaked reference by adding missing of_node_put() The call to of_parse_phandle() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. iproc_msi_init() also calls of_node_get() to increase refcount: proc_msi_init() -> iproc_msi_alloc_domains() -> pci_msi_create_irq_domain() -> msi_create_irq_domain() -> irq_domain_create_linear() -> __irq_domain_add() so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pcie-iproc.c:1323:3-9: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 1299, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-iproc.c:1330:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 1299, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Ray Jui Cc: Scott Branden Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-pci@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org --- drivers/pci/controller/pcie-iproc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index c20fd6bd68fd..9998c5cb44c4 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1320,14 +1320,18 @@ static int iproc_pcie_msi_enable(struct iproc_pcie *pcie) if (pcie->need_msi_steer) { ret = iproc_pcie_msi_steer(pcie, msi_node); if (ret) - return ret; + goto out_put_node; } /* * If another MSI controller is being used, the call below should fail * but that is okay */ - return iproc_msi_init(pcie, msi_node); + ret = iproc_msi_init(pcie, msi_node); + +out_put_node: + of_node_put(msi_node); + return ret; } static void iproc_pcie_msi_disable(struct iproc_pcie *pcie) -- cgit v1.2.3 From ff7a5a0a8562434f114035a5a4cbbeec5cb6320c Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 27 Feb 2019 12:40:42 +0800 Subject: PCI: mediatek: Fix a leaked reference by adding missing of_node_put() The call to of_get_next_child() returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. irq_domain_add_linear() also calls of_node_get() to increase refcount, so irq_domain will not be affected when it is released. Detected by coccinelle with the following warnings: ./drivers/pci/controller/pcie-mediatek.c:577:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 567, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-mediatek.c:583:3-9: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 567, but without a corresponding object release within this function. ./drivers/pci/controller/pcie-mediatek.c:586:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 567, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Lorenzo Pieralisi Acked-by: Honghui Zhang Cc: Ryder Lee Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Matthias Brugger Cc: linux-pci@vger.kernel.org Cc: linux-mediatek@lists.infradead.org Cc: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org --- drivers/pci/controller/pcie-mediatek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 0b6c72804e03..5c485de60466 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -578,6 +578,7 @@ static int mtk_pcie_init_irq_domain(struct mtk_pcie_port *port, port->irq_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &intx_domain_ops, port); + of_node_put(pcie_intc_node); if (!port->irq_domain) { dev_err(dev, "failed to get INTx IRQ domain\n"); return -ENODEV; -- cgit v1.2.3 From 73b9e4d3309c540d9c855322e6ccedfa8ef698fc Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 1 Mar 2019 10:22:15 +0530 Subject: PCI: iproc: Add CRS check in config read The IPROC PCIe host controller implementation returns CFG_RETRY_STATUS (0xffff0001) data when it receives a CRS completion, regardless of the address of the read or the CRS Software Visibility Enable bit. As a workaround the driver retries in software any read that returns CFG_RETRY_STATUS even though, for reads of registers that are not Vendor ID, the register value can correspond to CFG_RETRY_STATUS; this situation would cause a timeout and failure of reading a valid register value. IPROC PCIe host controller PAXB v2 has a register to show config read status flags like SC, UR, CRS and CA. Using this status flag, an extra check is added to confirm the CRS using status flags before reissuing a config read, fixing the issue. Signed-off-by: Srinath Mannam [lorenzo.pieralisi@arm.com: rewrote commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Scott Branden --- drivers/pci/controller/pcie-iproc.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index c20fd6bd68fd..b88225577a8f 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -60,6 +60,10 @@ #define APB_ERR_EN_SHIFT 0 #define APB_ERR_EN BIT(APB_ERR_EN_SHIFT) +#define CFG_RD_SUCCESS 0 +#define CFG_RD_UR 1 +#define CFG_RD_CRS 2 +#define CFG_RD_CA 3 #define CFG_RETRY_STATUS 0xffff0001 #define CFG_RETRY_STATUS_TIMEOUT_US 500000 /* 500 milliseconds */ @@ -289,6 +293,9 @@ enum iproc_pcie_reg { IPROC_PCIE_IARR4, IPROC_PCIE_IMAP4, + /* config read status */ + IPROC_PCIE_CFG_RD_STATUS, + /* link status */ IPROC_PCIE_LINK_STATUS, @@ -350,6 +357,7 @@ static const u16 iproc_pcie_reg_paxb_v2[] = { [IPROC_PCIE_IMAP3] = 0xe08, [IPROC_PCIE_IARR4] = 0xe68, [IPROC_PCIE_IMAP4] = 0xe70, + [IPROC_PCIE_CFG_RD_STATUS] = 0xee0, [IPROC_PCIE_LINK_STATUS] = 0xf0c, [IPROC_PCIE_APB_ERR_EN] = 0xf40, }; @@ -474,10 +482,12 @@ static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie, return (pcie->base + offset); } -static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p) +static unsigned int iproc_pcie_cfg_retry(struct iproc_pcie *pcie, + void __iomem *cfg_data_p) { int timeout = CFG_RETRY_STATUS_TIMEOUT_US; unsigned int data; + u32 status; /* * As per PCIe spec r3.1, sec 2.3.2, CRS Software Visibility only @@ -498,6 +508,15 @@ static unsigned int iproc_pcie_cfg_retry(void __iomem *cfg_data_p) */ data = readl(cfg_data_p); while (data == CFG_RETRY_STATUS && timeout--) { + /* + * CRS state is set in CFG_RD status register + * This will handle the case where CFG_RETRY_STATUS is + * valid config data. + */ + status = iproc_pcie_read_reg(pcie, IPROC_PCIE_CFG_RD_STATUS); + if (status != CFG_RD_CRS) + return data; + udelay(1); data = readl(cfg_data_p); } @@ -576,7 +595,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, if (!cfg_data_p) return PCIBIOS_DEVICE_NOT_FOUND; - data = iproc_pcie_cfg_retry(cfg_data_p); + data = iproc_pcie_cfg_retry(pcie, cfg_data_p); *val = data; if (size <= 2) -- cgit v1.2.3 From ea2df11f7221a149546e337f5404e8d1c932c104 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 1 Mar 2019 10:22:16 +0530 Subject: PCI: iproc: Allow outbound configuration for 32-bit I/O region The IProc host controller has I/O memory windows allocated in the AXI memory map that can be used to address PCI I/O memory space. Mapping from AXI memory windows to PCI outbound memory windows is carried out in the host controller through OARR/OMAP registers pairs that permit to define power of two region size AXI<->PCI mappings, the smallest of which is 128MB. Current code enables AXI memory window to PCI outbound memory window mapping only for AXI windows matching one of the OARR/OMAP window sizes, that are SoC dependent and the smallest of which is 128MB. Some SoCs implementing the IProc host controller have a 32-bit AXI memory window into PCI I/O memory space, eg: Base address | Size ----------------------------- (1) 0x42000000 | 0x2000000 (2) 0x400000000 | 0x80000000 but its size (32MB - (1) above) is smaller than the smallest AXI<->PCI region size provided by OARR (128MB), so the current driver rejects mappings for the 32-bit region making the IProc host controller driver unusable on 32-bit systems. However, there is no reason why the 32-bit I/O memory window cannot be enabled by mapping it through an OARR/OMAP region bigger in size (ie 32-bit AXI window size is 32MB but can be mapped using a 128MB OARR/OMAP region). Allow outbound window configuration of I/O memory windows that are smaller in size than the host controller OARR/OMAP region, so that the 32-bit AXI memory window can actually be enabled, making the IProc host controller operational on 32-bit systems. Link: https://lore.kernel.org/linux-pci/1551415936-30174-3-git-send-email-srinath.mannam@broadcom.com/ Signed-off-by: Srinath Mannam Signed-off-by: Abhishek Shah Signed-off-by: Ray Jui [lorenzo.pieralisi@arm.com: rewrote the commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Scott Branden --- drivers/pci/controller/pcie-iproc.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index b88225577a8f..080f142ce24d 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -955,8 +955,25 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, resource_size_t window_size = ob_map->window_sizes[size_idx] * SZ_1M; - if (size < window_size) - continue; + /* + * Keep iterating until we reach the last window and + * with the minimal window size at index zero. In this + * case, we take a compromise by mapping it using the + * minimum window size that can be supported + */ + if (size < window_size) { + if (size_idx > 0 || window_idx > 0) + continue; + + /* + * For the corner case of reaching the minimal + * window size that can be supported on the + * last window + */ + axi_addr = ALIGN_DOWN(axi_addr, window_size); + pci_addr = ALIGN_DOWN(pci_addr, window_size); + size = window_size; + } if (!IS_ALIGNED(axi_addr, window_size) || !IS_ALIGNED(pci_addr, window_size)) { -- cgit v1.2.3 From b2c615457b2891931d3e1eec5edf4b8b380e48fb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:56 +0100 Subject: PCI: rcar: Clean up remaining macros defining bits Replace macros using constants with BIT()s instead, no functional change. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org To: linux-pci@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index c8febb009454..5b8736f0cd6b 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -46,14 +46,14 @@ /* Transfer control */ #define PCIETCTLR 0x02000 -#define CFINIT 1 +#define CFINIT BIT(0) #define PCIETSTR 0x02004 -#define DATA_LINK_ACTIVE 1 +#define DATA_LINK_ACTIVE BIT(0) #define PCIEERRFR 0x02020 #define UNSUPPORTED_REQUEST BIT(4) #define PCIEMSIFR 0x02044 #define PCIEMSIALR 0x02048 -#define MSIFE 1 +#define MSIFE BIT(0) #define PCIEMSIAUR 0x0204c #define PCIEMSIIER 0x02050 -- cgit v1.2.3 From 7dc13a7939e09caa20ed3a0a8417f23b4ec4e6e2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:57 +0100 Subject: PCI: rcar: Replace unsigned long with u32/unsigned int in register accessors Replace unsigned long with u32 and unsigned int in register accessor functions, since they access 32bit registers. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 5b8736f0cd6b..3db693b4410e 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -152,14 +152,13 @@ struct rcar_pcie { struct rcar_msi msi; }; -static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val, - unsigned long reg) +static void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, + unsigned int reg) { writel(val, pcie->base + reg); } -static unsigned long rcar_pci_read_reg(struct rcar_pcie *pcie, - unsigned long reg) +static u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg) { return readl(pcie->base + reg); } -- cgit v1.2.3 From d8fa26609b91394f9f2d17ae6956a2c3e3632fbb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:58 +0100 Subject: PCI: rcar: Replace various variable types with unsigned ones for register values Replace various variable types with u32 or unsigned int type for variables holding register values, since the registers are 32bit. Note that rcar_pcie_msi_irq() still uses various variable types because both find_first_bit() and __fls() require various variable types as an argument. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 3db693b4410e..6699211fdc9a 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -170,7 +170,7 @@ enum { static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) { - int shift = 8 * (where & 3); + unsigned int shift = 8 * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); val &= ~(mask << shift); @@ -180,7 +180,7 @@ static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) static u32 rcar_read_conf(struct rcar_pcie *pcie, int where) { - int shift = 8 * (where & 3); + unsigned int shift = 8 * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); return val >> shift; @@ -191,7 +191,7 @@ static int rcar_pcie_config_access(struct rcar_pcie *pcie, unsigned char access_type, struct pci_bus *bus, unsigned int devfn, int where, u32 *data) { - int dev, func, reg, index; + unsigned int dev, func, reg, index; dev = PCI_SLOT(devfn); func = PCI_FUNC(devfn); @@ -295,8 +295,9 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { struct rcar_pcie *pcie = bus->sysdata; - int shift, ret; + unsigned int shift; u32 data; + int ret; ret = rcar_pcie_config_access(pcie, RCAR_PCI_ACCESS_READ, bus, devfn, where, &data); @@ -506,10 +507,10 @@ static int phy_wait_for_ack(struct rcar_pcie *pcie) } static void phy_write_reg(struct rcar_pcie *pcie, - unsigned int rate, unsigned int addr, - unsigned int lane, unsigned int data) + unsigned int rate, u32 addr, + unsigned int lane, u32 data) { - unsigned long phyaddr; + u32 phyaddr; phyaddr = WRITE_CMD | ((rate & 1) << RATE_POS) | @@ -1117,7 +1118,7 @@ static int rcar_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rcar_pcie *pcie; - unsigned int data; + u32 data; int err; int (*phy_init_fn)(struct rcar_pcie *); struct pci_host_bridge *bridge; -- cgit v1.2.3 From 29ffa6db40430e7c89fb1fc37cd78a90b27d4d2a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:40:59 +0100 Subject: PCI: rcar: Replace (8 * n) with (BITS_PER_BYTE * n) Replace (8 * n) with (BITS_PER_BYTE * n) to make bit shift operations consistent. No functional change. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 6699211fdc9a..96210768e774 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -170,7 +170,7 @@ enum { static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) { - unsigned int shift = 8 * (where & 3); + unsigned int shift = BITS_PER_BYTE * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); val &= ~(mask << shift); @@ -180,7 +180,7 @@ static void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data) static u32 rcar_read_conf(struct rcar_pcie *pcie, int where) { - unsigned int shift = 8 * (where & 3); + unsigned int shift = BITS_PER_BYTE * (where & 3); u32 val = rcar_pci_read_reg(pcie, where & ~3); return val >> shift; @@ -280,9 +280,9 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, } if (size == 1) - *val = (*val >> (8 * (where & 3))) & 0xff; + *val = (*val >> (BITS_PER_BYTE * (where & 3))) & 0xff; else if (size == 2) - *val = (*val >> (8 * (where & 2))) & 0xffff; + *val = (*val >> (BITS_PER_BYTE * (where & 2))) & 0xffff; dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", bus->number, devfn, where, size, (unsigned long)*val); @@ -308,11 +308,11 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, bus->number, devfn, where, size, (unsigned long)val); if (size == 1) { - shift = 8 * (where & 3); + shift = BITS_PER_BYTE * (where & 3); data &= ~(0xff << shift); data |= ((val & 0xff) << shift); } else if (size == 2) { - shift = 8 * (where & 2); + shift = BITS_PER_BYTE * (where & 2); data &= ~(0xffff << shift); data |= ((val & 0xffff) << shift); } else -- cgit v1.2.3 From 42a58f73e9ea4002692732d45a6ea1a0df9e125b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:41:00 +0100 Subject: PCI: rcar: Clean up debug messages Drop useless casts from debug messages, they are no longer needed due to the data type cleanup. Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 96210768e774..c6013f95bdb2 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -284,8 +284,8 @@ static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn, else if (size == 2) *val = (*val >> (BITS_PER_BYTE * (where & 2))) & 0xffff; - dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", - bus->number, devfn, where, size, (unsigned long)*val); + dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08x\n", + bus->number, devfn, where, size, *val); return ret; } @@ -304,8 +304,8 @@ static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn, if (ret != PCIBIOS_SUCCESSFUL) return ret; - dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08lx\n", - bus->number, devfn, where, size, (unsigned long)val); + dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x where=0x%04x size=%d val=0x%08x\n", + bus->number, devfn, where, size, val); if (size == 1) { shift = BITS_PER_BYTE * (where & 3); -- cgit v1.2.3 From 954b4b752a4c4e963b017ed8cef4c453c5ed308d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Mar 2019 12:41:01 +0100 Subject: PCI: rcar: Fix 64bit MSI message address handling The MSI message address in the RC address space can be 64 bit. The R-Car PCIe RC supports such a 64bit MSI message address as well. The code currently uses virt_to_phys(__get_free_pages()) to obtain a reserved page for the MSI message address, and the return value of which can be a 64 bit physical address on 64 bit system. However, the driver only programs PCIEMSIALR register with the bottom 32 bits of the virt_to_phys(__get_free_pages()) return value and does not program the top 32 bits into PCIEMSIAUR, but rather programs the PCIEMSIAUR register with 0x0. This worked fine on older 32 bit R-Car SoCs, however may fail on new 64 bit R-Car SoCs. Since from a PCIe controller perspective, an inbound MSI is a memory write to a special address (in case of this controller, defined by the value in PCIEMSIAUR:PCIEMSIALR), which triggers an interrupt, but never hits the DRAM _and_ because allocation of an MSI by a PCIe card driver obtains the MSI message address by reading PCIEMSIAUR:PCIEMSIALR in rcar_msi_setup_irqs(), incorrectly programmed PCIEMSIAUR cannot cause memory corruption or other issues. There is however the possibility that if virt_to_phys(__get_free_pages()) returned address above the 32bit boundary _and_ PCIEMSIAUR was programmed to 0x0 _and_ if the system had physical RAM at the address matching the value of PCIEMSIALR, a PCIe card driver could allocate a buffer with a physical address matching the value of PCIEMSIALR and a remote write to such a buffer by a PCIe card would trigger a spurious MSI. Fixes: e015f88c368d ("PCI: rcar: Add support for R-Car H3 to pcie-rcar") Signed-off-by: Marek Vasut Signed-off-by: Lorenzo Pieralisi Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Cc: Geert Uytterhoeven Cc: Phil Edworthy Cc: Simon Horman Cc: Wolfram Sang Cc: linux-renesas-soc@vger.kernel.org --- drivers/pci/controller/pcie-rcar.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index c6013f95bdb2..a25527185bf1 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -890,7 +890,7 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) { struct device *dev = pcie->dev; struct rcar_msi *msi = &pcie->msi; - unsigned long base; + phys_addr_t base; int err, i; mutex_init(&msi->lock); @@ -931,8 +931,8 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) msi->pages = __get_free_pages(GFP_KERNEL, 0); base = virt_to_phys((void *)msi->pages); - rcar_pci_write_reg(pcie, base | MSIFE, PCIEMSIALR); - rcar_pci_write_reg(pcie, 0, PCIEMSIAUR); + rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR); + rcar_pci_write_reg(pcie, upper_32_bits(base), PCIEMSIAUR); /* enable all MSI interrupts */ rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER); -- cgit v1.2.3 From f0d14edd2ba43b995bef4dd5da5ffe0ae19321a1 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Fri, 15 Mar 2019 02:29:43 -0500 Subject: PCI: rcar: Fix a potential NULL pointer dereference In case __get_free_pages() fails and returns NULL, fix the return value to -ENOMEM and release resources to avoid dereferencing a NULL pointer. Signed-off-by: Kangjie Lu Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/pci/controller/pcie-rcar.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index a25527185bf1..0004b6457124 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -929,6 +929,10 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) /* setup MSI data target */ msi->pages = __get_free_pages(GFP_KERNEL, 0); + if (!msi->pages) { + err = -ENOMEM; + goto err; + } base = virt_to_phys((void *)msi->pages); rcar_pci_write_reg(pcie, lower_32_bits(base) | MSIFE, PCIEMSIALR); -- cgit v1.2.3 From a27beb5820d1a52b1e2863a4ae5545a1dd4ab35a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 17 Mar 2019 10:34:45 +0100 Subject: PCI: rcar: Do not shadow the 'irq' variable The sparse tool rightfully detects: drivers/pci/controller/pcie-rcar.c:741:30: warning: symbol 'irq' shadows an earlier one Fix it now to avoid future surprises and for good coding style. No functional change intended. Signed-off-by: Wolfram Sang [lorenzo.pieralisi@arm.com: commit log refactoring] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman --- drivers/pci/controller/pcie-rcar.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rcar.c b/drivers/pci/controller/pcie-rcar.c index 0004b6457124..e4cebeb18470 100644 --- a/drivers/pci/controller/pcie-rcar.c +++ b/drivers/pci/controller/pcie-rcar.c @@ -738,15 +738,15 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data) while (reg) { unsigned int index = find_first_bit(®, 32); - unsigned int irq; + unsigned int msi_irq; /* clear the interrupt */ rcar_pci_write_reg(pcie, 1 << index, PCIEMSIFR); - irq = irq_find_mapping(msi->domain, index); - if (irq) { + msi_irq = irq_find_mapping(msi->domain, index); + if (msi_irq) { if (test_bit(index, msi->used)) - generic_handle_irq(irq); + generic_handle_irq(msi_irq); else dev_info(dev, "unhandled MSI\n"); } else { -- cgit v1.2.3 From 1beb55126937aff7601ddfca8df29870d29f2d86 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:20 +0530 Subject: PCI: keystone: Cleanup interrupt related macros No functional change. Change both MSI interrupt and legacy interrupt related macros to take an additional argument in order to return the correct register offset. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 14f2b0b4ed5e..5286a480f76b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -52,17 +52,17 @@ /* IRQ register defines */ #define IRQ_EOI 0x050 -#define IRQ_STATUS 0x184 -#define IRQ_ENABLE_SET 0x188 -#define IRQ_ENABLE_CLR 0x18c #define MSI_IRQ 0x054 -#define MSI0_IRQ_STATUS 0x104 -#define MSI0_IRQ_ENABLE_SET 0x108 -#define MSI0_IRQ_ENABLE_CLR 0x10c -#define IRQ_STATUS 0x184 +#define MSI_IRQ_STATUS(n) (0x104 + ((n) << 4)) +#define MSI_IRQ_ENABLE_SET(n) (0x108 + ((n) << 4)) +#define MSI_IRQ_ENABLE_CLR(n) (0x10c + ((n) << 4)) #define MSI_IRQ_OFFSET 4 +#define IRQ_STATUS(n) (0x184 + ((n) << 4)) +#define IRQ_ENABLE_SET(n) (0x188 + ((n) << 4)) +#define INTx_EN BIT(0) + #define ERR_IRQ_STATUS 0x1c4 #define ERR_IRQ_ENABLE_SET 0x1c8 #define ERR_AER BIT(5) /* ECRC error */ @@ -142,7 +142,7 @@ static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) u32 pending, vector; int src, virq; - pending = ks_pcie_app_readl(ks_pcie, MSI0_IRQ_STATUS + (offset << 4)); + pending = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset)); /* * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit @@ -169,7 +169,7 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_pcie_app_writel(ks_pcie, MSI0_IRQ_STATUS + (reg_offset << 4), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset), BIT(bit_pos)); ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); } @@ -181,7 +181,7 @@ static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_SET + (reg_offset << 4), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), BIT(bit_pos)); } @@ -192,7 +192,7 @@ static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); - ks_pcie_app_writel(ks_pcie, MSI0_IRQ_ENABLE_CLR + (reg_offset << 4), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), BIT(bit_pos)); } @@ -206,7 +206,7 @@ static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) int i; for (i = 0; i < PCI_NUM_INTX; i++) - ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET + (i << 4), 0x1); + ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), 0x1); } static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, @@ -217,7 +217,7 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, u32 pending; int virq; - pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS + (offset << 4)); + pending = ks_pcie_app_readl(ks_pcie, IRQ_STATUS(offset)); if (BIT(0) & pending) { virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset); -- cgit v1.2.3 From 1146c2953dcbd5eb01e415f528015206479e8fe3 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:21 +0530 Subject: PCI: keystone: Add separate functions for configuring MSI and legacy interrupt ks_pcie_get_irq_controller_info() is used to configure both MSI and legacy interrupt. This will prevent MSI or legacy interrupt specific intializations. Add separate functions to configure MSI and legacy interrupts. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 181 +++++++++++++++--------------- 1 file changed, 89 insertions(+), 92 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5286a480f76b..47f0dcf638f2 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -87,11 +87,9 @@ struct keystone_pcie { struct dw_pcie *pci; /* PCI Device ID */ u32 device_id; - int num_legacy_host_irqs; int legacy_host_irqs[PCI_NUM_INTX]; struct device_node *legacy_intc_np; - int num_msi_host_irqs; int msi_host_irqs[MAX_MSI_HOST_IRQS]; int num_lanes; u32 num_viewport; @@ -201,14 +199,6 @@ static int ks_pcie_msi_host_init(struct pcie_port *pp) return dw_pcie_allocate_domains(pp); } -static void ks_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie) -{ - int i; - - for (i = 0; i < PCI_NUM_INTX; i++) - ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), 0x1); -} - static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset) { @@ -495,17 +485,6 @@ static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie) ks_pcie->app = *res; - /* Create legacy IRQ domain */ - ks_pcie->legacy_irq_domain = - irq_domain_add_linear(ks_pcie->legacy_intc_np, - PCI_NUM_INTX, - &ks_pcie_legacy_irq_domain_ops, - NULL); - if (!ks_pcie->legacy_irq_domain) { - dev_err(dev, "Failed to add irq domain for legacy irqs\n"); - return -EINVAL; - } - return dw_pcie_host_init(pp); } @@ -622,85 +601,109 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie, - char *controller, int *num_irqs) +static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) { - int temp, max_host_irqs, legacy = 1, *host_irqs; struct device *dev = ks_pcie->pci->dev; - struct device_node *np_pcie = dev->of_node, **np_temp; - - if (!strcmp(controller, "msi-interrupt-controller")) - legacy = 0; - - if (legacy) { - np_temp = &ks_pcie->legacy_intc_np; - max_host_irqs = PCI_NUM_INTX; - host_irqs = &ks_pcie->legacy_host_irqs[0]; - } else { - np_temp = &ks_pcie->msi_intc_np; - max_host_irqs = MAX_MSI_HOST_IRQS; - host_irqs = &ks_pcie->msi_host_irqs[0]; - } + struct device_node *np = ks_pcie->np; + struct device_node *intc_np; + int irq_count, irq, ret, i; - /* interrupt controller is in a child node */ - *np_temp = of_get_child_by_name(np_pcie, controller); - if (!(*np_temp)) { - dev_err(dev, "Node for %s is absent\n", controller); - return -EINVAL; - } + if (!IS_ENABLED(CONFIG_PCI_MSI)) + return 0; - temp = of_irq_count(*np_temp); - if (!temp) { - dev_err(dev, "No IRQ entries in %s\n", controller); - of_node_put(*np_temp); + intc_np = of_get_child_by_name(np, "msi-interrupt-controller"); + if (!intc_np) { + dev_warn(dev, "msi-interrupt-controller node is absent\n"); return -EINVAL; } - if (temp > max_host_irqs) - dev_warn(dev, "Too many %s interrupts defined %u\n", - (legacy ? "legacy" : "MSI"), temp); + irq_count = of_irq_count(intc_np); + if (!irq_count) { + dev_err(dev, "No IRQ entries in msi-interrupt-controller\n"); + ret = -EINVAL; + goto err; + } - /* - * support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to - * 7 (MSI) - */ - for (temp = 0; temp < max_host_irqs; temp++) { - host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp); - if (!host_irqs[temp]) - break; + if (irq_count > MAX_MSI_HOST_IRQS) { + dev_warn(dev, "Too many MSI interrupt lines defined %u\n", + irq_count); + irq_count = MAX_MSI_HOST_IRQS; } - of_node_put(*np_temp); + for (i = 0; i < irq_count; i++) { + irq = irq_of_parse_and_map(intc_np, i); + if (!irq) { + ret = -EINVAL; + goto err; + } + ks_pcie->msi_host_irqs[i] = irq; - if (temp) { - *num_irqs = temp; - return 0; + irq_set_chained_handler_and_data(irq, ks_pcie_msi_irq_handler, + ks_pcie); } - return -EINVAL; + of_node_put(intc_np); + return 0; + +err: + of_node_put(intc_np); + return ret; } -static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) +static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie) { - int i; + struct device *dev = ks_pcie->pci->dev; + struct irq_domain *legacy_irq_domain; + struct device_node *np = ks_pcie->np; + struct device_node *intc_np; + int irq_count, irq, ret = 0, i; + + intc_np = of_get_child_by_name(np, "legacy-interrupt-controller"); + if (!intc_np) { + dev_warn(dev, "legacy-interrupt-controller node is absent\n"); + return -EINVAL; + } + + irq_count = of_irq_count(intc_np); + if (!irq_count) { + dev_err(dev, "No IRQ entries in legacy-interrupt-controller\n"); + ret = -EINVAL; + goto err; + } - /* Legacy IRQ */ - for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) { - irq_set_chained_handler_and_data(ks_pcie->legacy_host_irqs[i], + for (i = 0; i < irq_count; i++) { + irq = irq_of_parse_and_map(intc_np, i); + if (!irq) { + ret = -EINVAL; + goto err; + } + ks_pcie->legacy_host_irqs[i] = irq; + + irq_set_chained_handler_and_data(irq, ks_pcie_legacy_irq_handler, ks_pcie); } - ks_pcie_enable_legacy_irqs(ks_pcie); - - /* MSI IRQ */ - if (IS_ENABLED(CONFIG_PCI_MSI)) { - for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) { - irq_set_chained_handler_and_data(ks_pcie->msi_host_irqs[i], - ks_pcie_msi_irq_handler, - ks_pcie); - } + + legacy_irq_domain = + irq_domain_add_linear(intc_np, PCI_NUM_INTX, + &ks_pcie_legacy_irq_domain_ops, NULL); + if (!legacy_irq_domain) { + dev_err(dev, "Failed to add irq domain for legacy irqs\n"); + ret = -EINVAL; + goto err; } + ks_pcie->legacy_irq_domain = legacy_irq_domain; + + for (i = 0; i < PCI_NUM_INTX; i++) + ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), INTx_EN); + +err: + of_node_put(intc_np); + return ret; +} +static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) +{ if (ks_pcie->error_irq > 0) ks_pcie_enable_error_irq(ks_pcie); } @@ -754,6 +757,14 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); int ret; + ret = ks_pcie_config_legacy_irq(ks_pcie); + if (ret) + return ret; + + ret = ks_pcie_config_msi_irq(ks_pcie); + if (ret) + return ret; + dw_pcie_setup_rc(pp); ks_pcie_establish_link(ks_pcie); @@ -803,20 +814,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct device *dev = &pdev->dev; int ret; - ret = ks_pcie_get_irq_controller_info(ks_pcie, - "legacy-interrupt-controller", - &ks_pcie->num_legacy_host_irqs); - if (ret) - return ret; - - if (IS_ENABLED(CONFIG_PCI_MSI)) { - ret = ks_pcie_get_irq_controller_info(ks_pcie, - "msi-interrupt-controller", - &ks_pcie->num_msi_host_irqs); - if (ret) - return ret; - } - /* * Index 0 is the platform interrupt for error interrupt * from RC. This is optional. -- cgit v1.2.3 From f6f2900ca9b7c79d304e0cc264b010ed1c86a6b1 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:22 +0530 Subject: PCI: keystone: Use hwirq to get the MSI IRQ number offset ks_pcie_msi_irq_handler() uses 'virq' to get the IRQ number offset. This offset is used to get the correct MSI_IRQ_STATUS register corresponding to the IRQ line that raised the interrupt. There is no guarantee that 'virq' assigned for consecutive hardware IRQ will be contiguous and this might get us an incorrect IRQ number offset. Fix it here by using 'hwirq' to get the IRQ number offset. Since we don't store the 'virq' numbers of all the IRQ numbers, stop checking if irq count is greater than MAX_MSI_HOST_IRQS and remove MAX_MSI_HOST_IRQS. Link: https://lkml.kernel.org/r/bb081d21-7c03-0357-4294-7e92d95d838c@arm.com Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 47f0dcf638f2..fce25a0dcd08 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -74,7 +74,6 @@ #define ERR_IRQ_ALL (ERR_AER | ERR_AXI | ERR_CORR | \ ERR_NONFATAL | ERR_FATAL | ERR_SYS) -#define MAX_MSI_HOST_IRQS 8 /* PCIE controller device IDs */ #define PCIE_RC_K2HK 0xb008 #define PCIE_RC_K2E 0xb009 @@ -90,7 +89,7 @@ struct keystone_pcie { int legacy_host_irqs[PCI_NUM_INTX]; struct device_node *legacy_intc_np; - int msi_host_irqs[MAX_MSI_HOST_IRQS]; + int msi_host_irq; int num_lanes; u32 num_viewport; struct phy **phy; @@ -553,9 +552,9 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) static void ks_pcie_msi_irq_handler(struct irq_desc *desc) { - unsigned int irq = irq_desc_get_irq(desc); + unsigned int irq = desc->irq_data.hwirq; struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); - u32 offset = irq - ks_pcie->msi_host_irqs[0]; + u32 offset = irq - ks_pcie->msi_host_irq; struct dw_pcie *pci = ks_pcie->pci; struct device *dev = pci->dev; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -606,6 +605,7 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) struct device *dev = ks_pcie->pci->dev; struct device_node *np = ks_pcie->np; struct device_node *intc_np; + struct irq_data *irq_data; int irq_count, irq, ret, i; if (!IS_ENABLED(CONFIG_PCI_MSI)) @@ -624,19 +624,21 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) goto err; } - if (irq_count > MAX_MSI_HOST_IRQS) { - dev_warn(dev, "Too many MSI interrupt lines defined %u\n", - irq_count); - irq_count = MAX_MSI_HOST_IRQS; - } - for (i = 0; i < irq_count; i++) { irq = irq_of_parse_and_map(intc_np, i); if (!irq) { ret = -EINVAL; goto err; } - ks_pcie->msi_host_irqs[i] = irq; + + if (!ks_pcie->msi_host_irq) { + irq_data = irq_get_irq_data(irq); + if (!irq_data) { + ret = -EINVAL; + goto err; + } + ks_pcie->msi_host_irq = irq_data->hwirq; + } irq_set_chained_handler_and_data(irq, ks_pcie_msi_irq_handler, ks_pcie); -- cgit v1.2.3 From 66c10eca595293cd7a87afea112ca97179924d2a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:23 +0530 Subject: PCI: keystone: Cleanup ks_pcie_msi_irq_handler() ks_pcie_msi_irq_handler() invokes ks_pcie_handle_msi_irq() for handling the interrupts. Having two functions for handling the interrupt was used when keystone PCIe driver was implemented using two files but with commit b492aca35c98 ("PCI: keystone: Merge pci-keystone-dw.c and pci-keystone.c"), which merged the keystone PCIe driver to use a single file, two functions for handling the interrupt handler are not required. Handle MSI interrupt in a single interrupt handler here. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 64 ++++++++++++++----------------- 1 file changed, 28 insertions(+), 36 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index fce25a0dcd08..39542f2c312b 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -105,13 +105,6 @@ struct keystone_pcie { struct resource app; }; -static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, - u32 *bit_pos) -{ - *reg_offset = offset % 8; - *bit_pos = offset >> 3; -} - static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -131,31 +124,6 @@ static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset, writel(val, ks_pcie->va_app_base + offset); } -static void ks_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - u32 pending, vector; - int src, virq; - - pending = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset)); - - /* - * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit - * shows 1, 9, 17, 25 and so forth - */ - for (src = 0; src < 4; src++) { - if (BIT(src) & pending) { - vector = offset + (src << 3); - virq = irq_linear_revmap(pp->irq_domain, vector); - dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", - src, vector, virq); - generic_handle_irq(virq); - } - } -} - static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) { u32 reg_offset, bit_pos; @@ -164,7 +132,9 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) pci = to_dw_pcie_from_pp(pp); ks_pcie = to_keystone_pcie(pci); - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + + reg_offset = irq % 8; + bit_pos = irq >> 3; ks_pcie_app_writel(ks_pcie, MSI_IRQ_STATUS(reg_offset), BIT(bit_pos)); @@ -177,7 +147,9 @@ static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + reg_offset = irq % 8; + bit_pos = irq >> 3; + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), BIT(bit_pos)); } @@ -188,7 +160,9 @@ static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - update_reg_offset_bit_pos(irq, ®_offset, &bit_pos); + reg_offset = irq % 8; + bit_pos = irq >> 3; + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), BIT(bit_pos)); } @@ -556,8 +530,10 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); u32 offset = irq - ks_pcie->msi_host_irq; struct dw_pcie *pci = ks_pcie->pci; + struct pcie_port *pp = &pci->pp; struct device *dev = pci->dev; struct irq_chip *chip = irq_desc_get_chip(desc); + u32 vector, virq, reg, pos; dev_dbg(dev, "%s, irq %d\n", __func__, irq); @@ -567,7 +543,23 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc) * ack operation. */ chained_irq_enter(chip, desc); - ks_pcie_handle_msi_irq(ks_pcie, offset); + + reg = ks_pcie_app_readl(ks_pcie, MSI_IRQ_STATUS(offset)); + /* + * MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit + * shows 1, 9, 17, 25 and so forth + */ + for (pos = 0; pos < 4; pos++) { + if (!(reg & BIT(pos))) + continue; + + vector = offset + (pos << 3); + virq = irq_linear_revmap(pp->irq_domain, vector); + dev_dbg(dev, "irq: bit %d, vector %d, virq %d\n", pos, vector, + virq); + generic_handle_irq(virq); + } + chained_irq_exit(chip, desc); } -- cgit v1.2.3 From 9f67437b3a085865fbf5c2d0cbf60fb1b465411c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:24 +0530 Subject: PCI: dwc: Add support to use non default msi_irq_chip Platforms using DesignWare IP use dw_pci_msi_bottom_irq_chip for configuring the MSI controller logic within the DesignWare IP. However certain platforms like Keystone (K2G) which uses DesignWare IP have their own MSI controller logic. For handling such platforms, the irqchip ops use msi_irq_ack(), msi_set_irq(), msi_clear_irq() callback functions. Add support to use different msi_irq_chip with default set to dw_pci_msi_bottom_irq_chip. This is in preparation to get rid of msi_irq_ack(), msi_set_irq(), msi_clear_irq() and other Keystone specific dw_pcie_host_ops. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-host.c | 5 ++++- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 25087d3c9a82..e28cb082f50d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -245,7 +245,7 @@ static int dw_pcie_irq_domain_alloc(struct irq_domain *domain, for (i = 0; i < nr_irqs; i++) irq_domain_set_info(domain, virq + i, bit + i, - &dw_pci_msi_bottom_irq_chip, + pp->msi_irq_chip, pp, handle_edge_irq, NULL, NULL); @@ -277,6 +277,9 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node); + if (!pp->msi_irq_chip) + pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; + pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors, &dw_pcie_msi_domain_ops, pp); if (!pp->irq_domain) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 377f4c0b52da..6b0cea473ee7 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -179,6 +179,7 @@ struct pcie_port { struct irq_domain *irq_domain; struct irq_domain *msi_domain; dma_addr_t msi_data; + struct irq_chip *msi_irq_chip; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; raw_spinlock_t lock; -- cgit v1.2.3 From 117c3b60bd5372ec23f8c1a9652ad78dc2b9982a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:25 +0530 Subject: PCI: keystone: Use Keystone specific msi_irq_chip Use Keystone specific msi_irq_chip to configure the MSI controller logic in the PCIe keystone wrapper instead of using the default Designware msi_irq chip (dw_pci_msi_bottom_irq_chip) with callback functions for configuring the Keystone MSI controller. This will help to remove Keystone specific callback functions added in dw_pcie_host_ops. Move the default msi_irq_chip assignment to dw_pcie_host_init since platforms that doesn't use the default msi_irq_chip will assign msi_irq_chip in the msi_host_init() callback. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 96 +++++++++++++++++------ drivers/pci/controller/dwc/pcie-designware-host.c | 5 +- 2 files changed, 74 insertions(+), 27 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 39542f2c312b..b757692e2848 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -105,14 +105,6 @@ struct keystone_pcie { struct resource app; }; -static phys_addr_t ks_pcie_get_msi_addr(struct pcie_port *pp) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); - - return ks_pcie->app.start + MSI_IRQ; -} - static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset) { return readl(ks_pcie->va_app_base + offset); @@ -124,11 +116,14 @@ static void ks_pcie_app_writel(struct keystone_pcie *ks_pcie, u32 offset, writel(val, ks_pcie->va_app_base + offset); } -static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) +static void ks_pcie_msi_irq_ack(struct irq_data *data) { - u32 reg_offset, bit_pos; + struct pcie_port *pp = irq_data_get_irq_chip_data(data); struct keystone_pcie *ks_pcie; + u32 irq = data->hwirq; struct dw_pcie *pci; + u32 reg_offset; + u32 bit_pos; pci = to_dw_pcie_from_pp(pp); ks_pcie = to_keystone_pcie(pci); @@ -141,34 +136,91 @@ static void ks_pcie_msi_irq_ack(int irq, struct pcie_port *pp) ks_pcie_app_writel(ks_pcie, IRQ_EOI, reg_offset + MSI_IRQ_OFFSET); } -static void ks_pcie_msi_set_irq(struct pcie_port *pp, int irq) +static void ks_pcie_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { - u32 reg_offset, bit_pos; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + struct pcie_port *pp = irq_data_get_irq_chip_data(data); + struct keystone_pcie *ks_pcie; + struct dw_pcie *pci; + u64 msi_target; + + pci = to_dw_pcie_from_pp(pp); + ks_pcie = to_keystone_pcie(pci); + + msi_target = ks_pcie->app.start + MSI_IRQ; + msg->address_lo = lower_32_bits(msi_target); + msg->address_hi = upper_32_bits(msi_target); + msg->data = data->hwirq; + + dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n", + (int)data->hwirq, msg->address_hi, msg->address_lo); +} + +static int ks_pcie_msi_set_affinity(struct irq_data *irq_data, + const struct cpumask *mask, bool force) +{ + return -EINVAL; +} + +static void ks_pcie_msi_mask(struct irq_data *data) +{ + struct pcie_port *pp = irq_data_get_irq_chip_data(data); + struct keystone_pcie *ks_pcie; + u32 irq = data->hwirq; + struct dw_pcie *pci; + unsigned long flags; + u32 reg_offset; + u32 bit_pos; + + raw_spin_lock_irqsave(&pp->lock, flags); + + pci = to_dw_pcie_from_pp(pp); + ks_pcie = to_keystone_pcie(pci); reg_offset = irq % 8; bit_pos = irq >> 3; - ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), BIT(bit_pos)); + + raw_spin_unlock_irqrestore(&pp->lock, flags); } -static void ks_pcie_msi_clear_irq(struct pcie_port *pp, int irq) +static void ks_pcie_msi_unmask(struct irq_data *data) { - u32 reg_offset, bit_pos; - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + struct pcie_port *pp = irq_data_get_irq_chip_data(data); + struct keystone_pcie *ks_pcie; + u32 irq = data->hwirq; + struct dw_pcie *pci; + unsigned long flags; + u32 reg_offset; + u32 bit_pos; + + raw_spin_lock_irqsave(&pp->lock, flags); + + pci = to_dw_pcie_from_pp(pp); + ks_pcie = to_keystone_pcie(pci); reg_offset = irq % 8; bit_pos = irq >> 3; - ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_CLR(reg_offset), + ks_pcie_app_writel(ks_pcie, MSI_IRQ_ENABLE_SET(reg_offset), BIT(bit_pos)); + + raw_spin_unlock_irqrestore(&pp->lock, flags); } +static struct irq_chip ks_pcie_msi_irq_chip = { + .name = "KEYSTONE-PCI-MSI", + .irq_ack = ks_pcie_msi_irq_ack, + .irq_compose_msi_msg = ks_pcie_compose_msi_msg, + .irq_set_affinity = ks_pcie_msi_set_affinity, + .irq_mask = ks_pcie_msi_mask, + .irq_unmask = ks_pcie_msi_unmask, +}; + static int ks_pcie_msi_host_init(struct pcie_port *pp) { + pp->msi_irq_chip = &ks_pcie_msi_irq_chip; return dw_pcie_allocate_domains(pp); } @@ -785,11 +837,7 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = { .rd_other_conf = ks_pcie_rd_other_conf, .wr_other_conf = ks_pcie_wr_other_conf, .host_init = ks_pcie_host_init, - .msi_set_irq = ks_pcie_msi_set_irq, - .msi_clear_irq = ks_pcie_msi_clear_irq, - .get_msi_addr = ks_pcie_get_msi_addr, .msi_host_init = ks_pcie_msi_host_init, - .msi_irq_ack = ks_pcie_msi_irq_ack, .scan_bus = ks_pcie_v3_65_scan_bus, }; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index e28cb082f50d..9e47bad82bbc 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -277,9 +277,6 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node); - if (!pp->msi_irq_chip) - pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; - pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors, &dw_pcie_msi_domain_ops, pp); if (!pp->irq_domain) { @@ -462,6 +459,8 @@ int dw_pcie_host_init(struct pcie_port *pp) } if (!pp->ops->msi_host_init) { + pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip; + ret = dw_pcie_allocate_domains(pp); if (ret) goto error; -- cgit v1.2.3 From dad5258999e91ba368dbdd31ecac94e095acb844 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:26 +0530 Subject: PCI: dwc: Remove Keystone specific dw_pcie_host_ops Now that Keystone started using its own msi_irq_chip, remove Keystone specific callback functions defined in dw_pcie_host_ops. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-host.c | 50 +++++++---------------- drivers/pci/controller/dwc/pcie-designware.h | 5 --- 2 files changed, 14 insertions(+), 41 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 9e47bad82bbc..498422397609 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -126,18 +126,12 @@ static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); u64 msi_target; - if (pp->ops->get_msi_addr) - msi_target = pp->ops->get_msi_addr(pp); - else - msi_target = (u64)pp->msi_data; + msi_target = (u64)pp->msi_data; msg->address_lo = lower_32_bits(msi_target); msg->address_hi = upper_32_bits(msi_target); - if (pp->ops->get_msi_data) - msg->data = pp->ops->get_msi_data(pp, d->hwirq); - else - msg->data = d->hwirq; + msg->data = d->hwirq; dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n", (int)d->hwirq, msg->address_hi, msg->address_lo); @@ -157,17 +151,13 @@ static void dw_pci_bottom_mask(struct irq_data *d) raw_spin_lock_irqsave(&pp->lock, flags); - if (pp->ops->msi_clear_irq) { - pp->ops->msi_clear_irq(pp, d->hwirq); - } else { - ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; - bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; + ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; + bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - pp->irq_mask[ctrl] |= BIT(bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, - pp->irq_mask[ctrl]); - } + pp->irq_mask[ctrl] |= BIT(bit); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, + pp->irq_mask[ctrl]); raw_spin_unlock_irqrestore(&pp->lock, flags); } @@ -180,17 +170,13 @@ static void dw_pci_bottom_unmask(struct irq_data *d) raw_spin_lock_irqsave(&pp->lock, flags); - if (pp->ops->msi_set_irq) { - pp->ops->msi_set_irq(pp, d->hwirq); - } else { - ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; - res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; - bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; + ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; + res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; + bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - pp->irq_mask[ctrl] &= ~BIT(bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, - pp->irq_mask[ctrl]); - } + pp->irq_mask[ctrl] &= ~BIT(bit); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, + pp->irq_mask[ctrl]); raw_spin_unlock_irqrestore(&pp->lock, flags); } @@ -199,20 +185,12 @@ static void dw_pci_bottom_ack(struct irq_data *d) { struct pcie_port *pp = irq_data_get_irq_chip_data(d); unsigned int res, bit, ctrl; - unsigned long flags; ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL; res = ctrl * MSI_REG_CTRL_BLOCK_SIZE; bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL; - raw_spin_lock_irqsave(&pp->lock, flags); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit)); - - if (pp->ops->msi_irq_ack) - pp->ops->msi_irq_ack(d->hwirq, pp); - - raw_spin_unlock_irqrestore(&pp->lock, flags); } static struct irq_chip dw_pci_msi_bottom_irq_chip = { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 6b0cea473ee7..ca3a3190a6f5 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -145,14 +145,9 @@ struct dw_pcie_host_ops { int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); int (*host_init)(struct pcie_port *pp); - void (*msi_set_irq)(struct pcie_port *pp, int irq); - void (*msi_clear_irq)(struct pcie_port *pp, int irq); - phys_addr_t (*get_msi_addr)(struct pcie_port *pp); - u32 (*get_msi_data)(struct pcie_port *pp, int pos); void (*scan_bus)(struct pcie_port *pp); void (*set_num_vectors)(struct pcie_port *pp); int (*msi_host_init)(struct pcie_port *pp); - void (*msi_irq_ack)(int irq, struct pcie_port *pp); }; struct pcie_port { -- cgit v1.2.3 From fd8a44bd5b76dc77133f814dd63d414d49dc74c0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 21 Mar 2019 15:29:27 +0530 Subject: PCI: dwc: Remove default MSI initialization for platform specific MSI chips Platforms which populate msi_host_init() have their own MSI controller logic. Writing to MSI control registers on platforms which do not use Designware's MSI controller logic might have side effects. To be safe, do not write to MSI control registers if the platform uses its own MSI controller logic instead of Designware's MSI one. Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-host.c | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 498422397609..7e0ff7d428a9 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -626,17 +626,19 @@ void dw_pcie_setup_rc(struct pcie_port *pp) dw_pcie_setup(pci); - num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; - - /* Initialize IRQ Status array */ - for (ctrl = 0; ctrl < num_ctrls; ctrl++) { - pp->irq_mask[ctrl] = ~0; - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + - (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - 4, pp->irq_mask[ctrl]); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + - (ctrl * MSI_REG_CTRL_BLOCK_SIZE), - 4, ~0); + if (!pp->ops->msi_host_init) { + num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; + + /* Initialize IRQ Status array */ + for (ctrl = 0; ctrl < num_ctrls; ctrl++) { + pp->irq_mask[ctrl] = ~0; + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), + 4, pp->irq_mask[ctrl]); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + + (ctrl * MSI_REG_CTRL_BLOCK_SIZE), + 4, ~0); + } } /* Setup RC BARs */ -- cgit v1.2.3 From 6be22343cc546b46402869668da453d56921c14e Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Wed, 10 Apr 2019 14:54:16 +0800 Subject: PCI: mediatek: Get optional clocks with devm_clk_get_optional() Update the driver to use devm_clk_get_optional() to claim optional clocks instead of devm_clk_get(). Signed-off-by: Chunfeng Yun Signed-off-by: Lorenzo Pieralisi Acked-by: Ryder Lee Acked-by: Honghui Zhang Cc: Ryder Lee Cc: Honghui Zhang --- drivers/pci/controller/pcie-mediatek.c | 50 ++++++++++------------------------ 1 file changed, 15 insertions(+), 35 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 0b6c72804e03..adb6cb15daa2 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -915,49 +915,29 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie, /* sys_ck might be divided into the following parts in some chips */ snprintf(name, sizeof(name), "ahb_ck%d", slot); - port->ahb_ck = devm_clk_get(dev, name); - if (IS_ERR(port->ahb_ck)) { - if (PTR_ERR(port->ahb_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->ahb_ck = NULL; - } + port->ahb_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->ahb_ck)) + return PTR_ERR(port->ahb_ck); snprintf(name, sizeof(name), "axi_ck%d", slot); - port->axi_ck = devm_clk_get(dev, name); - if (IS_ERR(port->axi_ck)) { - if (PTR_ERR(port->axi_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->axi_ck = NULL; - } + port->axi_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->axi_ck)) + return PTR_ERR(port->axi_ck); snprintf(name, sizeof(name), "aux_ck%d", slot); - port->aux_ck = devm_clk_get(dev, name); - if (IS_ERR(port->aux_ck)) { - if (PTR_ERR(port->aux_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->aux_ck = NULL; - } + port->aux_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->aux_ck)) + return PTR_ERR(port->aux_ck); snprintf(name, sizeof(name), "obff_ck%d", slot); - port->obff_ck = devm_clk_get(dev, name); - if (IS_ERR(port->obff_ck)) { - if (PTR_ERR(port->obff_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->obff_ck = NULL; - } + port->obff_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->obff_ck)) + return PTR_ERR(port->obff_ck); snprintf(name, sizeof(name), "pipe_ck%d", slot); - port->pipe_ck = devm_clk_get(dev, name); - if (IS_ERR(port->pipe_ck)) { - if (PTR_ERR(port->pipe_ck) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - port->pipe_ck = NULL; - } + port->pipe_ck = devm_clk_get_optional(dev, name); + if (IS_ERR(port->pipe_ck)) + return PTR_ERR(port->pipe_ck); snprintf(name, sizeof(name), "pcie-rst%d", slot); port->reset = devm_reset_control_get_optional_exclusive(dev, name); -- cgit v1.2.3 From 9afb20d600da83639ad800f113884fadb78a43ae Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:22 +0530 Subject: PCI: keystone: Add start_link()/stop_link() dw_pcie_ops Add start_link()/stop_link() dw_pcie_ops and invoke ks_pcie_start_link() directly from host_init. start_link()/stop_link() ops are required for adding EP mode support. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 44 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index b757692e2848..07f55b355d75 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -460,18 +460,33 @@ static int ks_pcie_link_up(struct dw_pcie *pci) return (val == PORT_LOGIC_LTSSM_STATE_L0); } -static void ks_pcie_initiate_link_train(struct keystone_pcie *ks_pcie) +static void ks_pcie_stop_link(struct dw_pcie *pci) { + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); u32 val; /* Disable Link training */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); val &= ~LTSSM_EN_VAL; ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); +} + +static int ks_pcie_start_link(struct dw_pcie *pci) +{ + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + struct device *dev = pci->dev; + u32 val; + + if (dw_pcie_link_up(pci)) { + dev_dbg(dev, "link is already up\n"); + return 0; + } /* Initiate Link Training */ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS); ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val); + + return 0; } /** @@ -556,26 +571,6 @@ static void ks_pcie_quirk(struct pci_dev *dev) } DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, ks_pcie_quirk); -static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct device *dev = pci->dev; - - if (dw_pcie_link_up(pci)) { - dev_info(dev, "Link already up\n"); - return 0; - } - - ks_pcie_initiate_link_train(ks_pcie); - - /* check if the link is up or not */ - if (!dw_pcie_wait_for_link(pci)) - return 0; - - dev_err(dev, "phy link never came up\n"); - return -ETIMEDOUT; -} - static void ks_pcie_msi_irq_handler(struct irq_desc *desc) { unsigned int irq = desc->irq_data.hwirq; @@ -813,7 +808,7 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) dw_pcie_setup_rc(pp); - ks_pcie_establish_link(ks_pcie); + ks_pcie_stop_link(pci); ks_pcie_setup_rc_app_regs(ks_pcie); ks_pcie_setup_interrupts(ks_pcie); writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), @@ -830,6 +825,9 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) hook_fault_code(17, ks_pcie_fault, SIGBUS, 0, "Asynchronous external abort"); + ks_pcie_start_link(pci); + dw_pcie_wait_for_link(pci); + return 0; } @@ -892,6 +890,8 @@ static const struct of_device_id ks_pcie_of_match[] = { }; static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { + .start_link = ks_pcie_start_link, + .stop_link = ks_pcie_stop_link, .link_up = ks_pcie_link_up, }; -- cgit v1.2.3 From 0790eb175ee0d8979a6db6bf2ad81e7c83d616df Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:23 +0530 Subject: PCI: keystone: Cleanup error_irq configuration pci-keystone driver uses irq_of_parse_and_map() to get irq number of error_irq. Use platform_get_irq() instead and move platform_get_irq() and request_irq() of error_irq from ks_pcie_add_pcie_port to ks_pcie_probe since error_irq is common to both RC mode and EP mode. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 43 ++++++++++++------------------- 1 file changed, 17 insertions(+), 26 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 07f55b355d75..e50f8773e768 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -98,8 +98,6 @@ struct keystone_pcie { struct irq_domain *legacy_irq_domain; struct device_node *np; - int error_irq; - /* Application register space */ void __iomem *va_app_base; /* DT 1st resource */ struct resource app; @@ -743,12 +741,6 @@ err: return ret; } -static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) -{ - if (ks_pcie->error_irq > 0) - ks_pcie_enable_error_irq(ks_pcie); -} - /* * When a PCI device does not exist during config cycles, keystone host gets a * bus error instead of returning 0xffffffff. This handler always returns 0 @@ -810,7 +802,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) ks_pcie_stop_link(pci); ks_pcie_setup_rc_app_regs(ks_pcie); - ks_pcie_setup_interrupts(ks_pcie); writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8), pci->dbi_base + PCI_IO_BASE); @@ -854,23 +845,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct device *dev = &pdev->dev; int 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(dev, "no error IRQ defined\n"); - else { - ret = request_irq(ks_pcie->error_irq, ks_pcie_err_irq_handler, - IRQF_SHARED, "pcie-error-irq", ks_pcie); - if (ret < 0) { - dev_err(dev, "failed to request error IRQ %d\n", - ks_pcie->error_irq); - return ret; - } - } - pp->ops = &ks_pcie_host_ops; ret = ks_pcie_dw_host_init(ks_pcie); if (ret) { @@ -946,6 +920,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) u32 num_lanes; char name[10]; int ret; + int irq; int i; ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); @@ -965,6 +940,20 @@ static int __init ks_pcie_probe(struct platform_device *pdev) return ret; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "missing IRQ resource: %d\n", irq); + return irq; + } + + ret = request_irq(irq, ks_pcie_err_irq_handler, IRQF_SHARED, + "ks-pcie-error-irq", ks_pcie); + if (ret < 0) { + dev_err(dev, "failed to request error IRQ %d\n", + irq); + return ret; + } + ret = of_property_read_u32(np, "num-lanes", &num_lanes); if (ret) num_lanes = 1; @@ -1020,6 +1009,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (ret < 0) goto err_get_sync; + ks_pcie_enable_error_irq(ks_pcie); + return 0; err_get_sync: -- cgit v1.2.3 From f3560a9f88ae3aa2b2976a1a0175478f6fd32fe8 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:25 +0530 Subject: PCI: keystone: Perform host initialization in a single function No functional change. Instead of having two functions ks_pcie_add_pcie_port() and ks_pcie_dw_host_init() for initializing host, have a single function to perform all the host initialization. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 63 +++++++++++-------------------- 1 file changed, 23 insertions(+), 40 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e50f8773e768..566718ea7ebf 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -487,45 +487,6 @@ static int ks_pcie_start_link(struct dw_pcie *pci) return 0; } -/** - * ks_pcie_dw_host_init() - initialize host for v3_65 dw hardware - * - * Ioremap the register resources, initialize legacy irq domain - * and call dw_pcie_v3_65_host_init() API to initialize the Keystone - * PCI host controller. - */ -static int __init ks_pcie_dw_host_init(struct keystone_pcie *ks_pcie) -{ - struct dw_pcie *pci = ks_pcie->pci; - struct pcie_port *pp = &pci->pp; - struct device *dev = pci->dev; - struct platform_device *pdev = to_platform_device(dev); - struct resource *res; - - /* Index 0 is the config reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - - /* - * We set these same and is used in pcie rd/wr_other_conf - * functions - */ - pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; - pp->va_cfg1_base = pp->va_cfg0_base; - - /* Index 1 is the application reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - ks_pcie->va_app_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ks_pcie->va_app_base)) - return PTR_ERR(ks_pcie->va_app_base); - - ks_pcie->app = *res; - - return dw_pcie_host_init(pp); -} - static void ks_pcie_quirk(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; @@ -843,10 +804,32 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct dw_pcie *pci = ks_pcie->pci; struct pcie_port *pp = &pci->pp; struct device *dev = &pdev->dev; + struct resource *res; int ret; + /* Index 0 is the config reg. space address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pci->dbi_base)) + return PTR_ERR(pci->dbi_base); + + /* + * We set these same and is used in pcie rd/wr_other_conf + * functions + */ + pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; + pp->va_cfg1_base = pp->va_cfg0_base; + + /* Index 1 is the application reg. space address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ks_pcie->va_app_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ks_pcie->va_app_base)) + return PTR_ERR(ks_pcie->va_app_base); + + ks_pcie->app = *res; + pp->ops = &ks_pcie_host_ops; - ret = ks_pcie_dw_host_init(ks_pcie); + ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "failed to initialize host\n"); return ret; -- cgit v1.2.3 From 2341ab4fd5d7ee3db5c67e8ff8506722910df8e9 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:26 +0530 Subject: PCI: keystone: Use platform_get_resource_byname() to get memory resources Use platform_get_resource_byname() instead of platform_get_resource() which uses an index to get memory resources. While at that get the memory resource defined specifically for configuration space instead of deriving the configuration space address from dbics address space. Since the pci-keystone driver has never worked in the mainline kernel, DT backward compatibility is not an issue. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 566718ea7ebf..5eebef9b9ada 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -44,7 +44,6 @@ #define CFG_TYPE1 BIT(24) #define OB_SIZE 0x030 -#define SPACE0_REMOTE_CFG_OFFSET 0x1000 #define OB_OFFSET_INDEX(n) (0x200 + (8 * (n))) #define OB_OFFSET_HI(n) (0x204 + (8 * (n))) #define OB_ENABLEN BIT(0) @@ -807,21 +806,19 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct resource *res; int ret; - /* Index 0 is the config reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics"); pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); if (IS_ERR(pci->dbi_base)) return PTR_ERR(pci->dbi_base); - /* - * We set these same and is used in pcie rd/wr_other_conf - * functions - */ - pp->va_cfg0_base = pci->dbi_base + SPACE0_REMOTE_CFG_OFFSET; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); + pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(pp->va_cfg0_base)) + return PTR_ERR(pp->va_cfg0_base); + pp->va_cfg1_base = pp->va_cfg0_base; - /* Index 1 is the application reg. space address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app"); ks_pcie->va_app_base = devm_ioremap_resource(dev, res); if (IS_ERR(ks_pcie->va_app_base)) return PTR_ERR(ks_pcie->va_app_base); -- cgit v1.2.3 From 74356addc0b32e891327bcb1e36d7f798f7b1c7d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 9 Jan 2019 14:14:42 -0600 Subject: PCI: Fix comment typos Fix spelling errors and format function comments consistently. Changes whitespace and comments only; no functional change intended. Signed-off-by: Bjorn Helgaas Reviewed-by: Mukesh Ojha --- drivers/pci/controller/pci-host-generic.c | 2 +- drivers/pci/controller/pcie-iproc-msi.c | 2 +- drivers/pci/pci.c | 328 ++++++++++++++++-------------- 3 files changed, 172 insertions(+), 160 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c index dea3ec7592a2..75a2fb930d4b 100644 --- a/drivers/pci/controller/pci-host-generic.c +++ b/drivers/pci/controller/pci-host-generic.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Simple, generic PCI host controller driver targetting firmware-initialised + * Simple, generic PCI host controller driver targeting firmware-initialised * systems and virtual machines (e.g. the PCI emulation provided by kvmtool). * * Copyright (C) 2014 ARM Limited diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index cb3401a931f8..0a3f61be5625 100644 --- a/drivers/pci/controller/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c @@ -367,7 +367,7 @@ static void iproc_msi_handler(struct irq_desc *desc) /* * Now go read the tail pointer again to see if there are new - * oustanding events that came in during the above window. + * outstanding events that came in during the above window. */ } while (true); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7c1b362f599a..530eec3191e7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -197,8 +197,8 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar); /** * pci_dev_str_match_path - test if a path string matches a device - * @dev: the PCI device to test - * @path: string to match the device against + * @dev: the PCI device to test + * @path: string to match the device against * @endptr: pointer to the string after the match * * Test if a string (typically from a kernel parameter) formatted as a @@ -280,8 +280,8 @@ free_and_exit: /** * pci_dev_str_match - test if a string matches a device - * @dev: the PCI device to test - * @p: string to match the device against + * @dev: the PCI device to test + * @p: string to match the device against * @endptr: pointer to the string after the match * * Test if a string (typically from a kernel parameter) matches a specified @@ -341,7 +341,7 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p, } else { /* * PCI Bus, Device, Function IDs are specified - * (optionally, may include a path of devfns following it) + * (optionally, may include a path of devfns following it) */ ret = pci_dev_str_match_path(dev, p, &p); if (ret < 0) @@ -425,7 +425,7 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus, * Tell if a device supports a given PCI capability. * Returns the address of the requested capability structure within the * device's PCI configuration space or 0 in case the device does not - * support it. Possible values for @cap: + * support it. Possible values for @cap include: * * %PCI_CAP_ID_PM Power Management * %PCI_CAP_ID_AGP Accelerated Graphics Port @@ -450,11 +450,11 @@ EXPORT_SYMBOL(pci_find_capability); /** * pci_bus_find_capability - query for devices' capabilities - * @bus: the PCI bus to query + * @bus: the PCI bus to query * @devfn: PCI device to query - * @cap: capability code + * @cap: capability code * - * Like pci_find_capability() but works for pci devices that do not have a + * Like pci_find_capability() but works for PCI devices that do not have a * pci_dev structure set up yet. * * Returns the address of the requested capability structure within the @@ -535,7 +535,7 @@ EXPORT_SYMBOL_GPL(pci_find_next_ext_capability); * * Returns the address of the requested extended capability structure * within the device's PCI configuration space or 0 if the device does - * not support it. Possible values for @cap: + * not support it. Possible values for @cap include: * * %PCI_EXT_CAP_ID_ERR Advanced Error Reporting * %PCI_EXT_CAP_ID_VC Virtual Channel @@ -618,12 +618,13 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) EXPORT_SYMBOL_GPL(pci_find_ht_capability); /** - * pci_find_parent_resource - return resource region of parent bus of given region + * pci_find_parent_resource - return resource region of parent bus of given + * region * @dev: PCI device structure contains resources to be searched * @res: child resource record for which parent is sought * - * For given resource region of given device, return the resource - * region of parent bus the given region is contained in. + * For given resource region of given device, return the resource region of + * parent bus the given region is contained in. */ struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) @@ -800,7 +801,7 @@ static inline bool platform_pci_bridge_d3(struct pci_dev *dev) /** * pci_raw_set_power_state - Use PCI PM registers to set the power state of - * given PCI device + * given PCI device * @dev: PCI device to handle. * @state: PCI power state (D0, D1, D2, D3hot) to put the device into. * @@ -826,7 +827,8 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) if (state < PCI_D0 || state > PCI_D3hot) return -EINVAL; - /* Validate current state: + /* + * Validate current state: * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state */ @@ -837,14 +839,15 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) return -EINVAL; } - /* check if this device supports the desired state */ + /* Check if this device supports the desired state */ if ((state == PCI_D1 && !dev->d1_support) || (state == PCI_D2 && !dev->d2_support)) return -EIO; pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); - /* If we're (effectively) in D3, force entire word to 0. + /* + * If we're (effectively) in D3, force entire word to 0. * This doesn't affect PME_Status, disables PME_En, and * sets PowerState to 0. */ @@ -867,11 +870,13 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) break; } - /* enter specified state */ + /* Enter specified state */ pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); - /* Mandatory power management transition delays */ - /* see PCI PM 1.1 5.6.1 table 18 */ + /* + * Mandatory power management transition delays; see PCI PM 1.1 + * 5.6.1 table 18 + */ if (state == PCI_D3hot || dev->current_state == PCI_D3hot) pci_dev_d3_sleep(dev); else if (state == PCI_D2 || dev->current_state == PCI_D2) @@ -1085,16 +1090,18 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { int error; - /* bound the state we're entering */ + /* Bound the state we're entering */ if (state > PCI_D3cold) state = PCI_D3cold; else if (state < PCI_D0) state = PCI_D0; else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) + /* - * If the device or the parent bridge do not support PCI PM, - * ignore the request if we're doing anything other than putting - * it into D0 (which would only happen on boot). + * If the device or the parent bridge do not support PCI + * PM, ignore the request if we're doing anything other + * than putting it into D0 (which would only happen on + * boot). */ return 0; @@ -1104,8 +1111,10 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) __pci_start_power_transition(dev, state); - /* This device is quirked not to be put into D3, so - don't put it in D3 */ + /* + * This device is quirked not to be put into D3, so don't put it in + * D3 + */ if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) return 0; @@ -1127,12 +1136,11 @@ EXPORT_SYMBOL(pci_set_power_state); * pci_choose_state - Choose the power state of a PCI device * @dev: PCI device to be suspended * @state: target sleep state for the whole system. This is the value - * that is passed to suspend() function. + * that is passed to suspend() function. * * Returns PCI power state suitable for given device and given system * message. */ - pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { pci_power_t ret; @@ -1310,8 +1318,9 @@ static void pci_restore_ltr_state(struct pci_dev *dev) } /** - * pci_save_state - save the PCI configuration space of a device before suspending - * @dev: - PCI device that we're dealing with + * pci_save_state - save the PCI configuration space of a device before + * suspending + * @dev: PCI device that we're dealing with */ int pci_save_state(struct pci_dev *dev) { @@ -1422,7 +1431,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev) /** * pci_restore_state - Restore the saved state of a PCI device - * @dev: - PCI device that we're dealing with + * @dev: PCI device that we're dealing with */ void pci_restore_state(struct pci_dev *dev) { @@ -1599,8 +1608,8 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) * pci_reenable_device - Resume abandoned device * @dev: PCI device to be resumed * - * Note this function is a backend of pci_default_resume and is not supposed - * to be called by normal code, write proper resume handler and use it instead. + * NOTE: This function is a backend of pci_default_resume() and is not supposed + * to be called by normal code, write proper resume handler and use it instead. */ int pci_reenable_device(struct pci_dev *dev) { @@ -1675,9 +1684,9 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) * pci_enable_device_io - Initialize a device for use with IO space * @dev: PCI device to be initialized * - * Initialize device before it's used by a driver. Ask low-level code - * to enable I/O resources. Wake up the device if it was suspended. - * Beware, this function can fail. + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O resources. Wake up the device if it was suspended. + * Beware, this function can fail. */ int pci_enable_device_io(struct pci_dev *dev) { @@ -1689,9 +1698,9 @@ EXPORT_SYMBOL(pci_enable_device_io); * pci_enable_device_mem - Initialize a device for use with Memory space * @dev: PCI device to be initialized * - * Initialize device before it's used by a driver. Ask low-level code - * to enable Memory resources. Wake up the device if it was suspended. - * Beware, this function can fail. + * Initialize device before it's used by a driver. Ask low-level code + * to enable Memory resources. Wake up the device if it was suspended. + * Beware, this function can fail. */ int pci_enable_device_mem(struct pci_dev *dev) { @@ -1703,12 +1712,12 @@ EXPORT_SYMBOL(pci_enable_device_mem); * pci_enable_device - Initialize device before it's used by a driver. * @dev: PCI device to be initialized * - * Initialize device before it's used by a driver. Ask low-level code - * to enable I/O and memory. Wake up the device if it was suspended. - * Beware, this function can fail. + * Initialize device before it's used by a driver. Ask low-level code + * to enable I/O and memory. Wake up the device if it was suspended. + * Beware, this function can fail. * - * Note we don't actually enable the device many times if we call - * this function repeatedly (we just increment the count). + * Note we don't actually enable the device many times if we call + * this function repeatedly (we just increment the count). */ int pci_enable_device(struct pci_dev *dev) { @@ -1717,8 +1726,8 @@ int pci_enable_device(struct pci_dev *dev) EXPORT_SYMBOL(pci_enable_device); /* - * Managed PCI resources. This manages device on/off, intx/msi/msix - * on/off and BAR regions. pci_dev itself records msi/msix status, so + * Managed PCI resources. This manages device on/off, INTx/MSI/MSI-X + * on/off and BAR regions. pci_dev itself records MSI/MSI-X status, so * there's no need to track it separately. pci_devres is initialized * when a device is enabled using managed PCI device enable interface. */ @@ -1836,7 +1845,8 @@ int __weak pcibios_add_device(struct pci_dev *dev) } /** - * pcibios_release_device - provide arch specific hooks when releasing device dev + * pcibios_release_device - provide arch specific hooks when releasing + * device dev * @dev: the PCI device being released * * Permits the platform to provide architecture specific functionality when @@ -1927,8 +1937,7 @@ EXPORT_SYMBOL(pci_disable_device); * @dev: the PCIe device reset * @state: Reset state to enter into * - * - * Sets the PCIe reset state for the device. This is the default + * Set the PCIe reset state for the device. This is the default * implementation. Architecture implementations can override this. */ int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev, @@ -1942,7 +1951,6 @@ int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev, * @dev: the PCIe device reset * @state: Reset state to enter into * - * * Sets the PCI reset state for the device. */ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) @@ -2339,7 +2347,8 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup) } /** - * pci_prepare_to_sleep - prepare PCI device for system-wide transition into a sleep state + * pci_prepare_to_sleep - prepare PCI device for system-wide transition + * into a sleep state * @dev: Device to handle. * * Choose the power state appropriate for the device depending on whether @@ -2367,7 +2376,8 @@ int pci_prepare_to_sleep(struct pci_dev *dev) EXPORT_SYMBOL(pci_prepare_to_sleep); /** - * pci_back_from_sleep - turn PCI device on during system-wide transition into working state + * pci_back_from_sleep - turn PCI device on during system-wide transition + * into working state * @dev: Device to handle. * * Disable device's system wake-up capability and put it into D0. @@ -3005,7 +3015,7 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev, /** * _pci_add_cap_save_buffer - allocate buffer for saving given - * capability registers + * capability registers * @dev: the PCI device * @cap: the capability to allocate the buffer for * @extended: Standard or Extended capability ID @@ -3186,7 +3196,7 @@ static void pci_disable_acs_redir(struct pci_dev *dev) } /** - * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites + * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities * @dev: the PCI device */ static void pci_std_enable_acs(struct pci_dev *dev) @@ -3609,13 +3619,14 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) EXPORT_SYMBOL_GPL(pci_common_swizzle); /** - * pci_release_region - Release a PCI bar - * @pdev: PCI device whose resources were previously reserved by pci_request_region - * @bar: BAR to release + * pci_release_region - Release a PCI bar + * @pdev: PCI device whose resources were previously reserved by + * pci_request_region() + * @bar: BAR to release * - * Releases the PCI I/O and memory resources previously reserved by a - * successful call to pci_request_region. Call this function only - * after all use of the PCI regions has ceased. + * Releases the PCI I/O and memory resources previously reserved by a + * successful call to pci_request_region(). Call this function only + * after all use of the PCI regions has ceased. */ void pci_release_region(struct pci_dev *pdev, int bar) { @@ -3637,23 +3648,23 @@ void pci_release_region(struct pci_dev *pdev, int bar) EXPORT_SYMBOL(pci_release_region); /** - * __pci_request_region - Reserved PCI I/O and memory resource - * @pdev: PCI device whose resources are to be reserved - * @bar: BAR to be reserved - * @res_name: Name to be associated with resource. - * @exclusive: whether the region access is exclusive or not + * __pci_request_region - Reserved PCI I/O and memory resource + * @pdev: PCI device whose resources are to be reserved + * @bar: BAR to be reserved + * @res_name: Name to be associated with resource. + * @exclusive: whether the region access is exclusive or not * - * Mark the PCI region associated with PCI device @pdev BR @bar as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark the PCI region associated with PCI device @pdev BAR @bar as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * If @exclusive is set, then the region is marked so that userspace - * is explicitly not allowed to map the resource via /dev/mem or - * sysfs MMIO access. + * If @exclusive is set, then the region is marked so that userspace + * is explicitly not allowed to map the resource via /dev/mem or + * sysfs MMIO access. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. */ static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_name, int exclusive) @@ -3687,18 +3698,18 @@ err_out: } /** - * pci_request_region - Reserve PCI I/O and memory resource - * @pdev: PCI device whose resources are to be reserved - * @bar: BAR to be reserved - * @res_name: Name to be associated with resource + * pci_request_region - Reserve PCI I/O and memory resource + * @pdev: PCI device whose resources are to be reserved + * @bar: BAR to be reserved + * @res_name: Name to be associated with resource * - * Mark the PCI region associated with PCI device @pdev BAR @bar as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark the PCI region associated with PCI device @pdev BAR @bar as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. */ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) { @@ -3707,22 +3718,22 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) EXPORT_SYMBOL(pci_request_region); /** - * pci_request_region_exclusive - Reserved PCI I/O and memory resource - * @pdev: PCI device whose resources are to be reserved - * @bar: BAR to be reserved - * @res_name: Name to be associated with resource. + * pci_request_region_exclusive - Reserved PCI I/O and memory resource + * @pdev: PCI device whose resources are to be reserved + * @bar: BAR to be reserved + * @res_name: Name to be associated with resource. * - * Mark the PCI region associated with PCI device @pdev BR @bar as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark the PCI region associated with PCI device @pdev BAR @bar as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. * - * The key difference that _exclusive makes it that userspace is - * explicitly not allowed to map the resource via /dev/mem or - * sysfs. + * The key difference that _exclusive makes it that userspace is + * explicitly not allowed to map the resource via /dev/mem or + * sysfs. */ int pci_request_region_exclusive(struct pci_dev *pdev, int bar, const char *res_name) @@ -3791,12 +3802,13 @@ int pci_request_selected_regions_exclusive(struct pci_dev *pdev, int bars, EXPORT_SYMBOL(pci_request_selected_regions_exclusive); /** - * pci_release_regions - Release reserved PCI I/O and memory resources - * @pdev: PCI device whose resources were previously reserved by pci_request_regions + * pci_release_regions - Release reserved PCI I/O and memory resources + * @pdev: PCI device whose resources were previously reserved by + * pci_request_regions() * - * Releases all PCI I/O and memory resources previously reserved by a - * successful call to pci_request_regions. Call this function only - * after all use of the PCI regions has ceased. + * Releases all PCI I/O and memory resources previously reserved by a + * successful call to pci_request_regions(). Call this function only + * after all use of the PCI regions has ceased. */ void pci_release_regions(struct pci_dev *pdev) @@ -3806,17 +3818,17 @@ void pci_release_regions(struct pci_dev *pdev) EXPORT_SYMBOL(pci_release_regions); /** - * pci_request_regions - Reserved PCI I/O and memory resources - * @pdev: PCI device whose resources are to be reserved - * @res_name: Name to be associated with resource. + * pci_request_regions - Reserve PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * @res_name: Name to be associated with resource. * - * Mark all PCI regions associated with PCI device @pdev as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark all PCI regions associated with PCI device @pdev as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. */ int pci_request_regions(struct pci_dev *pdev, const char *res_name) { @@ -3825,20 +3837,19 @@ int pci_request_regions(struct pci_dev *pdev, const char *res_name) EXPORT_SYMBOL(pci_request_regions); /** - * pci_request_regions_exclusive - Reserved PCI I/O and memory resources - * @pdev: PCI device whose resources are to be reserved - * @res_name: Name to be associated with resource. + * pci_request_regions_exclusive - Reserve PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * @res_name: Name to be associated with resource. * - * Mark all PCI regions associated with PCI device @pdev as - * being reserved by owner @res_name. Do not access any - * address inside the PCI regions unless this call returns - * successfully. + * Mark all PCI regions associated with PCI device @pdev as being reserved + * by owner @res_name. Do not access any address inside the PCI regions + * unless this call returns successfully. * - * pci_request_regions_exclusive() will mark the region so that - * /dev/mem and the sysfs MMIO access will not be allowed. + * pci_request_regions_exclusive() will mark the region so that /dev/mem + * and the sysfs MMIO access will not be allowed. * - * Returns 0 on success, or %EBUSY on error. A warning - * message is also printed on failure. + * Returns 0 on success, or %EBUSY on error. A warning message is also + * printed on failure. */ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name) { @@ -3849,7 +3860,7 @@ EXPORT_SYMBOL(pci_request_regions_exclusive); /* * Record the PCI IO range (expressed as CPU physical address + size). - * Return a negative value if an error has occured, zero otherwise + * Return a negative value if an error has occurred, zero otherwise */ int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr, resource_size_t size) @@ -3905,14 +3916,14 @@ unsigned long __weak pci_address_to_pio(phys_addr_t address) } /** - * pci_remap_iospace - Remap the memory mapped I/O space - * @res: Resource describing the I/O space - * @phys_addr: physical address of range to be mapped + * pci_remap_iospace - Remap the memory mapped I/O space + * @res: Resource describing the I/O space + * @phys_addr: physical address of range to be mapped * - * Remap the memory mapped I/O space described by the @res - * and the CPU physical address @phys_addr into virtual address space. - * Only architectures that have memory mapped IO functions defined - * (and the PCI_IOBASE value defined) should call this function. + * Remap the memory mapped I/O space described by the @res and the CPU + * physical address @phys_addr into virtual address space. Only + * architectures that have memory mapped IO functions defined (and the + * PCI_IOBASE value defined) should call this function. */ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) { @@ -3928,8 +3939,10 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) return ioremap_page_range(vaddr, vaddr + resource_size(res), phys_addr, pgprot_device(PAGE_KERNEL)); #else - /* this architecture does not have memory mapped I/O space, - so this function should never be called */ + /* + * This architecture does not have memory mapped I/O space, + * so this function should never be called + */ WARN_ONCE(1, "This architecture does not support memory mapped I/O\n"); return -ENODEV; #endif @@ -3937,12 +3950,12 @@ int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) EXPORT_SYMBOL(pci_remap_iospace); /** - * pci_unmap_iospace - Unmap the memory mapped I/O space - * @res: resource to be unmapped + * pci_unmap_iospace - Unmap the memory mapped I/O space + * @res: resource to be unmapped * - * Unmap the CPU virtual address @res from virtual address space. - * Only architectures that have memory mapped IO functions defined - * (and the PCI_IOBASE value defined) should call this function. + * Unmap the CPU virtual address @res from virtual address space. Only + * architectures that have memory mapped IO functions defined (and the + * PCI_IOBASE value defined) should call this function. */ void pci_unmap_iospace(struct resource *res) { @@ -4288,7 +4301,7 @@ EXPORT_SYMBOL(pci_clear_mwi); * @pdev: the PCI device to operate on * @enable: boolean: whether to enable or disable PCI INTx * - * Enables/disables PCI INTx for device dev + * Enables/disables PCI INTx for device @pdev */ void pci_intx(struct pci_dev *pdev, int enable) { @@ -4364,9 +4377,8 @@ done: * pci_check_and_mask_intx - mask INTx on pending interrupt * @dev: the PCI device to operate on * - * Check if the device dev has its INTx line asserted, mask it and - * return true in that case. False is returned if no interrupt was - * pending. + * Check if the device dev has its INTx line asserted, mask it and return + * true in that case. False is returned if no interrupt was pending. */ bool pci_check_and_mask_intx(struct pci_dev *dev) { @@ -4378,9 +4390,9 @@ EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending * @dev: the PCI device to operate on * - * Check if the device dev has its INTx line asserted, unmask it if not - * and return true. False is returned and the mask remains active if - * there was still an interrupt pending. + * Check if the device dev has its INTx line asserted, unmask it if not and + * return true. False is returned and the mask remains active if there was + * still an interrupt pending. */ bool pci_check_and_unmask_intx(struct pci_dev *dev) { @@ -4389,7 +4401,7 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev) EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); /** - * pci_wait_for_pending_transaction - waits for pending transaction + * pci_wait_for_pending_transaction - wait for pending transaction * @dev: the PCI device to operate on * * Return 0 if transaction is pending 1 otherwise. @@ -4447,7 +4459,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) /** * pcie_has_flr - check if a device supports function level resets - * @dev: device to check + * @dev: device to check * * Returns true if the device advertises support for PCIe function level * resets. @@ -4466,7 +4478,7 @@ EXPORT_SYMBOL_GPL(pcie_has_flr); /** * pcie_flr - initiate a PCIe function level reset - * @dev: device to reset + * @dev: device to reset * * Initiate a function level reset on @dev. The caller should ensure the * device supports FLR before calling this function, e.g. by using the @@ -4810,6 +4822,7 @@ static void pci_dev_restore(struct pci_dev *dev) * * The device function is presumed to be unused and the caller is holding * the device mutex lock when this function is called. + * * Resetting the device will make the contents of PCI configuration space * random, so any caller of this must be prepared to reinitialise the * device including MSI, bus mastering, BARs, decoding IO and memory spaces, @@ -5373,8 +5386,8 @@ EXPORT_SYMBOL_GPL(pci_reset_bus); * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count * @dev: PCI device to query * - * Returns mmrbc: maximum designed memory read count in bytes - * or appropriate error value. + * Returns mmrbc: maximum designed memory read count in bytes or + * appropriate error value. */ int pcix_get_max_mmrbc(struct pci_dev *dev) { @@ -5396,8 +5409,8 @@ EXPORT_SYMBOL(pcix_get_max_mmrbc); * pcix_get_mmrbc - get PCI-X maximum memory read byte count * @dev: PCI device to query * - * Returns mmrbc: maximum memory read count in bytes - * or appropriate error value. + * Returns mmrbc: maximum memory read count in bytes or appropriate error + * value. */ int pcix_get_mmrbc(struct pci_dev *dev) { @@ -5421,7 +5434,7 @@ EXPORT_SYMBOL(pcix_get_mmrbc); * @mmrbc: maximum memory read count in bytes * valid values are 512, 1024, 2048, 4096 * - * If possible sets maximum memory read byte count, some bridges have erratas + * If possible sets maximum memory read byte count, some bridges have errata * that prevent this. */ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc) @@ -5466,8 +5479,7 @@ EXPORT_SYMBOL(pcix_set_mmrbc); * pcie_get_readrq - get PCI Express read request size * @dev: PCI device to query * - * Returns maximum memory read request in bytes - * or appropriate error value. + * Returns maximum memory read request in bytes or appropriate error value. */ int pcie_get_readrq(struct pci_dev *dev) { @@ -5495,10 +5507,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) return -EINVAL; /* - * If using the "performance" PCIe config, we clamp the - * read rq size to the max packet size to prevent the - * host bridge generating requests larger than we can - * cope with + * If using the "performance" PCIe config, we clamp the read rq + * size to the max packet size to keep the host bridge from + * generating requests larger than we can cope with. */ if (pcie_bus_config == PCIE_BUS_PERFORMANCE) { int mps = pcie_get_mps(dev); @@ -6144,6 +6155,7 @@ static int of_pci_bus_find_domain_nr(struct device *parent) if (parent) domain = of_get_pci_domain_nr(parent->of_node); + /* * Check DT domain and use_dt_domains values. * -- cgit v1.2.3 From c577f4a5a08bb9677e12ddafb62e2f3a901de87f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 30 Mar 2019 15:09:10 +0000 Subject: PCI: rockchip: Fix rockchip_pcie_ep_assert_intx() bitwise operations Currently the bitwise operations on the u16 variable 'status' with the setting ROCKCHIP_PCIE_EP_CMD_STATUS_IS are incorrect because ROCKCHIP_PCIE_EP_CMD_STATUS_IS is 1UL<<19 which is wider than the u16 variable. Fix this by making status a u32. Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller") Signed-off-by: Colin Ian King Signed-off-by: Lorenzo Pieralisi Reviewed-by: Mukesh Ojha Acked-by: Shawn Lin --- drivers/pci/controller/pcie-rockchip-ep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index a5d799e2dff2..d743b0a48988 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -350,7 +350,7 @@ static void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, u8 fn, struct rockchip_pcie *rockchip = &ep->rockchip; u32 r = ep->max_regions - 1; u32 offset; - u16 status; + u32 status; u8 msg_code; if (unlikely(ep->irq_pci_addr != ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR || -- cgit v1.2.3 From b1dee41b76927747c1c63c5196ce9eaec6d0e81a Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:27 +0530 Subject: PCI: keystone: Move resources initialization to prepare for EP support Move platform_get_resource() calls for resources that are applicable to both host and endpoint mode (ie "dbics" and "app") from ks_add_pcie_port() to the probe() callback, in preparation for adding endpoint support to pci-keystone driver. No functional change intended. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 5eebef9b9ada..95997885a05c 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -806,11 +806,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, struct resource *res; int ret; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics"); - pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); if (IS_ERR(pp->va_cfg0_base)) @@ -818,13 +813,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, pp->va_cfg1_base = pp->va_cfg0_base; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app"); - ks_pcie->va_app_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ks_pcie->va_app_base)) - return PTR_ERR(ks_pcie->va_app_base); - - ks_pcie->app = *res; - pp->ops = &ks_pcie_host_ops; ret = dw_pcie_host_init(pp); if (ret) { @@ -895,6 +883,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev) struct dw_pcie *pci; struct keystone_pcie *ks_pcie; struct device_link **link; + struct resource *res; + void __iomem *base; u32 num_viewport; struct phy **phy; u32 num_lanes; @@ -911,6 +901,19 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (!pci) return -ENOMEM; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app"); + ks_pcie->va_app_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ks_pcie->va_app_base)) + return PTR_ERR(ks_pcie->va_app_base); + + ks_pcie->app = *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbics"); + base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + pci->dbi_base = base; pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; -- cgit v1.2.3 From 156c6fef75a41bc463cc1e3c1b45de140443ae31 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:29 +0530 Subject: PCI: keystone: Explicitly set the PCIe mode Explicitly set the PCIe mode to BOOTCFG_DEVCFG instead of always relying on the default values. This is required when EP mode has to be explicitly written to BOOTCFG_DEVCFG register. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 95997885a05c..dfe54553d832 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -79,6 +79,15 @@ #define PCIE_RC_K2L 0xb00a #define PCIE_RC_K2G 0xb00b +#define KS_PCIE_DEV_TYPE_MASK (0x3 << 1) +#define KS_PCIE_DEV_TYPE(mode) ((mode) << 1) + +#define EP 0x0 +#define LEG_EP 0x1 +#define RC 0x2 + +#define KS_PCIE_SYSCLOCKOUTEN BIT(0) + #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) struct keystone_pcie { @@ -876,6 +885,30 @@ err_phy: return ret; } +static int ks_pcie_set_mode(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct regmap *syscon; + u32 val; + u32 mask; + int ret = 0; + + syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-mode"); + if (IS_ERR(syscon)) + return 0; + + mask = KS_PCIE_DEV_TYPE_MASK | KS_PCIE_SYSCLOCKOUTEN; + val = KS_PCIE_DEV_TYPE(RC) | KS_PCIE_SYSCLOCKOUTEN; + + ret = regmap_update_bits(syscon, 0, mask, val); + if (ret) { + dev_err(dev, "failed to set pcie mode\n"); + return ret; + } + + return 0; +} + static int __init ks_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -988,6 +1021,10 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } + ret = ks_pcie_set_mode(dev); + if (ret < 0) + goto err_get_sync; + ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) goto err_get_sync; -- cgit v1.2.3 From a9f4c2d2f99ec85ebc734a5bfb21a2cf93c169ad Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:31 +0530 Subject: PCI: dwc: Enable iATU unroll for endpoint too iatu_unroll_enabled flag is set only for Designware in host mode. However iATU unroll can be applicable for endpoint mode too. Set iatu_unroll_enabled flag in dw_pcie_setup() which is common for both host mode and endpoint mode. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 4 ---- drivers/pci/controller/dwc/pcie-designware-host.c | 19 ------------------- drivers/pci/controller/dwc/pcie-designware.c | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 23 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 24f5a775ad34..dc6a4bbd3ace 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -517,10 +517,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) dev_err(dev, "dbi_base/dbi_base2 is not populated\n"); return -EINVAL; } - if (pci->iatu_unroll_enabled && !pci->atu_base) { - dev_err(dev, "atu_base is not populated\n"); - return -EINVAL; - } ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows); if (ret < 0) { diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 7e0ff7d428a9..7bf6558341b6 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -608,17 +608,6 @@ static struct pci_ops dw_pcie_ops = { .write = dw_pcie_wr_conf, }; -static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) -{ - u32 val; - - val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT); - if (val == 0xffffffff) - return 1; - - return 0; -} - void dw_pcie_setup_rc(struct pcie_port *pp) { u32 val, ctrl, num_ctrls; @@ -672,14 +661,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp) * we should not program the ATU here. */ if (!pp->ops->rd_other_conf) { - /* Get iATU unroll support */ - pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci); - dev_dbg(pci->dev, "iATU unroll: %s\n", - pci->iatu_unroll_enabled ? "enabled" : "disabled"); - - if (pci->iatu_unroll_enabled && !pci->atu_base) - pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, PCIE_ATU_TYPE_MEM, pp->mem_base, pp->mem_bus_addr, pp->mem_size); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 31f6331ca46f..a14ca00f72aa 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -339,6 +339,17 @@ int dw_pcie_link_up(struct dw_pcie *pci) (!(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING))); } +static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci) +{ + u32 val; + + val = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT); + if (val == 0xffffffff) + return 1; + + return 0; +} + void dw_pcie_setup(struct dw_pcie *pci) { int ret; @@ -347,6 +358,14 @@ void dw_pcie_setup(struct dw_pcie *pci) struct device *dev = pci->dev; struct device_node *np = dev->of_node; + /* Get iATU unroll support */ + pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci); + dev_dbg(pci->dev, "iATU unroll: %s\n", + pci->iatu_unroll_enabled ? "enabled" : "disabled"); + + if (pci->iatu_unroll_enabled && !pci->atu_base) + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + ret = of_property_read_u32(np, "num-lanes", &lanes); if (ret) lanes = 0; -- cgit v1.2.3 From 2aadcb0cd39198833fabe1c45084f78686e71a6c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:32 +0530 Subject: PCI: dwc: Fix ATU identification for designware version >= 4.80 Synopsys designware version >= 4.80 uses a separate register space for programming ATU. The current code identifies if there exists a separate register space by accessing the register address of ATUs in designware version < 4.80. Accessing this address results in abort in the case of K2G. Fix it here by adding "version" member to struct dw_pcie. This should be set by platform specific drivers and designware core will use it to identify if the platform has a separate ATU space. For platforms which have not populated the version member, the old method of identification will still be used. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware.c | 14 ++++++++------ drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index a14ca00f72aa..4e2f7946da89 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -358,13 +358,15 @@ void dw_pcie_setup(struct dw_pcie *pci) struct device *dev = pci->dev; struct device_node *np = dev->of_node; - /* Get iATU unroll support */ - pci->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pci); - dev_dbg(pci->dev, "iATU unroll: %s\n", - pci->iatu_unroll_enabled ? "enabled" : "disabled"); + if (pci->version >= 0x480A || (!pci->version && + dw_pcie_iatu_unroll_enabled(pci))) { + pci->iatu_unroll_enabled = true; + if (!pci->atu_base) + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + } + dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? + "enabled" : "disabled"); - if (pci->iatu_unroll_enabled && !pci->atu_base) - pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; ret = of_property_read_u32(np, "num-lanes", &lanes); if (ret) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index ca3a3190a6f5..90a5b1215344 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -234,6 +234,7 @@ struct dw_pcie { struct pcie_port pp; struct dw_pcie_ep ep; const struct dw_pcie_ops *ops; + unsigned int version; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) -- cgit v1.2.3 From f316a2b53cd7f37963ae20ec7072eb27a349a4ce Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:33 +0530 Subject: PCI: keystone: Prevent ARM32 specific code to be compiled for ARM64 hook_fault_code() is an ARM32 specific API for hooking into data abort. AM65X platforms (that integrate ARM v8 cores and select CONFIG_ARM64 as arch) rely on pci-keystone.c but on them the enumeration of a non-present BDF does not trigger a bus error, so the fixup exception provided by calling hook_fault_code() is not needed and can be guarded with CONFIG_ARM. Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index dfe54553d832..93296d434f40 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -710,6 +710,7 @@ err: return ret; } +#ifdef CONFIG_ARM /* * When a PCI device does not exist during config cycles, keystone host gets a * bus error instead of returning 0xffffffff. This handler always returns 0 @@ -729,6 +730,7 @@ static int ks_pcie_fault(unsigned long addr, unsigned int fsr, return 0; } +#endif static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie) { @@ -778,12 +780,14 @@ static int __init ks_pcie_host_init(struct pcie_port *pp) if (ret < 0) return ret; +#ifdef CONFIG_ARM /* * PCIe access errors that result into OCP errors are caught by ARM as * "External aborts" */ hook_fault_code(17, ks_pcie_fault, SIGBUS, 0, "Asynchronous external abort"); +#endif ks_pcie_start_link(pci); dw_pcie_wait_for_link(pci); -- cgit v1.2.3 From 18b0415bc802a8bab5dedba5ae2757e83259e6ee Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:35 +0530 Subject: PCI: keystone: Add support for PCIe RC in AM654x Platforms Add PCIe RC support for AM654x Platforms in pci-keystone.c Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/Kconfig | 2 +- drivers/pci/controller/dwc/pci-keystone.c | 161 +++++++++++++++++++++++++++--- 2 files changed, 148 insertions(+), 15 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 6ea74b1c0d94..d1d00833e0b3 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -104,7 +104,7 @@ config PCIE_SPEAR13XX config PCI_KEYSTONE bool "TI Keystone PCIe controller" - depends on ARCH_KEYSTONE || (ARM && COMPILE_TEST) + depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST help diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 93296d434f40..a6a482bd648f 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +67,7 @@ #define ERR_IRQ_STATUS 0x1c4 #define ERR_IRQ_ENABLE_SET 0x1c8 #define ERR_AER BIT(5) /* ECRC error */ +#define AM6_ERR_AER BIT(4) /* AM6 ECRC error */ #define ERR_AXI BIT(4) /* AXI tag lookup fatal error */ #define ERR_CORR BIT(3) /* Correctable error */ #define ERR_NONFATAL BIT(2) /* Non-fatal error */ @@ -88,8 +91,15 @@ #define KS_PCIE_SYSCLOCKOUTEN BIT(0) +#define AM654_PCIE_DEV_TYPE_MASK 0x3 + #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) +struct ks_pcie_of_data { + const struct dw_pcie_host_ops *host_ops; + unsigned int version; +}; + struct keystone_pcie { struct dw_pcie *pci; /* PCI Device ID */ @@ -109,6 +119,7 @@ struct keystone_pcie { /* Application register space */ void __iomem *va_app_base; /* DT 1st resource */ struct resource app; + bool is_am6; }; static u32 ks_pcie_app_readl(struct keystone_pcie *ks_pcie, u32 offset) @@ -250,6 +261,16 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); } +static int ks_pcie_am654_msi_host_init(struct pcie_port *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct device *dev = pci->dev; + + dev_vdbg(dev, "dummy function so that DW core doesn't configure MSI\n"); + + return 0; +} + static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie) { ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL); @@ -276,10 +297,10 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie) if (reg & ERR_CORR) dev_dbg(dev, "Correctable Error\n"); - if (reg & ERR_AXI) + if (!ks_pcie->is_am6 && (reg & ERR_AXI)) dev_err(dev, "AXI tag lookup fatal Error\n"); - if (reg & ERR_AER) + if (reg & ERR_AER || (ks_pcie->is_am6 && (reg & AM6_ERR_AER))) dev_err(dev, "ECRC Error\n"); ks_pcie_app_writel(ks_pcie, ERR_IRQ_STATUS, reg); @@ -377,6 +398,9 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie) dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0); ks_pcie_clear_dbi_mode(ks_pcie); + if (ks_pcie->is_am6) + return; + val = ilog2(OB_WIN_SIZE); ks_pcie_app_writel(ks_pcie, OB_SIZE, val); @@ -619,6 +643,8 @@ static int ks_pcie_config_msi_irq(struct keystone_pcie *ks_pcie) intc_np = of_get_child_by_name(np, "msi-interrupt-controller"); if (!intc_np) { + if (ks_pcie->is_am6) + return 0; dev_warn(dev, "msi-interrupt-controller node is absent\n"); return -EINVAL; } @@ -668,6 +694,12 @@ static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie) intc_np = of_get_child_by_name(np, "legacy-interrupt-controller"); if (!intc_np) { + /* + * Since legacy interrupts are modeled as edge-interrupts in + * AM6, keep it disabled for now. + */ + if (ks_pcie->is_am6) + return 0; dev_warn(dev, "legacy-interrupt-controller node is absent\n"); return -EINVAL; } @@ -749,8 +781,10 @@ static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie) if (ret) return ret; + dw_pcie_dbi_ro_wr_en(pci); dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, id & PCIE_VENDORID_MASK); dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, id >> PCIE_DEVICEID_SHIFT); + dw_pcie_dbi_ro_wr_dis(pci); return 0; } @@ -803,6 +837,11 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = { .scan_bus = ks_pcie_v3_65_scan_bus, }; +static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = { + .host_init = ks_pcie_host_init, + .msi_host_init = ks_pcie_am654_msi_host_init, +}; + static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv) { struct keystone_pcie *ks_pcie = priv; @@ -826,7 +865,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, pp->va_cfg1_base = pp->va_cfg0_base; - pp->ops = &ks_pcie_host_ops; ret = dw_pcie_host_init(pp); if (ret) { dev_err(dev, "failed to initialize host\n"); @@ -836,14 +874,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, return 0; } -static const struct of_device_id ks_pcie_of_match[] = { - { - .type = "pci", - .compatible = "ti,keystone-pcie", - }, - { }, -}; - static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .start_link = ks_pcie_start_link, .stop_link = ks_pcie_stop_link, @@ -913,14 +943,67 @@ static int ks_pcie_set_mode(struct device *dev) return 0; } +static int ks_pcie_am654_set_mode(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct regmap *syscon; + u32 val; + u32 mask; + int ret = 0; + + syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pcie-mode"); + if (IS_ERR(syscon)) + return 0; + + mask = AM654_PCIE_DEV_TYPE_MASK; + val = RC; + + ret = regmap_update_bits(syscon, 0, mask, val); + if (ret) { + dev_err(dev, "failed to set pcie mode\n"); + return ret; + } + + return 0; +} + +static const struct ks_pcie_of_data ks_pcie_rc_of_data = { + .host_ops = &ks_pcie_host_ops, + .version = 0x365A, +}; + +static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = { + .host_ops = &ks_pcie_am654_host_ops, + .version = 0x490A, +}; + +static const struct of_device_id ks_pcie_of_match[] = { + { + .type = "pci", + .data = &ks_pcie_rc_of_data, + .compatible = "ti,keystone-pcie", + }, + { + .data = &ks_pcie_am654_rc_of_data, + .compatible = "ti,am654-pcie-rc", + }, + { }, +}; + static int __init ks_pcie_probe(struct platform_device *pdev) { + const struct dw_pcie_host_ops *host_ops; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + const struct ks_pcie_of_data *data; + const struct of_device_id *match; struct dw_pcie *pci; struct keystone_pcie *ks_pcie; struct device_link **link; + struct gpio_desc *gpiod; + void __iomem *atu_base; struct resource *res; + unsigned int version; void __iomem *base; u32 num_viewport; struct phy **phy; @@ -930,6 +1013,14 @@ static int __init ks_pcie_probe(struct platform_device *pdev) int irq; int i; + match = of_match_device(of_match_ptr(ks_pcie_of_match), dev); + data = (struct ks_pcie_of_data *)match->data; + if (!data) + return -EINVAL; + + version = data->version; + host_ops = data->host_ops; + ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); if (!ks_pcie) return -ENOMEM; @@ -950,9 +1041,13 @@ static int __init ks_pcie_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + if (of_device_is_compatible(np, "ti,am654-pcie-rc")) + ks_pcie->is_am6 = true; + pci->dbi_base = base; pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; + pci->version = version; ret = of_property_read_u32(np, "num-viewport", &num_viewport); if (ret < 0) { @@ -1011,6 +1106,15 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->num_viewport = num_viewport; ks_pcie->phy = phy; + gpiod = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get reset GPIO\n"); + goto err_link; + } + ret = ks_pcie_enable_phy(ks_pcie); if (ret) { dev_err(dev, "failed to enable phy\n"); @@ -1025,10 +1129,39 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - ret = ks_pcie_set_mode(dev); - if (ret < 0) - goto err_get_sync; + if (pci->version >= 0x480A) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu"); + atu_base = devm_ioremap_resource(dev, res); + if (IS_ERR(atu_base)) { + ret = PTR_ERR(atu_base); + goto err_get_sync; + } + + pci->atu_base = atu_base; + + ret = ks_pcie_am654_set_mode(dev); + if (ret < 0) + goto err_get_sync; + } else { + ret = ks_pcie_set_mode(dev); + if (ret < 0) + goto err_get_sync; + } + + /* + * "Power Sequencing and Reset Signal Timings" table in + * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 + * indicates PERST# should be deasserted after minimum of 100us + * once REFCLK is stable. The REFCLK to the connector in RC + * mode is selected while enabling the PHY. So deassert PERST# + * after 100 us. + */ + if (gpiod) { + usleep_range(100, 200); + gpiod_set_value_cansleep(gpiod, 1); + } + pci->pp.ops = host_ops; ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) goto err_get_sync; -- cgit v1.2.3 From b22af42b3e57c3a49a4c4a54c7d8a1363af75e90 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:36 +0530 Subject: PCI: keystone: Invoke phy_reset() API before enabling PHY SERDES connected to the PCIe controller in AM654 requires power on reset enable (POR_EN) to be set in the SERDES. The SERDES driver sets POR_EN in the reset ops and it has to be invoked before init or enable ops. In order for SERDES driver to set POR_EN, invoke the phy_reset() API in pci-keystone driver. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index a6a482bd648f..e4a816f53b8e 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -897,6 +897,10 @@ static int ks_pcie_enable_phy(struct keystone_pcie *ks_pcie) int num_lanes = ks_pcie->num_lanes; for (i = 0; i < num_lanes; i++) { + ret = phy_reset(ks_pcie->phy[i]); + if (ret < 0) + goto err_phy; + ret = phy_init(ks_pcie->phy[i]); if (ret < 0) goto err_phy; -- cgit v1.2.3 From fbb2de891cc4d69c0c80c4116cf870a99235cfe8 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:38 +0530 Subject: PCI: keystone: Add support to set the max link speed from DT PCIe in TI's AM654 devices is by default configured to work in GEN3 mode. However PCIe does not work reliably in GEN3 mode because of SERDES configuration. Add support to set the link speed to GEN1, GEN2 or GEN3 based on "max-link-speed" DT property with GEN2 as the default speed if "max-link-speed" is absent. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-keystone.c | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index e4a816f53b8e..312fd0c49bbb 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -28,6 +28,7 @@ #include #include +#include "../../pci.h" #include "pcie-designware.h" #define PCIE_VENDORID_MASK 0xffff @@ -89,6 +90,8 @@ #define LEG_EP 0x1 #define RC 0x2 +#define EXP_CAP_ID_OFFSET 0x70 + #define KS_PCIE_SYSCLOCKOUTEN BIT(0) #define AM654_PCIE_DEV_TYPE_MASK 0x3 @@ -971,6 +974,31 @@ static int ks_pcie_am654_set_mode(struct device *dev) return 0; } +static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed) +{ + u32 val; + + dw_pcie_dbi_ro_wr_en(pci); + + val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP); + if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { + val &= ~((u32)PCI_EXP_LNKCAP_SLS); + val |= link_speed; + dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP, + val); + } + + val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2); + if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) { + val &= ~((u32)PCI_EXP_LNKCAP_SLS); + val |= link_speed; + dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2, + val); + } + + dw_pcie_dbi_ro_wr_dis(pci); +} + static const struct ks_pcie_of_data ks_pcie_rc_of_data = { .host_ops = &ks_pcie_host_ops, .version = 0x365A, @@ -1011,6 +1039,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) void __iomem *base; u32 num_viewport; struct phy **phy; + int link_speed; u32 num_lanes; char name[10]; int ret; @@ -1165,6 +1194,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev) gpiod_set_value_cansleep(gpiod, 1); } + link_speed = of_pci_get_max_link_speed(np); + if (link_speed < 0) + link_speed = 2; + + ks_pcie_set_link_speed(pci, link_speed); + pci->pp.ops = host_ops; ret = ks_pcie_add_pcie_port(ks_pcie, pdev); if (ret < 0) -- cgit v1.2.3 From 626961dd6d32edcdbea1ebc488305533960b5d08 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:40 +0530 Subject: PCI: dwc: Add const qualifier to struct dw_pcie_ep_ops Add const qualifier to struct dw_pcie_ep_ops member of struct dw_pcie_ep. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pci-dra7xx.c | 2 +- drivers/pci/controller/dwc/pci-layerscape-ep.c | 2 +- drivers/pci/controller/dwc/pcie-artpec6.c | 2 +- drivers/pci/controller/dwc/pcie-designware-plat.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index ae84a69ae63a..b287dbf6914c 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -406,7 +406,7 @@ dra7xx_pcie_get_features(struct dw_pcie_ep *ep) return &dra7xx_pcie_epc_features; } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = dra7xx_pcie_ep_init, .raise_irq = dra7xx_pcie_raise_irq, .get_features = dra7xx_pcie_get_features, diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c index a42c9c3ae1cc..be61d96cc95e 100644 --- a/drivers/pci/controller/dwc/pci-layerscape-ep.c +++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c @@ -79,7 +79,7 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, } } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = ls_pcie_ep_init, .raise_irq = ls_pcie_ep_raise_irq, .get_features = ls_pcie_ep_get_features, diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c index dba83abfe764..d00252bd8fae 100644 --- a/drivers/pci/controller/dwc/pcie-artpec6.c +++ b/drivers/pci/controller/dwc/pcie-artpec6.c @@ -444,7 +444,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no, return 0; } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = artpec6_pcie_ep_init, .raise_irq = artpec6_pcie_raise_irq, }; diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c index 932dbd0b34b6..b58fdcbc664b 100644 --- a/drivers/pci/controller/dwc/pcie-designware-plat.c +++ b/drivers/pci/controller/dwc/pcie-designware-plat.c @@ -106,7 +106,7 @@ dw_plat_pcie_get_features(struct dw_pcie_ep *ep) return &dw_plat_pcie_epc_features; } -static struct dw_pcie_ep_ops pcie_ep_ops = { +static const struct dw_pcie_ep_ops pcie_ep_ops = { .ep_init = dw_plat_pcie_ep_init, .raise_irq = dw_plat_pcie_ep_raise_irq, .get_features = dw_plat_pcie_get_features, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 90a5b1215344..e36941ff7cf6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -196,7 +196,7 @@ struct dw_pcie_ep_ops { struct dw_pcie_ep { struct pci_epc *epc; - struct dw_pcie_ep_ops *ops; + const struct dw_pcie_ep_ops *ops; phys_addr_t phys_base; size_t addr_size; size_t page_size; -- cgit v1.2.3 From 421db1ab287eebe80fd203eb009ae92836c586ad Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:41 +0530 Subject: PCI: dwc: Fix dw_pcie_ep_find_capability() to return correct capability offset commit beb4641a787d ("PCI: dwc: Add MSI-X callbacks handler") while adding MSI-X callback handler, introduced dw_pcie_ep_find_capability() and __dw_pcie_ep_find_next_cap() for finding the MSI and MSIX capability. However if MSI or MSIX capability is the last capability (i.e there are no additional items in the capabilities list and the Next Capability Pointer is set to '0'), __dw_pcie_ep_find_next_cap will return '0' even though MSI or MSIX capability may be present because of incorrect ordering of the "next_cap_ptr" check. Fix it. Fixes: beb4641a787d ("PCI: dwc: Add MSI-X callbacks handler") Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index dc6a4bbd3ace..74477ad7467f 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -46,16 +46,19 @@ static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr, u8 cap_id, next_cap_ptr; u16 reg; + if (!cap_ptr) + return 0; + reg = dw_pcie_readw_dbi(pci, cap_ptr); - next_cap_ptr = (reg & 0xff00) >> 8; cap_id = (reg & 0x00ff); - if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX) + if (cap_id > PCI_CAP_ID_MAX) return 0; if (cap_id == cap) return cap_ptr; + next_cap_ptr = (reg & 0xff00) >> 8; return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); } @@ -67,9 +70,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap) reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST); next_cap_ptr = (reg & 0x00ff); - if (!next_cap_ptr) - return 0; - return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap); } -- cgit v1.2.3 From ddf567e3d9949aeb7992fb48a8663c81a15e7d81 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:42 +0530 Subject: PCI: dwc: Add callbacks for accessing dbi2 address space Certain platforms like TI's AM654 do not have aseparate address space for dbi2 instead they are accessed using the same address space as dbi with some configuration bit set. In order to support such platforms, add callbacks for accessing dbi2 address space. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware.c | 31 ++++++++++++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 12 +++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 4e2f7946da89..d7cc1a0c1de6 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -89,6 +89,37 @@ void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, dev_err(pci->dev, "Write DBI address failed\n"); } +u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size) +{ + int ret; + u32 val; + + if (pci->ops->read_dbi2) + return pci->ops->read_dbi2(pci, base, reg, size); + + ret = dw_pcie_read(base + reg, size, &val); + if (ret) + dev_err(pci->dev, "read DBI address failed\n"); + + return val; +} + +void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size, u32 val) +{ + int ret; + + if (pci->ops->write_dbi2) { + pci->ops->write_dbi2(pci, base, reg, size, val); + return; + } + + ret = dw_pcie_write(base + reg, size, val); + if (ret) + dev_err(pci->dev, "write DBI address failed\n"); +} + static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg) { u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index e36941ff7cf6..7abca9eb00bf 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -218,6 +218,10 @@ struct dw_pcie_ops { size_t size); void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg, size_t size, u32 val); + u32 (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, + size_t size); + void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, + size_t size, u32 val); int (*link_up)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); @@ -249,6 +253,10 @@ u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size); void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, size_t size, u32 val); +u32 __dw_pcie_read_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size); +void __dw_pcie_write_dbi2(struct dw_pcie *pci, void __iomem *base, u32 reg, + size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, @@ -292,12 +300,12 @@ static inline u8 dw_pcie_readb_dbi(struct dw_pcie *pci, u32 reg) static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val) { - __dw_pcie_write_dbi(pci, pci->dbi_base2, reg, 0x4, val); + __dw_pcie_write_dbi2(pci, pci->dbi_base2, reg, 0x4, val); } static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg) { - return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4); + return __dw_pcie_read_dbi2(pci, pci->dbi_base2, reg, 0x4); } static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val) -- cgit v1.2.3 From 21e2079fe4938e84c0c5c0996cc03d63d5f9cacc Mon Sep 17 00:00:00 2001 From: Vidya Sagar Date: Tue, 16 Apr 2019 16:21:44 +0530 Subject: PCI: tegra: Use the DMA-API to get the MSI address Since the upstream MSI memory writes are generated by downstream devices, it is logically correct to have MSI target memory coming from the DMA pool reserved for PCIe than from the general memory pool reserved for CPU access to avoid PCIe DMA addresses coinciding with MSI target address thereby raising unwanted MSI interrupts. Enforce this behaviour by retrieving the MSI address through the DMA API. Limit the MSI target address to 32-bits to make it work for PCIe endpoints that support only 32-bit MSI target address; endpoints that support 64-bit MSI target address work with 32-bit MSI target address too. Signed-off-by: Vidya Sagar [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Robin Murphy Reviewed-by: Thierry Reding Acked-by: Thierry Reding --- drivers/pci/controller/pci-tegra.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index f4f53d092e00..464ba2538d52 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -231,9 +231,9 @@ struct tegra_msi { struct msi_controller chip; DECLARE_BITMAP(used, INT_PCI_MSI_NR); struct irq_domain *domain; - unsigned long pages; struct mutex lock; - u64 phys; + void *virt; + dma_addr_t phys; int irq; }; @@ -1536,7 +1536,7 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie) err = platform_get_irq_byname(pdev, "msi"); if (err < 0) { dev_err(dev, "failed to get IRQ: %d\n", err); - goto err; + goto free_irq_domain; } msi->irq = err; @@ -1545,17 +1545,35 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie) tegra_msi_irq_chip.name, pcie); if (err < 0) { dev_err(dev, "failed to request IRQ: %d\n", err); - goto err; + goto free_irq_domain; + } + + /* Though the PCIe controller can address >32-bit address space, to + * facilitate endpoints that support only 32-bit MSI target address, + * the mask is set to 32-bit to make sure that MSI target address is + * always a 32-bit address + */ + err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + if (err < 0) { + dev_err(dev, "failed to set DMA coherent mask: %d\n", err); + goto free_irq; + } + + msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL, + DMA_ATTR_NO_KERNEL_MAPPING); + if (!msi->virt) { + dev_err(dev, "failed to allocate DMA memory for MSI\n"); + err = -ENOMEM; + goto free_irq; } - /* setup AFI/FPCI range */ - msi->pages = __get_free_pages(GFP_KERNEL, 0); - msi->phys = virt_to_phys((void *)msi->pages); host->msi = &msi->chip; return 0; -err: +free_irq: + free_irq(msi->irq, pcie); +free_irq_domain: irq_domain_remove(msi->domain); return err; } @@ -1592,7 +1610,8 @@ static void tegra_pcie_msi_teardown(struct tegra_pcie *pcie) struct tegra_msi *msi = &pcie->msi; unsigned int i, irq; - free_pages(msi->pages, 0); + dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys, + DMA_ATTR_NO_KERNEL_MAPPING); if (msi->irq > 0) free_irq(msi->irq, pcie); -- cgit v1.2.3 From 4166bfe53093b687a0b1b22e5d943e143b8089b2 Mon Sep 17 00:00:00 2001 From: Jonathan Chocron Date: Thu, 28 Mar 2019 13:57:56 +0200 Subject: PCI: al: Add Amazon Annapurna Labs PCIe host controller driver Add driver for Amazon's Annapurna Labs PCIe host controller. The controller is based on DesignWare's IP. The controller doesn't support accessing the Root Port's config space via ECAM, so we obtain its base address via an AMZN0001 device. Furthermore, the DesignWare PCIe controller doesn't filter out config transactions sent to devices 1 and up on its bus, so they are filtered by the driver. All subordinate buses do support ECAM access. Implementing specific PCI config access functions involves: - Adding an init function to obtain the Root Port's base address from an AMZN0001 device. - Adding a new entry in the MCFG quirk array. [bhelgaas: Note that there is no Kconfig option for this driver because it is only intended for use with the generic ACPI host bridge driver. This driver is only needed because the DesignWare IP doesn't completely support ECAM access to the root bus.] Link: https://lore.kernel.org/lkml/1553774276-24675-1-git-send-email-jonnyc@amazon.com Co-developed-by: Vladimir Aerov Signed-off-by: Jonathan Chocron Signed-off-by: Vladimir Aerov Signed-off-by: Bjorn Helgaas Reviewed-by: David Woodhouse Reviewed-by: Benjamin Herrenschmidt Acked-by: Lorenzo Pieralisi --- MAINTAINERS | 6 +++ drivers/acpi/pci_mcfg.c | 12 +++++ drivers/pci/controller/dwc/Makefile | 1 + drivers/pci/controller/dwc/pcie-al.c | 93 ++++++++++++++++++++++++++++++++++++ include/linux/pci-ecam.h | 1 + 5 files changed, 113 insertions(+) create mode 100644 drivers/pci/controller/dwc/pcie-al.c (limited to 'drivers/pci/controller') diff --git a/MAINTAINERS b/MAINTAINERS index e17ebf70b548..8b18d02a50cb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12014,6 +12014,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/ S: Supported F: drivers/pci/controller/ +PCIE DRIVER FOR ANNAPURNA LABS +M: Jonathan Chocron +L: linux-pci@vger.kernel.org +S: Maintained +F: drivers/pci/controller/dwc/pcie-al.c + PCIE DRIVER FOR AMLOGIC MESON M: Yue Wang L: linux-pci@vger.kernel.org diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index a4e8432fc2fb..b42be067fb83 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -52,6 +52,18 @@ struct mcfg_fixup { static struct mcfg_fixup mcfg_quirks[] = { /* { OEM_ID, OEM_TABLE_ID, REV, SEGMENT, BUS_RANGE, ops, cfgres }, */ +#define AL_ECAM(table_id, rev, seg, ops) \ + { "AMAZON", table_id, rev, seg, MCFG_BUS_ANY, ops } + + AL_ECAM("GRAVITON", 0, 0, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 1, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 2, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 3, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 4, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 5, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 6, &al_pcie_ops), + AL_ECAM("GRAVITON", 0, 7, &al_pcie_ops), + #define QCOM_ECAM32(seg) \ { "QCOM ", "QDF2432 ", 1, seg, MCFG_BUS_ANY, &pci_32b_ops } diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile index b5f3b83cc2b3..b085dfd4fab7 100644 --- a/drivers/pci/controller/dwc/Makefile +++ b/drivers/pci/controller/dwc/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o # depending on whether ACPI, the DT driver, or both are enabled. ifdef CONFIG_PCI +obj-$(CONFIG_ARM64) += pcie-al.o obj-$(CONFIG_ARM64) += pcie-hisi.o endif diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c new file mode 100644 index 000000000000..3ab58f0584a8 --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-al.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe host controller driver for Amazon's Annapurna Labs IP (used in chips + * such as Graviton and Alpine) + * + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Author: Jonathan Chocron + */ + +#include +#include +#include +#include "../../pci.h" + +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) + +struct al_pcie_acpi { + void __iomem *dbi_base; +}; + +static void __iomem *al_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, + int where) +{ + struct pci_config_window *cfg = bus->sysdata; + struct al_pcie_acpi *pcie = cfg->priv; + void __iomem *dbi_base = pcie->dbi_base; + + if (bus->number == cfg->busr.start) { + /* + * The DW PCIe core doesn't filter out transactions to other + * devices/functions on the root bus num, so we do this here. + */ + if (PCI_SLOT(devfn) > 0) + return NULL; + else + return dbi_base + where; + } + + return pci_ecam_map_bus(bus, devfn, where); +} + +static int al_pcie_init(struct pci_config_window *cfg) +{ + struct device *dev = cfg->parent; + struct acpi_device *adev = to_acpi_device(dev); + struct acpi_pci_root *root = acpi_driver_data(adev); + struct al_pcie_acpi *al_pcie; + struct resource *res; + int ret; + + al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL); + if (!al_pcie) + return -ENOMEM; + + res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + ret = acpi_get_rc_resources(dev, "AMZN0001", root->segment, res); + if (ret) { + dev_err(dev, "can't get rc dbi base address for SEG %d\n", + root->segment); + return ret; + } + + dev_dbg(dev, "Root port dbi res: %pR\n", res); + + al_pcie->dbi_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(al_pcie->dbi_base)) { + long err = PTR_ERR(al_pcie->dbi_base); + + dev_err(dev, "couldn't remap dbi base %pR (err:%ld)\n", + res, err); + return err; + } + + cfg->priv = al_pcie; + + return 0; +} + +struct pci_ecam_ops al_pcie_ops = { + .bus_shift = 20, + .init = al_pcie_init, + .pci_ops = { + .map_bus = al_pcie_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + } +}; + +#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */ diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 29efa09d686b..a73164c85e78 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -56,6 +56,7 @@ extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */ extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */ extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */ extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */ +extern struct pci_ecam_ops al_pcie_ops; /* Amazon Annapurna Labs PCIe */ #endif #ifdef CONFIG_PCI_HOST_COMMON -- cgit v1.2.3 From 8cff995405eb0b563e7a0d2c49838611ea3f2692 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 26 Apr 2019 14:50:04 +0530 Subject: PCI: iproc: Enable iProc config read for PAXBv2 iProc config read flag has to be enabled for PAXBv2 instead of PAXB. Fixes: f78e60a29d4f ("PCI: iproc: Reject unconfigured physical functions from PAXC") Signed-off-by: Srinath Mannam Signed-off-by: Lorenzo Pieralisi Reviewed-by: Ray Jui --- drivers/pci/controller/pcie-iproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 080f142ce24d..dd11d0226ff0 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1383,7 +1383,6 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) break; case IPROC_PCIE_PAXB: regs = iproc_pcie_reg_paxb; - pcie->iproc_cfg_read = true; pcie->has_apb_err_disable = true; if (pcie->need_ob_cfg) { pcie->ob_map = paxb_ob_map; @@ -1392,6 +1391,7 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) break; case IPROC_PCIE_PAXB_V2: regs = iproc_pcie_reg_paxb_v2; + pcie->iproc_cfg_read = true; pcie->has_apb_err_disable = true; if (pcie->need_ob_cfg) { pcie->ob_map = paxb_v2_ob_map; -- cgit v1.2.3 From 9e303be2e5d0705f3fc51c4c854e5d94e1b943c4 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:22 -0700 Subject: PCI: imx6: Simplify imx7d_pcie_wait_for_phy_pll_lock() Make use of regmap_read_poll_timeout() to simplify imx7d_pcie_wait_for_phy_pll_lock(). No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3d627f94a166..ea2617712a3b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -89,9 +89,8 @@ struct imx6_pcie { }; /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */ -#define PHY_PLL_LOCK_WAIT_MAX_RETRIES 2000 -#define PHY_PLL_LOCK_WAIT_USLEEP_MIN 50 #define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200 +#define PHY_PLL_LOCK_WAIT_TIMEOUT (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX) /* PCIe Root Complex registers (memory-mapped) */ #define PCIE_RC_IMX6_MSI_CAP 0x50 @@ -488,20 +487,14 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie) { u32 val; - unsigned int retries; struct device *dev = imx6_pcie->pci->dev; - for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) { - regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR22, &val); - - if (val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED) - return; - - usleep_range(PHY_PLL_LOCK_WAIT_USLEEP_MIN, - PHY_PLL_LOCK_WAIT_USLEEP_MAX); - } - - dev_err(dev, "PCIe PLL lock timeout\n"); + if (regmap_read_poll_timeout(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR22, val, + val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED, + PHY_PLL_LOCK_WAIT_USLEEP_MAX, + PHY_PLL_LOCK_WAIT_TIMEOUT)) + dev_err(dev, "PCIe PLL lock timeout\n"); } static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie) -- cgit v1.2.3 From ee6f37175b3f7ae1c3bc147d4779c6043ce25461 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:23 -0700 Subject: PCI: imx6: Drop imx6_pcie_wait_for_link() All calls to imx6_pcie_wait_for_link() share the same error path and the state of PHY debug registers will already be printed there, so there's no real reason we can't just use dw_pcie_wait_for_link(). Drop imx6_pcie_wait_for_link() and replace it with dw_pcie_wait_for_link(). Suggested-by: Lucas Stach Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index ea2617712a3b..bb3dcfdbf697 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -723,21 +723,6 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) return 0; } -static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) -{ - struct dw_pcie *pci = imx6_pcie->pci; - struct device *dev = pci->dev; - - /* check if the link is up or not */ - if (!dw_pcie_wait_for_link(pci)) - return 0; - - dev_dbg(dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n", - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0), - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1)); - return -ETIMEDOUT; -} - static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -796,7 +781,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) /* Start LTSSM. */ imx6_pcie_ltssm_enable(dev); - ret = imx6_pcie_wait_for_link(imx6_pcie); + ret = dw_pcie_wait_for_link(pci); if (ret) goto err_reset_phy; @@ -834,7 +819,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) } /* Make sure link training is finished as well! */ - ret = imx6_pcie_wait_for_link(imx6_pcie); + ret = dw_pcie_wait_for_link(pci); if (ret) { dev_err(dev, "Failed to bring link up!\n"); goto err_reset_phy; -- cgit v1.2.3 From c377690cffaf6a497b81304a83d3b2a2dad2942a Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:24 -0700 Subject: PCI: imx6: Return -ETIMEOUT from imx6_pcie_wait_for_speed_change() Change error code from -EINVAL to -ETIMEDOUT in imx6_pcie_wait_for_speed_change() since that error code seems more appropriate. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index bb3dcfdbf697..021ef121a058 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -739,7 +739,7 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) } dev_err(dev, "Speed change timeout\n"); - return -EINVAL; + return -ETIMEDOUT; } static void imx6_pcie_ltssm_enable(struct device *dev) -- cgit v1.2.3 From 680728e4cbee8ede008373c56fe6978946080008 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:25 -0700 Subject: PCI: imx6: Remove PCIE_PL_PFLR_* constants Code using these constants was removed in commit a71280722eeb ("PCI: imx6: Remove LTSSM disable workaround"). No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 021ef121a058..c0867df090f5 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -103,9 +103,6 @@ struct imx6_pcie { /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 -#define PCIE_PL_PFLR (PL_OFFSET + 0x08) -#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16) -#define PCIE_PL_PFLR_FORCE_LINK (1 << 15) #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) -- cgit v1.2.3 From 60ef4b072ba089440531287f72740d94ed1e8dd1 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:26 -0700 Subject: PCI: dwc: imx6: Share PHY debug register definitions Both pcie-designware.c and pci-imx6.c contain custom definitions for PHY debug registers R0/R1 and on top of that there's already a definition for R0 in pcie-designware.h. Move all of the definitions to pcie-designware.h. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 6 ++---- drivers/pci/controller/dwc/pcie-designware.c | 12 +++--------- drivers/pci/controller/dwc/pcie-designware.h | 3 +++ 3 files changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index c0867df090f5..eeacdebd9b50 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -103,8 +103,6 @@ struct imx6_pcie { /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 -#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) -#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) #define PCIE_PHY_CTRL (PL_OFFSET + 0x114) #define PCIE_PHY_CTRL_DATA_LOC 0 @@ -831,8 +829,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) err_reset_phy: dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n", - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0), - dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1)); + dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0), + dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG1)); imx6_pcie_reset_phy(imx6_pcie); return ret; } diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 31f6331ca46f..086e87a40316 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -14,12 +14,6 @@ #include "pcie-designware.h" -/* PCIe Port Logic registers */ -#define PLR_OFFSET 0x700 -#define PCIE_PHY_DEBUG_R1 (PLR_OFFSET + 0x2c) -#define PCIE_PHY_DEBUG_R1_LINK_UP (0x1 << 4) -#define PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING (0x1 << 29) - int dw_pcie_read(void __iomem *addr, int size, u32 *val) { if (!IS_ALIGNED((uintptr_t)addr, size)) { @@ -334,9 +328,9 @@ int dw_pcie_link_up(struct dw_pcie *pci) if (pci->ops->link_up) return pci->ops->link_up(pci); - val = readl(pci->dbi_base + PCIE_PHY_DEBUG_R1); - return ((val & PCIE_PHY_DEBUG_R1_LINK_UP) && - (!(val & PCIE_PHY_DEBUG_R1_LINK_IN_TRAINING))); + val = readl(pci->dbi_base + PCIE_PORT_DEBUG1); + return ((val & PCIE_PORT_DEBUG1_LINK_UP) && + (!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING))); } void dw_pcie_setup(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 377f4c0b52da..b33ae13194be 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -41,6 +41,9 @@ #define PCIE_PORT_DEBUG0 0x728 #define PORT_LOGIC_LTSSM_STATE_MASK 0x1f #define PORT_LOGIC_LTSSM_STATE_L0 0x11 +#define PCIE_PORT_DEBUG1 0x72C +#define PCIE_PORT_DEBUG1_LINK_UP BIT(4) +#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29) #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C #define PORT_LOGIC_SPEED_CHANGE BIT(17) -- cgit v1.2.3 From 276c76d7a15ada363b8efab7b50a52aeaf3b3fd5 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:27 -0700 Subject: PCI: imx6: Make use of BIT() in constant definitions Avoid using explicit left shifts and convert various definitions to use BIT() instead. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index eeacdebd9b50..5650642ab248 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -118,14 +118,14 @@ struct imx6_pcie { /* PHY registers (not memory-mapped) */ #define PCIE_PHY_ATEOVRD 0x10 -#define PCIE_PHY_ATEOVRD_EN (0x1 << 2) +#define PCIE_PHY_ATEOVRD_EN BIT(2) #define PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT 0 #define PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK 0x1 #define PCIE_PHY_MPLL_OVRD_IN_LO 0x11 #define PCIE_PHY_MPLL_MULTIPLIER_SHIFT 2 #define PCIE_PHY_MPLL_MULTIPLIER_MASK 0x7f -#define PCIE_PHY_MPLL_MULTIPLIER_OVRD (0x1 << 9) +#define PCIE_PHY_MPLL_MULTIPLIER_OVRD BIT(9) #define PCIE_PHY_RX_ASIC_OUT 0x100D #define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0) @@ -148,8 +148,8 @@ struct imx6_pcie { #define PCIE_PHY_CMN_REG26_ATT_MODE 0xBC #define PHY_RX_OVRD_IN_LO 0x1005 -#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) -#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) +#define PHY_RX_OVRD_IN_LO_RX_DATA_EN BIT(5) +#define PHY_RX_OVRD_IN_LO_RX_PLL_EN BIT(3) static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val) { -- cgit v1.2.3 From 3ca4133253a7ff37e56b3b00f1e03c3e7d20ea89 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:28 -0700 Subject: PCI: imx6: Simplify bit operations in PHY functions Simplify the code by incorporating left shifts into constant definitions as well as using FIELD_PREP/GENMASK. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5650642ab248..669e01353026 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -105,11 +105,11 @@ struct imx6_pcie { #define PL_OFFSET 0x700 #define PCIE_PHY_CTRL (PL_OFFSET + 0x114) -#define PCIE_PHY_CTRL_DATA_LOC 0 -#define PCIE_PHY_CTRL_CAP_ADR_LOC 16 -#define PCIE_PHY_CTRL_CAP_DAT_LOC 17 -#define PCIE_PHY_CTRL_WR_LOC 18 -#define PCIE_PHY_CTRL_RD_LOC 19 +#define PCIE_PHY_CTRL_DATA(x) FIELD_PREP(GENMASK(15, 0), (x)) +#define PCIE_PHY_CTRL_CAP_ADR BIT(16) +#define PCIE_PHY_CTRL_CAP_DAT BIT(17) +#define PCIE_PHY_CTRL_WR BIT(18) +#define PCIE_PHY_CTRL_RD BIT(19) #define PCIE_PHY_STAT (PL_OFFSET + 0x110) #define PCIE_PHY_STAT_ACK_LOC 16 @@ -178,17 +178,17 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr) u32 val; int ret; - val = addr << PCIE_PHY_CTRL_DATA_LOC; + val = PCIE_PHY_CTRL_DATA(addr); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); - val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC); + val |= PCIE_PHY_CTRL_CAP_ADR; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); ret = pcie_phy_poll_ack(imx6_pcie, 1); if (ret) return ret; - val = addr << PCIE_PHY_CTRL_DATA_LOC; + val = PCIE_PHY_CTRL_DATA(addr); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); return pcie_phy_poll_ack(imx6_pcie, 0); @@ -206,7 +206,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) return ret; /* assert Read signal */ - phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC; + phy_ctl = PCIE_PHY_CTRL_RD; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, phy_ctl); ret = pcie_phy_poll_ack(imx6_pcie, 1); @@ -234,11 +234,11 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) if (ret) return ret; - var = data << PCIE_PHY_CTRL_DATA_LOC; + var = PCIE_PHY_CTRL_DATA(data); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* capture data */ - var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC); + var |= PCIE_PHY_CTRL_CAP_DAT; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); ret = pcie_phy_poll_ack(imx6_pcie, 1); @@ -246,7 +246,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) return ret; /* deassert cap data */ - var = data << PCIE_PHY_CTRL_DATA_LOC; + var = PCIE_PHY_CTRL_DATA(data); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ @@ -255,7 +255,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) return ret; /* assert wr signal */ - var = 0x1 << PCIE_PHY_CTRL_WR_LOC; + var = PCIE_PHY_CTRL_WR; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack */ @@ -264,7 +264,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) return ret; /* deassert wr signal */ - var = data << PCIE_PHY_CTRL_DATA_LOC; + var = PCIE_PHY_CTRL_DATA(data); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ -- cgit v1.2.3 From c2c708bc1dbf9655211d3843e2f36c7951059cf0 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:29 -0700 Subject: PCI: imx6: Simplify pcie_phy_poll_ack() Simplify pcie_phy_poll_ack() by incorporating shifting into constant definition and convert the code to use 'bool'. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 669e01353026..3fd084357488 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -112,7 +112,7 @@ struct imx6_pcie { #define PCIE_PHY_CTRL_RD BIT(19) #define PCIE_PHY_STAT (PL_OFFSET + 0x110) -#define PCIE_PHY_STAT_ACK_LOC 16 +#define PCIE_PHY_STAT_ACK BIT(16) #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C @@ -151,16 +151,16 @@ struct imx6_pcie { #define PHY_RX_OVRD_IN_LO_RX_DATA_EN BIT(5) #define PHY_RX_OVRD_IN_LO_RX_PLL_EN BIT(3) -static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val) +static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, bool exp_val) { struct dw_pcie *pci = imx6_pcie->pci; - u32 val; + bool val; u32 max_iterations = 10; u32 wait_counter = 0; do { - val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); - val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1; + val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT) & + PCIE_PHY_STAT_ACK; wait_counter++; if (val == exp_val) @@ -184,14 +184,14 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr) val |= PCIE_PHY_CTRL_CAP_ADR; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; val = PCIE_PHY_CTRL_DATA(addr); dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, val); - return pcie_phy_poll_ack(imx6_pcie, 0); + return pcie_phy_poll_ack(imx6_pcie, false); } /* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */ @@ -209,7 +209,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) phy_ctl = PCIE_PHY_CTRL_RD; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, phy_ctl); - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; @@ -219,7 +219,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) /* deassert Read signal */ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x00); - return pcie_phy_poll_ack(imx6_pcie, 0); + return pcie_phy_poll_ack(imx6_pcie, false); } static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) @@ -241,7 +241,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) var |= PCIE_PHY_CTRL_CAP_DAT; dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; @@ -250,7 +250,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ - ret = pcie_phy_poll_ack(imx6_pcie, 0); + ret = pcie_phy_poll_ack(imx6_pcie, false); if (ret) return ret; @@ -259,7 +259,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack */ - ret = pcie_phy_poll_ack(imx6_pcie, 1); + ret = pcie_phy_poll_ack(imx6_pcie, true); if (ret) return ret; @@ -268,7 +268,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, var); /* wait for ack de-assertion */ - ret = pcie_phy_poll_ack(imx6_pcie, 0); + ret = pcie_phy_poll_ack(imx6_pcie, false); if (ret) return ret; -- cgit v1.2.3 From 37d5d32ae091c7acff23a080e3c179977fb943cd Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:30 -0700 Subject: PCI: imx6: Restrict PHY register data to 16-bit PHY registers on i.MX6 are 16-bit wide, so we can get rid of explicit masking if we restrict pcie_phy_read()/pcie_phy_write() to use 'u16' instead of 'int'. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3fd084357488..30e764b6cbcc 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -195,10 +195,10 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr) } /* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */ -static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) +static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, u16 *data) { struct dw_pcie *pci = imx6_pcie->pci; - u32 val, phy_ctl; + u32 phy_ctl; int ret; ret = pcie_phy_wait_ack(imx6_pcie, addr); @@ -213,8 +213,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) if (ret) return ret; - val = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); - *data = val & 0xffff; + *data = dw_pcie_readl_dbi(pci, PCIE_PHY_STAT); /* deassert Read signal */ dw_pcie_writel_dbi(pci, PCIE_PHY_CTRL, 0x00); @@ -222,7 +221,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data) return pcie_phy_poll_ack(imx6_pcie, false); } -static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) +static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, u16 data) { struct dw_pcie *pci = imx6_pcie->pci; u32 var; @@ -279,7 +278,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data) static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie) { - u32 tmp; + u16 tmp; if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY)) return; @@ -675,7 +674,7 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) { unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy); int mult, div; - u32 val; + u16 val; if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY)) return 0; -- cgit v1.2.3 From 76d6dc26331dfe3c275b16ac28f8b92f9614cd7e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:31 -0700 Subject: PCI: imx6: Use flags to indicate support for suspend Now that driver data has flags variable that can be used to indicate quirks/features supported we can switch the code to use it instead of having a special function that does so based on variant alone. No functional change intended. Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 30e764b6cbcc..3e45f49b8a4f 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -52,6 +52,7 @@ enum imx6_pcie_variants { #define IMX6_PCIE_FLAG_IMX6_PHY BIT(0) #define IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE BIT(1) +#define IMX6_PCIE_FLAG_SUPPORTS_SUSPEND BIT(2) struct imx6_pcie_drvdata { enum imx6_pcie_variants variant; @@ -965,17 +966,11 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) } } -static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie) -{ - return (imx6_pcie->drvdata->variant == IMX7D || - imx6_pcie->drvdata->variant == IMX6SX); -} - static int imx6_pcie_suspend_noirq(struct device *dev) { struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); - if (!imx6_pcie_supports_suspend(imx6_pcie)) + if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; imx6_pcie_pm_turnoff(imx6_pcie); @@ -991,7 +986,7 @@ static int imx6_pcie_resume_noirq(struct device *dev) struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); struct pcie_port *pp = &imx6_pcie->pci->pp; - if (!imx6_pcie_supports_suspend(imx6_pcie)) + if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; imx6_pcie_assert_core_reset(imx6_pcie); @@ -1221,7 +1216,8 @@ static const struct imx6_pcie_drvdata drvdata[] = { [IMX6SX] = { .variant = IMX6SX, .flags = IMX6_PCIE_FLAG_IMX6_PHY | - IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE, + IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE | + IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, }, [IMX6QP] = { .variant = IMX6QP, @@ -1230,6 +1226,7 @@ static const struct imx6_pcie_drvdata drvdata[] = { }, [IMX7D] = { .variant = IMX7D, + .flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, }, [IMX8MQ] = { .variant = IMX8MQ, -- cgit v1.2.3 From 87cb312777b5dc5eece8e1c58d4e0040eeea39fa Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sun, 14 Apr 2019 17:46:32 -0700 Subject: PCI: imx6: Use usleep_range() in imx6_pcie_enable_ref_clk() imx6_pcie_enable_ref_clk() is never called in atomic context, so there's no need to use udelay(). Replace it with usleep_range(). Signed-off-by: Andrey Smirnov Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach Cc: Lorenzo Pieralisi Cc: Bjorn Helgaas Cc: Chris Healy Cc: Lucas Stach Cc: linux-kernel@vger.kernel.org Cc: linux-pci@vger.kernel.org --- drivers/pci/controller/dwc/pci-imx6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3e45f49b8a4f..c6d6bde4d860 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -449,7 +449,7 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie) * reset time is too short, cannot meet the requirement. * add one ~10us delay here. */ - udelay(10); + usleep_range(10, 100); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); break; -- cgit v1.2.3 From 23284ad677a94f26afc92017d540ccaf26c1a581 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:43 +0530 Subject: PCI: keystone: Add support for PCIe EP in AM654x Platforms Add PCIe EP support for AM654x Platforms in pci-keystone.c Link: https://lore.kernel.org/linux-pci/20190325093947.32633-15-kishon@ti.com/ Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: made dev_vdbg() call a comment] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/Kconfig | 27 +++- drivers/pci/controller/dwc/pci-keystone.c | 250 ++++++++++++++++++++++++++---- 2 files changed, 240 insertions(+), 37 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index d1d00833e0b3..a6ce1ee51b4c 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -103,15 +103,32 @@ config PCIE_SPEAR13XX Say Y here if you want PCIe support on SPEAr13XX SoCs. config PCI_KEYSTONE - bool "TI Keystone PCIe controller" + bool + +config PCI_KEYSTONE_HOST + bool "PCI Keystone Host Mode" depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) depends on PCI_MSI_IRQ_DOMAIN select PCIE_DW_HOST + select PCI_KEYSTONE + default y help - Say Y here if you want to enable PCI controller support on Keystone - SoCs. The PCI controller on Keystone is based on DesignWare hardware - and therefore the driver re-uses the DesignWare core functions to - implement the driver. + Enables support for the PCIe controller in the Keystone SoC to + work in host mode. The PCI controller on Keystone is based on + DesignWare hardware and therefore the driver re-uses the + DesignWare core functions to implement the driver. + +config PCI_KEYSTONE_EP + bool "PCI Keystone Endpoint Mode" + depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST) + depends on PCI_ENDPOINT + select PCIE_DW_EP + select PCI_KEYSTONE + help + Enables support for the PCIe controller in the Keystone SoC to + work in endpoint mode. The PCI controller on Keystone is based + on DesignWare hardware and therefore the driver re-uses the + DesignWare core functions to implement the driver. config PCI_LAYERSCAPE bool "Freescale Layerscape PCIe controller" diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 312fd0c49bbb..af677254a072 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -52,6 +52,12 @@ #define OB_ENABLEN BIT(0) #define OB_WIN_SIZE 8 /* 8MB */ +#define PCIE_LEGACY_IRQ_ENABLE_SET(n) (0x188 + (0x10 * ((n) - 1))) +#define PCIE_LEGACY_IRQ_ENABLE_CLR(n) (0x18c + (0x10 * ((n) - 1))) +#define PCIE_EP_IRQ_SET 0x64 +#define PCIE_EP_IRQ_CLR 0x68 +#define INT_ENABLE BIT(0) + /* IRQ register defines */ #define IRQ_EOI 0x050 @@ -95,11 +101,16 @@ #define KS_PCIE_SYSCLOCKOUTEN BIT(0) #define AM654_PCIE_DEV_TYPE_MASK 0x3 +#define AM654_WIN_SIZE SZ_64K + +#define APP_ADDR_SPACE_0 (16 * SZ_1K) #define to_keystone_pcie(x) dev_get_drvdata((x)->dev) struct ks_pcie_of_data { + enum dw_pcie_device_mode mode; const struct dw_pcie_host_ops *host_ops; + const struct dw_pcie_ep_ops *ep_ops; unsigned int version; }; @@ -264,13 +275,11 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset); } +/* + * Dummy function so that DW core doesn't configure MSI + */ static int ks_pcie_am654_msi_host_init(struct pcie_port *pp) { - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - struct device *dev = pci->dev; - - dev_vdbg(dev, "dummy function so that DW core doesn't configure MSI\n"); - return 0; } @@ -877,12 +886,139 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie, return 0; } +static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base, + u32 reg, size_t size) +{ + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + u32 val; + + ks_pcie_set_dbi_mode(ks_pcie); + dw_pcie_read(base + reg, size, &val); + ks_pcie_clear_dbi_mode(ks_pcie); + return val; +} + +static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base, + u32 reg, size_t size, u32 val) +{ + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + ks_pcie_set_dbi_mode(ks_pcie); + dw_pcie_write(base + reg, size, val); + ks_pcie_clear_dbi_mode(ks_pcie); +} + static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = { .start_link = ks_pcie_start_link, .stop_link = ks_pcie_stop_link, .link_up = ks_pcie_link_up, + .read_dbi2 = ks_pcie_am654_read_dbi2, + .write_dbi2 = ks_pcie_am654_write_dbi2, +}; + +static void ks_pcie_am654_ep_init(struct dw_pcie_ep *ep) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + int flags; + + ep->page_size = AM654_WIN_SIZE; + flags = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32; + dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, APP_ADDR_SPACE_0 - 1); + dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, flags); +} + +static void ks_pcie_am654_raise_legacy_irq(struct keystone_pcie *ks_pcie) +{ + struct dw_pcie *pci = ks_pcie->pci; + u8 int_pin; + + int_pin = dw_pcie_readb_dbi(pci, PCI_INTERRUPT_PIN); + if (int_pin == 0 || int_pin > 4) + return; + + ks_pcie_app_writel(ks_pcie, PCIE_LEGACY_IRQ_ENABLE_SET(int_pin), + INT_ENABLE); + ks_pcie_app_writel(ks_pcie, PCIE_EP_IRQ_SET, INT_ENABLE); + mdelay(1); + ks_pcie_app_writel(ks_pcie, PCIE_EP_IRQ_CLR, INT_ENABLE); + ks_pcie_app_writel(ks_pcie, PCIE_LEGACY_IRQ_ENABLE_CLR(int_pin), + INT_ENABLE); +} + +static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no, + enum pci_epc_irq_type type, + u16 interrupt_num) +{ + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); + + switch (type) { + case PCI_EPC_IRQ_LEGACY: + ks_pcie_am654_raise_legacy_irq(ks_pcie); + break; + case PCI_EPC_IRQ_MSI: + dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); + break; + default: + dev_err(pci->dev, "UNKNOWN IRQ type\n"); + return -EINVAL; + } + + return 0; +} + +static const struct pci_epc_features ks_pcie_am654_epc_features = { + .linkup_notifier = false, + .msi_capable = true, + .msix_capable = false, + .reserved_bar = 1 << BAR_0 | 1 << BAR_1, + .bar_fixed_64bit = 1 << BAR_0, + .bar_fixed_size[2] = SZ_1M, + .bar_fixed_size[3] = SZ_64K, + .bar_fixed_size[4] = 256, + .bar_fixed_size[5] = SZ_1M, + .align = SZ_1M, }; +static const struct pci_epc_features* +ks_pcie_am654_get_features(struct dw_pcie_ep *ep) +{ + return &ks_pcie_am654_epc_features; +} + +static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = { + .ep_init = ks_pcie_am654_ep_init, + .raise_irq = ks_pcie_am654_raise_irq, + .get_features = &ks_pcie_am654_get_features, +}; + +static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie, + struct platform_device *pdev) +{ + int ret; + struct dw_pcie_ep *ep; + struct resource *res; + struct device *dev = &pdev->dev; + struct dw_pcie *pci = ks_pcie->pci; + + ep = &pci->ep; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); + if (!res) + return -EINVAL; + + ep->phys_base = res->start; + ep->addr_size = resource_size(res); + + ret = dw_pcie_ep_init(ep); + if (ret) { + dev_err(dev, "failed to initialize endpoint\n"); + return ret; + } + + return 0; +} + static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie) { int num_lanes = ks_pcie->num_lanes; @@ -950,7 +1086,8 @@ static int ks_pcie_set_mode(struct device *dev) return 0; } -static int ks_pcie_am654_set_mode(struct device *dev) +static int ks_pcie_am654_set_mode(struct device *dev, + enum dw_pcie_device_mode mode) { struct device_node *np = dev->of_node; struct regmap *syscon; @@ -963,7 +1100,18 @@ static int ks_pcie_am654_set_mode(struct device *dev) return 0; mask = AM654_PCIE_DEV_TYPE_MASK; - val = RC; + + switch (mode) { + case DW_PCIE_RC_TYPE: + val = RC; + break; + case DW_PCIE_EP_TYPE: + val = EP; + break; + default: + dev_err(dev, "INVALID device type %d\n", mode); + return -EINVAL; + } ret = regmap_update_bits(syscon, 0, mask, val); if (ret) { @@ -1006,6 +1154,13 @@ static const struct ks_pcie_of_data ks_pcie_rc_of_data = { static const struct ks_pcie_of_data ks_pcie_am654_rc_of_data = { .host_ops = &ks_pcie_am654_host_ops, + .mode = DW_PCIE_RC_TYPE, + .version = 0x490A, +}; + +static const struct ks_pcie_of_data ks_pcie_am654_ep_of_data = { + .ep_ops = &ks_pcie_am654_ep_ops, + .mode = DW_PCIE_EP_TYPE, .version = 0x490A, }; @@ -1019,16 +1174,22 @@ static const struct of_device_id ks_pcie_of_match[] = { .data = &ks_pcie_am654_rc_of_data, .compatible = "ti,am654-pcie-rc", }, + { + .data = &ks_pcie_am654_ep_of_data, + .compatible = "ti,am654-pcie-ep", + }, { }, }; static int __init ks_pcie_probe(struct platform_device *pdev) { const struct dw_pcie_host_ops *host_ops; + const struct dw_pcie_ep_ops *ep_ops; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; const struct ks_pcie_of_data *data; const struct of_device_id *match; + enum dw_pcie_device_mode mode; struct dw_pcie *pci; struct keystone_pcie *ks_pcie; struct device_link **link; @@ -1053,6 +1214,8 @@ static int __init ks_pcie_probe(struct platform_device *pdev) version = data->version; host_ops = data->host_ops; + ep_ops = data->ep_ops; + mode = data->mode; ks_pcie = devm_kzalloc(dev, sizeof(*ks_pcie), GFP_KERNEL); if (!ks_pcie) @@ -1078,16 +1241,11 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->is_am6 = true; pci->dbi_base = base; + pci->dbi_base2 = base; pci->dev = dev; pci->ops = &ks_pcie_dw_pcie_ops; pci->version = version; - ret = of_property_read_u32(np, "num-viewport", &num_viewport); - if (ret < 0) { - dev_err(dev, "unable to read *num-viewport* property\n"); - return ret; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "missing IRQ resource: %d\n", irq); @@ -1136,7 +1294,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev) ks_pcie->pci = pci; ks_pcie->link = link; ks_pcie->num_lanes = num_lanes; - ks_pcie->num_viewport = num_viewport; ks_pcie->phy = phy; gpiod = devm_gpiod_get_optional(dev, "reset", @@ -1172,7 +1329,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) pci->atu_base = atu_base; - ret = ks_pcie_am654_set_mode(dev); + ret = ks_pcie_am654_set_mode(dev, mode); if (ret < 0) goto err_get_sync; } else { @@ -1181,29 +1338,58 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - /* - * "Power Sequencing and Reset Signal Timings" table in - * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 - * indicates PERST# should be deasserted after minimum of 100us - * once REFCLK is stable. The REFCLK to the connector in RC - * mode is selected while enabling the PHY. So deassert PERST# - * after 100 us. - */ - if (gpiod) { - usleep_range(100, 200); - gpiod_set_value_cansleep(gpiod, 1); - } - link_speed = of_pci_get_max_link_speed(np); if (link_speed < 0) link_speed = 2; ks_pcie_set_link_speed(pci, link_speed); - pci->pp.ops = host_ops; - ret = ks_pcie_add_pcie_port(ks_pcie, pdev); - if (ret < 0) - goto err_get_sync; + switch (mode) { + case DW_PCIE_RC_TYPE: + if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_HOST)) { + ret = -ENODEV; + goto err_get_sync; + } + + ret = of_property_read_u32(np, "num-viewport", &num_viewport); + if (ret < 0) { + dev_err(dev, "unable to read *num-viewport* property\n"); + return ret; + } + + /* + * "Power Sequencing and Reset Signal Timings" table in + * PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0 + * indicates PERST# should be deasserted after minimum of 100us + * once REFCLK is stable. The REFCLK to the connector in RC + * mode is selected while enabling the PHY. So deassert PERST# + * after 100 us. + */ + if (gpiod) { + usleep_range(100, 200); + gpiod_set_value_cansleep(gpiod, 1); + } + + ks_pcie->num_viewport = num_viewport; + pci->pp.ops = host_ops; + ret = ks_pcie_add_pcie_port(ks_pcie, pdev); + if (ret < 0) + goto err_get_sync; + break; + case DW_PCIE_EP_TYPE: + if (!IS_ENABLED(CONFIG_PCI_KEYSTONE_EP)) { + ret = -ENODEV; + goto err_get_sync; + } + + pci->ep.ops = ep_ops; + ret = ks_pcie_add_pcie_ep(ks_pcie, pdev); + if (ret < 0) + goto err_get_sync; + break; + default: + dev_err(dev, "INVALID device type %d\n", mode); + } ks_pcie_enable_error_irq(ks_pcie); -- cgit v1.2.3 From fc9a77040b04c05f036515f40aa7cf4b9c91defd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:44 +0530 Subject: PCI: designware-ep: Configure Resizable BAR cap to advertise the smallest size Configure the Resizable BAR capability to advertise the smallest size (1MB) for a couple of reasons: - Host side resource allocation of BAR fails for larger sizes - Endpoint function driver does not allocate memory for all supported sizes in the Resizable BAR capability. If and when there is a usecase required to add more flexibility using the Resizable BAR capability, this can be revisited. Signed-off-by: Kishon Vijay Abraham I [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 74477ad7467f..0c208b9bda43 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -504,10 +504,32 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep) pci_epc_mem_exit(epc); } +static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) +{ + u32 header; + int pos = PCI_CFG_SPACE_SIZE; + + while (pos) { + header = dw_pcie_readl_dbi(pci, pos); + if (PCI_EXT_CAP_ID(header) == cap) + return pos; + + pos = PCI_EXT_CAP_NEXT(header); + if (!pos) + break; + } + + return 0; +} + int dw_pcie_ep_init(struct dw_pcie_ep *ep) { + int i; int ret; + u32 reg; void *addr; + unsigned int nbars; + unsigned int offset; struct pci_epc *epc; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct device *dev = pci->dev; @@ -591,6 +613,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX); + offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); + if (offset) { + reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); + nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> + PCI_REBAR_CTRL_NBAR_SHIFT; + + dw_pcie_dbi_ro_wr_en(pci); + for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) + dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0); + dw_pcie_dbi_ro_wr_dis(pci); + } + dw_pcie_setup(pci); return 0; -- cgit v1.2.3 From 6b7330303a8186fb211357e6d379237fe9d2ece1 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 25 Mar 2019 15:09:45 +0530 Subject: PCI: designware-ep: Use aligned ATU window for raising MSI interrupts Certain platforms like K2G reguires the outbound ATU window to be aligned. The alignment size is already present in mem->page_size. Use the alignment size present in mem->page_size to configure an aligned ATU window. In order to raise an interrupt, CPU has to write to address offset from the start of the window unlike before where writes were always to the beginning of the ATU window. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-designware-ep.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 0c208b9bda43..2bf5a35c0570 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -397,6 +397,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct pci_epc *epc = ep->epc; + unsigned int aligned_offset; u16 msg_ctrl, msg_data; u32 msg_addr_lower, msg_addr_upper, reg; u64 msg_addr; @@ -422,13 +423,15 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, reg = ep->msi_cap + PCI_MSI_DATA_32; msg_data = dw_pcie_readw_dbi(pci, reg); } - msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; + aligned_offset = msg_addr_lower & (epc->mem->page_size - 1); + msg_addr = ((u64)msg_addr_upper) << 32 | + (msg_addr_lower & ~aligned_offset); ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, epc->mem->page_size); if (ret) return ret; - writel(msg_data | (interrupt_num - 1), ep->msi_mem); + writel(msg_data | (interrupt_num - 1), ep->msi_mem + aligned_offset); dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); -- cgit v1.2.3 From 90199c951bd2a6248e55a8db3368a2568e3b3edc Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Fri, 3 May 2019 19:35:34 +0530 Subject: PCI: iproc: Add sorted dma ranges resource entries to host bridge The iProc host controller allows only a subset of physical address space as target of inbound PCI memory transaction addresses. PCI device memory transactions targeting memory regions that are not allowed for inbound transactions in the host controller are rejected by the host controller and cannot reach the upstream buses. The firmware device tree description defines the DMA ranges that are addressable by devices DMA transactions; parse the device tree dma-ranges property and add its ranges to the PCI host bridge dma_ranges list; the iova_reserve_pci_windows() call executed at iommu_dma_init_domain() will reserve the IOVA address ranges that are not addressable (ie memory holes in the dma-ranges set) so that they are not allocated to PCI devices for DMA transfers. All allowed address ranges are listed in the dma-ranges DT parameter. For example: dma-ranges = < \ 0x43000000 0x00 0x80000000 0x00 0x80000000 0x00 0x80000000 \ 0x43000000 0x08 0x00000000 0x08 0x00000000 0x08 0x00000000 \ 0x43000000 0x80 0x00000000 0x80 0x00000000 0x40 0x00000000> In the above example of dma-ranges, memory address from 0x0 - 0x80000000, 0x100000000 - 0x800000000, 0x1000000000 - 0x8000000000 and 0x10000000000 - 0xffffffffffffffff. are not allowed to be used as inbound addresses. Based-on-a-patch-by: Oza Pawandeep Signed-off-by: Srinath Mannam [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi [bhelgaas: fix function prototype style] Signed-off-by: Bjorn Helgaas Reviewed-by: Oza Pawandeep Reviewed-by: Eric Auger --- drivers/pci/controller/pcie-iproc.c | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index c20fd6bd68fd..f76a75bb7ae4 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1146,11 +1146,43 @@ err_ib: return ret; } +static int iproc_pcie_add_dma_range(struct device *dev, + struct list_head *resources, + struct of_pci_range *range) +{ + struct resource *res; + struct resource_entry *entry, *tmp; + struct list_head *head = resources; + + res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL); + if (!res) + return -ENOMEM; + + resource_list_for_each_entry(tmp, resources) { + if (tmp->res->start < range->cpu_addr) + head = &tmp->node; + } + + res->start = range->cpu_addr; + res->end = res->start + range->size - 1; + + entry = resource_list_create_entry(res, 0); + if (!entry) + return -ENOMEM; + + entry->offset = res->start - range->cpu_addr; + resource_list_add(entry, head); + + return 0; +} + static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) { + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); struct of_pci_range range; struct of_pci_range_parser parser; int ret; + LIST_HEAD(resources); /* Get the dma-ranges from DT */ ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node); @@ -1158,13 +1190,23 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) return ret; for_each_of_pci_range(&parser, &range) { + ret = iproc_pcie_add_dma_range(pcie->dev, + &resources, + &range); + if (ret) + goto out; /* Each range entry corresponds to an inbound mapping region */ ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM); if (ret) - return ret; + goto out; } + list_splice_init(&resources, &host->dma_ranges); + return 0; +out: + pci_free_resource_list(&resources); + return ret; } static int iproce_pcie_get_msi(struct iproc_pcie *pcie, -- cgit v1.2.3 From 322f03436692481993d389f539c016d20bb0fa1d Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Mon, 25 Mar 2019 16:42:55 +0100 Subject: PCI: qcom: Use default config space read function Move the device class fudge to a proper fixup function, and remove qcom_pcie_rd_own_conf() which has become useless. dw_pcie_setup_rc() already did the right thing, but it's broken on older qcom chips, such as 8064. Signed-off-by: Marc Gonzalez Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index a7f703556790..0ed235d560e3 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1129,25 +1129,8 @@ err_deinit: return ret; } -static int qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, - u32 *val) -{ - struct dw_pcie *pci = to_dw_pcie_from_pp(pp); - - /* the device class is not reported correctly from the register */ - if (where == PCI_CLASS_REVISION && size == 4) { - *val = readl(pci->dbi_base + PCI_CLASS_REVISION); - *val &= 0xff; /* keep revision id */ - *val |= PCI_CLASS_BRIDGE_PCI << 16; - return PCIBIOS_SUCCESSFUL; - } - - return dw_pcie_read(pci->dbi_base + where, size, val); -} - static const struct dw_pcie_host_ops qcom_pcie_dw_ops = { .host_init = qcom_pcie_host_init, - .rd_own_conf = qcom_pcie_rd_own_conf, }; /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */ @@ -1309,6 +1292,12 @@ static const struct of_device_id qcom_pcie_match[] = { { } }; +static void qcom_fixup_class(struct pci_dev *dev) +{ + dev->class = PCI_CLASS_BRIDGE_PCI << 8; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, PCI_ANY_ID, qcom_fixup_class); + static struct platform_driver qcom_pcie_driver = { .probe = qcom_pcie_probe, .driver = { -- cgit v1.2.3 From 3ebc269c197ee6a9788aeb76ebcc9132814a75e5 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:56:25 +0000 Subject: PCI: dwc: Fix dw_pcie_free_msi() if msi_irq is invalid Check msi_irq variable before calling irq_set_chained_handler() and irq_set_handler_data(), lest we call those functions for an invalid MSI IRQ. Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 25087d3c9a82..1040939f45b4 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -298,8 +298,10 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) void dw_pcie_free_msi(struct pcie_port *pp) { - irq_set_chained_handler(pp->msi_irq, NULL); - irq_set_handler_data(pp->msi_irq, NULL); + if (pp->msi_irq) { + irq_set_chained_handler(pp->msi_irq, NULL); + irq_set_handler_data(pp->msi_irq, NULL); + } irq_domain_remove(pp->msi_domain); irq_domain_remove(pp->irq_domain); -- cgit v1.2.3 From dc69a3d567941784c3d00e1d0834582b42b0b3e7 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:57:17 +0000 Subject: PCI: dwc: Free MSI IRQ page in dw_pcie_free_msi() To avoid a memory leak, free the page allocated for MSI IRQ in dw_pcie_free_msi(). Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 12 ++++++++---- drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 1040939f45b4..a71b874ae3c0 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -305,20 +305,24 @@ void dw_pcie_free_msi(struct pcie_port *pp) irq_domain_remove(pp->msi_domain); irq_domain_remove(pp->irq_domain); + + if (pp->msi_page) + __free_page(pp->msi_page); } void dw_pcie_msi_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct device *dev = pci->dev; - struct page *page; u64 msi_target; - page = alloc_page(GFP_KERNEL); - pp->msi_data = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + pp->msi_page = alloc_page(GFP_KERNEL); + pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE, + DMA_FROM_DEVICE); if (dma_mapping_error(dev, pp->msi_data)) { dev_err(dev, "Failed to map MSI data\n"); - __free_page(page); + __free_page(pp->msi_page); + pp->msi_page = NULL; return; } msi_target = (u64)pp->msi_data; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 377f4c0b52da..6fb0a1879932 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -179,6 +179,7 @@ struct pcie_port { struct irq_domain *irq_domain; struct irq_domain *msi_domain; dma_addr_t msi_data; + struct page *msi_page; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; raw_spinlock_t lock; -- cgit v1.2.3 From 9e2b5de5604a6ff2626c51e77014d92c9299722c Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:57:54 +0000 Subject: PCI: dwc: Free MSI in dw_pcie_host_init() error path If we ever did MSI-related initializations, we need to call dw_pcie_free_msi() in the error code path. Remove the IS_ENABLED(CONFIG_PCI_MSI) check for MSI init because pci_msi_enabled() already has a stub for !CONFIG_PCI_MSI. Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index a71b874ae3c0..acc9be5cf34a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -445,7 +445,7 @@ int dw_pcie_host_init(struct pcie_port *pp) if (ret) pci->num_viewport = 2; - if (IS_ENABLED(CONFIG_PCI_MSI) && pci_msi_enabled()) { + if (pci_msi_enabled()) { /* * If a specific SoC driver needs to change the * default number of vectors, it needs to implement @@ -483,7 +483,7 @@ int dw_pcie_host_init(struct pcie_port *pp) if (pp->ops->host_init) { ret = pp->ops->host_init(pp); if (ret) - goto error; + goto err_free_msi; } pp->root_bus_nr = pp->busn->start; @@ -497,7 +497,7 @@ int dw_pcie_host_init(struct pcie_port *pp) ret = pci_scan_root_bus_bridge(bridge); if (ret) - goto error; + goto err_free_msi; bus = bridge->bus; @@ -513,6 +513,9 @@ int dw_pcie_host_init(struct pcie_port *pp) pci_bus_add_devices(bus); return 0; +err_free_msi: + if (pci_msi_enabled() && !pp->ops->msi_host_init) + dw_pcie_free_msi(pp); error: pci_free_host_bridge(bridge); return ret; -- cgit v1.2.3 From e6fdd3bf5aecd8615f31a5128775b9abcf3e0d86 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:58:53 +0000 Subject: PCI: dwc: Use devm_pci_alloc_host_bridge() to simplify code Use devm_pci_alloc_host_bridge() to simplify the error code path. This also fixes a leak in the dw_pcie_host_init() error path. Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel CC: stable@vger.kernel.org # v4.13+ --- drivers/pci/controller/dwc/pcie-designware-host.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index acc9be5cf34a..dcc7405aff9a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -358,7 +358,7 @@ int dw_pcie_host_init(struct pcie_port *pp) dev_err(dev, "Missing *config* reg space\n"); } - bridge = pci_alloc_host_bridge(0); + bridge = devm_pci_alloc_host_bridge(dev, 0); if (!bridge) return -ENOMEM; @@ -369,7 +369,7 @@ int dw_pcie_host_init(struct pcie_port *pp) ret = devm_request_pci_bus_resources(dev, &bridge->windows); if (ret) - goto error; + return ret; /* Get the I/O and memory ranges from DT */ resource_list_for_each_entry_safe(win, tmp, &bridge->windows) { @@ -413,8 +413,7 @@ int dw_pcie_host_init(struct pcie_port *pp) resource_size(pp->cfg)); if (!pci->dbi_base) { dev_err(dev, "Error with ioremap\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } } @@ -425,8 +424,7 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->cfg0_base, pp->cfg0_size); if (!pp->va_cfg0_base) { dev_err(dev, "Error with ioremap in function\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } } @@ -436,8 +434,7 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->cfg1_size); if (!pp->va_cfg1_base) { dev_err(dev, "Error with ioremap\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } } @@ -460,14 +457,14 @@ int dw_pcie_host_init(struct pcie_port *pp) pp->num_vectors == 0) { dev_err(dev, "Invalid number of vectors\n"); - goto error; + return -EINVAL; } } if (!pp->ops->msi_host_init) { ret = dw_pcie_allocate_domains(pp); if (ret) - goto error; + return ret; if (pp->msi_irq) irq_set_chained_handler_and_data(pp->msi_irq, @@ -476,7 +473,7 @@ int dw_pcie_host_init(struct pcie_port *pp) } else { ret = pp->ops->msi_host_init(pp); if (ret < 0) - goto error; + return ret; } } @@ -516,8 +513,6 @@ int dw_pcie_host_init(struct pcie_port *pp) err_free_msi: if (pci_msi_enabled() && !pp->ops->msi_host_init) dw_pcie_free_msi(pp); -error: - pci_free_host_bridge(bridge); return ret; } -- cgit v1.2.3 From fe23274f72f4e3be93134aac0ae1e1fd522f438a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 29 Mar 2019 11:59:26 +0000 Subject: PCI: dwc: Save root bus for driver remove hooks Currently DWC host does not support the remove callback, but nothing prevents us from supporting it. Save the root bus for clean up work in driver remove code paths to allow DWC host drivers to implement their remove hook as, eg: static int foo_pcie_remove(struct platform_device *pdev) { ... pci_stop_root_bus(pp->root_bus); pci_remove_root_bus(pp->root_bus); dw_pcie_free_msi(pp); ... } Signed-off-by: Jisheng Zhang Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Acked-by: Gustavo Pimentel --- drivers/pci/controller/dwc/pcie-designware-host.c | 12 ++++++------ drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index dcc7405aff9a..3e4169e738a5 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -341,7 +341,7 @@ int dw_pcie_host_init(struct pcie_port *pp) struct device_node *np = dev->of_node; struct platform_device *pdev = to_platform_device(dev); struct resource_entry *win, *tmp; - struct pci_bus *bus, *child; + struct pci_bus *child; struct pci_host_bridge *bridge; struct resource *cfg_res; int ret; @@ -496,18 +496,18 @@ int dw_pcie_host_init(struct pcie_port *pp) if (ret) goto err_free_msi; - bus = bridge->bus; + pp->root_bus = bridge->bus; if (pp->ops->scan_bus) pp->ops->scan_bus(pp); - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); + pci_bus_size_bridges(pp->root_bus); + pci_bus_assign_resources(pp->root_bus); - list_for_each_entry(child, &bus->children, node) + list_for_each_entry(child, &pp->root_bus->children, node) pcie_bus_configure_settings(child); - pci_bus_add_devices(bus); + pci_bus_add_devices(pp->root_bus); return 0; err_free_msi: diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 6fb0a1879932..adff0c713665 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -182,6 +182,7 @@ struct pcie_port { struct page *msi_page; u32 num_vectors; u32 irq_mask[MAX_MSI_CTRLS]; + struct pci_bus *root_bus; raw_spinlock_t lock; DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); }; -- cgit v1.2.3 From 1b8df7aa78748ddafc6f3b16a6328a3c500087b3 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 4 Apr 2019 18:45:17 +0200 Subject: PCI: imx6: Allow asynchronous probing Establishing a PCIe link can take a while; allow asynchronous probing so that link establishment can happen in the background while other devices are being probed. Signed-off-by: Lucas Stach Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Fabio Estevam --- drivers/pci/controller/dwc/pci-imx6.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/pci/controller') diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 3d627f94a166..2eb39d5de4f6 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -1279,6 +1279,7 @@ static struct platform_driver imx6_pcie_driver = { .of_match_table = imx6_pcie_of_match, .suppress_bind_attrs = true, .pm = &imx6_pcie_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = imx6_pcie_probe, .shutdown = imx6_pcie_shutdown, -- cgit v1.2.3