Message ID | 1391452428-22917-2-git-send-email-Liviu.Dudau@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Sat, Feb 8, 2014 at 6:22 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote: > On Sat, Feb 08, 2014 at 12:21:56AM +0000, Tanmay Inamdar wrote: >> On Thu, Feb 6, 2014 at 2:18 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote: >> > On Wed, Feb 05, 2014 at 10:26:27PM +0000, Tanmay Inamdar wrote: >> >> Hello Liviu, >> >> >> >> I did not get the first email of this particular patch on any of >> >> subscribed mailing lists (don't know why), hence replying here. >> > >> > Strange, it shows in the MARC and GMANE archive for linux-pci, probably >> > a hickup on your receiving side? >> > >> >> >> >> +struct pci_host_bridge * >> >> +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, >> >> + void *host_data, struct list_head *resources) >> >> +{ >> >> + struct pci_bus *root_bus; >> >> + struct pci_host_bridge *bridge; >> >> + >> >> + /* first parse the host bridge bus ranges */ >> >> + if (pci_host_bridge_of_get_ranges(parent->of_node, resources)) >> >> + return NULL; >> >> + >> >> + /* then create the root bus */ >> >> + root_bus = pci_create_root_bus(parent, busno, ops, host_data, resources); >> >> + if (!root_bus) >> >> + return NULL; >> >> + >> >> + bridge = to_pci_host_bridge(root_bus->bridge); >> >> + >> >> + return bridge; >> >> +} >> >> >> >> You are keeping the domain_nr inside pci_host_bridge structure. In >> >> above API, domain_nr is required in 'pci_find_bus' function called >> >> from 'pci_create_root_bus'. Since the bridge is allocated after >> >> creating root bus, 'pci_find_bus' always gets domain_nr as 0. This >> >> will cause problem for scanning multiple domains. >> > >> > Good catch. I was switching between creating a pci_controller in arch/arm64 and >> > adding the needed bits in pci_host_bridge. After internal review I've decided to >> > add the domain_nr to pci_host_bridge, but forgot to update the code everywhere. >> > >> > Thanks for reviewing this, will fix in v2. >> > >> > Do you find porting to the new API straight forward? >> >> It is quite straight forward for MEM regions but for IO regions it is >> not. You always assume IO resource starting at 0x0. IMO, this will >> cause problem for systems with multiple ports / IO windows. You can >> take a look at 'drivers/pci/host/pcie-designware.c'. >> >> Also the manipulations of addresses for IO_RESOURCES can be dangerous. >> It can make some value negative. For example if my PCI IO range starts >> in 32 bit address range say 0x8000_0000 with CPU address >> 0xb0_8000_0000, window->offset after manipulation will become >> negative. >> >> Personally I would like to do get all the PCI and CPU addresses from >> my device tree as is and do the 'pci_add_resource_offset'. This will >> help me setup my regions correctly without any further arithmetic. >> Please let me know what you think. > > Yes, that parsing code of ranges is incorrect in light of the current discussion. I > will try to propose a fix in the v2 series. Okay. Thanks. > > Regarding your PCI IO range: if your bus address starts at 0x8000_0000, would > that not cause problems with devices that use less than 32bits for address > decoding? It is a rather unusual setup, I believe the x86 world (even PCI spec?) > mandates IO bus ranges in the first 16MB of address range? > Yes. It will cause problem with few devices. Anyways it was just an example. > Best regards, > Liviu > >> >> > >> > Best regards, >> > Liviu >> > >> >> >> >> >> >> On Mon, Feb 3, 2014 at 10:46 AM, Arnd Bergmann <arnd@arndb.de> wrote: >> >> > On Monday 03 February 2014 18:33:48 Liviu Dudau wrote: >> >> >> +/** >> >> >> + * pci_host_bridge_of_get_ranges - Parse PCI host bridge resources from DT >> >> >> + * @dev: device node of the host bridge having the range property >> >> >> + * @resources: list where the range of resources will be added after DT parsing >> >> >> + * >> >> >> + * This function will parse the "ranges" property of a PCI host bridge device >> >> >> + * node and setup the resource mapping based on its content. It is expected >> >> >> + * that the property conforms with the Power ePAPR document. >> >> >> + * >> >> >> + * Each architecture will then apply their filtering based on the limitations >> >> >> + * of each platform. One general restriction seems to be the number of IO space >> >> >> + * ranges, the PCI framework makes intensive use of struct resource management, >> >> >> + * and for IORESOURCE_IO types they can only be requested if they are contained >> >> >> + * within the global ioport_resource, so that should be limited to one IO space >> >> >> + * range. >> >> > >> >> > Actually we have quite a different set of restrictions around I/O space on ARM32 >> >> > at the moment: Each host bridge can have its own 64KB range in an arbitrary >> >> > location on MMIO space, and the total must not exceed 2MB of I/O space. >> >> > >> >> >> + */ >> >> >> +static int pci_host_bridge_of_get_ranges(struct device_node *dev, >> >> >> + struct list_head *resources) >> >> >> +{ >> >> >> + struct resource *res; >> >> >> + struct of_pci_range range; >> >> >> + struct of_pci_range_parser parser; >> >> >> + int err; >> >> >> + >> >> >> + pr_info("PCI host bridge %s ranges:\n", dev->full_name); >> >> >> + >> >> >> + /* Check for ranges property */ >> >> >> + err = of_pci_range_parser_init(&parser, dev); >> >> >> + if (err) >> >> >> + return err; >> >> >> + >> >> >> + pr_debug("Parsing ranges property...\n"); >> >> >> + for_each_of_pci_range(&parser, &range) { >> >> >> + /* Read next ranges element */ >> >> >> + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ", >> >> >> + range.pci_space, range.pci_addr); >> >> >> + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n", >> >> >> + range.cpu_addr, range.size); >> >> >> + >> >> >> + /* If we failed translation or got a zero-sized region >> >> >> + * (some FW try to feed us with non sensical zero sized regions >> >> >> + * such as power3 which look like some kind of attempt >> >> >> + * at exposing the VGA memory hole) then skip this range >> >> >> + */ >> >> >> + if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) >> >> >> + continue; >> >> >> + >> >> >> + res = kzalloc(sizeof(struct resource), GFP_KERNEL); >> >> >> + if (!res) { >> >> >> + err = -ENOMEM; >> >> >> + goto bridge_ranges_nomem; >> >> >> + } >> >> >> + >> >> >> + of_pci_range_to_resource(&range, dev, res); >> >> >> + >> >> >> + pci_add_resource_offset(resources, res, >> >> >> + range.cpu_addr - range.pci_addr); >> >> >> + } >> >> > >> >> > I believe of_pci_range_to_resource() will return the MMIO aperture for the >> >> > I/O space window here, which is not what you are supposed to pass into >> >> > pci_add_resource_offset. >> >> > >> >> >> +EXPORT_SYMBOL(pci_host_bridge_of_init); >> >> > >> >> > EXPORT_SYMBOL_GPL >> >> > >> >> >> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c >> >> >> index 6e34498..16febae 100644 >> >> >> --- a/drivers/pci/probe.c >> >> >> +++ b/drivers/pci/probe.c >> >> >> @@ -1787,6 +1787,17 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, >> >> >> list_for_each_entry_safe(window, n, resources, list) { >> >> >> list_move_tail(&window->list, &bridge->windows); >> >> >> res = window->res; >> >> >> + /* >> >> >> + * IO resources are stored in the kernel with a CPU start >> >> >> + * address of zero. Adjust the data accordingly and remember >> >> >> + * the offset >> >> >> + */ >> >> >> + if (resource_type(res) == IORESOURCE_IO) { >> >> >> + bridge->io_offset = res->start; >> >> >> + res->end -= res->start; >> >> >> + window->offset -= res->start; >> >> >> + res->start = 0; >> >> >> + } >> >> >> offset = window->offset; >> >> >> if (res->flags & IORESOURCE_BUS) >> >> > >> >> > Won't this break all existing host bridges? >> >> > >> >> > Arnd >> >> > >> >> > _______________________________________________ >> >> > linux-arm-kernel mailing list >> >> > linux-arm-kernel@lists.infradead.org >> >> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >> >> >> > >> > -- >> > ==================== >> > | I would like to | >> > | fix the world, | >> > | but they're not | >> > | giving me the | >> > \ source code! / >> > --------------- >> > ¯\_(?)_/¯ >> > >> > -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. >> > >> > ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590 >> > ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782 >> > >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-pci" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > > -- > ==================== > | I would like to | > | fix the world, | > | but they're not | > | giving me the | > \ source code! / > --------------- > ¯\_(?)_/¯ > > -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. > > ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590 > ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782 >
On Thursday, February 06, 2014 7:18 PM, Liviu Dudau wrote: > On Wed, Feb 05, 2014 at 10:26:27PM +0000, Tanmay Inamdar wrote: > > Hello Liviu, > > > > I did not get the first email of this particular patch on any of > > subscribed mailing lists (don't know why), hence replying here. > > Strange, it shows in the MARC and GMANE archive for linux-pci, probably > a hickup on your receiving side? > > > > > +struct pci_host_bridge * > > +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, > > + void *host_data, struct list_head *resources) > > +{ > > + struct pci_bus *root_bus; > > + struct pci_host_bridge *bridge; > > + > > + /* first parse the host bridge bus ranges */ > > + if (pci_host_bridge_of_get_ranges(parent->of_node, resources)) > > + return NULL; > > + > > + /* then create the root bus */ > > + root_bus = pci_create_root_bus(parent, busno, ops, host_data, resources); > > + if (!root_bus) > > + return NULL; > > + > > + bridge = to_pci_host_bridge(root_bus->bridge); > > + > > + return bridge; > > +} > > > > You are keeping the domain_nr inside pci_host_bridge structure. In > > above API, domain_nr is required in 'pci_find_bus' function called > > from 'pci_create_root_bus'. Since the bridge is allocated after > > creating root bus, 'pci_find_bus' always gets domain_nr as 0. This > > will cause problem for scanning multiple domains. > > Good catch. I was switching between creating a pci_controller in arch/arm64 and > adding the needed bits in pci_host_bridge. After internal review I've decided to > add the domain_nr to pci_host_bridge, but forgot to update the code everywhere. Hi Liviu Dudau, One more thing, I am reviewing and compiling your patch. Would you consider adding 'struct pci_sys_data' and 'struct hw_pci'? Currently, 4 PCIe Host drivers (pci-mvebu.c, pci-tegra.c, pci-rcar-gen2.c, pcie-designware.c) are using 'struct pci_sys_data' and 'struct hw_pci' in their drivers. Without this, it makes build errors. In arm32, 'struct pci_sys_data' and 'struct hw_pci' is defined in "arch/arm/include/asm/mach/pci.h". Tanmay Inamdar, Your 'APM X-Gene PCIe' patch also needs 'struct pci_sys_data' and 'struct hw_pci'. With Liviu Dudau's patch, it will make build errors. Would you check this? Thank you. Best regards, Jingoo Han > > Thanks for reviewing this, will fix in v2. > > Do you find porting to the new API straight forward? >
On > -----Original Message----- > From: Jingoo Han [mailto:jg1.han@samsung.com] > Sent: Thursday, February 13, 2014 5:10 PM > To: 'Liviu Dudau'; 'Tanmay Inamdar' > Cc: 'Arnd Bergmann'; devicetree@vger.kernel.org; 'linaro-kernel'; 'linux-pci'; 'Will Deacon'; 'LKML'; > 'Catalin Marinas'; 'Bjorn Helgaas'; 'LAKML'; 'Jingoo Han' > Subject: Re: [PATCH] pci: Add support for creating a generic host_bridge from device tree > > On Thursday, February 06, 2014 7:18 PM, Liviu Dudau wrote: > > On Wed, Feb 05, 2014 at 10:26:27PM +0000, Tanmay Inamdar wrote: > > > Hello Liviu, > > > > > > I did not get the first email of this particular patch on any of > > > subscribed mailing lists (don't know why), hence replying here. > > > > Strange, it shows in the MARC and GMANE archive for linux-pci, probably > > a hickup on your receiving side? > > > > > > > > +struct pci_host_bridge * > > > +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, > > > + void *host_data, struct list_head *resources) > > > +{ > > > + struct pci_bus *root_bus; > > > + struct pci_host_bridge *bridge; > > > + > > > + /* first parse the host bridge bus ranges */ > > > + if (pci_host_bridge_of_get_ranges(parent->of_node, resources)) > > > + return NULL; > > > + > > > + /* then create the root bus */ > > > + root_bus = pci_create_root_bus(parent, busno, ops, host_data, resources); > > > + if (!root_bus) > > > + return NULL; > > > + > > > + bridge = to_pci_host_bridge(root_bus->bridge); > > > + > > > + return bridge; > > > +} > > > > > > You are keeping the domain_nr inside pci_host_bridge structure. In > > > above API, domain_nr is required in 'pci_find_bus' function called > > > from 'pci_create_root_bus'. Since the bridge is allocated after > > > creating root bus, 'pci_find_bus' always gets domain_nr as 0. This > > > will cause problem for scanning multiple domains. > > > > Good catch. I was switching between creating a pci_controller in arch/arm64 and > > adding the needed bits in pci_host_bridge. After internal review I've decided to > > add the domain_nr to pci_host_bridge, but forgot to update the code everywhere. > > Hi Liviu Dudau, > > One more thing, > I am reviewing and compiling your patch. > Would you consider adding 'struct pci_sys_data' and 'struct hw_pci'? > > Currently, 4 PCIe Host drivers (pci-mvebu.c, pci-tegra.c, > pci-rcar-gen2.c, pcie-designware.c) are using 'struct pci_sys_data' > and 'struct hw_pci' in their drivers. Without this, it makes build > errors. > > In arm32, 'struct pci_sys_data' and 'struct hw_pci' is defined > in "arch/arm/include/asm/mach/pci.h". > > Tanmay Inamdar, > Your 'APM X-Gene PCIe' patch also needs 'struct pci_sys_data' and > 'struct hw_pci'. With Liviu Dudau's patch, it will make build > errors. Would you check this? I mean the patch '[PATCH] arm64: Add architecture support for PCI'. With this patch, it makes build errors in PCIe Host drivers such as pcie-designware.c. Best regards, Jingoo Han
On Thu, Feb 13, 2014 at 12:10 AM, Jingoo Han <jg1.han@samsung.com> wrote: > On Thursday, February 06, 2014 7:18 PM, Liviu Dudau wrote: >> On Wed, Feb 05, 2014 at 10:26:27PM +0000, Tanmay Inamdar wrote: >> > Hello Liviu, >> > >> > I did not get the first email of this particular patch on any of >> > subscribed mailing lists (don't know why), hence replying here. >> >> Strange, it shows in the MARC and GMANE archive for linux-pci, probably >> a hickup on your receiving side? >> >> > >> > +struct pci_host_bridge * >> > +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, >> > + void *host_data, struct list_head *resources) >> > +{ >> > + struct pci_bus *root_bus; >> > + struct pci_host_bridge *bridge; >> > + >> > + /* first parse the host bridge bus ranges */ >> > + if (pci_host_bridge_of_get_ranges(parent->of_node, resources)) >> > + return NULL; >> > + >> > + /* then create the root bus */ >> > + root_bus = pci_create_root_bus(parent, busno, ops, host_data, resources); >> > + if (!root_bus) >> > + return NULL; >> > + >> > + bridge = to_pci_host_bridge(root_bus->bridge); >> > + >> > + return bridge; >> > +} >> > >> > You are keeping the domain_nr inside pci_host_bridge structure. In >> > above API, domain_nr is required in 'pci_find_bus' function called >> > from 'pci_create_root_bus'. Since the bridge is allocated after >> > creating root bus, 'pci_find_bus' always gets domain_nr as 0. This >> > will cause problem for scanning multiple domains. >> >> Good catch. I was switching between creating a pci_controller in arch/arm64 and >> adding the needed bits in pci_host_bridge. After internal review I've decided to >> add the domain_nr to pci_host_bridge, but forgot to update the code everywhere. > > Hi Liviu Dudau, > > One more thing, > I am reviewing and compiling your patch. > Would you consider adding 'struct pci_sys_data' and 'struct hw_pci'? > > Currently, 4 PCIe Host drivers (pci-mvebu.c, pci-tegra.c, > pci-rcar-gen2.c, pcie-designware.c) are using 'struct pci_sys_data' > and 'struct hw_pci' in their drivers. Without this, it makes build > errors. > > In arm32, 'struct pci_sys_data' and 'struct hw_pci' is defined > in "arch/arm/include/asm/mach/pci.h". > > Tanmay Inamdar, > Your 'APM X-Gene PCIe' patch also needs 'struct pci_sys_data' and > 'struct hw_pci'. With Liviu Dudau's patch, it will make build > errors. Would you check this? X-Gene PCIe host driver is dependent on arm64 PCI patch. My previous approach was based on 32bit arm PCI support. With Liviu's approach, I will have to make changes in host driver to get rid of hw_pci and pci_sys_data which are no longer required. IMO it should not cause build errors for PCI host drivers dependent on architectures other than arm64. Can you post the error? > > Thank you. > > Best regards, > Jingoo Han > >> >> Thanks for reviewing this, will fix in v2. >> >> Do you find porting to the new API straight forward? >> >
> -----Original Message----- > From: Tanmay Inamdar [mailto:tinamdar@apm.com] > Sent: Thursday, February 13, 2014 5:37 PM > To: Jingoo Han > Cc: Liviu Dudau; Arnd Bergmann; devicetree@vger.kernel.org; linaro-kernel; linux-pci; Will Deacon; > LKML; Catalin Marinas; Bjorn Helgaas; LAKML > Subject: Re: [PATCH] pci: Add support for creating a generic host_bridge from device tree > > On Thu, Feb 13, 2014 at 12:10 AM, Jingoo Han <jg1.han@samsung.com> wrote: > > On Thursday, February 06, 2014 7:18 PM, Liviu Dudau wrote: > >> On Wed, Feb 05, 2014 at 10:26:27PM +0000, Tanmay Inamdar wrote: > >> > Hello Liviu, > >> > > >> > I did not get the first email of this particular patch on any of > >> > subscribed mailing lists (don't know why), hence replying here. > >> > >> Strange, it shows in the MARC and GMANE archive for linux-pci, probably > >> a hickup on your receiving side? > >> > >> > > >> > +struct pci_host_bridge * > >> > +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, > >> > + void *host_data, struct list_head *resources) > >> > +{ > >> > + struct pci_bus *root_bus; > >> > + struct pci_host_bridge *bridge; > >> > + > >> > + /* first parse the host bridge bus ranges */ > >> > + if (pci_host_bridge_of_get_ranges(parent->of_node, resources)) > >> > + return NULL; > >> > + > >> > + /* then create the root bus */ > >> > + root_bus = pci_create_root_bus(parent, busno, ops, host_data, resources); > >> > + if (!root_bus) > >> > + return NULL; > >> > + > >> > + bridge = to_pci_host_bridge(root_bus->bridge); > >> > + > >> > + return bridge; > >> > +} > >> > > >> > You are keeping the domain_nr inside pci_host_bridge structure. In > >> > above API, domain_nr is required in 'pci_find_bus' function called > >> > from 'pci_create_root_bus'. Since the bridge is allocated after > >> > creating root bus, 'pci_find_bus' always gets domain_nr as 0. This > >> > will cause problem for scanning multiple domains. > >> > >> Good catch. I was switching between creating a pci_controller in arch/arm64 and > >> adding the needed bits in pci_host_bridge. After internal review I've decided to > >> add the domain_nr to pci_host_bridge, but forgot to update the code everywhere. > > > > Hi Liviu Dudau, > > > > One more thing, > > I am reviewing and compiling your patch. > > Would you consider adding 'struct pci_sys_data' and 'struct hw_pci'? > > > > Currently, 4 PCIe Host drivers (pci-mvebu.c, pci-tegra.c, > > pci-rcar-gen2.c, pcie-designware.c) are using 'struct pci_sys_data' > > and 'struct hw_pci' in their drivers. Without this, it makes build > > errors. > > > > In arm32, 'struct pci_sys_data' and 'struct hw_pci' is defined > > in "arch/arm/include/asm/mach/pci.h". > > > > Tanmay Inamdar, > > Your 'APM X-Gene PCIe' patch also needs 'struct pci_sys_data' and > > 'struct hw_pci'. With Liviu Dudau's patch, it will make build > > errors. Would you check this? > > X-Gene PCIe host driver is dependent on arm64 PCI patch. My previous > approach was based on 32bit arm PCI support. With Liviu's approach, I > will have to make changes in host driver to get rid of hw_pci and > pci_sys_data which are no longer required. I want to use 'drivers/pci/host/pcie-designware.c' for both arm32 and arm64, without any code changes. However, it looks impossible. I made 'drivers/pci/host/pcie-designware.c' based on 32bit arm PCI support. Then, with Liviu's patch, do I have to make new code for arm64, even though the same HW PCIe IP is used? - For arm32 drivers/pci/host/pcie-designware.c - For arm64 drivers/pci/host/pcie-designware-arm64.c > > IMO it should not cause build errors for PCI host drivers dependent on > architectures other than arm64. Can you post the error? > I post the build errors. CC drivers/pci/host/pcie-designware.o CHK kernel/config_data.h drivers/pci/host/pcie-designware.c:72:52: warning: 'struct pci_sys_data' declared inside parameter list [enabled by default] static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) ^ drivers/pci/host/pcie-designware.c:72:52: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default] drivers/pci/host/pcie-designware.c: In function 'sys_to_pcie' drivers/pci/host/pcie-designware.c:74:12: error: dereferencing pointer to incomplete type return sys->private_data; ^ drivers/pci/host/pcie-designware.c: In function 'dw_pcie_msi_map' drivers/pci/host/pcie-designware.c:384:2: error: implicit declaration of function 'set_irq_flags' [-Werror=implicit-function-declaration] set_irq_flags(irq, IRQF_VALID); ^ drivers/pci/host/pcie-designware.c:384:21: error: 'IRQF_VALID??undeclared (first use in this function) set_irq_flags(irq, IRQF_VALID); ^ drivers/pci/host/pcie-designware.c:384:21: note: each undeclared identifier is reported only once for each function it appears in drivers/pci/host/pcie-designware.c: In function 'dw_pcie_host_init' drivers/pci/host/pcie-designware.c:492:2: error: invalid use of undefined type 'struct hw_pci' dw_pci.nr_controllers = 1; ^ drivers/pci/host/pcie-designware.c:493:2: error: invalid use of undefined type 'struct hw_pci' dw_pci.private_data = (void **)&pp; ^ drivers/pci/host/pcie-designware.c:495:2: error: implicit declaration of function 'pci_common_init' [-Werror=implicit-function-declaration] pci_common_init(&dw_pci); ^ drivers/pci/host/pcie-designware.c:498:2: error: invalid use of undefined type 'struct hw_pci' dw_pci.domain++; ^ drivers/pci/host/pcie-designware.c: At top level: drivers/pci/host/pcie-designware.c:698:41: warning: 'struct pci_sys_data??declared inside parameter list [enabled by default] static int dw_pcie_setup(int nr, struct pci_sys_data *sys) ^ drivers/pci/host/pcie-designware.c: In function 'dw_pcie_setup' drivers/pci/host/pcie-designware.c:702:2: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [enabled by default] pp = sys_to_pcie(sys); ^ drivers/pci/host/pcie-designware.c:72:33: note: expected 'struct pci_sys_data *' but argument is of type 'struct pci_sys_data *' static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) ^ drivers/pci/host/pcie-designware.c:708:6: error: dereferencing pointer to incomplete type sys->io_offset = global_io_offset - pp->config.io_bus_addr; ^ drivers/pci/host/pcie-designware.c:711:31: error: dereferencing pointer to incomplete type pci_add_resource_offset(&sys->resources, &pp->io, ^ drivers/pci/host/pcie-designware.c:712:9: error: dereferencing pointer to incomplete type sys->io_offset); ^ drivers/pci/host/pcie-designware.c:715:5: error: dereferencing pointer to incomplete type sys->mem_offset = pp->mem.start - pp->config.mem_bus_addr; ^ drivers/pci/host/pcie-designware.c:716:30: error: dereferencing pointer to incomplete type pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset); ^ drivers/pci/host/pcie-designware.c:716:56: error: dereferencing pointer to incomplete type pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset); ^ drivers/pci/host/pcie-designware.c: At top level: drivers/pci/host/pcie-designware.c:721:56: warning: 'struct pci_sys_data' declared inside parameter list [enabled by default] static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys) ^ drivers/pci/host/pcie-designware.c: In function 'dw_pcie_scan_bus' drivers/pci/host/pcie-designware.c:724:9: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [enabled by default] struct pcie_port *pp = sys_to_pcie(sys); ^ drivers/pci/host/pcie-designware.c:72:33: note: expected 'struct pci_sys_data *' but argument is of type 'sruct pci_sys_data *' static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) ^ drivers/pci/host/pcie-designware.c:727:24: error: dereferencing pointer to incomplete type pp->root_bus_nr = sys->busnr; ^ drivers/pci/host/pcie-designware.c:728:36: error: dereferencing pointer to incomplete type bus = pci_scan_root_bus(NULL, sys->busnr, &dw_pcie_ops, ^ drivers/pci/host/pcie-designware.c:729:15: error: dereferencing pointer to incomplete type sys, &sys->resources); ^ drivers/pci/host/pcie-designware.c: At top level: drivers/pci/host/pcie-designware.c:755:15: error: variable 'dw_pci' has initializer but incomplete type static struct hw_pci dw_pci = { ^ drivers/pci/host/pcie-designware.c:756:2: error: unknown field 'setup' specified in initializer .setup = dw_pcie_setup, ^ drivers/pci/host/pcie-designware.c:756:2: warning: excess elements in struct initializer [enabled by default] drivers/pci/host/pcie-designware.c:756:2: warning: (near initialization for 'dw_pci' [enabled by default] drivers/pci/host/pcie-designware.c:757:2: error: unknown field 'scan' specified in initializer .scan = dw_pcie_scan_bus, ^ drivers/pci/host/pcie-designware.c:757:2: warning: excess elements in struct initializer [enabled by default] drivers/pci/host/pcie-designware.c:757:2: warning: (near initialization for 'dw_pci' [enabled by default] drivers/pci/host/pcie-designware.c:758:2: error: unknown field 'map_irq' specified in initializer .map_irq = dw_pcie_map_irq, ^ drivers/pci/host/pcie-designware.c:758:2: warning: excess elements in struct initializer [enabled by default] drivers/pci/host/pcie-designware.c:758:2: warning: (near initialization for 'dw_pci' [enabled by default] drivers/pci/host/pcie-designware.c:759:2: error: unknown field 'add_bus' specified in initializer .add_bus = dw_pcie_add_bus, ^ drivers/pci/host/pcie-designware.c:759:2: warning: excess elements in struct initializer [enabled by default] drivers/pci/host/pcie-designware.c:759:2: warning: (near initialization for 'dw_pci' [enabled by default] cc1: some warnings being treated as errors make[3]: *** [drivers/pci/host/pcie-designware.o] Error 1 > > > >> > >> Thanks for reviewing this, will fix in v2. > >> > >> Do you find porting to the new API straight forward? > >> > >
On Thu, Feb 13, 2014 at 08:57:41AM +0000, Jingoo Han wrote: > > > > -----Original Message----- > > From: Tanmay Inamdar [mailto:tinamdar@apm.com] > > Sent: Thursday, February 13, 2014 5:37 PM > > To: Jingoo Han > > Cc: Liviu Dudau; Arnd Bergmann; devicetree@vger.kernel.org; linaro-kernel; linux-pci; Will Deacon; > > LKML; Catalin Marinas; Bjorn Helgaas; LAKML > > Subject: Re: [PATCH] pci: Add support for creating a generic host_bridge from device tree > > > > On Thu, Feb 13, 2014 at 12:10 AM, Jingoo Han <jg1.han@samsung.com> wrote: > > > On Thursday, February 06, 2014 7:18 PM, Liviu Dudau wrote: > > >> On Wed, Feb 05, 2014 at 10:26:27PM +0000, Tanmay Inamdar wrote: > > >> > Hello Liviu, > > >> > > > >> > I did not get the first email of this particular patch on any of > > >> > subscribed mailing lists (don't know why), hence replying here. > > >> > > >> Strange, it shows in the MARC and GMANE archive for linux-pci, probably > > >> a hickup on your receiving side? > > >> > > >> > > > >> > +struct pci_host_bridge * > > >> > +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, > > >> > + void *host_data, struct list_head *resources) > > >> > +{ > > >> > + struct pci_bus *root_bus; > > >> > + struct pci_host_bridge *bridge; > > >> > + > > >> > + /* first parse the host bridge bus ranges */ > > >> > + if (pci_host_bridge_of_get_ranges(parent->of_node, resources)) > > >> > + return NULL; > > >> > + > > >> > + /* then create the root bus */ > > >> > + root_bus = pci_create_root_bus(parent, busno, ops, host_data, resources); > > >> > + if (!root_bus) > > >> > + return NULL; > > >> > + > > >> > + bridge = to_pci_host_bridge(root_bus->bridge); > > >> > + > > >> > + return bridge; > > >> > +} > > >> > > > >> > You are keeping the domain_nr inside pci_host_bridge structure. In > > >> > above API, domain_nr is required in 'pci_find_bus' function called > > >> > from 'pci_create_root_bus'. Since the bridge is allocated after > > >> > creating root bus, 'pci_find_bus' always gets domain_nr as 0. This > > >> > will cause problem for scanning multiple domains. > > >> > > >> Good catch. I was switching between creating a pci_controller in arch/arm64 and > > >> adding the needed bits in pci_host_bridge. After internal review I've decided to > > >> add the domain_nr to pci_host_bridge, but forgot to update the code everywhere. > > > > > > Hi Liviu Dudau, > > > > > > One more thing, > > > I am reviewing and compiling your patch. > > > Would you consider adding 'struct pci_sys_data' and 'struct hw_pci'? > > > > > > Currently, 4 PCIe Host drivers (pci-mvebu.c, pci-tegra.c, > > > pci-rcar-gen2.c, pcie-designware.c) are using 'struct pci_sys_data' > > > and 'struct hw_pci' in their drivers. Without this, it makes build > > > errors. > > > > > > In arm32, 'struct pci_sys_data' and 'struct hw_pci' is defined > > > in "arch/arm/include/asm/mach/pci.h". > > > > > > Tanmay Inamdar, > > > Your 'APM X-Gene PCIe' patch also needs 'struct pci_sys_data' and > > > 'struct hw_pci'. With Liviu Dudau's patch, it will make build > > > errors. Would you check this? > > > > X-Gene PCIe host driver is dependent on arm64 PCI patch. My previous > > approach was based on 32bit arm PCI support. With Liviu's approach, I > > will have to make changes in host driver to get rid of hw_pci and > > pci_sys_data which are no longer required. > > I want to use 'drivers/pci/host/pcie-designware.c' for both arm32 > and arm64, without any code changes. However, it looks impossible. > > I made 'drivers/pci/host/pcie-designware.c' based on 32bit arm PCI > support. Then, with Liviu's patch, do I have to make new code for arm64, > even though the same HW PCIe IP is used? Hi Jingoo, Arnd has asked about the transition path for 32bit arm PCI host bridges and I don't think we came up with a solution yet. My preferred solution would be to modify the arch/arm API to be more in line with the generic code and not have to use hw_pci and pci_sys_data anymore. That should fix your problem of having a single code base for your host controller. If you look at the pci_sys_data and hw_pci structures, you can see that there is a bit of duplication between the two and also that some of the data contained in that structure is generic enough to be contained in the PCI infrastructure code rather than down in the arch-dependent code. I confess that I have no in-depth knowledge of the reasons why the arm code looks like this and if it is still required with the current infrastructure code. Russell can provide us with entertaining stories here, I'm sure, on why the code looks like it does. I have not done any work in this area yet, but if I were to update the generic arm code I would try to make the code use the pci_host_bridge structure rather than pci_sys_data. The hw_pci will disappear with the new APIs. > > - For arm32 > drivers/pci/host/pcie-designware.c > > - For arm64 > drivers/pci/host/pcie-designware-arm64.c > > > > > > IMO it should not cause build errors for PCI host drivers dependent on > > architectures other than arm64. Can you post the error? > > > > I post the build errors. IMHO it is not worth trying to have the host bridge code cope with two APIs. It's going to lead to problems no matter what. Best regards, Liviu > > CC drivers/pci/host/pcie-designware.o > CHK kernel/config_data.h > drivers/pci/host/pcie-designware.c:72:52: warning: 'struct pci_sys_data' declared inside parameter list [enabled by default] > static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) > ^ > drivers/pci/host/pcie-designware.c:72:52: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default] > drivers/pci/host/pcie-designware.c: In function 'sys_to_pcie' > drivers/pci/host/pcie-designware.c:74:12: error: dereferencing pointer to incomplete type > return sys->private_data; > ^ > drivers/pci/host/pcie-designware.c: In function 'dw_pcie_msi_map' > drivers/pci/host/pcie-designware.c:384:2: error: implicit declaration of function 'set_irq_flags' [-Werror=implicit-function-declaration] > set_irq_flags(irq, IRQF_VALID); > ^ > drivers/pci/host/pcie-designware.c:384:21: error: 'IRQF_VALID??undeclared (first use in this function) > set_irq_flags(irq, IRQF_VALID); > ^ > drivers/pci/host/pcie-designware.c:384:21: note: each undeclared identifier is reported only once for each function it appears in > drivers/pci/host/pcie-designware.c: In function 'dw_pcie_host_init' > drivers/pci/host/pcie-designware.c:492:2: error: invalid use of undefined type 'struct hw_pci' > dw_pci.nr_controllers = 1; > ^ > drivers/pci/host/pcie-designware.c:493:2: error: invalid use of undefined type 'struct hw_pci' > dw_pci.private_data = (void **)&pp; > ^ > drivers/pci/host/pcie-designware.c:495:2: error: implicit declaration of function 'pci_common_init' [-Werror=implicit-function-declaration] > pci_common_init(&dw_pci); > ^ > drivers/pci/host/pcie-designware.c:498:2: error: invalid use of undefined type 'struct hw_pci' > dw_pci.domain++; > ^ > drivers/pci/host/pcie-designware.c: At top level: > drivers/pci/host/pcie-designware.c:698:41: warning: 'struct pci_sys_data??declared inside parameter list [enabled by default] > static int dw_pcie_setup(int nr, struct pci_sys_data *sys) > ^ > drivers/pci/host/pcie-designware.c: In function 'dw_pcie_setup' > drivers/pci/host/pcie-designware.c:702:2: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [enabled by default] > pp = sys_to_pcie(sys); > ^ > drivers/pci/host/pcie-designware.c:72:33: note: expected 'struct pci_sys_data *' but argument is of type 'struct pci_sys_data *' > static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) > ^ > drivers/pci/host/pcie-designware.c:708:6: error: dereferencing pointer to incomplete type > sys->io_offset = global_io_offset - pp->config.io_bus_addr; > ^ > drivers/pci/host/pcie-designware.c:711:31: error: dereferencing pointer to incomplete type > pci_add_resource_offset(&sys->resources, &pp->io, > ^ > drivers/pci/host/pcie-designware.c:712:9: error: dereferencing pointer to incomplete type > sys->io_offset); > ^ > drivers/pci/host/pcie-designware.c:715:5: error: dereferencing pointer to incomplete type > sys->mem_offset = pp->mem.start - pp->config.mem_bus_addr; > ^ > drivers/pci/host/pcie-designware.c:716:30: error: dereferencing pointer to incomplete type > pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset); > ^ > drivers/pci/host/pcie-designware.c:716:56: error: dereferencing pointer to incomplete type > pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset); > ^ > drivers/pci/host/pcie-designware.c: At top level: > drivers/pci/host/pcie-designware.c:721:56: warning: 'struct pci_sys_data' declared inside parameter list [enabled by default] > static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys) > ^ > drivers/pci/host/pcie-designware.c: In function 'dw_pcie_scan_bus' > drivers/pci/host/pcie-designware.c:724:9: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [enabled by default] > struct pcie_port *pp = sys_to_pcie(sys); > ^ > drivers/pci/host/pcie-designware.c:72:33: note: expected 'struct pci_sys_data *' but argument is of type 'sruct pci_sys_data *' > static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) > ^ > drivers/pci/host/pcie-designware.c:727:24: error: dereferencing pointer to incomplete type > pp->root_bus_nr = sys->busnr; > ^ > drivers/pci/host/pcie-designware.c:728:36: error: dereferencing pointer to incomplete type > bus = pci_scan_root_bus(NULL, sys->busnr, &dw_pcie_ops, > ^ > drivers/pci/host/pcie-designware.c:729:15: error: dereferencing pointer to incomplete type > sys, &sys->resources); > ^ > drivers/pci/host/pcie-designware.c: At top level: > drivers/pci/host/pcie-designware.c:755:15: error: variable 'dw_pci' has initializer but incomplete type > static struct hw_pci dw_pci = { > ^ > drivers/pci/host/pcie-designware.c:756:2: error: unknown field 'setup' specified in initializer > .setup = dw_pcie_setup, > ^ > drivers/pci/host/pcie-designware.c:756:2: warning: excess elements in struct initializer [enabled by default] > drivers/pci/host/pcie-designware.c:756:2: warning: (near initialization for 'dw_pci' [enabled by default] > drivers/pci/host/pcie-designware.c:757:2: error: unknown field 'scan' specified in initializer > .scan = dw_pcie_scan_bus, > ^ > drivers/pci/host/pcie-designware.c:757:2: warning: excess elements in struct initializer [enabled by default] > drivers/pci/host/pcie-designware.c:757:2: warning: (near initialization for 'dw_pci' [enabled by default] > drivers/pci/host/pcie-designware.c:758:2: error: unknown field 'map_irq' specified in initializer > .map_irq = dw_pcie_map_irq, > ^ > drivers/pci/host/pcie-designware.c:758:2: warning: excess elements in struct initializer [enabled by default] > drivers/pci/host/pcie-designware.c:758:2: warning: (near initialization for 'dw_pci' [enabled by default] > drivers/pci/host/pcie-designware.c:759:2: error: unknown field 'add_bus' specified in initializer > .add_bus = dw_pcie_add_bus, > ^ > drivers/pci/host/pcie-designware.c:759:2: warning: excess elements in struct initializer [enabled by default] > drivers/pci/host/pcie-designware.c:759:2: warning: (near initialization for 'dw_pci' [enabled by default] > cc1: some warnings being treated as errors > make[3]: *** [drivers/pci/host/pcie-designware.o] Error 1 > > > > > > > >> > > >> Thanks for reviewing this, will fix in v2. > > >> > > >> Do you find porting to the new API straight forward? > > >> > > > > >
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 06ace62..9d11deb 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c @@ -6,6 +6,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/module.h> +#include <linux/of_address.h> #include "pci.h" @@ -91,3 +92,94 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res, res->end = region->end + offset; } EXPORT_SYMBOL(pcibios_bus_to_resource); + +/** + * pci_host_bridge_of_get_ranges - Parse PCI host bridge resources from DT + * @dev: device node of the host bridge having the range property + * @resources: list where the range of resources will be added after DT parsing + * + * This function will parse the "ranges" property of a PCI host bridge device + * node and setup the resource mapping based on its content. It is expected + * that the property conforms with the Power ePAPR document. + * + * Each architecture will then apply their filtering based on the limitations + * of each platform. One general restriction seems to be the number of IO space + * ranges, the PCI framework makes intensive use of struct resource management, + * and for IORESOURCE_IO types they can only be requested if they are contained + * within the global ioport_resource, so that should be limited to one IO space + * range. + */ +static int pci_host_bridge_of_get_ranges(struct device_node *dev, + struct list_head *resources) +{ + struct resource *res; + struct of_pci_range range; + struct of_pci_range_parser parser; + int err; + + pr_info("PCI host bridge %s ranges:\n", dev->full_name); + + /* Check for ranges property */ + err = of_pci_range_parser_init(&parser, dev); + if (err) + return err; + + pr_debug("Parsing ranges property...\n"); + for_each_of_pci_range(&parser, &range) { + /* Read next ranges element */ + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ", + range.pci_space, range.pci_addr); + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n", + range.cpu_addr, range.size); + + /* If we failed translation or got a zero-sized region + * (some FW try to feed us with non sensical zero sized regions + * such as power3 which look like some kind of attempt + * at exposing the VGA memory hole) then skip this range + */ + if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) + continue; + + res = kzalloc(sizeof(struct resource), GFP_KERNEL); + if (!res) { + err = -ENOMEM; + goto bridge_ranges_nomem; + } + + of_pci_range_to_resource(&range, dev, res); + + pci_add_resource_offset(resources, res, + range.cpu_addr - range.pci_addr); + } + + /* Apply architecture specific fixups for the ranges */ + pcibios_fixup_bridge_ranges(resources); + + return 0; + +bridge_ranges_nomem: + pci_free_resource_list(resources); + return err; +} + +struct pci_host_bridge * +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, + void *host_data, struct list_head *resources) +{ + struct pci_bus *root_bus; + struct pci_host_bridge *bridge; + + /* first parse the host bridge bus ranges */ + if (pci_host_bridge_of_get_ranges(parent->of_node, resources)) + return NULL; + + /* then create the root bus */ + root_bus = pci_create_root_bus(parent, busno, ops, host_data, resources); + if (!root_bus) + return NULL; + + bridge = to_pci_host_bridge(root_bus->bridge); + + return bridge; +} +EXPORT_SYMBOL(pci_host_bridge_of_init); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6e34498..16febae 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1787,6 +1787,17 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, list_for_each_entry_safe(window, n, resources, list) { list_move_tail(&window->list, &bridge->windows); res = window->res; + /* + * IO resources are stored in the kernel with a CPU start + * address of zero. Adjust the data accordingly and remember + * the offset + */ + if (resource_type(res) == IORESOURCE_IO) { + bridge->io_offset = res->start; + res->end -= res->start; + window->offset -= res->start; + res->start = 0; + } offset = window->offset; if (res->flags & IORESOURCE_BUS) pci_bus_insert_busn_res(b, bus, res->end); diff --git a/include/linux/pci.h b/include/linux/pci.h index fb57c89..8953997 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -394,6 +394,8 @@ struct pci_host_bridge_window { struct pci_host_bridge { struct device dev; struct pci_bus *bus; /* root bus */ + resource_size_t io_offset; /* CPU address offset for io resources */ + int domain_nr; struct list_head windows; /* pci_host_bridge_windows */ void (*release_fn)(struct pci_host_bridge *); void *release_data; @@ -1762,11 +1764,23 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus) return bus ? bus->dev.of_node : NULL; } +struct pci_host_bridge * +pci_host_bridge_of_init(struct device *parent, int busno, struct pci_ops *ops, + void *host_data, struct list_head *resources); + +void pcibios_fixup_bridge_ranges(struct list_head *resources); #else /* CONFIG_OF */ static inline void pci_set_of_node(struct pci_dev *dev) { } static inline void pci_release_of_node(struct pci_dev *dev) { } static inline void pci_set_bus_of_node(struct pci_bus *bus) { } static inline void pci_release_bus_of_node(struct pci_bus *bus) { } + +static inline struct pci_host_bridge * +pci_host_bridge_of_init(struct device *parent, struct pci_ops *ops, + void *host_data, struct list_head *resources) +{ + return NULL; +} #endif /* CONFIG_OF */ #ifdef CONFIG_EEH
Several platforms use a rather generic version of parsing the device tree to find the host bridge ranges. Move that into the generic PCI code and use it to create a pci_host_bridge structure that can be used by arch code. Based on early attempts by Andrew Murray to unify the code. Used powerpc and microblaze PCI code as starting point. Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> Cc: Catalin Marinas <Catalin.Marinas@arm.com> Cc: Will Deacon <Will.Deacon@arm.com> --- drivers/pci/host-bridge.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/probe.c | 11 ++++++ include/linux/pci.h | 14 ++++++++ 3 files changed, 117 insertions(+)