From 41f8bba7f5552d033583777dede2df7c36e7853d Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:21 +0100 Subject: of/pci: Add pci_register_io_range() and pci_pio_to_address() Some architectures do not have a simple view of the PCI I/O space and instead use a range of CPU addresses that map to bus addresses. For some architectures these ranges will be expressed by OF bindings in a device tree file. This patch introduces a pci_register_io_range() helper function with a generic implementation that can be used by such architectures to keep track of the I/O ranges described by the PCI bindings. If the PCI_IOBASE macro is not defined, that signals lack of support for PCI and we return an error. In order to retrieve the CPU address associated with an I/O port, a new helper function pci_pio_to_address() is introduced. This will search in the list of ranges registered with pci_register_io_range() and return the CPU address that corresponds to the given port. [arnd: add dummy !CONFIG_OF pci_pio_to_address() to fix build errors] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas Reviewed-by: Catalin Marinas Acked-by: Rob Herring CC: Grant Likely --- include/linux/of_address.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux') diff --git a/include/linux/of_address.h b/include/linux/of_address.h index fb7b7221e063..497a04356ff8 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -55,7 +55,9 @@ extern void __iomem *of_iomap(struct device_node *device, int index); extern const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags); +extern int pci_register_io_range(phys_addr_t addr, resource_size_t size); extern unsigned long pci_address_to_pio(phys_addr_t addr); +extern phys_addr_t pci_pio_to_address(unsigned long pio); extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, struct device_node *node); @@ -80,6 +82,11 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index, return NULL; } +static inline phys_addr_t pci_pio_to_address(unsigned long pio) +{ + return 0; +} + static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, struct device_node *node) { -- cgit v1.2.3 From 83bbde1cc0ec9d156b9271e29ffe0dc89c687feb Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:24 +0100 Subject: of/pci: Move of_pci_range_to_resource() to of/address.c We need to enhance of_pci_range_to_resources() enough that it won't make sense for it to be inline anymore. Move it to drivers/of/address.c, under #ifdef CONFIG_PCI. of_address.h previously implemented of_pci_range_to_resources() unconditionally, regardless of any config options. The implementation in address.c is defined only when CONFIG_OF_ADDRESS=y and CONFIG_PCI=y, so add a dummy version to avoid build errors when CONFIG_OF or CONFIG_OF_ADDRESS is not defined. [bhelgaas: drop extra detail from changelog, move def under CONFIG_PCI, add dummy of_pci_range_to_resource() for build errors (from Arnd)] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas CC: Grant Likely CC: Rob Herring CC: Arnd Bergmann CC: Catalin Marinas --- include/linux/of_address.h | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 497a04356ff8..a38e1c846c23 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -23,17 +23,6 @@ struct of_pci_range { #define for_each_of_pci_range(parser, range) \ for (; of_pci_range_parser_one(parser, range);) -static inline void of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res) -{ - res->flags = range->flags; - res->start = range->cpu_addr; - res->end = range->cpu_addr + range->size - 1; - res->parent = res->child = res->sibling = NULL; - res->name = np->full_name; -} - /* Translate a DMA address from device space to CPU space */ extern u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr); @@ -145,6 +134,9 @@ extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); +extern void of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res); #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) @@ -157,6 +149,12 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, { return NULL; } +static inline void of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res) +{ + return -ENOSYS; +} #endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */ #endif /* __OF_ADDRESS_H */ -- cgit v1.2.3 From 0b0b0893d49b34201a6c4416b1a707b580b91e3d Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:25 +0100 Subject: of/pci: Fix the conversion of IO ranges into IO resources The ranges property for a host bridge controller in DT describes the mapping between the PCI bus address and the CPU physical address. The resources framework however expects that the IO resources start at a pseudo "port" address 0 (zero) and have a maximum size of IO_SPACE_LIMIT. The conversion from PCI ranges to resources failed to take that into account, returning a CPU physical address instead of a port number. Also fix all the drivers that depend on the old behaviour by fetching the CPU physical address based on the port number where it is being needed. Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas Acked-by: Linus Walleij CC: Grant Likely CC: Rob Herring CC: Arnd Bergmann CC: Thierry Reding CC: Simon Horman CC: Catalin Marinas --- include/linux/of_address.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/of_address.h b/include/linux/of_address.h index a38e1c846c23..8cb14eb393d6 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -134,9 +134,9 @@ extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); -extern void of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res); +extern int of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res); #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) @@ -149,9 +149,9 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, { return NULL; } -static inline void of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res) +static inline int of_pci_range_to_resource(struct of_pci_range *range, + struct device_node *np, + struct resource *res) { return -ENOSYS; } -- cgit v1.2.3 From 670ba0c8883b576d0aec28bd7a838358a4be1406 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 29 Sep 2014 15:29:26 +0100 Subject: PCI: Add generic domain handling The handling of PCI domains (or PCI segments in ACPI speak) is usually a straightforward affair but its implementation is currently left to the architectural code, with pci_domain_nr(b) querying the value of the domain associated with bus b. This patch introduces CONFIG_PCI_DOMAINS_GENERIC as an option that can be selected if an architecture wants a simple implementation where the value of the domain associated with a bus is stored in struct pci_bus. The architectures that select CONFIG_PCI_DOMAINS_GENERIC will then have to implement pci_bus_assign_domain_nr() as a way of setting the domain number associated with a root bus. All child buses except the root bus will inherit the domain_nr value from their parent. Signed-off-by: Catalin Marinas [Renamed pci_set_domain_nr() to pci_bus_assign_domain_nr()] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas CC: Arnd Bergmann --- include/linux/pci.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 61978a460841..a494e5d775c3 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -456,6 +456,9 @@ struct pci_bus { unsigned char primary; /* number of primary bridge */ unsigned char max_bus_speed; /* enum pci_bus_speed */ unsigned char cur_bus_speed; /* enum pci_bus_speed */ +#ifdef CONFIG_PCI_DOMAINS_GENERIC + int domain_nr; +#endif char name[48]; @@ -1288,6 +1291,24 @@ static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } #endif /* CONFIG_PCI_DOMAINS */ +/* + * Generic implementation for PCI domain support. If your + * architecture does not need custom management of PCI + * domains then this implementation will be used + */ +#ifdef CONFIG_PCI_DOMAINS_GENERIC +static inline int pci_domain_nr(struct pci_bus *bus) +{ + return bus->domain_nr; +} +void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent); +#else +static inline void pci_bus_assign_domain_nr(struct pci_bus *bus, + struct device *parent) +{ +} +#endif + /* some architectures require additional setup to direct VGA traffic */ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode, unsigned int command_bits, u32 flags); -- cgit v1.2.3 From 41e5c0f81d3e676d671d96a0a1fafb27abfbd9d7 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:27 +0100 Subject: of/pci: Add pci_get_new_domain_nr() and of_get_pci_domain_nr() Add pci_get_new_domain_nr() to allocate a new domain number and of_get_pci_domain_nr() to retrieve the PCI domain number of a given device from DT. Host bridge drivers or architecture-specific code can choose to implement their PCI domain number policy using these two functions. Using of_get_pci_domain_nr() guarantees a stable PCI domain number on every boot provided that all host bridge controllers are assigned a number in the device tree using "linux,pci-domain" property. Mixing use of pci_get_new_domain_nr() and of_get_pci_domain_nr() is not recommended as it can lead to potentially conflicting domain numbers being assigned to root buses behind different host bridges. Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas CC: Arnd Bergmann CC: Grant Likely CC: Rob Herring CC: Catalin Marinas --- include/linux/of_pci.h | 7 +++++++ include/linux/pci.h | 3 +++ 2 files changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index dde3a4a0fa5d..71062e9602f5 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -15,6 +15,7 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, int of_pci_get_devfn(struct device_node *np); int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); int of_pci_parse_bus_range(struct device_node *node, struct resource *res); +int of_get_pci_domain_nr(struct device_node *node); #else static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq) { @@ -43,6 +44,12 @@ of_pci_parse_bus_range(struct device_node *node, struct resource *res) { return -EINVAL; } + +static inline int +of_get_pci_domain_nr(struct device_node *node) +{ + return -1; +} #endif #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI) diff --git a/include/linux/pci.h b/include/linux/pci.h index a494e5d775c3..150da2d644e7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1285,10 +1285,12 @@ void pci_cfg_access_unlock(struct pci_dev *dev); */ #ifdef CONFIG_PCI_DOMAINS extern int pci_domains_supported; +int pci_get_new_domain_nr(void); #else enum { pci_domains_supported = 0 }; static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } #endif /* CONFIG_PCI_DOMAINS */ /* @@ -1417,6 +1419,7 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; } +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } #define dev_is_pci(d) (false) #define dev_is_pf(d) (false) -- cgit v1.2.3 From cbe4097f8ae699ebbdaf8c95ecab38d47e0bd5da Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:28 +0100 Subject: of/pci: Add support for parsing PCI host bridge resources from DT Provide a function to parse the PCI DT ranges that can be used to create a pci_host_bridge structure together with its associated bus. Signed-off-by: Liviu Dudau [make io_base parameter optional] Signed-off-by: Robert Richter Signed-off-by: Bjorn Helgaas CC: Arnd Bergmann CC: Grant Likely CC: Rob Herring CC: Catalin Marinas --- include/linux/of_pci.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux') diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 71062e9602f5..1fd207e7a847 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -52,6 +52,12 @@ of_get_pci_domain_nr(struct device_node *node) } #endif +#if defined(CONFIG_OF_ADDRESS) +int of_pci_get_host_bridge_resources(struct device_node *dev, + unsigned char busno, unsigned char bus_max, + struct list_head *resources, resource_size_t *io_base); +#endif + #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI) int of_pci_msi_chip_add(struct msi_chip *chip); void of_pci_msi_chip_remove(struct msi_chip *chip); -- cgit v1.2.3 From 8b921acfeffdb0b45085da862fc301a2d25ed2cf Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 29 Sep 2014 15:29:30 +0100 Subject: PCI: Add pci_remap_iospace() to map bus I/O resources Add pci_remap_iospace() to map bus I/O resources into the CPU virtual address space. Architectures with special needs may provide their own version, but most should be able to use this one. This function is useful for PCI host bridge drivers that need to map the PCI I/O resources into virtual memory space. [bhelgaas: phys_addr description, drop temporary "err" variable] Signed-off-by: Liviu Dudau Signed-off-by: Bjorn Helgaas Reviewed-by: Rob Herring Reviewed-by: Catalin Marinas CC: Arnd Bergmann --- include/linux/pci.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 150da2d644e7..b4995fdfffb1 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1100,6 +1100,9 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus, resource_size_t), void *alignf_data); + +int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr); + static inline dma_addr_t pci_bus_address(struct pci_dev *pdev, int bar) { struct pci_bus_region region; -- cgit v1.2.3