免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5027 | 回复: 3
打印 上一主题 下一主题

linux环境下读写一次双口ram尽然要十几个毫秒。(附驱动代码) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-04-29 21:59 |只看该作者 |倒序浏览
20可用积分
linux环境下读写一次双口ram尽然要十几个毫秒。(附驱动代码)
我用的双口ram是IDT70V28,手册上说的读写时间应该是几个纳秒,我写了个linux驱动,然后做测试,发现读写一次的时间尽然是十几个到几
十个毫秒!(通过点IO管脚,用示波器看),而且不能在多个线程访问双口ram(访问不同的地址都不行!)。并且读写数据的时间基本和读写
数据的长度没有太多关系,只是和读写次数关系非常明显。
搞了两个星期,也没有找到问题,请高人指点!谢谢帮忙
//以下为驱动程序全文
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/arch/hardware.h>    //必须
#include <asm/io.h>
#include <asm/irq.h>  
#undef DPRINTK                               /* undef it, just in case */
#ifdef SDRAM_DEBUG
/* This one if debugging is on, and kernel space */
#define DPRINTK(fmt, args...) printk("can: "fmt, ## args)
#else
#define DPRINTK(fmt, args...) /* not debugging: nothing */
#endif
//定义双口RAM字符设备结构
typedef struct _sdram_dev
{
    struct cdev chrdev;
    unsigned short * data_addr;                  //数据口
    unsigned int data_max;
    unsigned int user_idx;
}sdram_dev,*sdram_dev_t;

//全局变量,常量;
static int sdram_major=0;
static struct class* sdram_class;
unsigned int SDRAM_offset=0;
#define DSDRAM_NAME             "double_sdram"
#define DATA_EBI_BASE_ADDRESS   (0x20000000)
#define ADDR_SDRAM_SIZE         (128*1024)
//SDRAM设备指针
static sdram_dev_t DSdram_dev;
//设备指针
static struct platform_device* DSdram_devices = NULL;
//BANK配置
void init_bank_board(void)
{
    //bank 2 is set to 16-bit
    __raw_writel(0x1000ffef,SMCBCR2);  
    DPRINTK("GPIO_AINTTYPE1=0x%x\r\n",__raw_readl(GPIO_AINTTYPE1));
    DPRINTK("GPIO_AINTTYPE2=0x%x\r\n",__raw_readl(GPIO_AINTTYPE2));
      
}
//**********************************************************
//ioctl函数:
//**********************************************************
static int dsdram_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)
{
  
SDRAM_offset=arg;
//printk("Set Offset :0x%x \r\n",SDRAM_offset);

return 0;
}
//write函数
static ssize_t dsdram_write(struct file* file, const char *buffer, size_t length,loff_t* loff)
{
    unsigned short *data_addr = NULL;
if (length > ADDR_SDRAM_SIZE) {
  printk("Reading more than 128K bytes data, this is not supported.\n");
  printk("Defaulting to 128K bytes data.\n");
  length = ADDR_SDRAM_SIZE;
}
    //length = length/2;
    data_addr = (DSdram_dev->data_addr)+SDRAM_offset;
   
if(copy_from_user(data_addr, (unsigned short *)buffer, length))
        return -EFAULT;

SDRAM_offset=0;
return (length);
              
}

//读函数
ssize_t dsdram_read(struct file *file, char *buffer, size_t length, loff_t *offset)
{
    unsigned short *data_addr = NULL;
if (length > ADDR_SDRAM_SIZE) {
  printk("Reading more than 128K bytes data, this is not supported.\n");
  printk("Defaulting to 128K bytes data.\n");
  length = ADDR_SDRAM_SIZE;
}
   
    //length = length/2;
   
    data_addr = (DSdram_dev->data_addr)+SDRAM_offset;
if(copy_to_user((unsigned short *)buffer, data_addr, length))
        return -EFAULT;

SDRAM_offset=0;
return (length);
}

//open 函数
static int dsdram_open(struct inode *inode, struct file *file)
{
    sdram_dev_t hdev = NULL;
    hdev = DSdram_dev;
    if(++hdev->user_idx == 1)
    {
   
     //申请内存区域,以检测该地址空间是否被使用;
        if (!request_mem_region(DATA_EBI_BASE_ADDRESS,ADDR_SDRAM_SIZE,DSDRAM_NAME))
            printk("Error request mem address for 0x20000000 ! \r\n");   
   
     hdev->data_addr = (unsigned short*)ioremap(DATA_EBI_BASE_ADDRESS,ADDR_SDRAM_SIZE);
     hdev->data_max  = ADDR_SDRAM_SIZE;  
    }
    DPRINTK("open succeed\n\r");
return 0;
}
//release函数
static int  dsdram_release(struct inode *inode, struct file *file)
{
    sdram_dev_t hdev=NULL;
    hdev = DSdram_dev;
    if(--hdev->user_idx == 0)
    {
        //取消内存区域映射;
        iounmap((unsigned short *)hdev->data_addr);

        //释放申请的内存区域;
        release_mem_region(DATA_EBI_BASE_ADDRESS,ADDR_SDRAM_SIZE);      
    }
   
return 0;
}
//文件操作函数结构
struct file_operations dsdram_fops=
{
.owner      =   THIS_MODULE,
.read       =   dsdram_read,
.write      =   dsdram_write,
.ioctl     =  dsdram_ioctl,
.open       =   dsdram_open,
.release    =   dsdram_release,
};
//系统探测函数
static int __devinit dsdram_probe(struct platform_device *pdev)
{
    int ret;
    dev_t dev_id;
    struct class_device* cls_sdram_dev;
    sdram_dev_t hdev;
    printk("device %s-%d detected!\n", pdev->name, pdev->id);
//config gpio and bank
init_bank_board();

    DSdram_dev = hdev = kmalloc(sizeof(sdram_dev), GFP_KERNEL);
    dev_id = MKDEV(sdram_major, 0);
    pdev->dev.devt = dev_id;
    cdev_init(&hdev->chrdev, &dsdram_fops);
    hdev->chrdev.owner = THIS_MODULE;
    hdev->user_idx = 0;
    ret = cdev_add(&hdev->chrdev, dev_id, 1);
    if (ret)
    {
        printk("fail to register driver for " DSDRAM_NAME "%d!\n", pdev->id);
        return ret;
    }
    platform_set_drvdata(pdev, hdev);

    cls_sdram_dev = class_device_create(sdram_class,NULL,dev_id,&pdev->dev,
                                    DSDRAM_NAME);
    if (IS_ERR(cls_sdram_dev))
        return PTR_ERR(cls_sdram_dev);

    printk("driver for "DSDRAM_NAME" registered\n");
    return ret;
}

