get_dma_ops - notro/udrm-kernel GitHub Wiki

get_dma_ops()

static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
        if (xen_initial_domain())
                return xen_dma_ops;
        else
                return __generic_dma_ops(dev);
}

static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
        if (dev && dev->archdata.dma_ops)
                return dev->archdata.dma_ops;
        return &arm_dma_ops;
}

of_platform_populate()->of_platform_bus_create()->of_platform_device_create_pdata()

static struct platform_device *of_platform_device_create_pdata(
                                        struct device_node *np,
                                        const char *bus_id,
                                        void *platform_data,
                                        struct device *parent)
{
<snip>
        of_dma_configure(&dev->dev, dev->dev.of_node);
<snip>
}

of_dma_configure()

Sets from Device Tree (Raspberry Pi):

  • dev->archdata.dma_coherent = false;
  • dev->archdata.dma_ops = &arm_dma_ops;
  • dev->dma_pfn_offset
/**
 * 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;
        const 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);
}

/**
 * of_dma_is_coherent - Check if device is coherent
 * @np: device node
 *
 * It returns true if "dma-coherent" property was found
 * for this device in DT.
 */
bool of_dma_is_coherent(struct device_node *np)
{
        struct device_node *node = of_node_get(np);

        while (node) {
                if (of_property_read_bool(node, "dma-coherent")) {
                        of_node_put(node);
                        return true;
                }
                node = of_get_next_parent(node);
        }
        of_node_put(node);
        return false;
}

arch_setup_dma_ops()

void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
                        const struct iommu_ops *iommu, bool coherent)
{
        struct dma_map_ops *dma_ops;

        dev->archdata.dma_coherent = coherent;
        if (arm_setup_iommu_dma_ops(dev, dma_base, size, iommu))
                dma_ops = arm_get_iommu_dma_map_ops(coherent);
        else
                dma_ops = arm_get_dma_map_ops(coherent);

        set_dma_ops(dev, dma_ops);
}

static struct dma_map_ops *arm_get_dma_map_ops(bool coherent)
{
        return coherent ? &arm_coherent_dma_ops : &arm_dma_ops;
}

static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
{
        BUG_ON(!dev);
        dev->archdata.dma_ops = ops;
}

arm_dma_ops

struct dma_map_ops arm_dma_ops = {
        .alloc                  = arm_dma_alloc,
        .free                   = arm_dma_free,
        .mmap                   = arm_dma_mmap,
        .get_sgtable            = arm_dma_get_sgtable,
        .map_page               = arm_dma_map_page,
        .unmap_page             = arm_dma_unmap_page,
        .map_sg                 = arm_dma_map_sg,
        .unmap_sg               = arm_dma_unmap_sg,
        .sync_single_for_cpu    = arm_dma_sync_single_for_cpu,
        .sync_single_for_device = arm_dma_sync_single_for_device,
        .sync_sg_for_cpu        = arm_dma_sync_sg_for_cpu,
        .sync_sg_for_device     = arm_dma_sync_sg_for_device,
};
⚠️ **GitHub.com Fallback** ⚠️