From ed748621031c2a205749997421e59fb4dfb1e909 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 3 Mar 2015 12:52:08 -0500 Subject: of: iommu: Add ptr to OF node arg to of_iommu_configure() of_iommu_configure() is called from of_dma_configure() to setup iommu ops using DT property. This API is currently used for platform devices for which DMA configuration (including IOMMU ops) may come from the device's parent. To extend this functionality for PCI devices, this API needs to take a parent node ptr as an argument instead of assuming device's parent. This is needed since for PCI, the DMA configuration may be defined in the DT node of the root bus bridge's parent device. Currently only dma-range is used for PCI and IOMMU is not supported. Return error if the device is PCI. Add "parent" parameter (a struct device_node *) to of_iommu_configure(). Tested-by: Suravee Suthikulpanit (AMD Seattle) Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas Reviewed-by: Catalin Marinas Acked-by: Rob Herring Acked-by: Will Deacon CC: Joerg Roedel CC: Grant Likely CC: Russell King CC: Arnd Bergmann --- include/linux/of_iommu.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index 16c75547d725..ffbe4707d4aa 100644 --- a/include/linux/of_iommu.h +++ b/include/linux/of_iommu.h @@ -12,7 +12,8 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix, size_t *size); extern void of_iommu_init(void); -extern struct iommu_ops *of_iommu_configure(struct device *dev); +extern struct iommu_ops *of_iommu_configure(struct device *dev, + struct device_node *master_np); #else @@ -24,7 +25,8 @@ static inline int of_get_dma_window(struct device_node *dn, const char *prefix, } static inline void of_iommu_init(void) { } -static inline struct iommu_ops *of_iommu_configure(struct device *dev) +static inline struct iommu_ops *of_iommu_configure(struct device *dev, + struct device_node *master_np) { return NULL; } -- cgit v1.3-6-gb490 From 1f5c69aa51f9c7c8d2a5c2e4dc339f6c7d5c15cd Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 3 Mar 2015 12:52:09 -0500 Subject: of: Move of_dma_configure() to device.c to help re-use Move of_dma_configure() to device.c so it can be re-used for PCI devices to obtain DMA configuration from DT. Also add a second argument so that for PCI, the DT node of root bus host bridge can be used to obtain the DMA configuration for the slave PCI device. Tested-by: Suravee Suthikulpanit (AMD Seattle) Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas Reviewed-by: Catalin Marinas Acked-by: Will Deacon Acked-by: Rob Herring CC: Joerg Roedel CC: Grant Likely CC: Russell King CC: Arnd Bergmann --- drivers/of/device.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/of/platform.c | 58 ++-------------------------------------------- include/linux/of_device.h | 3 +++ 3 files changed, 64 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/drivers/of/device.c b/drivers/of/device.c index 46d6c75c1404..31a7875b34a4 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -66,6 +69,62 @@ int of_device_add(struct platform_device *ofdev) return device_add(&ofdev->dev); } +/** + * of_dma_configure - Setup DMA configuration + * @dev: Device to apply DMA configuration + * @np: Pointer to OF node having DMA configuration + * + * Try to get devices's DMA configuration from DT and update it + * accordingly. + * + * If platform code needs to use its own special DMA configuration, it + * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events + * to fix up DMA configuration. + */ +void of_dma_configure(struct device *dev, struct device_node *np) +{ + u64 dma_addr, paddr, size; + int ret; + bool coherent; + unsigned long offset; + struct iommu_ops *iommu; + + /* + * Set default dma-mask to 32 bit. Drivers are expected to setup + * the correct supported dma_mask. + */ + dev->coherent_dma_mask = DMA_BIT_MASK(32); + + /* + * Set it to coherent_dma_mask by default if the architecture + * code has not set it. + */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + + ret = of_dma_get_range(np, &dma_addr, &paddr, &size); + if (ret < 0) { + dma_addr = offset = 0; + size = dev->coherent_dma_mask; + } else { + offset = PFN_DOWN(paddr - dma_addr); + dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset); + } + + dev->dma_pfn_offset = offset; + + coherent = of_dma_is_coherent(np); + dev_dbg(dev, "device is%sdma coherent\n", + coherent ? " " : " not "); + + iommu = of_iommu_configure(dev, np); + dev_dbg(dev, "device is%sbehind an iommu\n", + iommu ? " " : " not "); + + arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent); +} +EXPORT_SYMBOL_GPL(of_dma_configure); + int of_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 667c6f13f12b..a01f57c9e34e 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -150,59 +149,6 @@ struct platform_device *of_device_alloc(struct device_node *np, } EXPORT_SYMBOL(of_device_alloc); -/** - * of_dma_configure - Setup DMA configuration - * @dev: Device to apply DMA configuration - * - * Try to get devices's DMA configuration from DT and update it - * accordingly. - * - * In case if platform code need to use own special DMA configuration,it - * can use Platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE event - * to fix up DMA configuration. - */ -static void of_dma_configure(struct device *dev) -{ - u64 dma_addr, paddr, size; - int ret; - bool coherent; - unsigned long offset; - struct iommu_ops *iommu; - - /* - * Set default dma-mask to 32 bit. Drivers are expected to setup - * the correct supported dma_mask. - */ - dev->coherent_dma_mask = DMA_BIT_MASK(32); - - /* - * Set it to coherent_dma_mask by default if the architecture - * code has not set it. - */ - if (!dev->dma_mask) - dev->dma_mask = &dev->coherent_dma_mask; - - ret = of_dma_get_range(dev->of_node, &dma_addr, &paddr, &size); - if (ret < 0) { - dma_addr = offset = 0; - size = dev->coherent_dma_mask; - } else { - offset = PFN_DOWN(paddr - dma_addr); - dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset); - } - dev->dma_pfn_offset = offset; - - coherent = of_dma_is_coherent(dev->of_node); - dev_dbg(dev, "device is%sdma coherent\n", - coherent ? " " : " not "); - - iommu = of_iommu_configure(dev, dev->of_node); - dev_dbg(dev, "device is%sbehind an iommu\n", - iommu ? " " : " not "); - - arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent); -} - static void of_dma_deconfigure(struct device *dev) { arch_teardown_dma_ops(dev); @@ -236,7 +182,7 @@ static struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; - of_dma_configure(&dev->dev); + of_dma_configure(&dev->dev, dev->dev.of_node); if (of_device_add(dev) != 0) { of_dma_deconfigure(&dev->dev); @@ -299,7 +245,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node, dev_set_name(&dev->dev, "%s", bus_id); else of_device_make_bus_id(&dev->dev); - of_dma_configure(&dev->dev); + of_dma_configure(&dev->dev, dev->dev.of_node); /* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, "arm,primecell-periphid", NULL); diff --git a/include/linux/of_device.h b/include/linux/of_device.h index ef370210ffb2..22801b10cef5 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -53,6 +53,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) return of_node_get(cpu_dev->of_node); } +void of_dma_configure(struct device *dev, struct device_node *np); #else /* CONFIG_OF */ static inline int of_driver_match_device(struct device *dev, @@ -90,6 +91,8 @@ static inline struct device_node *of_cpu_device_node_get(int cpu) { return NULL; } +static inline void of_dma_configure(struct device *dev, struct device_node *np) +{} #endif /* CONFIG_OF */ #endif /* _LINUX_OF_DEVICE_H */ -- cgit v1.3-6-gb490 From 6675a601d72be408025e675599702e30a99188aa Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 3 Mar 2015 12:52:11 -0500 Subject: PCI: Add helper functions pci_get[put]_host_bridge_device() Add helper functions to get/put the root bus's host bridge device. Tested-by: Suravee Suthikulpanit (AMD Seattle) Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas Reviewed-by: Catalin Marinas Acked-by: Will Deacon CC: Joerg Roedel CC: Grant Likely CC: Rob Herring CC: Russell King CC: Arnd Bergmann --- drivers/pci/host-bridge.c | 14 ++++++++++++++ include/linux/pci.h | 3 +++ 2 files changed, 17 insertions(+) (limited to 'include/linux') diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 39b2dbe585aa..3e5bbf9e8889 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c @@ -23,6 +23,20 @@ static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus) return to_pci_host_bridge(root_bus->bridge); } +struct device *pci_get_host_bridge_device(struct pci_dev *dev) +{ + struct pci_bus *root_bus = find_pci_root_bus(dev->bus); + struct device *bridge = root_bus->bridge; + + kobject_get(&bridge->kobj); + return bridge; +} + +void pci_put_host_bridge_device(struct device *dev) +{ + kobject_put(&dev->kobj); +} + void pci_set_host_bridge_release(struct pci_host_bridge *bridge, void (*release_fn)(struct pci_host_bridge *), void *release_data) diff --git a/include/linux/pci.h b/include/linux/pci.h index 211e9da8a7d7..a379513bddef 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -510,6 +510,9 @@ static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev) return dev->bus->self; } +struct device *pci_get_host_bridge_device(struct pci_dev *dev); +void pci_put_host_bridge_device(struct device *dev); + #ifdef CONFIG_PCI_MSI static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev) { -- cgit v1.3-6-gb490 From c49b8fc26e115a37eca6f7bcef1847eb80f2a4fd Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 3 Mar 2015 12:52:12 -0500 Subject: of/pci: Add of_pci_dma_configure() to update DMA configuration Add of_pci_dma_configure() to allow updating the DMA configuration of the PCI device using the configuration from DT of the parent of the root bridge device. Use the newly added APIs pci_get/put_host_bridge_device() for implementing this. [bhelgaas: fold in fix for host bridges with no parent OF device] Tested-by: Suravee Suthikulpanit (AMD Seattle) Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas Reviewed-by: Catalin Marinas Acked-by: Rob Herring Acked-by: Will Deacon CC: Joerg Roedel CC: Grant Likely CC: Russell King CC: Arnd Bergmann --- drivers/of/of_pci.c | 21 +++++++++++++++++++++ include/linux/of_pci.h | 3 +++ 2 files changed, 24 insertions(+) (limited to 'include/linux') diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 62426d81a4d6..5751dc5b6494 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -116,6 +117,26 @@ int of_get_pci_domain_nr(struct device_node *node) } EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); +/** + * of_pci_dma_configure - Setup DMA configuration + * @dev: ptr to pci_dev struct of the PCI device + * + * Function to update PCI devices's DMA configuration using the same + * info from the OF node of host bridge's parent (if any). + */ +void of_pci_dma_configure(struct pci_dev *pci_dev) +{ + struct device *dev = &pci_dev->dev; + struct device *bridge = pci_get_host_bridge_device(pci_dev); + + if (!bridge->parent) + return; + + of_dma_configure(dev, bridge->parent->of_node); + pci_put_host_bridge_device(bridge); +} +EXPORT_SYMBOL_GPL(of_pci_dma_configure); + #if defined(CONFIG_OF_ADDRESS) /** * of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index ce0e5abeb454..29fd3fe1c035 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -16,6 +16,7 @@ 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); +void of_pci_dma_configure(struct pci_dev *pci_dev); #else static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq) { @@ -50,6 +51,8 @@ of_get_pci_domain_nr(struct device_node *node) { return -1; } + +static inline void of_pci_dma_configure(struct pci_dev *pci_dev) { } #endif #if defined(CONFIG_OF_ADDRESS) -- cgit v1.3-6-gb490