static int __devexit dsdram_remove(struct platform_device *pdev)
{
    sdram_dev_t hdev;
    class_device_destroy(sdram_class, pdev->dev.devt);
    hdev = platform_get_drvdata(pdev);
    if (hdev)
    {
        cdev_del(&hdev->chrdev);
        kfree(hdev);
    }
    platform_set_drvdata(pdev, NULL);
   
    pdev->dev.devt = 0;
    printk(DSDRAM_NAME "removed!\n");
    return 0;
}

#ifdef CONFIG_PM
static int dsdram_suspend(struct platform_device *pdev, pm_message_t state)
{
return 0;
}
static int dsdram_resume(struct platform_device *pdev)
{
return 0;
}
#else
#define dsdram_suspend NULL
#define dsdram_resume NULL
#endif
static struct platform_driver dsdram_driver =
{   
    .probe      = dsdram_probe,   
    .remove     = __devexit_p(dsdram_remove),
#ifdef CONFIG_PM   
    .suspend    = dsdram_suspend,
    .resume     = dsdram_resume,
#endif
    .driver     =
    {     
        .name   = DSDRAM_NAME,        
        .owner  = THIS_MODULE,  
    },
};

//*********************************************************
//初始化模块函数;
//*********************************************************
static int __init dousdram_init_module(void)
{
    int ret;
    dev_t dev = MKDEV(sdram_major, 0);
    DSdram_devices = platform_device_alloc(DSDRAM_NAME, 0);
    if (!DSdram_devices)
        return -ENOMEM;
    ret = platform_device_add(DSdram_devices);
    if (ret < 0) {
        platform_device_put(DSdram_devices);
        return ret;
    }
  
    /* Figure out our device number. */
    if (sdram_major)
        ret = register_chrdev_region(dev, 1, DSDRAM_NAME);
    else
    {
        ret = alloc_chrdev_region(&dev, 0, 1, DSDRAM_NAME);
        if (ret)
        {
            printk(KERN_WARNING "DSDRAM_MODULE_NAME: unable to get major %d\n", sdram_major);
            return ret;
  }
        sdram_major = MAJOR(dev);
    }
    //create class
    sdram_class = class_create(THIS_MODULE, DSDRAM_NAME);
    if (IS_ERR(sdram_class))
        return PTR_ERR(sdram_class);
    ret = platform_driver_register(&dsdram_driver);
    return ret;
}

//*********************************************************
//清除模块函数;
//*********************************************************
static void __exit dousdram_cleanup_module(void)
{
    platform_driver_unregister(&dsdram_driver);
    class_destroy(sdram_class);
    unregister_chrdev_region(MKDEV(sdram_major, 0), 1);
   
    platform_device_unregister(DSdram_devices);
    DPRINTK("unregister driver " DSDRAM_NAME "\n");
   
}
module_init(dousdram_init_module);
module_exit(dousdram_cleanup_module);
MODULE_LICENSE("GPL");

论坛徽章:
0
2 [报告]
发表于 2008-04-29 23:18 |只看该作者
可以在驱动层实现mmap函数,在应用层获得地址后直接对ram读写。

或者在内核里面做一个缓冲区,不要在读写时直接调用copy_XXX_user,拷贝到缓冲区后,调用io操作。

论坛徽章:
0
3 [报告]
发表于 2008-05-30 21:00 |只看该作者
70v28不是64K吗?
用readw和writew试试,不用copy_from_user和copy_to_user

论坛徽章:
24
15-16赛季CBA联赛之北京
日期:2018-08-17 18:43:33技术图书徽章
日期:2018-08-22 12:53:57技术图书徽章
日期:2018-08-22 12:54:20技术图书徽章
日期:2018-08-22 12:54:3015-16赛季CBA联赛之福建
日期:2018-10-19 16:58:1619周年集字徽章-庆
日期:2019-08-27 13:28:5619周年集字徽章-19
日期:2019-08-27 13:31:2619周年集字徽章-19
日期:2019-08-27 13:31:2615-16赛季CBA联赛之同曦
日期:2019-09-05 12:03:2819周年集字徽章-周
日期:2019-09-06 18:54:5415-16赛季CBA联赛之上海
日期:2018-07-25 11:55:2615-16赛季CBA联赛之青岛
日期:2018-07-10 14:13:18
4 [报告]
发表于 2008-06-05 16:26 |只看该作者
原帖由 zclever 于 2008-5-30 21:00 发表
70v28不是64K吗?
用readw和writew试试,不用copy_from_user和copy_to_user

不是很明白, 为什么不能用 copy_xxx_user()这个函数的影响在哪里呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP