* [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller @ 2018-01-10 22:47 Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile Cyrille Pitchen ` (5 more replies) 0 siblings, 6 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw) To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen Hi all, this series of patches adds support to the Cadence PCIe controller. It was tested on a ARM64 platform emulated by a Palladium running the pci-next kernel. The host mode was tested with some PCIe devices connected to the Palladium through a speed-bridge. Some of those devices were a USB host controller and a SATA controller. The PCIe host controller was also tested with a second controller configured in endpoint mode and connected back to back to the first controller. The EndPoint Controller (EPC) driver was removed only because I didn't have time to take all Kishon's comments into account. However, using a fixed patch based on patch 7 of the v2 series + another patch fixing the EPF device name chosen by pci_epf_make(), I was abled to probe both function 0 and function 1 of the of the 2nd Cadence PCIe controller configured in endpoint mode (new hardware design since v2 so function 1 is now available). Currently I'm facing 2 issues, which I didn't have enough time to investigate and to fix yet: 1 - when the vendor:device IDs are set to 104c:b500 for both functions, then I remove both devfn (echo 1 > /sys/bus/pci/devices/$BDF/remove) before scanning the PCI bus again (echo 1 > /sys/bus/pci/rescan), the PCI enumeration fails reporting that the PCI memory is exhausted. 2 - when I set the vendor:device IDs to 104c:0100 for function 0 and 104c:b500 and remove only function 1 before scanning the PCI bus again, I now pass the PCI enumeration. I also pass the 'pcitest -b <BAR>' test but I fail on the MSI test ('pcitest -m <MSI>'). I'm still investigating on those issues. Best regards, Cyrille ChangeLog v2 -> v3: - rebase on today's linux-pci/next (20180110) patch1: - rework the commit message of patch 1 and add two new comments on why endpoint library users must be linked after the endpoint library itself and why the dwc rule uses obj-y instead of obj-$(CONFIG_PCIE_CONFIG_DW). - update patch 1 to add missing ifdef CONFIG_PCI / endif in drivers/pci/dwc/Makefile around the obj-$(CONFIG_ARM64) += pcie-hisi.o rule, like for the other obj-$(CONFIG_ARM64) rules in drivers/pci/host/Makefile. patch2: unchanged patch3: - update patch 3 so the bridge hooks/members initialization is left to the host bridges probe routines. patch4: unchanged patch5: - collect 'Reviewed-by' tag from Rob Herring for the DT bindings. patch6: - remove explanation in the commit message on why obj-$(CONFIG_PCIE_CANDENCE) is placed after obj-$(CONFIG_PCI_ENDPOINT) in drivers/pci/Makefile since a comment on it has been added into patch1. - remove menuconfig PCI_CADENCE in drivers/pci/cadence/Kconfig to match drivers/pci/dwc/Kconfig. - adapt patch6 to the changes done in patch3 for the pci_host_probe() function. v1 -> v2: - add new properties in the device-tree bindings: 'cdns,max-outbound-regions' and 'cdns,no-bar-match-nbits'. - add a new patch to regroup all makefile rules in drivers/pci/Makefile, hence cleaning drivers/Makefile up. - change the license text to use the recommanded format: // SPDX-License-Identifier: GPL-2.0 - add a new patch updating the API of the EPC library to add support to multi-function devices. - add a 2 new patches to share more common code between host controller drivers - remove some useless tests - add more comments in both drivers. - fix DT bindings examples - remove useless init of the primary, secondary and sub-ordinate bus numbers in the PCI configuration space of the root port. - remove cdns_pcie_ep_stop() function and rework cdns_pcie_ep_start() function Cyrille Pitchen (5): PCI: Regroup all PCI related entries into drivers/pci/Makefile PCI: OF: Add generic function to parse and allocate PCI resources PCI: Add generic function to probe PCI host controllers PCI: Add vendor ID for Cadence PCI: cadence: Add host driver for Cadence PCIe controller Scott Telford (1): dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller .../bindings/pci/cdns,cdns-pcie-host.txt | 60 ++++ MAINTAINERS | 7 + drivers/Makefile | 5 +- drivers/pci/Kconfig | 2 + drivers/pci/Makefile | 14 +- drivers/pci/cadence/Kconfig | 16 + drivers/pci/cadence/Makefile | 3 + drivers/pci/cadence/pcie-cadence-host.c | 336 +++++++++++++++++++++ drivers/pci/cadence/pcie-cadence.c | 68 +++++ drivers/pci/cadence/pcie-cadence.h | 196 ++++++++++++ drivers/pci/dwc/Makefile | 2 + drivers/pci/host/Makefile | 2 + drivers/pci/host/pci-host-common.c | 74 +---- drivers/pci/of.c | 51 ++++ drivers/pci/probe.c | 33 ++ include/linux/pci.h | 10 + include/linux/pci_ids.h | 2 + 17 files changed, 805 insertions(+), 76 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt create mode 100644 drivers/pci/cadence/Kconfig create mode 100644 drivers/pci/cadence/Makefile create mode 100644 drivers/pci/cadence/pcie-cadence-host.c create mode 100644 drivers/pci/cadence/pcie-cadence.c create mode 100644 drivers/pci/cadence/pcie-cadence.h -- 2.11.0 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile 2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen @ 2018-01-10 22:47 ` Cyrille Pitchen [not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> ` (4 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw) To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen Clean up drivers/Makefile by moving the pci/endpoint and pci/dwc entries from drivers/Makefile into drivers/pci/Makefile. Since we don't want to introduce any dependency between CONFIG_PCI and CONFIG_PCI_ENDPOINT, we now always execute drivers/pci/Makefile. Hence all Makefiles in drivers/pci/ were updated accordingly so no file is compiled when CONFIG_PCI is not defined. Also, we add a comment to reinforce that EPC and EPF libraries must be initialized before their users. Hence built-in EPC drivers, such as those of Designware, are linked after the endpoint core libraries. Finally, we add another comment to explain why obj-y has been chosen instead of obj-$(CONFIG_PCIE_DW) to parse the dwc/ sub-folder. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> --- drivers/Makefile | 5 +---- drivers/pci/Kconfig | 1 + drivers/pci/Makefile | 13 ++++++++++--- drivers/pci/dwc/Makefile | 2 ++ drivers/pci/host/Makefile | 2 ++ 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/Makefile b/drivers/Makefile index e06f7f633f73..8189b1edec00 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -16,10 +16,7 @@ obj-$(CONFIG_PINCTRL) += pinctrl/ obj-$(CONFIG_GPIOLIB) += gpio/ obj-y += pwm/ -obj-$(CONFIG_PCI) += pci/ -obj-$(CONFIG_PCI_ENDPOINT) += pci/endpoint/ -# PCI dwc controller drivers -obj-y += pci/dwc/ +obj-y += pci/ obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_RAPIDIO) += rapidio/ diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index bda151788f3f..7eeb969ab86a 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -125,6 +125,7 @@ config PCI_PASID config PCI_LABEL def_bool y if (DMI || ACPI) + depends on PCI select NLS config PCI_HYPERV diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index c7819b973df7..ddb5aa6640d7 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -3,12 +3,15 @@ # Makefile for the PCI bus specific drivers. # -obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \ +obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o remove.o pci.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ irq.o vpd.o setup-bus.o vc.o mmap.o setup-irq.o +ifdef CONFIG_PCI obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += slot.o +obj-$(CONFIG_OF) += of.o +endif obj-$(CONFIG_PCI_QUIRKS) += quirks.o @@ -44,10 +47,14 @@ obj-$(CONFIG_PCI_ECAM) += ecam.o obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o -obj-$(CONFIG_OF) += of.o - ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG # PCI host controller drivers obj-y += host/ obj-y += switch/ + +obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ + +# Endpoint library must be initialized before its users +# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW +obj-y += dwc/ diff --git a/drivers/pci/dwc/Makefile b/drivers/pci/dwc/Makefile index a9d8a6fb48e3..5d2ce72c7a52 100644 --- a/drivers/pci/dwc/Makefile +++ b/drivers/pci/dwc/Makefile @@ -25,4 +25,6 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o # ARM64 and use internal ifdefs to only build the pieces we need # depending on whether ACPI, the DT driver, or both are enabled. +ifdef CONFIG_PCI obj-$(CONFIG_ARM64) += pcie-hisi.o +endif diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 34ec1d88f961..3b1059190867 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -34,6 +34,8 @@ obj-$(CONFIG_VMD) += vmd.o # ARM64 and use internal ifdefs to only build the pieces we need # depending on whether ACPI, the DT driver, or both are enabled. +ifdef CONFIG_PCI obj-$(CONFIG_ARM64) += pci-thunder-ecam.o obj-$(CONFIG_ARM64) += pci-thunder-pem.o obj-$(CONFIG_ARM64) += pci-xgene.o +endif -- 2.11.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* [PATCH v3 2/6] PCI: OF: Add generic function to parse and allocate PCI resources [not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2018-01-10 22:47 ` Cyrille Pitchen 0 siblings, 0 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw) To: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0, lorenzo.pieralisi-5wv7dgnIgG8, linux-pci-u79uwXL29TY76Z2rM5mHXA Cc: adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ, dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ, eandrews-vna1KIf7WgpBDgjK7y7TUQ, thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0, linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA, Cyrille Pitchen The patch moves the gen_pci_parse_request_of_pci_ranges() function from drivers/pci/host/pci-host-common.c into drivers/pci/of.c to easily share common source code between PCI host drivers. Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> --- drivers/pci/host/pci-host-common.c | 49 ++---------------------------------- drivers/pci/of.c | 51 ++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 9 +++++++ 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c index c4b891c84703..a613ea310e76 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/host/pci-host-common.c @@ -24,50 +24,6 @@ #include <linux/pci-ecam.h> #include <linux/platform_device.h> -static int gen_pci_parse_request_of_pci_ranges(struct device *dev, - struct list_head *resources, struct resource **bus_range) -{ - int err, res_valid = 0; - struct device_node *np = dev->of_node; - resource_size_t iobase; - struct resource_entry *win, *tmp; - - err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase); - if (err) - return err; - - err = devm_request_pci_bus_resources(dev, resources); - if (err) - return err; - - resource_list_for_each_entry_safe(win, tmp, resources) { - struct resource *res = win->res; - - switch (resource_type(res)) { - case IORESOURCE_IO: - err = pci_remap_iospace(res, iobase); - if (err) { - dev_warn(dev, "error %d: failed to map resource %pR\n", - err, res); - resource_list_destroy_entry(win); - } - break; - case IORESOURCE_MEM: - res_valid |= !(res->flags & IORESOURCE_PREFETCH); - break; - case IORESOURCE_BUS: - *bus_range = res; - break; - } - } - - if (res_valid) - return 0; - - dev_err(dev, "non-prefetchable memory resource required\n"); - return -EINVAL; -} - static void gen_pci_unmap_cfg(void *ptr) { pci_ecam_free((struct pci_config_window *)ptr); @@ -82,9 +38,9 @@ static struct pci_config_window *gen_pci_init(struct device *dev, struct pci_config_window *cfg; /* Parse our PCI ranges and request their resources */ - err = gen_pci_parse_request_of_pci_ranges(dev, resources, &bus_range); + err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); if (err) - goto err_out; + return ERR_PTR(err); err = of_address_to_resource(dev->of_node, 0, &cfgres); if (err) { @@ -135,7 +91,6 @@ int pci_host_common_probe(struct platform_device *pdev, of_pci_check_probe_only(); /* Parse and map our Configuration Space windows */ - INIT_LIST_HEAD(&resources); cfg = gen_pci_init(dev, &resources, ops); if (IS_ERR(cfg)) return PTR_ERR(cfg); diff --git a/drivers/pci/of.c b/drivers/pci/of.c index e112da11630e..54e210501b73 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -88,3 +88,54 @@ struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) return NULL; #endif } + +int pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *resources, + struct resource **bus_range) +{ + int err, res_valid = 0; + struct device_node *np = dev->of_node; + resource_size_t iobase; + struct resource_entry *win, *tmp; + + INIT_LIST_HEAD(resources); + err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase); + if (err) + return err; + + err = devm_request_pci_bus_resources(dev, resources); + if (err) + goto out_release_res; + + resource_list_for_each_entry_safe(win, tmp, resources) { + struct resource *res = win->res; + + switch (resource_type(res)) { + case IORESOURCE_IO: + err = pci_remap_iospace(res, iobase); + if (err) { + dev_warn(dev, "error %d: failed to map resource %pR\n", + err, res); + resource_list_destroy_entry(win); + } + break; + case IORESOURCE_MEM: + res_valid |= !(res->flags & IORESOURCE_PREFETCH); + break; + case IORESOURCE_BUS: + if (bus_range) + *bus_range = res; + break; + } + } + + if (res_valid) + return 0; + + dev_err(dev, "non-prefetchable memory resource required\n"); + err = -EINVAL; + + out_release_res: + pci_free_resource_list(resources); + return err; +} diff --git a/include/linux/pci.h b/include/linux/pci.h index 978aad7841e5..a1b0672fd38a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2163,6 +2163,9 @@ void pci_release_of_node(struct pci_dev *dev); void pci_set_bus_of_node(struct pci_bus *bus); void pci_release_bus_of_node(struct pci_bus *bus); struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); +int pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *resources, + struct resource **bus_range); /* Arch may override this (weak) */ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus); @@ -2187,6 +2190,12 @@ static inline struct device_node * pci_device_to_OF_node(const struct pci_dev *pdev) { return NULL; } static inline struct irq_domain * pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } +static inline int pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *resources, + struct resource **bus_range) +{ + return -EINVAL; +} #endif /* CONFIG_OF */ #ifdef CONFIG_ACPI -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers 2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile Cyrille Pitchen [not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2018-01-10 22:47 ` Cyrille Pitchen 2018-01-16 15:25 ` Lorenzo Pieralisi 2018-01-10 22:47 ` [PATCH v3 4/6] PCI: Add vendor ID for Cadence Cyrille Pitchen ` (2 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw) To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen This patchs moves generic source code from drivers/pci/host/pci-host-common.c into drivers/pci/probe.c. Indeed the extracted lines of code were duplicated by many host controller drivers. Regrouping them into a generic function gives a change to properly share this code without introducing a useless dependency to PCI_HOST_COMMON, which selects PCI_ECAM when not needed by most host controller drivers. We also add a missing call of pci_free_resource_list() from pci_host_common_probe() when probing fails, as done inside gen_pci_init() when this later function fails. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> --- drivers/pci/host/pci-host-common.c | 25 +++---------------------- drivers/pci/probe.c | 33 +++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c index a613ea310e76..df25b4a4edaf 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/host/pci-host-common.c @@ -72,7 +72,6 @@ int pci_host_common_probe(struct platform_device *pdev, const char *type; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct pci_bus *bus, *child; struct pci_host_bridge *bridge; struct pci_config_window *cfg; struct list_head resources; @@ -107,29 +106,11 @@ int pci_host_common_probe(struct platform_device *pdev, bridge->map_irq = of_irq_parse_and_map_pci; bridge->swizzle_irq = pci_common_swizzle; - ret = pci_scan_root_bus_bridge(bridge); - if (ret < 0) { - dev_err(dev, "Scanning root bridge failed"); + ret = pci_host_probe(bridge); + if (ret) { + pci_free_resource_list(&resources); return ret; } - bus = bridge->bus; - - /* - * We insert PCI resources into the iomem_resource and - * ioport_resource trees in either pci_bus_claim_resources() - * or pci_bus_assign_resources(). - */ - if (pci_has_flag(PCI_PROBE_ONLY)) { - pci_bus_claim_resources(bus); - } else { - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); - - list_for_each_entry(child, &bus->children, node) - pcie_bus_configure_settings(child); - } - - pci_bus_add_devices(bus); return 0; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 1360db508035..178328d06a32 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2685,6 +2685,39 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, } EXPORT_SYMBOL_GPL(pci_create_root_bus); +int pci_host_probe(struct pci_host_bridge *bridge) +{ + struct pci_bus *bus, *child; + int ret; + + ret = pci_scan_root_bus_bridge(bridge); + if (ret < 0) { + dev_err(bridge->dev.parent, "Scanning root bridge failed"); + return ret; + } + + bus = bridge->bus; + + /* + * We insert PCI resources into the iomem_resource and + * ioport_resource trees in either pci_bus_claim_resources() + * or pci_bus_assign_resources(). + */ + if (pci_has_flag(PCI_PROBE_ONLY)) { + pci_bus_claim_resources(bus); + } else { + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + } + + pci_bus_add_devices(bus); + return 0; +} +EXPORT_SYMBOL_GPL(pci_host_probe); + int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) { struct resource *res = &b->busn_res; diff --git a/include/linux/pci.h b/include/linux/pci.h index a1b0672fd38a..0ca261fda900 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -879,6 +879,7 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); struct pci_bus *pci_create_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources); +int pci_host_probe(struct pci_host_bridge *bridge); int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax); int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax); void pci_bus_release_busn_res(struct pci_bus *b); -- 2.11.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers 2018-01-10 22:47 ` [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers Cyrille Pitchen @ 2018-01-16 15:25 ` Lorenzo Pieralisi 2018-01-18 22:58 ` Cyrille Pitchen 0 siblings, 1 reply; 14+ messages in thread From: Lorenzo Pieralisi @ 2018-01-16 15:25 UTC (permalink / raw) To: Cyrille Pitchen Cc: bhelgaas, kishon, linux-pci, adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree On Wed, Jan 10, 2018 at 11:47:32PM +0100, Cyrille Pitchen wrote: > This patchs moves generic source code from > drivers/pci/host/pci-host-common.c into drivers/pci/probe.c. > > Indeed the extracted lines of code were duplicated by many host > controller drivers. Regrouping them into a generic function gives a > change to properly share this code without introducing a useless > dependency to PCI_HOST_COMMON, which selects PCI_ECAM when not needed by > most host controller drivers. > > We also add a missing call of pci_free_resource_list() from > pci_host_common_probe() when probing fails, as done inside gen_pci_init() I have to ask you to split this change into another patch. First add the missing pci_free_resource_list() then add this patch. Do you have time to respin quickly ? I would like to merge this series for v4.16. Thanks, Lorenzo > when this later function fails. > > Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> > --- > drivers/pci/host/pci-host-common.c | 25 +++---------------------- > drivers/pci/probe.c | 33 +++++++++++++++++++++++++++++++++ > include/linux/pci.h | 1 + > 3 files changed, 37 insertions(+), 22 deletions(-) > > diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c > index a613ea310e76..df25b4a4edaf 100644 > --- a/drivers/pci/host/pci-host-common.c > +++ b/drivers/pci/host/pci-host-common.c > @@ -72,7 +72,6 @@ int pci_host_common_probe(struct platform_device *pdev, > const char *type; > struct device *dev = &pdev->dev; > struct device_node *np = dev->of_node; > - struct pci_bus *bus, *child; > struct pci_host_bridge *bridge; > struct pci_config_window *cfg; > struct list_head resources; > @@ -107,29 +106,11 @@ int pci_host_common_probe(struct platform_device *pdev, > bridge->map_irq = of_irq_parse_and_map_pci; > bridge->swizzle_irq = pci_common_swizzle; > > - ret = pci_scan_root_bus_bridge(bridge); > - if (ret < 0) { > - dev_err(dev, "Scanning root bridge failed"); > + ret = pci_host_probe(bridge); > + if (ret) { > + pci_free_resource_list(&resources); > return ret; > } > > - bus = bridge->bus; > - > - /* > - * We insert PCI resources into the iomem_resource and > - * ioport_resource trees in either pci_bus_claim_resources() > - * or pci_bus_assign_resources(). > - */ > - if (pci_has_flag(PCI_PROBE_ONLY)) { > - pci_bus_claim_resources(bus); > - } else { > - pci_bus_size_bridges(bus); > - pci_bus_assign_resources(bus); > - > - list_for_each_entry(child, &bus->children, node) > - pcie_bus_configure_settings(child); > - } > - > - pci_bus_add_devices(bus); > return 0; > } > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index 1360db508035..178328d06a32 100644 > --- a/drivers/pci/probe.c > +++ b/drivers/pci/probe.c > @@ -2685,6 +2685,39 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, > } > EXPORT_SYMBOL_GPL(pci_create_root_bus); > > +int pci_host_probe(struct pci_host_bridge *bridge) > +{ > + struct pci_bus *bus, *child; > + int ret; > + > + ret = pci_scan_root_bus_bridge(bridge); > + if (ret < 0) { > + dev_err(bridge->dev.parent, "Scanning root bridge failed"); > + return ret; > + } > + > + bus = bridge->bus; > + > + /* > + * We insert PCI resources into the iomem_resource and > + * ioport_resource trees in either pci_bus_claim_resources() > + * or pci_bus_assign_resources(). > + */ > + if (pci_has_flag(PCI_PROBE_ONLY)) { > + pci_bus_claim_resources(bus); > + } else { > + pci_bus_size_bridges(bus); > + pci_bus_assign_resources(bus); > + > + list_for_each_entry(child, &bus->children, node) > + pcie_bus_configure_settings(child); > + } > + > + pci_bus_add_devices(bus); > + return 0; > +} > +EXPORT_SYMBOL_GPL(pci_host_probe); > + > int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) > { > struct resource *res = &b->busn_res; > diff --git a/include/linux/pci.h b/include/linux/pci.h > index a1b0672fd38a..0ca261fda900 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -879,6 +879,7 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); > struct pci_bus *pci_create_root_bus(struct device *parent, int bus, > struct pci_ops *ops, void *sysdata, > struct list_head *resources); > +int pci_host_probe(struct pci_host_bridge *bridge); > int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax); > int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax); > void pci_bus_release_busn_res(struct pci_bus *b); > -- > 2.11.0 > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers 2018-01-16 15:25 ` Lorenzo Pieralisi @ 2018-01-18 22:58 ` Cyrille Pitchen 0 siblings, 0 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-18 22:58 UTC (permalink / raw) To: Lorenzo Pieralisi Cc: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0, linux-pci-u79uwXL29TY76Z2rM5mHXA, adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ, dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ, eandrews-vna1KIf7WgpBDgjK7y7TUQ, thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0, linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA Hi Lorenzo, Le 16/01/2018 à 16:25, Lorenzo Pieralisi a écrit : > On Wed, Jan 10, 2018 at 11:47:32PM +0100, Cyrille Pitchen wrote: >> This patchs moves generic source code from >> drivers/pci/host/pci-host-common.c into drivers/pci/probe.c. >> >> Indeed the extracted lines of code were duplicated by many host >> controller drivers. Regrouping them into a generic function gives a >> change to properly share this code without introducing a useless >> dependency to PCI_HOST_COMMON, which selects PCI_ECAM when not needed by >> most host controller drivers. >> >> We also add a missing call of pci_free_resource_list() from >> pci_host_common_probe() when probing fails, as done inside gen_pci_init() > I have to ask you to split this change into another patch. > > First add the missing pci_free_resource_list() then add this patch. > > Do you have time to respin quickly ? I would like to merge this > series for v4.16. > Sorry, I've been a little bit busy. I've just done it and submit v4. patch 3 from v3 split into patches 3 and 4 in v4. Best regards, Cyrille > Thanks, > Lorenzo > >> when this later function fails. >> >> Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> >> --- >> drivers/pci/host/pci-host-common.c | 25 +++---------------------- >> drivers/pci/probe.c | 33 +++++++++++++++++++++++++++++++++ >> include/linux/pci.h | 1 + >> 3 files changed, 37 insertions(+), 22 deletions(-) >> >> diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c >> index a613ea310e76..df25b4a4edaf 100644 >> --- a/drivers/pci/host/pci-host-common.c >> +++ b/drivers/pci/host/pci-host-common.c >> @@ -72,7 +72,6 @@ int pci_host_common_probe(struct platform_device *pdev, >> const char *type; >> struct device *dev = &pdev->dev; >> struct device_node *np = dev->of_node; >> - struct pci_bus *bus, *child; >> struct pci_host_bridge *bridge; >> struct pci_config_window *cfg; >> struct list_head resources; >> @@ -107,29 +106,11 @@ int pci_host_common_probe(struct platform_device *pdev, >> bridge->map_irq = of_irq_parse_and_map_pci; >> bridge->swizzle_irq = pci_common_swizzle; >> >> - ret = pci_scan_root_bus_bridge(bridge); >> - if (ret < 0) { >> - dev_err(dev, "Scanning root bridge failed"); >> + ret = pci_host_probe(bridge); >> + if (ret) { >> + pci_free_resource_list(&resources); >> return ret; >> } >> >> - bus = bridge->bus; >> - >> - /* >> - * We insert PCI resources into the iomem_resource and >> - * ioport_resource trees in either pci_bus_claim_resources() >> - * or pci_bus_assign_resources(). >> - */ >> - if (pci_has_flag(PCI_PROBE_ONLY)) { >> - pci_bus_claim_resources(bus); >> - } else { >> - pci_bus_size_bridges(bus); >> - pci_bus_assign_resources(bus); >> - >> - list_for_each_entry(child, &bus->children, node) >> - pcie_bus_configure_settings(child); >> - } >> - >> - pci_bus_add_devices(bus); >> return 0; >> } >> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c >> index 1360db508035..178328d06a32 100644 >> --- a/drivers/pci/probe.c >> +++ b/drivers/pci/probe.c >> @@ -2685,6 +2685,39 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, >> } >> EXPORT_SYMBOL_GPL(pci_create_root_bus); >> >> +int pci_host_probe(struct pci_host_bridge *bridge) >> +{ >> + struct pci_bus *bus, *child; >> + int ret; >> + >> + ret = pci_scan_root_bus_bridge(bridge); >> + if (ret < 0) { >> + dev_err(bridge->dev.parent, "Scanning root bridge failed"); >> + return ret; >> + } >> + >> + bus = bridge->bus; >> + >> + /* >> + * We insert PCI resources into the iomem_resource and >> + * ioport_resource trees in either pci_bus_claim_resources() >> + * or pci_bus_assign_resources(). >> + */ >> + if (pci_has_flag(PCI_PROBE_ONLY)) { >> + pci_bus_claim_resources(bus); >> + } else { >> + pci_bus_size_bridges(bus); >> + pci_bus_assign_resources(bus); >> + >> + list_for_each_entry(child, &bus->children, node) >> + pcie_bus_configure_settings(child); >> + } >> + >> + pci_bus_add_devices(bus); >> + return 0; >> +} >> +EXPORT_SYMBOL_GPL(pci_host_probe); >> + >> int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) >> { >> struct resource *res = &b->busn_res; >> diff --git a/include/linux/pci.h b/include/linux/pci.h >> index a1b0672fd38a..0ca261fda900 100644 >> --- a/include/linux/pci.h >> +++ b/include/linux/pci.h >> @@ -879,6 +879,7 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); >> struct pci_bus *pci_create_root_bus(struct device *parent, int bus, >> struct pci_ops *ops, void *sysdata, >> struct list_head *resources); >> +int pci_host_probe(struct pci_host_bridge *bridge); >> int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax); >> int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax); >> void pci_bus_release_busn_res(struct pci_bus *b); >> -- >> 2.11.0 >> > -- Cyrille Pitchen, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 4/6] PCI: Add vendor ID for Cadence 2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen ` (2 preceding siblings ...) 2018-01-10 22:47 ` [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers Cyrille Pitchen @ 2018-01-10 22:47 ` Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen 5 siblings, 0 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw) To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen This patch adds a new PCI vendor ID for Cadence. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> --- include/linux/pci_ids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ab20dc5db423..eb13e84e1fef 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2381,6 +2381,8 @@ #define PCI_VENDOR_ID_LENOVO 0x17aa +#define PCI_VENDOR_ID_CDNS 0x17cd + #define PCI_VENDOR_ID_ARECA 0x17d3 #define PCI_DEVICE_ID_ARECA_1110 0x1110 #define PCI_DEVICE_ID_ARECA_1120 0x1120 -- 2.11.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller 2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen ` (3 preceding siblings ...) 2018-01-10 22:47 ` [PATCH v3 4/6] PCI: Add vendor ID for Cadence Cyrille Pitchen @ 2018-01-10 22:47 ` Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen 5 siblings, 0 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw) To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen From: Scott Telford <stelford@cadence.com> This patch adds documentation for the DT bindings of the Cadence PCIe controller when configured in host (Root Complex) mode. Signed-off-by: Scott Telford <stelford@cadence.com> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> Reviewed-by: Rob Herring <robh@kernel.org> --- .../bindings/pci/cdns,cdns-pcie-host.txt | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt new file mode 100644 index 000000000000..20a33f38f69d --- /dev/null +++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.txt @@ -0,0 +1,60 @@ +* Cadence PCIe host controller + +This PCIe controller inherits the base properties defined in +host-generic-pci.txt. + +Required properties: +- compatible: Should contain "cdns,cdns-pcie-host" to identify the IP used. +- reg: Should contain the controller register base address, PCIe configuration + window base address, and AXI interface region base address respectively. +- reg-names: Must be "reg", "cfg" and "mem" respectively. +- #address-cells: Set to <3> +- #size-cells: Set to <2> +- device_type: Set to "pci" +- ranges: Ranges for the PCI memory and I/O regions +- #interrupt-cells: Set to <1> +- interrupt-map-mask and interrupt-map: Standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers. + +Optional properties: +- cdns,max-outbound-regions: Set to maximum number of outbound regions + (default 32) +- cdns,no-bar-match-nbits: Set into the no BAR match register to configure the + number of least significant bits kept during inbound (PCIe -> AXI) address + translations (default 32) +- vendor-id: The PCI vendor ID (16 bits, default is design dependent) +- device-id: The PCI device ID (16 bits, default is design dependent) + +Example: + +pcie@fb000000 { + compatible = "cdns,cdns-pcie-host"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + linux,pci-domain = <0>; + cdns,max-outbound-regions = <16>; + cdns,no-bar-match-nbits = <32>; + vendor-id = /bits/ 16 <0x17cd>; + device-id = /bits/ 16 <0x0200>; + + reg = <0x0 0xfb000000 0x0 0x01000000>, + <0x0 0x41000000 0x0 0x00001000>, + <0x0 0x40000000 0x0 0x04000000>; + reg-names = "reg", "cfg", "mem"; + + ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>, + <0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>; + + #interrupt-cells = <0x1>; + + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 14 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 15 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 16 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 17 0x1>; + + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + + msi-parent = <&its_pci>; +}; -- 2.11.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller 2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen ` (4 preceding siblings ...) 2018-01-10 22:47 ` [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller Cyrille Pitchen @ 2018-01-10 22:47 ` Cyrille Pitchen 2018-01-16 11:16 ` Kishon Vijay Abraham I 2018-01-16 16:07 ` Lorenzo Pieralisi 5 siblings, 2 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-10 22:47 UTC (permalink / raw) To: bhelgaas, kishon, lorenzo.pieralisi, linux-pci Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree, Cyrille Pitchen This patch adds support to the Cadence PCIe controller in host mode. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> --- MAINTAINERS | 7 + drivers/pci/Kconfig | 1 + drivers/pci/Makefile | 1 + drivers/pci/cadence/Kconfig | 16 ++ drivers/pci/cadence/Makefile | 3 + drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++ drivers/pci/cadence/pcie-cadence.c | 68 +++++++ drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++ 8 files changed, 628 insertions(+) create mode 100644 drivers/pci/cadence/Kconfig create mode 100644 drivers/pci/cadence/Makefile create mode 100644 drivers/pci/cadence/pcie-cadence-host.c create mode 100644 drivers/pci/cadence/pcie-cadence.c create mode 100644 drivers/pci/cadence/pcie-cadence.h diff --git a/MAINTAINERS b/MAINTAINERS index 13945646b95d..cc24c74a946e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10402,6 +10402,13 @@ S: Maintained F: Documentation/devicetree/bindings/pci/pci-armada8k.txt F: drivers/pci/dwc/pcie-armada8k.c +PCI DRIVER FOR CADENCE PCIE IP +M: Alan Douglas <adouglas@cadence.com> +L: linux-pci@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pci/cdns,*.txt +F: drivers/pci/cadence/pcie-cadence* + PCI DRIVER FOR FREESCALE LAYERSCAPE M: Minghuan Lian <minghuan.Lian@freescale.com> M: Mingkai Hu <mingkai.hu@freescale.com> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 7eeb969ab86a..dee90cc1dcaf 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -136,6 +136,7 @@ config PCI_HYPERV PCI devices from a PCI backend to support PCI driver domains. source "drivers/pci/hotplug/Kconfig" +source "drivers/pci/cadence/Kconfig" source "drivers/pci/dwc/Kconfig" source "drivers/pci/host/Kconfig" source "drivers/pci/endpoint/Kconfig" diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index ddb5aa6640d7..941970936840 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,5 +56,6 @@ obj-y += switch/ obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ # Endpoint library must be initialized before its users +obj-$(CONFIG_PCIE_CADENCE) += cadence/ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW obj-y += dwc/ diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig new file mode 100644 index 000000000000..0123d384a628 --- /dev/null +++ b/drivers/pci/cadence/Kconfig @@ -0,0 +1,16 @@ +menu "Cadence PCIe controllers support" + +config PCIE_CADENCE + bool + +config PCIE_CADENCE_HOST + bool "Cadence PCIe host controller" + depends on OF + select IRQ_DOMAIN + select PCIE_CADENCE + help + Say Y here if you want to support the Cadence PCIe controller in host + mode. This PCIe controller may be embedded into many different vendors + SoCs. + +endmenu diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile new file mode 100644 index 000000000000..589601a8ff89 --- /dev/null +++ b/drivers/pci/cadence/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o +obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/cadence/pcie-cadence-host.c new file mode 100644 index 000000000000..26caf8963e3c --- /dev/null +++ b/drivers/pci/cadence/pcie-cadence-host.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Cadence +// Cadence PCIe host controller driver. +// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> + +#include <linux/kernel.h> +#include <linux/of_address.h> +#include <linux/of_pci.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include "pcie-cadence.h" + +/** + * struct cdns_pcie_rc - private data for this PCIe Root Complex driver + * @pcie: Cadence PCIe controller + * @dev: pointer to PCIe device + * @cfg_res: start/end offsets in the physical system memory to map PCI + * configuration space accesses + * @bus_range: first/last buses behind the PCIe host controller + * @cfg_base: IO mapped window to access the PCI configuration space of a + * single function at a time + * @max_regions: maximum number of regions supported by the hardware + * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address + * translation (nbits sets into the "no BAR match" register) + * @vendor_id: PCI vendor ID + * @device_id: PCI device ID + */ +struct cdns_pcie_rc { + struct cdns_pcie pcie; + struct device *dev; + struct resource *cfg_res; + struct resource *bus_range; + void __iomem *cfg_base; + u32 max_regions; + u32 no_bar_nbits; + u16 vendor_id; + u16 device_id; +}; + +static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, + int where) +{ + struct pci_host_bridge *bridge = pci_find_host_bridge(bus); + struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge); + struct cdns_pcie *pcie = &rc->pcie; + unsigned int busn = bus->number; + u32 addr0, desc0; + + if (busn == rc->bus_range->start) { + /* + * Only the root port (devfn == 0) is connected to this bus. + * All other PCI devices are behind some bridge hence on another + * bus. + */ + if (devfn) + return NULL; + + return pcie->reg_base + (where & 0xfff); + } + + /* Update Output registers for AXI region 0. */ + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) | + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0); + + /* Configuration Type 0 or Type 1 access. */ + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); + /* + * The bus number was already set once for all in desc1 by + * cdns_pcie_host_init_address_translation(). + */ + if (busn == rc->bus_range->start + 1) + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0; + else + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1; + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0); + + return rc->cfg_base + (where & 0xfff); +} + +static struct pci_ops cdns_pcie_host_ops = { + .map_bus = cdns_pci_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; + +static const struct of_device_id cdns_pcie_host_of_match[] = { + { .compatible = "cdns,cdns-pcie-host" }, + + { }, +}; + +static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc) +{ + struct cdns_pcie *pcie = &rc->pcie; + u32 value, ctrl; + + /* + * Set the root complex BAR configuration register: + * - disable both BAR0 and BAR1. + * - enable Prefetchable Memory Base and Limit registers in type 1 + * config space (64 bits). + * - enable IO Base and Limit registers in type 1 config + * space (32 bits). + */ + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; + value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | + CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | + CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | + CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS; + cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); + + /* Set root port configuration space */ + if (rc->vendor_id != 0xffff) + cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id); + if (rc->device_id != 0xffff) + cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id); + + cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0); + cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0); + cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); + + return 0; +} + +static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) +{ + struct cdns_pcie *pcie = &rc->pcie; + struct resource *cfg_res = rc->cfg_res; + struct resource *mem_res = pcie->mem_res; + struct resource *bus_range = rc->bus_range; + struct device *dev = rc->dev; + struct device_node *np = dev->of_node; + struct of_pci_range_parser parser; + struct of_pci_range range; + u32 addr0, addr1, desc1; + u64 cpu_addr; + int r, err; + + /* + * Reserve region 0 for PCI configure space accesses: + * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by + * cdns_pci_map_bus(), other region registers are set here once for all. + */ + addr1 = 0; /* Should be programmed to zero. */ + desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); + + cpu_addr = cfg_res->start - mem_res->start; + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | + (lower_32_bits(cpu_addr) & GENMASK(31, 8)); + addr1 = upper_32_bits(cpu_addr); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1); + + err = of_pci_range_parser_init(&parser, np); + if (err) + return err; + + r = 1; + for_each_of_pci_range(&parser, &range) { + bool is_io; + + if (r >= rc->max_regions) + break; + + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) + is_io = false; + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) + is_io = true; + else + continue; + + cdns_pcie_set_outbound_region(pcie, r, is_io, + range.cpu_addr, + range.pci_addr, + range.size); + r++; + } + + /* + * Set Root Port no BAR match Inbound Translation registers: + * needed for MSI and DMA. + * Root Port BAR0 and BAR1 are disabled, hence no need to set their + * inbound translation registers. + */ + addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits); + addr1 = 0; + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1); + + return 0; +} + +static int cdns_pcie_host_init(struct device *dev, + struct list_head *resources, + struct cdns_pcie_rc *rc) +{ + struct resource *bus_range = NULL; + int err; + + /* Parse our PCI ranges and request their resources */ + err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); + if (err) + return err; + + rc->bus_range = bus_range; + rc->pcie.bus = bus_range->start; + + err = cdns_pcie_host_init_root_port(rc); + if (err) + goto err_out; + + err = cdns_pcie_host_init_address_translation(rc); + if (err) + goto err_out; + + return 0; + + err_out: + pci_free_resource_list(resources); + return err; +} + +static int cdns_pcie_host_probe(struct platform_device *pdev) +{ + const char *type; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct pci_host_bridge *bridge; + struct list_head resources; + struct cdns_pcie_rc *rc; + struct cdns_pcie *pcie; + struct resource *res; + int ret; + + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); + if (!bridge) + return -ENOMEM; + + rc = pci_host_bridge_priv(bridge); + rc->dev = dev; + + pcie = &rc->pcie; + pcie->is_rc = true; + + rc->max_regions = 32; + of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions); + + rc->no_bar_nbits = 32; + of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits); + + rc->vendor_id = 0xffff; + of_property_read_u16(np, "vendor-id", &rc->vendor_id); + + rc->device_id = 0xffff; + of_property_read_u16(np, "device-id", &rc->device_id); + + type = of_get_property(np, "device_type", NULL); + if (!type || strcmp(type, "pci")) { + dev_err(dev, "invalid \"device_type\" %s\n", type); + return -EINVAL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); + pcie->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(pcie->reg_base)) { + dev_err(dev, "missing \"reg\"\n"); + return PTR_ERR(pcie->reg_base); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); + rc->cfg_base = devm_pci_remap_cfg_resource(dev, res); + if (IS_ERR(rc->cfg_base)) { + dev_err(dev, "missing \"cfg\"\n"); + return PTR_ERR(rc->cfg_base); + } + rc->cfg_res = res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); + if (!res) { + dev_err(dev, "missing \"mem\"\n"); + return -EINVAL; + } + pcie->mem_res = res; + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "pm_runtime_get_sync() failed\n"); + goto err_get_sync; + } + + ret = cdns_pcie_host_init(dev, &resources, rc); + if (ret) + goto err_init; + + list_splice_init(&resources, &bridge->windows); + bridge->dev.parent = dev; + bridge->busnr = pcie->bus; + bridge->ops = &cdns_pcie_host_ops; + bridge->map_irq = of_irq_parse_and_map_pci; + bridge->swizzle_irq = pci_common_swizzle; + + ret = pci_host_probe(bridge); + if (ret < 0) + goto err_host_probe; + + return 0; + + err_host_probe: + pci_free_resource_list(&resources); + + err_init: + pm_runtime_put_sync(dev); + + err_get_sync: + pm_runtime_disable(dev); + + return ret; +} + +static struct platform_driver cdns_pcie_host_driver = { + .driver = { + .name = "cdns-pcie-host", + .of_match_table = cdns_pcie_host_of_match, + }, + .probe = cdns_pcie_host_probe, +}; +builtin_platform_driver(cdns_pcie_host_driver); diff --git a/drivers/pci/cadence/pcie-cadence.c b/drivers/pci/cadence/pcie-cadence.c new file mode 100644 index 000000000000..5c76e7f4c5f9 --- /dev/null +++ b/drivers/pci/cadence/pcie-cadence.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Cadence +// Cadence PCIe controller driver. +// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> + +#include <linux/kernel.h> + +#include "pcie-cadence.h" + +void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io, + u64 cpu_addr, u64 pci_addr, size_t size) +{ + /* + * roundup_pow_of_two() returns an unsigned long, which is not suited + * for 64bit values. + */ + u64 sz = 1ULL << fls64(size - 1); + int nbits = ilog2(sz); + u32 addr0, addr1, desc0, desc1; + + if (nbits < 8) + nbits = 8; + + /* Set the PCI address */ + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) | + (lower_32_bits(pci_addr) & GENMASK(31, 8)); + addr1 = upper_32_bits(pci_addr); + + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1); + + /* Set the PCIe header descriptor */ + if (is_io) + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO; + else + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM; + desc1 = 0; + + if (pcie->is_rc) { + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); + desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus); + } + + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1); + + /* Set the CPU address */ + cpu_addr -= pcie->mem_res->start; + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) | + (lower_32_bits(cpu_addr) & GENMASK(31, 8)); + addr1 = upper_32_bits(cpu_addr); + + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1); +} + +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r) +{ + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0); + + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0); + + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); +} diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/cadence/pcie-cadence.h new file mode 100644 index 000000000000..3a15b4016352 --- /dev/null +++ b/drivers/pci/cadence/pcie-cadence.h @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Cadence +// Cadence PCIe controller driver. +// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> + +#ifndef _PCIE_CADENCE_H +#define _PCIE_CADENCE_H + +#include <linux/kernel.h> +#include <linux/pci.h> + +/* + * Local Management Registers + */ +#define CDNS_PCIE_LM_BASE 0x00100000 + +/* Vendor ID Register */ +#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044) +#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0) +#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0 +#define CDNS_PCIE_LM_ID_VENDOR(vid) \ + (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK) +#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16) +#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16 +#define CDNS_PCIE_LM_ID_SUBSYS(sub) \ + (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK) + +/* Root Port Requestor ID Register */ +#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228) +#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0) +#define CDNS_PCIE_LM_RP_RID_SHIFT 0 +#define CDNS_PCIE_LM_RP_RID_(rid) \ + (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK) + +/* Root Complex BAR Configuration Register */ +#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \ + (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \ + (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \ + (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \ + (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK) +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17) +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0 +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18) +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19) +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0 +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20) +#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31) + +/* BAR control values applicable to both Endpoint Function and Root Complex */ +#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7 + + +/* + * Root Port Registers (PCI configuration space for the root port function) + */ +#define CDNS_PCIE_RP_BASE 0x00200000 + + +/* + * Address Translation Registers + */ +#define CDNS_PCIE_AT_BASE 0x00400000 + +/* Region r Outbound AXI to PCIe Address Translation Register 0 */ +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \ + (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \ + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \ + (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \ + (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK) + +/* Region r Outbound AXI to PCIe Address Translation Register 1 */ +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \ + (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020) + +/* Region r Outbound PCIe Descriptor Register 0 */ +#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \ + (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0) +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2 +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6 +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd +/* Bit 23 MUST be set in RC mode. */ +#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23) +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24) +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \ + (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK) + +/* Region r Outbound PCIe Descriptor Register 1 */ +#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \ + (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0) +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \ + ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK) + +/* Region r AXI Region Base Address Register 0 */ +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \ + (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0) +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \ + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK) + +/* Region r AXI Region Base Address Register 1 */ +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \ + (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020) + +/* Root Port BAR Inbound PCIe to AXI Address Translation Register */ +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \ + (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008) +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0) +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \ + (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK) +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \ + (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008) + +enum cdns_pcie_rp_bar { + RP_BAR0, + RP_BAR1, + RP_NO_BAR +}; + +/** + * struct cdns_pcie - private data for Cadence PCIe controller drivers + * @reg_base: IO mapped register base + * @mem_res: start/end offsets in the physical system memory to map PCI accesses + * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint. + * @bus: In Root Complex mode, the bus number + */ +struct cdns_pcie { + void __iomem *reg_base; + struct resource *mem_res; + bool is_rc; + u8 bus; +}; + +/* Register access */ +static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value) +{ + writeb(value, pcie->reg_base + reg); +} + +static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value) +{ + writew(value, pcie->reg_base + reg); +} + +static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value) +{ + writel(value, pcie->reg_base + reg); +} + +static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg) +{ + return readl(pcie->reg_base + reg); +} + +/* Root Port register access */ +static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie, + u32 reg, u8 value) +{ + writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); +} + +static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie, + u32 reg, u16 value) +{ + writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); +} + +void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io, + u64 cpu_addr, u64 pci_addr, size_t size); + +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r); + +#endif /* _PCIE_CADENCE_H */ -- 2.11.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller 2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen @ 2018-01-16 11:16 ` Kishon Vijay Abraham I [not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org> 2018-01-16 16:07 ` Lorenzo Pieralisi 1 sibling, 1 reply; 14+ messages in thread From: Kishon Vijay Abraham I @ 2018-01-16 11:16 UTC (permalink / raw) To: Cyrille Pitchen, bhelgaas, lorenzo.pieralisi, linux-pci Cc: adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree Hi Cyrille, On Thursday 11 January 2018 04:17 AM, Cyrille Pitchen wrote: > This patch adds support to the Cadence PCIe controller in host mode. > > Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> > --- > MAINTAINERS | 7 + > drivers/pci/Kconfig | 1 + > drivers/pci/Makefile | 1 + > drivers/pci/cadence/Kconfig | 16 ++ > drivers/pci/cadence/Makefile | 3 + > drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++ > drivers/pci/cadence/pcie-cadence.c | 68 +++++++ > drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++ > 8 files changed, 628 insertions(+) > create mode 100644 drivers/pci/cadence/Kconfig > create mode 100644 drivers/pci/cadence/Makefile > create mode 100644 drivers/pci/cadence/pcie-cadence-host.c > create mode 100644 drivers/pci/cadence/pcie-cadence.c > create mode 100644 drivers/pci/cadence/pcie-cadence.h > > diff --git a/MAINTAINERS b/MAINTAINERS > index 13945646b95d..cc24c74a946e 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -10402,6 +10402,13 @@ S: Maintained > F: Documentation/devicetree/bindings/pci/pci-armada8k.txt > F: drivers/pci/dwc/pcie-armada8k.c > > +PCI DRIVER FOR CADENCE PCIE IP > +M: Alan Douglas <adouglas@cadence.com> > +L: linux-pci@vger.kernel.org > +S: Maintained > +F: Documentation/devicetree/bindings/pci/cdns,*.txt > +F: drivers/pci/cadence/pcie-cadence* > + > PCI DRIVER FOR FREESCALE LAYERSCAPE > M: Minghuan Lian <minghuan.Lian@freescale.com> > M: Mingkai Hu <mingkai.hu@freescale.com> > diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig > index 7eeb969ab86a..dee90cc1dcaf 100644 > --- a/drivers/pci/Kconfig > +++ b/drivers/pci/Kconfig > @@ -136,6 +136,7 @@ config PCI_HYPERV > PCI devices from a PCI backend to support PCI driver domains. > > source "drivers/pci/hotplug/Kconfig" > +source "drivers/pci/cadence/Kconfig" > source "drivers/pci/dwc/Kconfig" > source "drivers/pci/host/Kconfig" > source "drivers/pci/endpoint/Kconfig" > diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile > index ddb5aa6640d7..941970936840 100644 > --- a/drivers/pci/Makefile > +++ b/drivers/pci/Makefile > @@ -56,5 +56,6 @@ obj-y += switch/ > obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ > > # Endpoint library must be initialized before its users > +obj-$(CONFIG_PCIE_CADENCE) += cadence/ > # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW > obj-y += dwc/ > diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig > new file mode 100644 > index 000000000000..0123d384a628 > --- /dev/null > +++ b/drivers/pci/cadence/Kconfig > @@ -0,0 +1,16 @@ > +menu "Cadence PCIe controllers support" > + > +config PCIE_CADENCE > + bool > + > +config PCIE_CADENCE_HOST > + bool "Cadence PCIe host controller" > + depends on OF > + select IRQ_DOMAIN > + select PCIE_CADENCE > + help > + Say Y here if you want to support the Cadence PCIe controller in host > + mode. This PCIe controller may be embedded into many different vendors > + SoCs. > + > +endmenu > diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile > new file mode 100644 > index 000000000000..589601a8ff89 > --- /dev/null > +++ b/drivers/pci/cadence/Makefile > @@ -0,0 +1,3 @@ > +# SPDX-License-Identifier: GPL-2.0 > +obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o > +obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o > diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/cadence/pcie-cadence-host.c > new file mode 100644 > index 000000000000..26caf8963e3c > --- /dev/null > +++ b/drivers/pci/cadence/pcie-cadence-host.c > @@ -0,0 +1,336 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// Copyright (c) 2017 Cadence > +// Cadence PCIe host controller driver. > +// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> > + > +#include <linux/kernel.h> > +#include <linux/of_address.h> > +#include <linux/of_pci.h> > +#include <linux/platform_device.h> > +#include <linux/pm_runtime.h> > + > +#include "pcie-cadence.h" > + > +/** > + * struct cdns_pcie_rc - private data for this PCIe Root Complex driver > + * @pcie: Cadence PCIe controller > + * @dev: pointer to PCIe device > + * @cfg_res: start/end offsets in the physical system memory to map PCI > + * configuration space accesses > + * @bus_range: first/last buses behind the PCIe host controller > + * @cfg_base: IO mapped window to access the PCI configuration space of a > + * single function at a time > + * @max_regions: maximum number of regions supported by the hardware > + * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address > + * translation (nbits sets into the "no BAR match" register) > + * @vendor_id: PCI vendor ID > + * @device_id: PCI device ID > + */ > +struct cdns_pcie_rc { > + struct cdns_pcie pcie; > + struct device *dev; > + struct resource *cfg_res; > + struct resource *bus_range; > + void __iomem *cfg_base; > + u32 max_regions; > + u32 no_bar_nbits; > + u16 vendor_id; > + u16 device_id; > +}; > + > +static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, > + int where) > +{ > + struct pci_host_bridge *bridge = pci_find_host_bridge(bus); > + struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge); > + struct cdns_pcie *pcie = &rc->pcie; > + unsigned int busn = bus->number; > + u32 addr0, desc0; > + > + if (busn == rc->bus_range->start) { > + /* > + * Only the root port (devfn == 0) is connected to this bus. > + * All other PCI devices are behind some bridge hence on another > + * bus. > + */ > + if (devfn) > + return NULL; > + > + return pcie->reg_base + (where & 0xfff); > + } > + > + /* Update Output registers for AXI region 0. */ > + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | > + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) | > + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0); > + > + /* Configuration Type 0 or Type 1 access. */ > + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | > + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); > + /* > + * The bus number was already set once for all in desc1 by > + * cdns_pcie_host_init_address_translation(). > + */ > + if (busn == rc->bus_range->start + 1) > + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0; > + else > + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1; > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0); > + > + return rc->cfg_base + (where & 0xfff); > +} > + > +static struct pci_ops cdns_pcie_host_ops = { > + .map_bus = cdns_pci_map_bus, > + .read = pci_generic_config_read, > + .write = pci_generic_config_write, > +}; > + > +static const struct of_device_id cdns_pcie_host_of_match[] = { > + { .compatible = "cdns,cdns-pcie-host" }, > + > + { }, > +}; > + > +static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc) > +{ > + struct cdns_pcie *pcie = &rc->pcie; > + u32 value, ctrl; > + > + /* > + * Set the root complex BAR configuration register: > + * - disable both BAR0 and BAR1. > + * - enable Prefetchable Memory Base and Limit registers in type 1 > + * config space (64 bits). > + * - enable IO Base and Limit registers in type 1 config > + * space (32 bits). > + */ > + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; > + value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | > + CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | > + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | > + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | > + CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | > + CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS; > + cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); > + > + /* Set root port configuration space */ > + if (rc->vendor_id != 0xffff) > + cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id); > + if (rc->device_id != 0xffff) > + cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id); > + > + cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0); > + cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0); > + cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); > + > + return 0; > +} > + > +static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) > +{ > + struct cdns_pcie *pcie = &rc->pcie; > + struct resource *cfg_res = rc->cfg_res; > + struct resource *mem_res = pcie->mem_res; > + struct resource *bus_range = rc->bus_range; > + struct device *dev = rc->dev; > + struct device_node *np = dev->of_node; > + struct of_pci_range_parser parser; > + struct of_pci_range range; > + u32 addr0, addr1, desc1; > + u64 cpu_addr; > + int r, err; > + > + /* > + * Reserve region 0 for PCI configure space accesses: > + * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by > + * cdns_pci_map_bus(), other region registers are set here once for all. > + */ > + addr1 = 0; /* Should be programmed to zero. */ > + desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); > + > + cpu_addr = cfg_res->start - mem_res->start; > + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | > + (lower_32_bits(cpu_addr) & GENMASK(31, 8)); > + addr1 = upper_32_bits(cpu_addr); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1); > + > + err = of_pci_range_parser_init(&parser, np); > + if (err) > + return err; > + > + r = 1; > + for_each_of_pci_range(&parser, &range) { > + bool is_io; > + > + if (r >= rc->max_regions) > + break; > + > + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) > + is_io = false; > + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) > + is_io = true; > + else > + continue; > + > + cdns_pcie_set_outbound_region(pcie, r, is_io, > + range.cpu_addr, > + range.pci_addr, > + range.size); > + r++; > + } > + > + /* > + * Set Root Port no BAR match Inbound Translation registers: > + * needed for MSI and DMA. > + * Root Port BAR0 and BAR1 are disabled, hence no need to set their > + * inbound translation registers. > + */ > + addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits); > + addr1 = 0; > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1); > + > + return 0; > +} > + > +static int cdns_pcie_host_init(struct device *dev, > + struct list_head *resources, > + struct cdns_pcie_rc *rc) > +{ > + struct resource *bus_range = NULL; > + int err; > + > + /* Parse our PCI ranges and request their resources */ > + err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); > + if (err) > + return err; > + > + rc->bus_range = bus_range; > + rc->pcie.bus = bus_range->start; > + > + err = cdns_pcie_host_init_root_port(rc); > + if (err) > + goto err_out; > + > + err = cdns_pcie_host_init_address_translation(rc); > + if (err) > + goto err_out; > + > + return 0; > + > + err_out: > + pci_free_resource_list(resources); > + return err; > +} > + > +static int cdns_pcie_host_probe(struct platform_device *pdev) > +{ > + const char *type; > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + struct pci_host_bridge *bridge; > + struct list_head resources; > + struct cdns_pcie_rc *rc; > + struct cdns_pcie *pcie; > + struct resource *res; > + int ret; > + > + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); > + if (!bridge) > + return -ENOMEM; > + > + rc = pci_host_bridge_priv(bridge); > + rc->dev = dev; > + > + pcie = &rc->pcie; > + pcie->is_rc = true; > + > + rc->max_regions = 32; > + of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions); > + > + rc->no_bar_nbits = 32; > + of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits); > + > + rc->vendor_id = 0xffff; > + of_property_read_u16(np, "vendor-id", &rc->vendor_id); > + > + rc->device_id = 0xffff; > + of_property_read_u16(np, "device-id", &rc->device_id); > + > + type = of_get_property(np, "device_type", NULL); > + if (!type || strcmp(type, "pci")) { > + dev_err(dev, "invalid \"device_type\" %s\n", type); > + return -EINVAL; > + } > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); > + pcie->reg_base = devm_ioremap_resource(dev, res); > + if (IS_ERR(pcie->reg_base)) { > + dev_err(dev, "missing \"reg\"\n"); > + return PTR_ERR(pcie->reg_base); > + } > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); > + rc->cfg_base = devm_pci_remap_cfg_resource(dev, res); > + if (IS_ERR(rc->cfg_base)) { > + dev_err(dev, "missing \"cfg\"\n"); > + return PTR_ERR(rc->cfg_base); > + } > + rc->cfg_res = res; > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); > + if (!res) { > + dev_err(dev, "missing \"mem\"\n"); > + return -EINVAL; > + } > + pcie->mem_res = res; > + > + pm_runtime_enable(dev); > + ret = pm_runtime_get_sync(dev); > + if (ret < 0) { > + dev_err(dev, "pm_runtime_get_sync() failed\n"); > + goto err_get_sync; > + } > + > + ret = cdns_pcie_host_init(dev, &resources, rc); > + if (ret) > + goto err_init; > + > + list_splice_init(&resources, &bridge->windows); > + bridge->dev.parent = dev; > + bridge->busnr = pcie->bus; > + bridge->ops = &cdns_pcie_host_ops; > + bridge->map_irq = of_irq_parse_and_map_pci; > + bridge->swizzle_irq = pci_common_swizzle; > + > + ret = pci_host_probe(bridge); > + if (ret < 0) > + goto err_host_probe; > + > + return 0; > + > + err_host_probe: > + pci_free_resource_list(&resources); > + > + err_init: > + pm_runtime_put_sync(dev); > + > + err_get_sync: > + pm_runtime_disable(dev); > + > + return ret; > +} > + > +static struct platform_driver cdns_pcie_host_driver = { > + .driver = { > + .name = "cdns-pcie-host", > + .of_match_table = cdns_pcie_host_of_match, > + }, > + .probe = cdns_pcie_host_probe, > +}; In the case of DWC, designware core is modeled as a library which has API's to be invoked by various platform specific glue drivers. But with the cadence approach we'll have two separate drivers: the cadence core driver and the platform specific glue drivers. Is this approach chosen for a specific reason? Thanks Kishon ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org>]
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller [not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org> @ 2018-01-16 15:09 ` Lorenzo Pieralisi 2018-01-18 23:13 ` Cyrille Pitchen 1 sibling, 0 replies; 14+ messages in thread From: Lorenzo Pieralisi @ 2018-01-16 15:09 UTC (permalink / raw) To: Kishon Vijay Abraham I Cc: Cyrille Pitchen, bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA, adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ, dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ, eandrews-vna1KIf7WgpBDgjK7y7TUQ, thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0, linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA On Tue, Jan 16, 2018 at 04:46:12PM +0530, Kishon Vijay Abraham I wrote: [...] > > +static struct platform_driver cdns_pcie_host_driver = { > > + .driver = { > > + .name = "cdns-pcie-host", > > + .of_match_table = cdns_pcie_host_of_match, > > + }, > > + .probe = cdns_pcie_host_probe, > > +}; > > In the case of DWC, designware core is modeled as a library which has > API's to be invoked by various platform specific glue drivers. > > But with the cadence approach we'll have two separate drivers: the > cadence core driver and the platform specific glue drivers. Is this > approach chosen for a specific reason? That's a fair point but I do not think that's a concern at the moment. If/when other platform drivers are built around the generic IP we just have to refactor this driver and turn into a core library + a PCI host bridge driver like dwc does, at the moment I do not necessarily see the reason for splitting them. Cyrille ? Thanks, Lorenzo -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller [not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org> 2018-01-16 15:09 ` Lorenzo Pieralisi @ 2018-01-18 23:13 ` Cyrille Pitchen 1 sibling, 0 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-18 23:13 UTC (permalink / raw) To: Kishon Vijay Abraham I, bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, lorenzo.pieralisi-5wv7dgnIgG8, linux-pci-u79uwXL29TY76Z2rM5mHXA Cc: adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ, dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ, eandrews-vna1KIf7WgpBDgjK7y7TUQ, thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0, linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA Hi Kishon, Le 16/01/2018 à 12:16, Kishon Vijay Abraham I a écrit : > Hi Cyrille, > > On Thursday 11 January 2018 04:17 AM, Cyrille Pitchen wrote: >> This patch adds support to the Cadence PCIe controller in host mode. >> >> Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> >> --- >> MAINTAINERS | 7 + >> drivers/pci/Kconfig | 1 + >> drivers/pci/Makefile | 1 + >> drivers/pci/cadence/Kconfig | 16 ++ >> drivers/pci/cadence/Makefile | 3 + >> drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++ >> drivers/pci/cadence/pcie-cadence.c | 68 +++++++ >> drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++ >> 8 files changed, 628 insertions(+) >> create mode 100644 drivers/pci/cadence/Kconfig >> create mode 100644 drivers/pci/cadence/Makefile >> create mode 100644 drivers/pci/cadence/pcie-cadence-host.c >> create mode 100644 drivers/pci/cadence/pcie-cadence.c >> create mode 100644 drivers/pci/cadence/pcie-cadence.h >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 13945646b95d..cc24c74a946e 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -10402,6 +10402,13 @@ S: Maintained >> F: Documentation/devicetree/bindings/pci/pci-armada8k.txt >> F: drivers/pci/dwc/pcie-armada8k.c >> >> +PCI DRIVER FOR CADENCE PCIE IP >> +M: Alan Douglas <adouglas-vna1KIf7WgpBDgjK7y7TUQ@public.gmane.org> >> +L: linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org >> +S: Maintained >> +F: Documentation/devicetree/bindings/pci/cdns,*.txt >> +F: drivers/pci/cadence/pcie-cadence* >> + >> PCI DRIVER FOR FREESCALE LAYERSCAPE >> M: Minghuan Lian <minghuan.Lian-KZfg59tc24xl57MIdRCFDg@public.gmane.org> >> M: Mingkai Hu <mingkai.hu-KZfg59tc24xl57MIdRCFDg@public.gmane.org> >> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig >> index 7eeb969ab86a..dee90cc1dcaf 100644 >> --- a/drivers/pci/Kconfig >> +++ b/drivers/pci/Kconfig >> @@ -136,6 +136,7 @@ config PCI_HYPERV >> PCI devices from a PCI backend to support PCI driver domains. >> >> source "drivers/pci/hotplug/Kconfig" >> +source "drivers/pci/cadence/Kconfig" >> source "drivers/pci/dwc/Kconfig" >> source "drivers/pci/host/Kconfig" >> source "drivers/pci/endpoint/Kconfig" >> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile >> index ddb5aa6640d7..941970936840 100644 >> --- a/drivers/pci/Makefile >> +++ b/drivers/pci/Makefile >> @@ -56,5 +56,6 @@ obj-y += switch/ >> obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ >> >> # Endpoint library must be initialized before its users >> +obj-$(CONFIG_PCIE_CADENCE) += cadence/ >> # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW >> obj-y += dwc/ >> diff --git a/drivers/pci/cadence/Kconfig b/drivers/pci/cadence/Kconfig >> new file mode 100644 >> index 000000000000..0123d384a628 >> --- /dev/null >> +++ b/drivers/pci/cadence/Kconfig >> @@ -0,0 +1,16 @@ >> +menu "Cadence PCIe controllers support" >> + >> +config PCIE_CADENCE >> + bool >> + >> +config PCIE_CADENCE_HOST >> + bool "Cadence PCIe host controller" >> + depends on OF >> + select IRQ_DOMAIN >> + select PCIE_CADENCE >> + help >> + Say Y here if you want to support the Cadence PCIe controller in host >> + mode. This PCIe controller may be embedded into many different vendors >> + SoCs. >> + >> +endmenu >> diff --git a/drivers/pci/cadence/Makefile b/drivers/pci/cadence/Makefile >> new file mode 100644 >> index 000000000000..589601a8ff89 >> --- /dev/null >> +++ b/drivers/pci/cadence/Makefile >> @@ -0,0 +1,3 @@ >> +# SPDX-License-Identifier: GPL-2.0 >> +obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o >> +obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o >> diff --git a/drivers/pci/cadence/pcie-cadence-host.c b/drivers/pci/cadence/pcie-cadence-host.c >> new file mode 100644 >> index 000000000000..26caf8963e3c >> --- /dev/null >> +++ b/drivers/pci/cadence/pcie-cadence-host.c >> @@ -0,0 +1,336 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +// Copyright (c) 2017 Cadence >> +// Cadence PCIe host controller driver. >> +// Author: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> >> + >> +#include <linux/kernel.h> >> +#include <linux/of_address.h> >> +#include <linux/of_pci.h> >> +#include <linux/platform_device.h> >> +#include <linux/pm_runtime.h> >> + >> +#include "pcie-cadence.h" >> + >> +/** >> + * struct cdns_pcie_rc - private data for this PCIe Root Complex driver >> + * @pcie: Cadence PCIe controller >> + * @dev: pointer to PCIe device >> + * @cfg_res: start/end offsets in the physical system memory to map PCI >> + * configuration space accesses >> + * @bus_range: first/last buses behind the PCIe host controller >> + * @cfg_base: IO mapped window to access the PCI configuration space of a >> + * single function at a time >> + * @max_regions: maximum number of regions supported by the hardware >> + * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address >> + * translation (nbits sets into the "no BAR match" register) >> + * @vendor_id: PCI vendor ID >> + * @device_id: PCI device ID >> + */ >> +struct cdns_pcie_rc { >> + struct cdns_pcie pcie; >> + struct device *dev; >> + struct resource *cfg_res; >> + struct resource *bus_range; >> + void __iomem *cfg_base; >> + u32 max_regions; >> + u32 no_bar_nbits; >> + u16 vendor_id; >> + u16 device_id; >> +}; >> + >> +static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, >> + int where) >> +{ >> + struct pci_host_bridge *bridge = pci_find_host_bridge(bus); >> + struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge); >> + struct cdns_pcie *pcie = &rc->pcie; >> + unsigned int busn = bus->number; >> + u32 addr0, desc0; >> + >> + if (busn == rc->bus_range->start) { >> + /* >> + * Only the root port (devfn == 0) is connected to this bus. >> + * All other PCI devices are behind some bridge hence on another >> + * bus. >> + */ >> + if (devfn) >> + return NULL; >> + >> + return pcie->reg_base + (where & 0xfff); >> + } >> + >> + /* Update Output registers for AXI region 0. */ >> + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | >> + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) | >> + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0); >> + >> + /* Configuration Type 0 or Type 1 access. */ >> + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | >> + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); >> + /* >> + * The bus number was already set once for all in desc1 by >> + * cdns_pcie_host_init_address_translation(). >> + */ >> + if (busn == rc->bus_range->start + 1) >> + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0; >> + else >> + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1; >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0); >> + >> + return rc->cfg_base + (where & 0xfff); >> +} >> + >> +static struct pci_ops cdns_pcie_host_ops = { >> + .map_bus = cdns_pci_map_bus, >> + .read = pci_generic_config_read, >> + .write = pci_generic_config_write, >> +}; >> + >> +static const struct of_device_id cdns_pcie_host_of_match[] = { >> + { .compatible = "cdns,cdns-pcie-host" }, >> + >> + { }, >> +}; >> + >> +static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc) >> +{ >> + struct cdns_pcie *pcie = &rc->pcie; >> + u32 value, ctrl; >> + >> + /* >> + * Set the root complex BAR configuration register: >> + * - disable both BAR0 and BAR1. >> + * - enable Prefetchable Memory Base and Limit registers in type 1 >> + * config space (64 bits). >> + * - enable IO Base and Limit registers in type 1 config >> + * space (32 bits). >> + */ >> + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; >> + value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | >> + CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | >> + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | >> + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | >> + CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | >> + CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS; >> + cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); >> + >> + /* Set root port configuration space */ >> + if (rc->vendor_id != 0xffff) >> + cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id); >> + if (rc->device_id != 0xffff) >> + cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id); >> + >> + cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0); >> + cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0); >> + cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); >> + >> + return 0; >> +} >> + >> +static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) >> +{ >> + struct cdns_pcie *pcie = &rc->pcie; >> + struct resource *cfg_res = rc->cfg_res; >> + struct resource *mem_res = pcie->mem_res; >> + struct resource *bus_range = rc->bus_range; >> + struct device *dev = rc->dev; >> + struct device_node *np = dev->of_node; >> + struct of_pci_range_parser parser; >> + struct of_pci_range range; >> + u32 addr0, addr1, desc1; >> + u64 cpu_addr; >> + int r, err; >> + >> + /* >> + * Reserve region 0 for PCI configure space accesses: >> + * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by >> + * cdns_pci_map_bus(), other region registers are set here once for all. >> + */ >> + addr1 = 0; /* Should be programmed to zero. */ >> + desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); >> + >> + cpu_addr = cfg_res->start - mem_res->start; >> + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | >> + (lower_32_bits(cpu_addr) & GENMASK(31, 8)); >> + addr1 = upper_32_bits(cpu_addr); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1); >> + >> + err = of_pci_range_parser_init(&parser, np); >> + if (err) >> + return err; >> + >> + r = 1; >> + for_each_of_pci_range(&parser, &range) { >> + bool is_io; >> + >> + if (r >= rc->max_regions) >> + break; >> + >> + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) >> + is_io = false; >> + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) >> + is_io = true; >> + else >> + continue; >> + >> + cdns_pcie_set_outbound_region(pcie, r, is_io, >> + range.cpu_addr, >> + range.pci_addr, >> + range.size); >> + r++; >> + } >> + >> + /* >> + * Set Root Port no BAR match Inbound Translation registers: >> + * needed for MSI and DMA. >> + * Root Port BAR0 and BAR1 are disabled, hence no need to set their >> + * inbound translation registers. >> + */ >> + addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits); >> + addr1 = 0; >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1); >> + >> + return 0; >> +} >> + >> +static int cdns_pcie_host_init(struct device *dev, >> + struct list_head *resources, >> + struct cdns_pcie_rc *rc) >> +{ >> + struct resource *bus_range = NULL; >> + int err; >> + >> + /* Parse our PCI ranges and request their resources */ >> + err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); >> + if (err) >> + return err; >> + >> + rc->bus_range = bus_range; >> + rc->pcie.bus = bus_range->start; >> + >> + err = cdns_pcie_host_init_root_port(rc); >> + if (err) >> + goto err_out; >> + >> + err = cdns_pcie_host_init_address_translation(rc); >> + if (err) >> + goto err_out; >> + >> + return 0; >> + >> + err_out: >> + pci_free_resource_list(resources); >> + return err; >> +} >> + >> +static int cdns_pcie_host_probe(struct platform_device *pdev) >> +{ >> + const char *type; >> + struct device *dev = &pdev->dev; >> + struct device_node *np = dev->of_node; >> + struct pci_host_bridge *bridge; >> + struct list_head resources; >> + struct cdns_pcie_rc *rc; >> + struct cdns_pcie *pcie; >> + struct resource *res; >> + int ret; >> + >> + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); >> + if (!bridge) >> + return -ENOMEM; >> + >> + rc = pci_host_bridge_priv(bridge); >> + rc->dev = dev; >> + >> + pcie = &rc->pcie; >> + pcie->is_rc = true; >> + >> + rc->max_regions = 32; >> + of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions); >> + >> + rc->no_bar_nbits = 32; >> + of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits); >> + >> + rc->vendor_id = 0xffff; >> + of_property_read_u16(np, "vendor-id", &rc->vendor_id); >> + >> + rc->device_id = 0xffff; >> + of_property_read_u16(np, "device-id", &rc->device_id); >> + >> + type = of_get_property(np, "device_type", NULL); >> + if (!type || strcmp(type, "pci")) { >> + dev_err(dev, "invalid \"device_type\" %s\n", type); >> + return -EINVAL; >> + } >> + >> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); >> + pcie->reg_base = devm_ioremap_resource(dev, res); >> + if (IS_ERR(pcie->reg_base)) { >> + dev_err(dev, "missing \"reg\"\n"); >> + return PTR_ERR(pcie->reg_base); >> + } >> + >> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); >> + rc->cfg_base = devm_pci_remap_cfg_resource(dev, res); >> + if (IS_ERR(rc->cfg_base)) { >> + dev_err(dev, "missing \"cfg\"\n"); >> + return PTR_ERR(rc->cfg_base); >> + } >> + rc->cfg_res = res; >> + >> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); >> + if (!res) { >> + dev_err(dev, "missing \"mem\"\n"); >> + return -EINVAL; >> + } >> + pcie->mem_res = res; >> + >> + pm_runtime_enable(dev); >> + ret = pm_runtime_get_sync(dev); >> + if (ret < 0) { >> + dev_err(dev, "pm_runtime_get_sync() failed\n"); >> + goto err_get_sync; >> + } >> + >> + ret = cdns_pcie_host_init(dev, &resources, rc); >> + if (ret) >> + goto err_init; >> + >> + list_splice_init(&resources, &bridge->windows); >> + bridge->dev.parent = dev; >> + bridge->busnr = pcie->bus; >> + bridge->ops = &cdns_pcie_host_ops; >> + bridge->map_irq = of_irq_parse_and_map_pci; >> + bridge->swizzle_irq = pci_common_swizzle; >> + >> + ret = pci_host_probe(bridge); >> + if (ret < 0) >> + goto err_host_probe; >> + >> + return 0; >> + >> + err_host_probe: >> + pci_free_resource_list(&resources); >> + >> + err_init: >> + pm_runtime_put_sync(dev); >> + >> + err_get_sync: >> + pm_runtime_disable(dev); >> + >> + return ret; >> +} >> + >> +static struct platform_driver cdns_pcie_host_driver = { >> + .driver = { >> + .name = "cdns-pcie-host", >> + .of_match_table = cdns_pcie_host_of_match, >> + }, >> + .probe = cdns_pcie_host_probe, >> +}; > > In the case of DWC, designware core is modeled as a library which has API's to > be invoked by various platform specific glue drivers. > > But with the cadence approach we'll have two separate drivers: the cadence core > driver and the platform specific glue drivers. Is this approach chosen for a > specific reason? I don't know yet how many chips will integrate the Cadence PCIe controller or what customizations would be required. I thought we may have a chance to handle all the variants with different 'compatible' DT values and their associated .data in the 'struct of_device_id', or maybe with some additional DT properties but still the single pcie-cadence-host.c file to drive all host flavors. Also I was thinking about regrouping all endpoint flavors in pcie-cadence-enpoint.c. I can't figure out yet whether it would be enough. Best regards, Cyrille > > Thanks > Kishon > -- Cyrille Pitchen, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller 2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen 2018-01-16 11:16 ` Kishon Vijay Abraham I @ 2018-01-16 16:07 ` Lorenzo Pieralisi [not found] ` <20180116160733.GA3644-4tUPXFaYRHv6sAKXYmQ0tx/iLCjYCKR+VpNB7YpNyf8@public.gmane.org> 1 sibling, 1 reply; 14+ messages in thread From: Lorenzo Pieralisi @ 2018-01-16 16:07 UTC (permalink / raw) To: Cyrille Pitchen Cc: bhelgaas, kishon, linux-pci, adouglas, stelford, dgary, kgopi, eandrews, thomas.petazzoni, sureshp, nsekhar, linux-kernel, robh, devicetree On Wed, Jan 10, 2018 at 11:47:35PM +0100, Cyrille Pitchen wrote: > This patch adds support to the Cadence PCIe controller in host mode. > > Signed-off-by: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> > --- > MAINTAINERS | 7 + > drivers/pci/Kconfig | 1 + > drivers/pci/Makefile | 1 + > drivers/pci/cadence/Kconfig | 16 ++ > drivers/pci/cadence/Makefile | 3 + > drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++ > drivers/pci/cadence/pcie-cadence.c | 68 +++++++ > drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++ [...] > +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r) > +{ > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0); > + > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0); > + > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); > + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); > +} Unused function, please remove it. > diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/cadence/pcie-cadence.h > new file mode 100644 > index 000000000000..3a15b4016352 > --- /dev/null > +++ b/drivers/pci/cadence/pcie-cadence.h > @@ -0,0 +1,196 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// Copyright (c) 2017 Cadence > +// Cadence PCIe controller driver. > +// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com> > + > +#ifndef _PCIE_CADENCE_H > +#define _PCIE_CADENCE_H > + > +#include <linux/kernel.h> > +#include <linux/pci.h> > + > +/* > + * Local Management Registers > + */ > +#define CDNS_PCIE_LM_BASE 0x00100000 > + > +/* Vendor ID Register */ > +#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044) > +#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0) > +#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0 > +#define CDNS_PCIE_LM_ID_VENDOR(vid) \ > + (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK) > +#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16) > +#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16 > +#define CDNS_PCIE_LM_ID_SUBSYS(sub) \ > + (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK) > + > +/* Root Port Requestor ID Register */ > +#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228) > +#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0) > +#define CDNS_PCIE_LM_RP_RID_SHIFT 0 > +#define CDNS_PCIE_LM_RP_RID_(rid) \ > + (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK) > + > +/* Root Complex BAR Configuration Register */ > +#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \ > + (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \ > + (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \ > + (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14) > +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \ > + (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK) > +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17) > +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0 > +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18) > +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19) > +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0 > +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20) > +#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31) > + > +/* BAR control values applicable to both Endpoint Function and Root Complex */ > +#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0 > +#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1 > +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4 > +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5 > +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6 > +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7 > + > + > +/* > + * Root Port Registers (PCI configuration space for the root port function) > + */ > +#define CDNS_PCIE_RP_BASE 0x00200000 > + > + > +/* > + * Address Translation Registers > + */ > +#define CDNS_PCIE_AT_BASE 0x00400000 > + > +/* Region r Outbound AXI to PCIe Address Translation Register 0 */ > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \ > + (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020) > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0) > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \ > + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK) > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12) > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \ > + (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK) > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20) > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \ > + (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK) > + > +/* Region r Outbound AXI to PCIe Address Translation Register 1 */ > +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \ > + (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020) > + > +/* Region r Outbound PCIe Descriptor Register 0 */ > +#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \ > + (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020) > +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0) > +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2 > +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6 > +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa > +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb > +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc > +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd > +/* Bit 23 MUST be set in RC mode. */ > +#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23) > +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24) > +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \ > + (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK) > + > +/* Region r Outbound PCIe Descriptor Register 1 */ > +#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \ > + (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020) > +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0) > +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \ > + ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK) > + > +/* Region r AXI Region Base Address Register 0 */ > +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \ > + (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020) > +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0) > +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \ > + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK) > + > +/* Region r AXI Region Base Address Register 1 */ > +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \ > + (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020) > + > +/* Root Port BAR Inbound PCIe to AXI Address Translation Register */ > +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \ > + (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008) > +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0) > +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \ > + (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK) > +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \ > + (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008) > + > +enum cdns_pcie_rp_bar { > + RP_BAR0, > + RP_BAR1, > + RP_NO_BAR > +}; > + > +/** > + * struct cdns_pcie - private data for Cadence PCIe controller drivers > + * @reg_base: IO mapped register base > + * @mem_res: start/end offsets in the physical system memory to map PCI accesses > + * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint. > + * @bus: In Root Complex mode, the bus number > + */ > +struct cdns_pcie { > + void __iomem *reg_base; > + struct resource *mem_res; > + bool is_rc; > + u8 bus; > +}; > + > +/* Register access */ > +static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value) > +{ > + writeb(value, pcie->reg_base + reg); > +} > + > +static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value) > +{ > + writew(value, pcie->reg_base + reg); > +} > + > +static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value) > +{ > + writel(value, pcie->reg_base + reg); > +} > + > +static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg) > +{ > + return readl(pcie->reg_base + reg); > +} > + > +/* Root Port register access */ > +static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie, > + u32 reg, u8 value) > +{ > + writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); > +} > + > +static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie, > + u32 reg, u16 value) > +{ > + writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); > +} > + > +void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io, > + u64 cpu_addr, u64 pci_addr, size_t size); > + > +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r); Ditto. I understand it is hard to untangle code that was written with both EP and host bridge support in mind but, as I state below every patch has to make sense on its own. > + > +#endif /* _PCIE_CADENCE_H */ Technically speaking, this 3-file (.c .h) split is not necessary and can turn out unnecessary churn if we never merge the endpoint code - actually you would not even need a special cadence directory, just a host bridge driver file. Bottom line, as you know: every patch has to be self contained. It is already quite late -rc, I understand that changes this late are error prone so I will accept that this file splitting is necessary for "future" patches - if you manage to squash changes into a file I'd appreciate though, it does not make sense to export functions that are used in just one compilation unit (and some that are not used at all). Thanks, Lorenzo ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <20180116160733.GA3644-4tUPXFaYRHv6sAKXYmQ0tx/iLCjYCKR+VpNB7YpNyf8@public.gmane.org>]
* Re: [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller [not found] ` <20180116160733.GA3644-4tUPXFaYRHv6sAKXYmQ0tx/iLCjYCKR+VpNB7YpNyf8@public.gmane.org> @ 2018-01-18 23:23 ` Cyrille Pitchen 0 siblings, 0 replies; 14+ messages in thread From: Cyrille Pitchen @ 2018-01-18 23:23 UTC (permalink / raw) To: Lorenzo Pieralisi Cc: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, kishon-l0cyMroinI0, linux-pci-u79uwXL29TY76Z2rM5mHXA, adouglas-vna1KIf7WgpBDgjK7y7TUQ, stelford-vna1KIf7WgpBDgjK7y7TUQ, dgary-vna1KIf7WgpBDgjK7y7TUQ, kgopi-vna1KIf7WgpBDgjK7y7TUQ, eandrews-vna1KIf7WgpBDgjK7y7TUQ, thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, sureshp-vna1KIf7WgpBDgjK7y7TUQ, nsekhar-l0cyMroinI0, linux-kernel-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA Hi Lorenzo Le 16/01/2018 à 17:07, Lorenzo Pieralisi a écrit : > On Wed, Jan 10, 2018 at 11:47:35PM +0100, Cyrille Pitchen wrote: >> This patch adds support to the Cadence PCIe controller in host mode. >> >> Signed-off-by: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> >> --- >> MAINTAINERS | 7 + >> drivers/pci/Kconfig | 1 + >> drivers/pci/Makefile | 1 + >> drivers/pci/cadence/Kconfig | 16 ++ >> drivers/pci/cadence/Makefile | 3 + >> drivers/pci/cadence/pcie-cadence-host.c | 336 ++++++++++++++++++++++++++++++++ >> drivers/pci/cadence/pcie-cadence.c | 68 +++++++ >> drivers/pci/cadence/pcie-cadence.h | 196 +++++++++++++++++++ > > [...] > >> +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r) >> +{ >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0); >> + >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0); >> + >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); >> + cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); >> +} > > Unused function, please remove it. done in v4. > >> diff --git a/drivers/pci/cadence/pcie-cadence.h b/drivers/pci/cadence/pcie-cadence.h >> new file mode 100644 >> index 000000000000..3a15b4016352 >> --- /dev/null >> +++ b/drivers/pci/cadence/pcie-cadence.h >> @@ -0,0 +1,196 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +// Copyright (c) 2017 Cadence >> +// Cadence PCIe controller driver. >> +// Author: Cyrille Pitchen <cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> >> + >> +#ifndef _PCIE_CADENCE_H >> +#define _PCIE_CADENCE_H >> + >> +#include <linux/kernel.h> >> +#include <linux/pci.h> >> + >> +/* >> + * Local Management Registers >> + */ >> +#define CDNS_PCIE_LM_BASE 0x00100000 >> + >> +/* Vendor ID Register */ >> +#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044) >> +#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0) >> +#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0 >> +#define CDNS_PCIE_LM_ID_VENDOR(vid) \ >> + (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK) >> +#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16) >> +#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16 >> +#define CDNS_PCIE_LM_ID_SUBSYS(sub) \ >> + (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK) >> + >> +/* Root Port Requestor ID Register */ >> +#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228) >> +#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0) >> +#define CDNS_PCIE_LM_RP_RID_SHIFT 0 >> +#define CDNS_PCIE_LM_RP_RID_(rid) \ >> + (((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK) >> + >> +/* Root Complex BAR Configuration Register */ >> +#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \ >> + (((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \ >> + (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \ >> + (((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \ >> + (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0 >> +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0 >> +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20) >> +#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31) >> + >> +/* BAR control values applicable to both Endpoint Function and Root Complex */ >> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0 >> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1 >> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4 >> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5 >> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6 >> +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7 >> + >> + >> +/* >> + * Root Port Registers (PCI configuration space for the root port function) >> + */ >> +#define CDNS_PCIE_RP_BASE 0x00200000 >> + >> + >> +/* >> + * Address Translation Registers >> + */ >> +#define CDNS_PCIE_AT_BASE 0x00400000 >> + >> +/* Region r Outbound AXI to PCIe Address Translation Register 0 */ >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \ >> + (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020) >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0) >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \ >> + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK) >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12) >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \ >> + (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK) >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20) >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \ >> + (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK) >> + >> +/* Region r Outbound AXI to PCIe Address Translation Register 1 */ >> +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \ >> + (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020) >> + >> +/* Region r Outbound PCIe Descriptor Register 0 */ >> +#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \ >> + (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020) >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0) >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2 >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6 >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd >> +/* Bit 23 MUST be set in RC mode. */ >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23) >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24) >> +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \ >> + (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK) >> + >> +/* Region r Outbound PCIe Descriptor Register 1 */ >> +#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \ >> + (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020) >> +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0) >> +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \ >> + ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK) >> + >> +/* Region r AXI Region Base Address Register 0 */ >> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \ >> + (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020) >> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0) >> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \ >> + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK) >> + >> +/* Region r AXI Region Base Address Register 1 */ >> +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \ >> + (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020) >> + >> +/* Root Port BAR Inbound PCIe to AXI Address Translation Register */ >> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \ >> + (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008) >> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0) >> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \ >> + (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK) >> +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \ >> + (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008) >> + >> +enum cdns_pcie_rp_bar { >> + RP_BAR0, >> + RP_BAR1, >> + RP_NO_BAR >> +}; >> + >> +/** >> + * struct cdns_pcie - private data for Cadence PCIe controller drivers >> + * @reg_base: IO mapped register base >> + * @mem_res: start/end offsets in the physical system memory to map PCI accesses >> + * @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint. >> + * @bus: In Root Complex mode, the bus number >> + */ >> +struct cdns_pcie { >> + void __iomem *reg_base; >> + struct resource *mem_res; >> + bool is_rc; >> + u8 bus; >> +}; >> + >> +/* Register access */ >> +static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value) >> +{ >> + writeb(value, pcie->reg_base + reg); >> +} >> + >> +static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value) >> +{ >> + writew(value, pcie->reg_base + reg); >> +} >> + >> +static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value) >> +{ >> + writel(value, pcie->reg_base + reg); >> +} >> + >> +static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg) >> +{ >> + return readl(pcie->reg_base + reg); >> +} >> + >> +/* Root Port register access */ >> +static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie, >> + u32 reg, u8 value) >> +{ >> + writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); >> +} >> + >> +static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie, >> + u32 reg, u16 value) >> +{ >> + writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg); >> +} >> + >> +void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u32 r, bool is_io, >> + u64 cpu_addr, u64 pci_addr, size_t size); >> + >> +void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r); > > Ditto. I understand it is hard to untangle code that was written with > both EP and host bridge support in mind but, as I state below every > patch has to make sense on its own. done in v4. > >> + >> +#endif /* _PCIE_CADENCE_H */ > > Technically speaking, this 3-file (.c .h) split is not necessary and can > turn out unnecessary churn if we never merge the endpoint code - > actually you would not even need a special cadence directory, just a > host bridge driver file. > > Bottom line, as you know: every patch has to be self contained. > > It is already quite late -rc, I understand that changes this late > are error prone so I will accept that this file splitting is necessary > for "future" patches - if you manage to squash changes into a file I'd > appreciate though, it does not make sense to export functions that are > used in just one compilation unit (and some that are not used at all). Sorry, I didn't have time to squash the 3 files into a single one. I can do it in v5 if you think it's better. I plan to work on the endpoint driver with multi-functions this week-end, hence I hope I will be able to add this driver back in v5. I've just been sending v4 anyway so at least you will have former patch 3 from v3 split into new patches 3 and 4 in v4 as you requested. So if you want to merge at least the new generic patches [1 - 4] for v4.16, they are available :) Best regards, Cyrille > > Thanks, > Lorenzo > -- Cyrille Pitchen, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2018-01-18 23:23 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-01-10 22:47 [PATCH v3 0/6] PCI: Add support to the Cadence PCIe controller Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 1/6] PCI: Regroup all PCI related entries into drivers/pci/Makefile Cyrille Pitchen [not found] ` <cover.1515621150.git.cyrille.pitchen-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2018-01-10 22:47 ` [PATCH v3 2/6] PCI: OF: Add generic function to parse and allocate PCI resources Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 3/6] PCI: Add generic function to probe PCI host controllers Cyrille Pitchen 2018-01-16 15:25 ` Lorenzo Pieralisi 2018-01-18 22:58 ` Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 4/6] PCI: Add vendor ID for Cadence Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 5/6] dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller Cyrille Pitchen 2018-01-10 22:47 ` [PATCH v3 6/6] PCI: cadence: Add host driver for Cadence PCIe controller Cyrille Pitchen 2018-01-16 11:16 ` Kishon Vijay Abraham I [not found] ` <e3d88d5b-e770-d2e5-20b2-62551d5f4f8f-l0cyMroinI0@public.gmane.org> 2018-01-16 15:09 ` Lorenzo Pieralisi 2018-01-18 23:13 ` Cyrille Pitchen 2018-01-16 16:07 ` Lorenzo Pieralisi [not found] ` <20180116160733.GA3644-4tUPXFaYRHv6sAKXYmQ0tx/iLCjYCKR+VpNB7YpNyf8@public.gmane.org> 2018-01-18 23:23 ` Cyrille Pitchen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).