<commit_before>/**
 * @file axidma_chrdev.c
 * @date Saturday, November 14, 2015 at 12:03:13 PM EST
 * @author <NAME> (bmperez)
 * @author <NAME> (jaewonch)
 *
 * This file contains the implementation of the character device for the AXI DMA
 * module.
 *
 * @bug No known bugs.
 **/

// Kernel dependencies
#include <linux/list.h>         // Linked list definitions and functions
#include <linux/sched.h>        // `Current` global variable for current task
#include <linux/device.h>       // Device and class creation functions
#include <linux/cdev.h>         // Character device functions
#include <linux/ioctl.h>        // IOCTL macros and definitions
#include <linux/fs.h>           // File operations and file types
#include <linux/mm.h>           // Memory types and remapping functions
#include <linux/uaccess.h>      // Userspace memory access functions
#include <linux/slab.h>         // Kernel allocation functions
#include <linux/errno.h>        // Linux error codes
#include <linux/of_device.h>    // Device tree device related functions

#include <linux/dma-buf.h>      // DMA shared buffers interface
#include <linux/scatterlist.h>  // Scatter-gather table definitions

// Local dependencies
#include "axidma.h"             // Local definitions
#include "axidma_ioctl.h"       // IOCTL interface for the device

/*----------------------------------------------------------------------------
 * Internal Definitions
 *----------------------------------------------------------------------------*/

// TODO: Maybe this can be improved?
static struct axidma_device *axidma_dev;

// A structure that represents a DMA buffer allocation
struct axidma_dma_allocation {
    size_t size;                // Size of the buffer
    void *user_addr;            // User virtual address of the buffer
    void *kern_addr;            // Kernel virtual address of the buffer
    dma_addr_t dma_addr;        // DMA bus address of the buffer
    struct list_head list;      // List node pointers for allocation list
};

/* A structure that represents a DMA buffer allocation imported from another
 * driver in the kernel, through the DMA buffer sharing interface. */
struct axidma_external_allocation {
    int fd;                                 // File descritpor for buffer share
    struct dma_buf *dma_buf;                // Structure representing the buffer
    struct dma_buf_attachment *dma_attach;  // Structre represnting attachment
    size_t size;                            // Total size of the buffer
    void *user_addr;                        // Buffer's user virtual address
    struct sg_table *sg_table;              // DMA scatter-gather table
    struct list_head list;                  // Node pointers for the list
};

/*----------------------------------------------------------------------------
 * VMA Operations
 *----------------------------------------------------------------------------*/

static bool valid_dma_request(void *dma_start, size_t dma_size, void *user_addr,
                              size_t user_size)
{
    return dma_start <= user_addr &&
           (char *)user_addr + user_size <= (char *)dma_start + dma_size;
}

/* Converts the given user space virtual address to a DMA address. If the
 * conversion is unsuccessful, then (dma_addr_t)NULL is returned. */
dma_addr_t axidma_uservirt_to_dma(struct axidma_device *dev, void *user_addr,
                                  size_t size)
{
    bool valid;
    dma_addr_t offset;
    struct list_head *iter;
    struct axidma_dma_allocation *dma_alloc;
    struct axidma_external_allocation *dma_ext_alloc;

    // First iterate over DMA buffers allocated by this driver
    list_for_each(iter, &dev->dmabuf_list)
    {
        dma_alloc = container_of(iter, struct axidma_dma_allocation, list);
        valid = valid_dma_request(dma_alloc->user_addr, dma_alloc->size,
                                  user_addr, size);
        if (valid) {
            offset = (dma_addr_t)(user_addr - dma_alloc->user_addr);
            return dma_alloc->dma_addr;
        }
    }

    // Otherwise, iterate over the DMA buffers allocated by other drivers
    list_for_each(iter, &dev->external_dmabufs)
    {
        dma_ext_alloc = container_of(iter, struct axidma_external_allocation,
                                     list);
        valid = valid_dma_request(dma_ext_alloc->user_addr, dma_ext_alloc->size,
                                  user_addr, size);
        if (valid) {
            offset = (dma_addr_t)(user_addr - dma_ext_alloc->user_addr);
            return sg_dma_address(&dma_ext_alloc->sg_table->sgl[0]) + offset;
        }
    }

    // No matching allocation was found
    return (dma_addr_t)NULL;
}

static int axidma_get_external(struct axidma_device *dev,
                               struct axidma_register_buffer *ext_buf)<commit_msg>DMA buffer offset was not added by own allocated memory<commit_after>/**
 * @file axidma_chrdev.c
 * @date Saturday, November 14, 2015 at 12:03:13 PM EST
 * @author <NAME> (bmperez)
 * @author <NAME> (jaewonch)
 *
 * This file contains the implementation of the character device for the AXI DMA
 * module.
 *
 * @bug No known bugs.
 **/

