4

我正在使用嵌入在具有 Linux 内核 2.6.33 的 Virtex4 FPGA 中的 PowerPC 405 进行开发。

到目前为止,我一直在为在 FPGA 中以内核可加载模块的形式实现的平台设备编写驱动程序。使用平面开放固件设备树文件注册设备。要创建设备文件,我使用 OF 函数获取设备节点,然后注册一个新的miscdevice,然后自动注册一个次要设备号并为我创建设备文件。这也创建了一个device嵌入在miscdevice(ie miscdevice.this_device)

现在的问题是我需要执行 DMA 操作。我尝试使用 调用该dma_alloc_coherent()函数miscdevice.this_device,但该设备未与任何总线关联并且总是返回错误。我做了一些挖掘,结果发现它struct of_devicestruct device嵌入了一个(即of_device.dev)。当我尝试将它与 一起使用时dma_alloc_coherent(),它工作得很好。

所以现在我有两种不同的struct device结构,一种用于管理我的字符设备文件,另一种用于管理底层的 Open Firmware 系统调用、总线和 DMA 事务。当然,这些设备在 sysfs 中并不相互关联。

device我的问题是,是否有可能以某种方式请求为我从 OF 层获得的结构创建一个设备文件,而不是使用 Misc Device API 创建一个新设备?这样,所有内容都将与单个device结构相关联。

4

2 回答 2

3

我认为您对 dma_alloc_coherent() 的修复是正确的。

但是我认为使用结构 of_device 中嵌入的设备结构来替换您创建的 miscdevice 是不对的。of_device 是开放固件数据库中对象的描述。并且根据 Linux 设备驱动模型,设备结构嵌入在 Linux Kernel 的各种设备对象中。而且我认为您将 miscdevice 注册为一个字符设备,应该有关联的 file_operations 结构。

一言以蔽之,它们是不同的观点,不能相互替代。

于 2013-05-31T02:59:01.013 回答
0

我使用 miscdevice.this_device 为树莓派编写了一些实验性 dma 驱动程序

#include <linux/module.h>   /* Needed by all modules */
#include <linux/kernel.h>   /* Needed for KERN_INFO */
#include <linux/miscdevice.h>
#include "gpio.h"
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include "DMA.h"
#include <linux/of_irq.h>

static int my_open(struct inode *i, struct file *f)
{
    printk(KERN_INFO "Driver: open() %d\n", current->pid);
    return 0;
}
static int my_close(struct inode *i, struct file *f)
{
    printk(KERN_INFO "Driver: close()\n");
    return 0;
}

static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
    printk(KERN_INFO "Driver: read()\n");
    return 0;
}

char databuf[100];
static ssize_t my_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
    if(copy_from_user(databuf, buf, 100) != 0) return 0;
    printk("Data from the user: %s\n", databuf);
    return len;
}

  static struct file_operations sample_fops =
{
    .owner = THIS_MODULE,
    .open = my_open,
    .release = my_close,
    .read = my_read,
    .write = my_write
};

struct miscdevice sample_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "ledButton",
    .fops = &sample_fops,
    .mode = 0666,
};

//static struct dmadata_s *cpu_addr;
//dma_addr_t dma_addr;

struct dma_cb *virt_cb;
dma_addr_t phys_cb;

uint32_t *virt_src;
dma_addr_t phys_src;

uint32_t *virt_dst;
dma_addr_t phys_dst;

static irqreturn_t dma_irq_fn(int irq, void *dev_id)
{
    printk("destAddr %u\n", *virt_dst);
    dma_regs->CS.INT = 1;
    return IRQ_HANDLED;
}

static struct device *dev;

