From patchwork Fri Apr 29 23:01:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 102403 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp1044626qge; Fri, 29 Apr 2016 16:02:57 -0700 (PDT) X-Received: by 10.66.86.161 with SMTP id q1mr20201611paz.59.1461970976443; Fri, 29 Apr 2016 16:02:56 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id ia2si57407pad.150.2016.04.29.16.02.56; Fri, 29 Apr 2016 16:02:56 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752888AbcD2XCu (ORCPT + 29 others); Fri, 29 Apr 2016 19:02:50 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:56850 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752598AbcD2XCW (ORCPT ); Fri, 29 Apr 2016 19:02:22 -0400 Received: from wuerfel.lan. ([78.42.132.4]) by mrelayeu.kundenserver.de (mreue101) with ESMTPA (Nemesis) id 0MHGU7-1ar2E43e6t-00E3zU; Sat, 30 Apr 2016 01:01:48 +0200 From: Arnd Bergmann To: Bjorn Helgaas Cc: catalin.marinas@arm.com, linux-pci@vger.kernel.org, will.deacon@arm.com, Lorenzo Pieralisi , Tomasz Nowicki , ddaney@caviumnetworks.com, robert.richter@caviumnetworks.com, msalter@redhat.com, Liviu.Dudau@arm.com, jchandra@broadcom.com, linux-kernel@vger.kernel.org, hanjun.guo@linaro.org, Suravee.Suthikulpanit@amd.com, Thierry Reding , Arnd Bergmann Subject: [PATCH 1/3] [RFC] pci: add new method for register PCI hosts Date: Sat, 30 Apr 2016 01:01:37 +0200 Message-Id: <1461970899-4150603-2-git-send-email-arnd@arndb.de> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1461970899-4150603-1-git-send-email-arnd@arndb.de> References: <1461970899-4150603-1-git-send-email-arnd@arndb.de> X-Provags-ID: V03:K0:BJA69xuwEUxinC34Xt7QrwCiM4HddHzIBJrJ3brTNjUeAQAWjiq w65EMwQJIUq07EB/D4g1yXEfOq/MbIGwRyIIBZygm2PgLKEwHKYl0Tv9B88TZl2TNu7MCuq hDFSlLlFJ6uk9cqOc4XqwDVQ6Lmcz74J2Uws6yFHUZoG0DFi83t8AqvZjBxEdhkOwuNhF3R /aSArzxP+N5xrN3f/3HaQ== X-UI-Out-Filterresults: notjunk:1; V01:K0:/14NlcYmfw4=:aFLDhyQswLAm3aAFGqKaTH 8HYeZei0pzBG1uk+Io7uqNvalygpRgePPrXdAte7Pz0QoTPPHeJxWTTusH5xW94xo7MmbGe/W 4uPlp/UlL/1Rl9Y/nnOrRkCjxfQ1/WI/CW1oEkO8wS43rEASPXfhl6/THqqy7mpa/qyOdlenK xxGTIPqA/sd682E1Jkv1qYbNHRUHbmg1tVMNWGkqzi0W0QBzaKjsDRegfcmxz/NTl5dJRxTGp fWvkqgwez80Nqzpa4KdkrB/9RzWEptQsuQdWIk/InmvuIG8lpVA1lT0lfIy+WptPrMDCHxTCQ OsLymuzD5VOVD3Og6HsIVPXiNKxa2IER3NOdMJshTZ7i0NlSTUhjfpErimjkdl8ZcllPeP3I8 0zWYf0Z4yrjjEptGBuPFV9JBhPq5MHUMqKtWUo6c4xlLpHWW80b7vl2+3K2mscncp7HCgkNVh L/LN2TmuVThOFbRvhsWP0waEiWfVV2hqFAkrSDcAMpORZ5qFnrR5uF9Yp0MvfF9HHy1fLIUTL GuKGuRP0f2VvLVVOjdMcp11phy9OSlv2Rmo2usVPSLcDAovoVpmsPHv5lCim3muhwNmCQP67r Bpk9vQXKoIGE37MlVfp/qRm42+ElXKkq5gkIuTtEZWxUBKWIZvzvbdURm+gKr9fgl2ZGYbHe3 XxVqFBR2CeRq/CJqdiGnDlGm5GvwTYGLElER8A4y93DtU79WAasOimgvX5SbNGfze2O8= Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch makes the existing 'pci_host_bridge' structure a proper device that is usable by PCI host drivers in a more standard way. In addition to the existing pci_scan_bus, pci_scan_root_bus, pci_scan_root_bus_msi, and pci_create_root_bus interfaces, this unfortunately means having to add yet another interface doing basically the same thing, and add some extra code in the initial step. However, this time it's more likely to be extensible enough that we won't have to do another one again in the future, and we should be able to reduce code much more as a result. The main idea is to pull the allocation of 'struct pci_host_bridge' out of the registration, and let individual host drivers and architecture code fill the members before calling the registration function. There are a number of things we can do based on this: * Use a single memory allocation for the driver-specific structure and the generic PCI host bridge * consolidate the contents of driver specific structures by moving them into pci_host_bridge * Add a consistent interface for removing a PCI host bridge again when unloading a host driver module * Replace the architecture specific __weak pcibios_* functions with callbacks in a pci_host_bridge device * Move common boilerplate code from host drivers into the generic function, based on contents of the structure * Extend pci_host_bridge with additional members when needed without having to add arguments to pci_scan_*. * Move members of struct pci_bus into pci_host_bridge to avoid having lots of identical copies. As mentioned in a previous email, one open question is whether we want to export a function for allocating a pci_host_bridge device in combination with the per-device structure or let the driver itself call kzalloc. Signed-off-by: Arnd Bergmann --- drivers/pci/probe.c | 100 ++++++++++++++++++++++++++++++---------------------- include/linux/pci.h | 7 +++- 2 files changed, 63 insertions(+), 44 deletions(-) -- 2.7.0 diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ae7daeb83e21..fe9d9221b11e 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -520,19 +520,6 @@ static void pci_release_host_bridge_dev(struct device *dev) kfree(bridge); } -static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) -{ - struct pci_host_bridge *bridge; - - bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); - if (!bridge) - return NULL; - - INIT_LIST_HEAD(&bridge->windows); - bridge->bus = b; - return bridge; -} - static const unsigned char pcix_bus_speed[] = { PCI_SPEED_UNKNOWN, /* 0 */ PCI_SPEED_66MHz_PCIX, /* 1 */ @@ -2108,51 +2095,47 @@ void __weak pcibios_remove_bus(struct pci_bus *bus) { } -struct pci_bus *pci_create_root_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, struct list_head *resources) +int pci_register_host(struct pci_host_bridge *bridge) { int error; - struct pci_host_bridge *bridge; struct pci_bus *b, *b2; struct resource_entry *window, *n; + LIST_HEAD(resources); struct resource *res; resource_size_t offset; char bus_addr[64]; char *fmt; + struct device *parent = bridge->dev.parent; b = pci_alloc_bus(NULL); if (!b) - return NULL; + return -ENOMEM; + bridge->bus = b; - b->sysdata = sysdata; - b->ops = ops; - b->number = b->busn_res.start = bus; + /* temporarily move resources off the list */ + list_splice_init(&bridge->windows, &resources); + b->sysdata = bridge->sysdata; + b->msi = bridge->msi; + b->ops = bridge->ops; + b->number = b->busn_res.start = bridge->busnr; pci_bus_assign_domain_nr(b, parent); - b2 = pci_find_bus(pci_domain_nr(b), bus); + b2 = pci_find_bus(pci_domain_nr(b), bridge->busnr); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ dev_dbg(&b2->dev, "bus already known\n"); + error = -EEXIST; goto err_out; } - bridge = pci_alloc_host_bridge(b); - if (!bridge) - goto err_out; - - bridge->dev.parent = parent; - bridge->dev.release = pci_release_host_bridge_dev; - dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); + dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bridge->busnr); error = pcibios_root_bridge_prepare(bridge); - if (error) { - kfree(bridge); + if (error) goto err_out; - } error = device_register(&bridge->dev); - if (error) { + if (error) put_device(&bridge->dev); - goto err_out; - } + b->bridge = get_device(&bridge->dev); device_enable_async_suspend(b->bridge); pci_set_bus_of_node(b); @@ -2163,7 +2146,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, b->dev.class = &pcibus_class; b->dev.parent = b->bridge; - dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus); + dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bridge->busnr); error = device_register(&b->dev); if (error) goto class_dev_reg_err; @@ -2179,12 +2162,12 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev)); /* Add initial resources to the bus */ - resource_list_for_each_entry_safe(window, n, resources) { + resource_list_for_each_entry_safe(window, n, &resources) { list_move_tail(&window->node, &bridge->windows); res = window->res; offset = window->offset; if (res->flags & IORESOURCE_BUS) - pci_bus_insert_busn_res(b, bus, res->end); + pci_bus_insert_busn_res(b, bridge->busnr, res->end); else pci_bus_add_resource(b, res, 0); if (offset) { @@ -2204,16 +2187,16 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, list_add_tail(&b->node, &pci_root_buses); up_write(&pci_bus_sem); - return b; + return 0; class_dev_reg_err: put_device(&bridge->dev); device_unregister(&bridge->dev); err_out: kfree(b); - return NULL; + return error; } -EXPORT_SYMBOL_GPL(pci_create_root_bus); +EXPORT_SYMBOL_GPL(pci_register_host); int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) { @@ -2278,6 +2261,39 @@ void pci_bus_release_busn_res(struct pci_bus *b) res, ret ? "can not be" : "is"); } +static struct pci_bus * pci_create_root_bus_msi(struct device *parent, + int bus, struct pci_ops *ops, void *sysdata, + struct list_head *resources, struct msi_controller *msi) +{ + struct pci_host_bridge *bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + int ret; + + if (!bridge) + return NULL; + + bridge->dev.parent = parent; + bridge->dev.release = pci_release_host_bridge_dev; + bridge->busnr = bus; + bridge->ops = ops; + bridge->sysdata = sysdata; + bridge->msi = msi; + list_splice_init(resources, &bridge->windows); + + ret = pci_register_host(bridge); + if (ret) + return NULL; + + return bridge->bus; +} + +struct pci_bus *pci_create_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, struct list_head *resources) +{ + return pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, + NULL); +} +EXPORT_SYMBOL_GPL(pci_create_root_bus); + struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources, struct msi_controller *msi) @@ -2293,12 +2309,10 @@ struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, break; } - b = pci_create_root_bus(parent, bus, ops, sysdata, resources); + b = pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, msi); if (!b) return NULL; - b->msi = msi; - if (!found) { dev_info(&b->dev, "No busn resource found for root bus, will use [bus %02x-ff]\n", diff --git a/include/linux/pci.h b/include/linux/pci.h index 81f070a47ee7..8bb5dff617a1 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -400,10 +400,14 @@ static inline int pci_channel_offline(struct pci_dev *pdev) struct pci_host_bridge { struct device dev; - struct pci_bus *bus; /* root bus */ + struct pci_ops *ops; + void *sysdata; + int busnr; + struct pci_bus *bus; /* points to root */ struct list_head windows; /* resource_entry */ void (*release_fn)(struct pci_host_bridge *); void *release_data; + struct msi_controller *msi; unsigned int ignore_reset_delay:1; /* for entire hierarchy */ /* Resource alignment requirements */ resource_size_t (*align_resource)(struct pci_dev *dev, @@ -812,6 +816,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_register_host(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); From patchwork Fri Apr 29 23:01:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 102404 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp1044468qge; Fri, 29 Apr 2016 16:02:30 -0700 (PDT) X-Received: by 10.98.95.4 with SMTP id t4mr10611796pfb.162.1461970950786; Fri, 29 Apr 2016 16:02:30 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id fn8si20385687pab.197.2016.04.29.16.02.30; Fri, 29 Apr 2016 16:02:30 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752703AbcD2XCX (ORCPT + 29 others); Fri, 29 Apr 2016 19:02:23 -0400 Received: from mout.kundenserver.de ([212.227.17.10]:64840 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752412AbcD2XCT (ORCPT ); Fri, 29 Apr 2016 19:02:19 -0400 Received: from wuerfel.lan. ([78.42.132.4]) by mrelayeu.kundenserver.de (mreue101) with ESMTPA (Nemesis) id 0LZvrB-1bPXAP1fGn-00llvC; Sat, 30 Apr 2016 01:01:48 +0200 From: Arnd Bergmann To: Bjorn Helgaas Cc: catalin.marinas@arm.com, linux-pci@vger.kernel.org, will.deacon@arm.com, Lorenzo Pieralisi , Tomasz Nowicki , ddaney@caviumnetworks.com, robert.richter@caviumnetworks.com, msalter@redhat.com, Liviu.Dudau@arm.com, jchandra@broadcom.com, linux-kernel@vger.kernel.org, hanjun.guo@linaro.org, Suravee.Suthikulpanit@amd.com, Thierry Reding , Arnd Bergmann Subject: [PATCH 2/3] [RFC] pci: host-common: use new pci_register_host interface Date: Sat, 30 Apr 2016 01:01:38 +0200 Message-Id: <1461970899-4150603-3-git-send-email-arnd@arndb.de> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1461970899-4150603-1-git-send-email-arnd@arndb.de> References: <1461970899-4150603-1-git-send-email-arnd@arndb.de> X-Provags-ID: V03:K0:iokEKVOf003atV7SMYlCDb9jaWhccatyO56JnpwXj+hlA24AE/l vmS95VSaUwPc54iLM3ut4BNqfDUb7QJI46ZB1qrEq1AHKoVIzAMLsMJiXt3ezP6LaB3NQQu Md4FpWYEdlE1T/I52MhENYq6sGI+JmHrIEKStJNNsnU7nzKF8SCeY0W8ZkHNhvJyr7RRLeH uWSj75azb2JS7TW6qh6iw== X-UI-Out-Filterresults: notjunk:1; V01:K0:XwfGaV5isbY=:w9K5eZDv2xIg11bvPzt5zt EzUDUq+LYFj5u9ZwYw5B2dqJAaVCckEalTmbLlkoHHtmLv7ccjOdjRsslmLqHY1d32Gagxeo9 djJW6WaWs3QkGKlScM+dz0s9YByS3EiNo7MHwUd4NqYCATqylN+I8px01QfnoyufuU4gh38FQ hCe/ucXw9kWpe0kZ6FZxNNIFL37R18k9iEQHHtJ4bhWdIf/K9TeZXCNUoAS6R++9q459/SVZa jk5eyp9hLNZ12XNJtC1lhHuzN5H/oiphiLVH4rq7v7OMkM55DuVTKGk7Ad1QGGSSoHmZZdGD1 8mez+I2sPlfmldOAKB/+7IOxm8jIZAckTKFcz/zwUw64/rXiyydPxoK9TkZ5gmjcMw5VSXV1C 3yoh8q0xGsmNko0utLVFrxVaRE6NTSyt5oo4lfHDuWv+CXP1fiCjbEmChghqCZ8QhciSzkEKK eqwn8dRX/W4laethQsuLJBCH++4r/BC00bHTx6sFv58LFEpn4UV7Jd0ELgYn7zL4TyXV/Qu87 fah+8GQ9C3LnK1aZ0qhewX6zXq+kWnvf6VgdbYJ2EpDP74eHh/QHGfS3xEWflXCWGUs+XllqY Os7uNjEufNVcYKS6ikEFCN8WdwbRBoEhp0TFKp2HIqVxwntNHxy3Px6RIpTNbgJejJKggfxXP lTIp94I1t6YVGxjgIL3iji23W38HuJblCwbP40w5XKHCZIYIr2CBzctKgpa+fHzMrcxo= Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This changes the pci-host-common implementation to call the new pci_register_host() interface instead of pci_scan_root_bus(). As a result, we get to share the pci_host_bridge structure as it was originally intended anyway: We ended up having two copies of pci_host_bridge here because we never got it done until now. We can also remove the now unused "resources" list_head, as we add the resources to the pci_host_bridge directly. On top of this, further generalizations are possible to shrink the pci-host-common.c file, in particular requesting the resources and scanning for child devices can be moved into pci_register_host(). Signed-off-by: Arnd Bergmann --- drivers/pci/host/pci-host-common.c | 38 ++++++++++++++++++++++++-------------- drivers/pci/host/pci-host-common.h | 1 - 2 files changed, 24 insertions(+), 15 deletions(-) -- 2.7.0 diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c index e9f850f07968..3fc529f0297e 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/host/pci-host-common.c @@ -26,7 +26,7 @@ static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) { - pci_free_resource_list(&pci->resources); + pci_free_resource_list(&pci->host.windows); } static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) @@ -37,12 +37,12 @@ static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) resource_size_t iobase; struct resource_entry *win; - err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, + err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->host.windows, &iobase); if (err) return err; - resource_list_for_each_entry(win, &pci->resources) { + resource_list_for_each_entry(win, &pci->host.windows) { struct resource *parent, *res = win->res; switch (resource_type(res)) { @@ -130,6 +130,14 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) return 0; } +static void gen_pci_release(struct device *dev) +{ + struct gen_pci *pci = container_of(dev, struct gen_pci, host.dev); + + gen_pci_release_of_pci_ranges(pci); + kfree(pci); +} + int pci_host_common_probe(struct platform_device *pdev, struct gen_pci *pci) { @@ -137,7 +145,7 @@ 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_bus *child; type = of_get_property(np, "device_type", NULL); if (!type || strcmp(type, "pci")) { @@ -148,8 +156,8 @@ int pci_host_common_probe(struct platform_device *pdev, of_pci_check_probe_only(); pci->host.dev.parent = dev; + pci->host.dev.release = gen_pci_release; INIT_LIST_HEAD(&pci->host.windows); - INIT_LIST_HEAD(&pci->resources); /* Parse our PCI ranges and request their resources */ err = gen_pci_parse_request_of_pci_ranges(pci); @@ -168,24 +176,26 @@ int pci_host_common_probe(struct platform_device *pdev, pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); - bus = pci_scan_root_bus(dev, pci->cfg.bus_range->start, - &pci->cfg.ops->ops, pci, &pci->resources); - if (!bus) { - dev_err(dev, "Scanning rootbus failed"); - return -ENODEV; + pci->host.ops = &pci->cfg.ops->ops; + pci->host.sysdata = pci; + pci->host.busnr = pci->cfg.bus_range->start; + err = pci_register_host(&pci->host); + if (!err) { + dev_err(dev, "registering host failed"); + return err; } pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci); if (!pci_has_flag(PCI_PROBE_ONLY)) { - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); + pci_bus_size_bridges(pci->host.bus); + pci_bus_assign_resources(pci->host.bus); - list_for_each_entry(child, &bus->children, node) + list_for_each_entry(child, &pci->host.bus->children, node) pcie_bus_configure_settings(child); } - pci_bus_add_devices(bus); + pci_bus_add_devices(pci->host.bus); return 0; } diff --git a/drivers/pci/host/pci-host-common.h b/drivers/pci/host/pci-host-common.h index 09f3fa0a55d7..c89a756420ee 100644 --- a/drivers/pci/host/pci-host-common.h +++ b/drivers/pci/host/pci-host-common.h @@ -38,7 +38,6 @@ struct gen_pci_cfg_windows { struct gen_pci { struct pci_host_bridge host; struct gen_pci_cfg_windows cfg; - struct list_head resources; }; int pci_host_common_probe(struct platform_device *pdev, From patchwork Fri Apr 29 23:01:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 102405 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp1044475qge; Fri, 29 Apr 2016 16:02:31 -0700 (PDT) X-Received: by 10.98.18.11 with SMTP id a11mr33183701pfj.102.1461970951136; Fri, 29 Apr 2016 16:02:31 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id fn8si20385687pab.197.2016.04.29.16.02.30; Fri, 29 Apr 2016 16:02:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752786AbcD2XCZ (ORCPT + 29 others); Fri, 29 Apr 2016 19:02:25 -0400 Received: from mout.kundenserver.de ([217.72.192.74]:60924 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752553AbcD2XCU (ORCPT ); Fri, 29 Apr 2016 19:02:20 -0400 Received: from wuerfel.lan. ([78.42.132.4]) by mrelayeu.kundenserver.de (mreue101) with ESMTPA (Nemesis) id 0Mf0OX-1bK9v33m2r-00OYfq; Sat, 30 Apr 2016 01:01:49 +0200 From: Arnd Bergmann To: Bjorn Helgaas Cc: catalin.marinas@arm.com, linux-pci@vger.kernel.org, will.deacon@arm.com, Lorenzo Pieralisi , Tomasz Nowicki , ddaney@caviumnetworks.com, robert.richter@caviumnetworks.com, msalter@redhat.com, Liviu.Dudau@arm.com, jchandra@broadcom.com, linux-kernel@vger.kernel.org, hanjun.guo@linaro.org, Suravee.Suthikulpanit@amd.com, Thierry Reding , Arnd Bergmann Subject: [PATCH 3/3] [RFC] pci: tegra: use new pci_register_host interface Date: Sat, 30 Apr 2016 01:01:39 +0200 Message-Id: <1461970899-4150603-4-git-send-email-arnd@arndb.de> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1461970899-4150603-1-git-send-email-arnd@arndb.de> References: <1461970899-4150603-1-git-send-email-arnd@arndb.de> X-Provags-ID: V03:K0:3Y7hui+WgT4ZoJP/UsUYegpEbHlfZSX+CRc68eoeK7Wm6rOfVzA 0SF12G+xH/7gfx9pwLgANviDo8/rer0cefzixN8VMa3DQ0HQdIFb1298QQej8yLDgn44R6G hwdAtjByarzt7UTUT6iWRnBLAlqMZPglI9BKz1fzz2kTLgiUxeRng8WyDtUxRmbrdoHPZlR AEw2m0+vdVF1GWzmyfwvw== X-UI-Out-Filterresults: notjunk:1; V01:K0:Mrh5YM7XuCk=:bw3uMLxvKaPL7/Iptm9Xag AV3GmpTDtsRDQpl+9L8FirbuebY/quyw+xVePUiwxFkXXlAJV97w9W6/Feo5kxOxjmnPbD2ZZ Vakm3dcWzluegowBumteRG/OZcoqKkPsF2CYlLb5mtQ72ZmrsVx7OhAwnv9a2NNd+mMfrmG7o 5/SPzZEPoCTK3Vga8bTQXPKytf2T22dwIZqS/nZ0GbjaIWNMK0untwI/oVyjUlzyqmfNId/pX KQMw/nATgGfJ1h8oBnWcr1Q8rrI+7MKJdsN5ffTAd5DjVxiLoPz8hgVi2692MFR3hjz5sJUie JlImZ6lEUGCyU7EN0DcjItIgBoXi70mlBPD/TUvW2T+WMWhUkK+FAtWCwVXJ5Olu1K4YMVLcg 17Q8OSHbXFb4nR8lalxlDSshAMS8togWEJT4UplLdciF/ks7SKBYZfN2ZyYaU0paoN2w0j6TP T0EJR8pj6qFFUhTBZWiD73vGe9ibIWJDcMiZgKFLZPg5j5HXYMJXM8kC7aBCGkCd1KEzhSUCG OVH1Lr8BbmRPYAa4S43qkshcZle5MqGbB/6nGn8jQ1bLi/2Nada5JUuRlXiagbQDGNeBMrtiW BoCMJFtohWBHgQBj2ty5X/kjAK30eCaBrDfbwY1UOZD1fDWrVPtekWTRTw6K0btnWjv8875X2 k9oxfdEEwNxAH8XrdJH/7B95QY+O0HWGyjdKyJlDXyj0MOgr2zjcedaX1HJjTQ5Ra1Hw= Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Tegra is one of the remaining platforms that still use the traditional pci_common_init_dev() interface for probing PCI host bridges. This demonstrates how to convert it to the pci_register_host interface I just added in a previous patch. This leads to a more linear probe sequence that can handle errors better because we avoid callbacks into the driver, and it makes the driver architecture independent. As a side note, I should mention that I noticed this driver does not register any IORESOURCE_IO resource with the bus, but instead registers the I/O port window as a memory resource, which is surely a bug. Signed-off-by: Arnd Bergmann --- drivers/pci/host/pci-tegra.c | 67 ++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 31 deletions(-) -- 2.7.0 diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index c388468c202a..ece4f5d0180b 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -265,6 +265,7 @@ static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip) } struct tegra_pcie { + struct pci_host_bridge bridge; struct device *dev; void __iomem *pads; @@ -615,14 +616,10 @@ static void tegra_pcie_relax_enable(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); -static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) +static int tegra_pcie_request_resources(struct tegra_pcie *pcie) { - struct tegra_pcie *pcie = sys_to_pcie(sys); int err; - sys->mem_offset = pcie->offset.mem; - sys->io_offset = pcie->offset.io; - err = devm_request_resource(pcie->dev, &pcie->all, &pcie->io); if (err < 0) return err; @@ -639,15 +636,15 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) if (err) return err; - pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset); - pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); - pci_add_resource_offset(&sys->resources, &pcie->prefetch, - sys->mem_offset); - pci_add_resource(&sys->resources, &pcie->busn); + pci_add_resource_offset(&pcie->bridge.windows, &pcie->pio, pcie->offset.io); + pci_add_resource_offset(&pcie->bridge.windows, &pcie->mem, pcie->offset.mem); + pci_add_resource_offset(&pcie->bridge.windows, &pcie->prefetch, + pcie->offset.mem); + pci_add_resource(&pcie->bridge.windows, &pcie->busn); pci_ioremap_io(pcie->pio.start, pcie->io.start); - return 1; + return 0; } static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) @@ -1535,6 +1532,7 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) } /* setup AFI/FPCI range */ + pcie->bridge.msi = &msi->chip; msi->pages = __get_free_pages(GFP_KERNEL, 0); base = virt_to_phys((void *)msi->pages); @@ -2036,10 +2034,9 @@ retry: return false; } -static int tegra_pcie_enable(struct tegra_pcie *pcie) +static void tegra_pcie_enable_ports(struct tegra_pcie *pcie) { struct tegra_pcie_port *port, *tmp; - struct hw_pci hw; list_for_each_entry_safe(port, tmp, &pcie->ports, list) { dev_info(pcie->dev, "probing port %u, using %u lanes\n", @@ -2055,22 +2052,6 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie) tegra_pcie_port_disable(port); tegra_pcie_port_free(port); } - - memset(&hw, 0, sizeof(hw)); - -#ifdef CONFIG_PCI_MSI - hw.msi_ctrl = &pcie->msi.chip; -#endif - - hw.nr_controllers = 1; - hw.private_data = (void **)&pcie; - hw.setup = tegra_pcie_setup; - hw.map_irq = tegra_pcie_map_irq; - hw.ops = &tegra_pcie_ops; - - pci_common_init_dev(pcie->dev, &hw); - - return 0; } static const struct tegra_pcie_soc_data tegra20_pcie_data = { @@ -2230,6 +2211,8 @@ static int tegra_pcie_probe(struct platform_device *pdev) { const struct of_device_id *match; struct tegra_pcie *pcie; + struct pci_host_bridge *bridge; + struct pci_bus *child; int err; match = of_match_device(tegra_pcie_of_match, &pdev->dev); @@ -2244,6 +2227,7 @@ static int tegra_pcie_probe(struct platform_device *pdev) INIT_LIST_HEAD(&pcie->ports); pcie->soc_data = match->data; pcie->dev = &pdev->dev; + bridge = &pcie->bridge; err = tegra_pcie_parse_dt(pcie); if (err < 0) @@ -2261,6 +2245,10 @@ static int tegra_pcie_probe(struct platform_device *pdev) if (err) goto put_resources; + err = tegra_pcie_request_resources(pcie); + if (err) + goto put_resources; + /* setup the AFI address translations */ tegra_pcie_setup_translations(pcie); @@ -2274,12 +2262,29 @@ static int tegra_pcie_probe(struct platform_device *pdev) } } - err = tegra_pcie_enable(pcie); + tegra_pcie_enable_ports(pcie); + + pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); + bridge->busnr = pcie->busn.start; + bridge->dev.parent = &pdev->dev; + bridge->sysdata = pcie; + bridge->ops = &tegra_pcie_ops; + err = pci_register_host(bridge); + if (err < 0) { - dev_err(&pdev->dev, "failed to enable PCIe ports: %d\n", err); + dev_err(&pdev->dev, "failed to register host: %d\n", err); goto disable_msi; } + pci_fixup_irqs(pci_common_swizzle, tegra_pcie_map_irq); + pci_bus_size_bridges(bridge->bus); + pci_bus_assign_resources(bridge->bus); + + list_for_each_entry(child, &bridge->bus->children, node) + pcie_bus_configure_settings(child); + + pci_bus_add_devices(bridge->bus); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_pcie_debugfs_init(pcie); if (err < 0)