summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/device.c84
-rw-r--r--drivers/of/of_pci.c21
-rw-r--r--drivers/of/platform.c58
3 files changed, 107 insertions, 56 deletions
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 46d6c75c1404..20c1332a0018 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -2,6 +2,9 @@
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_iommu.h>
+#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -66,6 +69,87 @@ 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 coherent_dma_mask to 32 bit. Drivers are expected to
+ * setup the correct supported mask.
+ */
+ if (!dev->coherent_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 + 1;
+ } else {
+ offset = PFN_DOWN(paddr - dma_addr);
+
+ /*
+ * Add a work around to treat the size as mask + 1 in case
+ * it is defined in DT as a mask.
+ */
+ if (size & 1) {
+ dev_warn(dev, "Invalid size 0x%llx for dma-range\n",
+ size);
+ size = size + 1;
+ }
+
+ if (!size) {
+ dev_err(dev, "Adjusted size 0x%llx invalid\n", size);
+ return;
+ }
+ dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
+ }
+
+ dev->dma_pfn_offset = offset;
+
+ /*
+ * Limit coherent and dma mask based on size and default mask
+ * set by the driver.
+ */
+ dev->coherent_dma_mask = min(dev->coherent_dma_mask,
+ DMA_BIT_MASK(ilog2(dma_addr + size)));
+ *dev->dma_mask = min((*dev->dma_mask),
+ DMA_BIT_MASK(ilog2(dma_addr + size)));
+
+ 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/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 <linux/export.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
@@ -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/drivers/of/platform.c b/drivers/of/platform.c
index b189733a1539..a01f57c9e34e 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -19,7 +19,6 @@
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
-#include <linux/of_iommu.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -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_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);
OpenPOWER on IntegriCloud