sdk-hwV1.3/lichee/linux-4.9/drivers/char/mem_operation/mem_operation_drv.c

142 lines
3.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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");