int IRQ_DMA0;
static int __init ofcd_init(void) /* Constructor */
{
    int error, mret;
    struct device_node * np = NULL;
    
    error = misc_register(&sample_device);
    if (error) {
        pr_err("can't misc_register :(\n");
        return error;
    }

    dev = sample_device.this_device;
    dev->coherent_dma_mask = ~0;
    dev->dma_mask = &dev->coherent_dma_mask;

//  dev_set_name(dev, "mydmadev");
    
//  cpu_addr = (struct dmadata_s*)kmalloc(sizeof(struct dmadata_s), GFP_KERNEL | GFP_DMA);
    //dma_addr = dma_map_single(dev, cpu_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
    virt_cb = dma_alloc_coherent(dev, 32, &phys_cb, GFP_KERNEL | GFP_DMA);
    if(virt_cb == 0 || phys_cb == 0){
        printk("DMA cb error\n");
    }

    virt_src = dma_alloc_coherent(dev, 4, &phys_src, GFP_KERNEL | GFP_DMA);
    if(virt_src == 0 || phys_src == 0){
        printk("DMA src error\n");
    }

    virt_dst = dma_alloc_coherent(dev, 4, &phys_dst, GFP_KERNEL | GFP_DMA);
    if(virt_dst == 0 || phys_dst == 0){
        printk("DMA dst error\n");
    }

    memset(virt_cb, 0, sizeof(*virt_cb));
    dma_regs = (struct dma_ch *)ioremap(DMA_BASE, sizeof(struct dma_ch));
    
    
//  strcpy(cpu_addr->srcAddr, "DMA0");
    *virt_src = 200;
    virt_cb->TI.SRC_INC = 1;
    virt_cb->TI.DEST_INC = 1;
    virt_cb->TI.INTEN = 1;
    virt_cb->SOURCE_AD = (uint32_t)phys_src;
    virt_cb->DEST_AD = (uint32_t)phys_dst;
    virt_cb->TXFR_LEN = 4;
    virt_cb->reserved[0] = 0;
    virt_cb->reserved[1] = 0;
    
    printk("srcAddr %u\n", *virt_src);
    printk("destAddr %u\n", *virt_dst);
    
    //dma_regs->CS = (DMA_CS_t){.RESET = 1, .END = 1};
    dma_regs->CS.RESET = 1;
    udelay(10);
//  dma_regs->CS = (DMA_CS_t){.END = 1, .INT = 1};
    dma_regs->CS.INT = 1;
    dma_regs->CS.END = 1;
    dma_regs->CONBLK_AD = (uint32_t)phys_cb;
    //dma_regs->DEBUG = (DMA_DEBUG_t){.READ_LAST_NOT_SET_ERROR = 1, .FIFO_ERROR = 1, .READ_ERROR = 1};
    dma_regs->DEBUG.READ_LAST_NOT_SET_ERROR = 1;
    dma_regs->DEBUG.FIFO_ERROR = 1;
    dma_regs->DEBUG.READ_ERROR =1;
    udelay(10);
//  dma_regs->CS = (DMA_CS_t){.RESET = 1, .PRIORITY = 8, .PANIC_PRIORITY = 8, .ACTIVE = 1};
    dma_regs->CS.RESET = 1;
    udelay(10);
    dma_regs->CS.PRIORITY = 8;
    dma_regs->CS.PANIC_PRIORITY = 8;
    dma_regs->CS.ACTIVE = 1;
    if(dma_regs->CS.ERROR) printk("ERROR %d %d\n", dma_regs->CS.ACTIVE, dma_regs->CS.PANIC_PRIORITY);



    //np = of_find_compatible_node(NULL,NULL,"brcm,bcm2835-system-timer");
    np = of_find_node_by_path("/soc/dma@7e007000");
    if (np == NULL){
        printk("Error node not found\n");
    }
//  printk("node name %s\n", np->name);
    
    IRQ_DMA0 = irq_of_parse_and_map(np, 0);
    if (IRQ_DMA0 <= 0) {
        printk("Can't parse IRQ\n");
    }

    mret = request_irq(IRQ_DMA0, dma_irq_fn, IRQF_SHARED, "dma", &dma_irq_fn);
    if (mret < 0) printk(KERN_ALERT "%s: dma request_irg failed with %d\n", __func__, mret);

    return 0;
}
 
static void __exit ofcd_exit(void) /* Destructor */
{
    free_irq( IRQ_DMA0, &dma_irq_fn );
    //dma_unmap_single(dev, dma_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
    //kfree(cpu_addr);
    dma_free_coherent(dev, 32, virt_cb, phys_cb);
    dma_free_coherent(dev, 4, virt_src, phys_src);
    dma_free_coherent(dev, 4, virt_dst, phys_dst);
    iounmap(dma_regs);
//  device_unregister(dev);
    misc_deregister(&sample_device);
    printk(KERN_INFO "Module unregistered\n");
}

module_init(ofcd_init);
module_exit(ofcd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MBajor>");
MODULE_DESCRIPTION("PiCNC driver");
MODULE_VERSION("0.1");

我希望这会有所帮助。

于 2021-05-24T16:15:21.167 回答