添加操作物理内存的驱动
This commit is contained in:
parent
61d0558997
commit
84730e85fc
|
@ -1127,6 +1127,7 @@ CONFIG_SUNXI_SYS_INFO=y
|
|||
CONFIG_DUMP_REG=y
|
||||
CONFIG_DUMP_REG_MISC=y
|
||||
# CONFIG_SUNXI_TIMER_TEST is not set
|
||||
# CONFIG_MEM_OPERATION is not set
|
||||
# CONFIG_SUNXI_TRANSFORM is not set
|
||||
# CONFIG_SUNXI_DI is not set
|
||||
CONFIG_SUNXI_G2D=y
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
};
|
||||
|
||||
reserved-memory {
|
||||
wakeup_source: wakeup_source {
|
||||
reg = <0x0 0x4307F000 0x0 0x00001000>;
|
||||
no-map;
|
||||
};
|
||||
e907_fw: e907_fw {
|
||||
reg = <0x0 0x43080000 0x0 0x00190000>;
|
||||
};
|
||||
|
|
|
@ -1254,6 +1254,7 @@ CONFIG_SUNXI_SYS_INFO=y
|
|||
CONFIG_DUMP_REG=y
|
||||
CONFIG_DUMP_REG_MISC=y
|
||||
# CONFIG_SUNXI_TIMER_TEST is not set
|
||||
CONFIG_MEM_OPERATION=y
|
||||
# CONFIG_SUNXI_TRANSFORM is not set
|
||||
# CONFIG_SUNXI_DI is not set
|
||||
CONFIG_SUNXI_G2D=y
|
||||
|
|
|
@ -596,6 +596,7 @@ source "drivers/char/sunxi-scr/Kconfig"
|
|||
source "drivers/char/sunxi-sysinfo/Kconfig"
|
||||
source "drivers/char/dump_reg/Kconfig"
|
||||
source "drivers/char/timer_test/Kconfig"
|
||||
source "drivers/char/mem_operation/Kconfig"
|
||||
source "drivers/char/sunxi_tr/Kconfig"
|
||||
source "drivers/char/sunxi-di/Kconfig"
|
||||
source "drivers/char/sunxi_g2d/Kconfig"
|
||||
|
|
|
@ -64,6 +64,7 @@ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
|
|||
obj-$(CONFIG_ARCH_SUNXI) += sunxi-sysinfo/
|
||||
|
||||
obj-$(CONFIG_SUNXI_TIMER_TEST) += timer_test/
|
||||
obj-$(CONFIG_MEM_OPERATION) += mem_operation/
|
||||
obj-$(CONFIG_DUMP_REG) += dump_reg/
|
||||
obj-$(CONFIG_SUNXI_TRANSFORM) += sunxi_tr/
|
||||
obj-y += sunxi-di/
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# sunxi timer test configuration.
|
||||
#
|
||||
|
||||
config MEM_OPERATION
|
||||
tristate "mem operation test driver"
|
||||
default n
|
||||
help
|
||||
Nothing help.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
obj-$(CONFIG_MEM_OPERATION) += mem_operation_drv.o
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#define WEIGHT_ADDR 0x4307F000 // 权重加载的内存地址处
|
||||
#define MEM_ACCESS_RELEASE_PHYS_ADDR _IOR('M', 0, unsigned int) // 自定义ioctl命令,用于释放预留内存
|
||||
|
||||
static int major = 0;
|
||||
static struct class *mem_operation_class;
|
||||
|
||||
static int check_page_reserved(unsigned long addr)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = pfn_to_page(addr >> PAGE_SHIFT); // 将虚拟地址转换为页面索引,然后得到页面结构
|
||||
if (PageReserved(page)) {
|
||||
printk(KERN_INFO "Page at address 0x%lx is reserved.\n", addr);
|
||||
return 0;
|
||||
} else {
|
||||
printk(KERN_INFO "Page at address 0x%lx is not reserved.\n", addr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int mem_operation_drv_open (struct inode *node, struct file *file)
|
||||
{
|
||||
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mem_operation_drv_close (struct inode *node, struct file *file)
|
||||
{
|
||||
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mem_operation_drv_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long phy = WEIGHT_ADDR;
|
||||
|
||||
if(check_page_reserved(WEIGHT_ADDR) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* 设置属性: cache, buffer */
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
|
||||
/* map */
|
||||
if (remap_pfn_range(vma, vma->vm_start, phy >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
|
||||
printk("mmap remap_pfn_range failed\n");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long mem_operation_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case MEM_ACCESS_RELEASE_PHYS_ADDR: {
|
||||
unsigned int mem_size;
|
||||
|
||||
if (get_user(mem_size, (unsigned long __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
if(check_page_reserved(WEIGHT_ADDR) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
memblock_free(WEIGHT_ADDR, mem_size);
|
||||
free_reserved_area(__va(WEIGHT_ADDR), __va(WEIGHT_ADDR + mem_size), -1, "wakeup_source");
|
||||
printk("release phy addr: 0x%x, size: %d\n", WEIGHT_ADDR, mem_size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct file_operations mem_operation_drv = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = mem_operation_drv_open,
|
||||
.release = mem_operation_drv_close,
|
||||
.mmap = mem_operation_drv_mmap,
|
||||
.unlocked_ioctl = mem_operation_drv_ioctl,
|
||||
};
|
||||
|
||||
static int __init mem_operation_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||
major = register_chrdev(0, "mem_operation", &mem_operation_drv); /* /dev/mem_operation */
|
||||
|
||||
mem_operation_class = class_create(THIS_MODULE, "mem_operation_class");
|
||||
err = PTR_ERR(mem_operation_class);
|
||||
if (IS_ERR(mem_operation_class)) {
|
||||
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||
unregister_chrdev(major, "mem_operation");
|
||||
return -1;
|
||||
}
|
||||
|
||||
device_create(mem_operation_class, NULL, MKDEV(major, 0), NULL, "mem_operation"); /* 设备节点: /dev/mem_operation */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit mem_operation_exit(void)
|
||||
{
|
||||
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||
device_destroy(mem_operation_class, MKDEV(major, 0));
|
||||
class_destroy(mem_operation_class);
|
||||
unregister_chrdev(major, "mem_operation");
|
||||
}
|
||||
|
||||
module_init(mem_operation_init);
|
||||
module_exit(mem_operation_exit);
|
||||
MODULE_LICENSE("GPL");
|
Loading…
Reference in New Issue