// Kernel dependencies
#include <linux/list.h>         // Linked list definitions and functions
#include <linux/sched.h>        // `Current` global variable for current task
#include <linux/device.h>       // Device and class creation functions
#include <linux/cdev.h>         // Character device functions
#include <linux/ioctl.h>        // IOCTL macros and definitions
#include <linux/fs.h>           // File operations and file types
#include <linux/mm.h>           // Memory types and remapping functions
#include <linux/uaccess.h>      // Userspace memory access functions
#include <linux/slab.h>         // Kernel allocation functions
#include <linux/errno.h>        // Linux error codes
#include <linux/of_device.h>    // Device tree device related functions

#include <linux/dma-buf.h>      // DMA shared buffers interface
#include <linux/scatterlist.h>  // Scatter-gather table definitions

// Local dependencies
#include "axidma.h"             // Local definitions
#include "axidma_ioctl.h"       // IOCTL interface for the device

/*----------------------------------------------------------------------------
 * Internal Definitions
 *----------------------------------------------------------------------------*/

// TODO: Maybe this can be improved?
static struct axidma_device *axidma_dev;

// A structure that represents a DMA buffer allocation
struct axidma_dma_allocation {
    size_t size;                // Size of the buffer
    void *user_addr;            // User virtual address of the buffer
    void *kern_addr;            // Kernel virtual address of the buffer
    dma_addr_t dma_addr;        // DMA bus address of the buffer
    struct list_head list;      // List node pointers for allocation list
};

/* A structure that represents a DMA buffer allocation imported from another
 * driver in the kernel, through the DMA buffer sharing interface. */
struct axidma_external_allocation {
    int fd;                                 // File descritpor for buffer share
    struct dma_buf *dma_buf;                // Structure representing the buffer
    struct dma_buf_attachment *dma_attach;  // Structre represnting attachment
    size_t size;                            // Total size of the buffer
    void *user_addr;                        // Buffer's user virtual address
    struct sg_table *sg_table;              // DMA scatter-gather table
    struct list_head list;                  // Node pointers for the list
};

/*----------------------------------------------------------------------------
 * VMA Operations
 *----------------------------------------------------------------------------*/

static bool valid_dma_request(void *dma_start, size_t dma_size, void *user_addr,
                              size_t user_size)
{
    return dma_start <= user_addr &&
           (char *)user_addr + user_size <= (char *)dma_start + dma_size;
}

/* Converts the given user space virtual address to a DMA address. If the
 * conversion is unsuccessful, then (dma_addr_t)NULL is returned. */
dma_addr_t axidma_uservirt_to_dma(struct axidma_device *dev, void *user_addr,
                                  size_t size)
{
    bool valid;
    dma_addr_t offset;
    struct list_head *iter;
    struct axidma_dma_allocation *dma_alloc;
    struct axidma_external_allocation *dma_ext_alloc;

    // First iterate over DMA buffers allocated by this driver
    list_for_each(iter, &dev->dmabuf_list)
    {
        dma_alloc = container_of(iter, struct axidma_dma_allocation, list);
        valid = valid_dma_request(dma_alloc->user_addr, dma_alloc->size,
                                  user_addr, size);
        if (valid) {
            offset = (dma_addr_t)(user_addr - dma_alloc->user_addr);
            return dma_alloc->dma_addr + offset;
        }
    }

    // Otherwise, iterate over the DMA buffers allocated by other drivers
    list_for_each(iter, &dev->external_dmabufs)
    {
        dma_ext_alloc = container_of(iter, struct axidma_external_allocation,
                                     list);
        valid = valid_dma_request(dma_ext_alloc->user_addr, dma_ext_alloc->size,
                                  user_addr, size);
        if (valid) {
            offset = (dma_addr_t)(user_addr - dma_ext_alloc->user_addr);
            return sg_dma_address(&dma_ext_alloc->sg_table->sgl[0]) + offset;
        }
    }

    // No matching allocation was found
    return (dma_addr_t)NULL;
}

static int axidma_get_external(struct axidma_device *dev,
                               struct axidma_register_buffer *ext_buf)
{'fraction_non_alphanumeric': 0.14083204930662557, 'fraction_numerical': 0.0026707755521314844, 'mean_word_length': 1.921968787515006, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '475955', 'n_tokens_mistral': 2650, 'n_tokens_neox': 2580, 'n_words': 805}