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

198 lines
5.3 KiB
C
Executable File
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>
#include <linux/io.h>
#define WEIGHT_ADDR 0x4307F000 // 权重加载的内存地址处
#define M_PAGE_SIZE (4 * 1024) // 内存对齐应该是4K
#define MEM_ACCESS_RELEASE_PHYS_ADDR _IOR('M', 0, unsigned int)
#define MEM_ACCESS_GET_WKSRC_SRC _IOW('M', 1, unsigned int)
#define MEM_ACCESS_SET_WKSRC_SRC _IOR('M', 2, unsigned int)
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;
}
typedef struct {
unsigned char readData[sizeof(int)];
} wakeup_src_t;
static long mem_operation_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
wakeup_src_t wakeupsrc = {.readData[0] = 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;
}
case MEM_ACCESS_GET_WKSRC_SRC:
{
void __iomem *vaddr = NULL;
// vaddr = ioremap(WEIGHT_ADDR, sizeof(wakeupsrc));
// vaddr = ioremap_nocache(PHYS_ADDR, SIZE);
vaddr = memremap(WEIGHT_ADDR, M_PAGE_SIZE, MEMREMAP_WB);
if (!vaddr)
{
return -EINVAL;
}
wakeupsrc.readData[0] = readb(vaddr);
// memcpy_fromio(buffer, vaddr, SIZE);
// copy_to_user(arg, vaddr, SIZE) ?
// printk(KERN_EMERG "give wake up source:%d\n", wakeupsrc.readData[0]);
if (copy_to_user(arg, &wakeupsrc, sizeof(wakeupsrc)))
{
// iounmap(vaddr);
memunmap(vaddr);
return -EINVAL;
}
// iounmap(vaddr);
memunmap(vaddr);
break;
}
case MEM_ACCESS_SET_WKSRC_SRC:
{
void __iomem *vaddr = NULL;
if (copy_from_user(&wakeupsrc, (void __user *)arg, sizeof(wakeupsrc)))
{
return -EFAULT;
}
vaddr = memremap(WEIGHT_ADDR, M_PAGE_SIZE, MEMREMAP_WB);
if (!vaddr)
{
return -EINVAL;
}
writeb(wakeupsrc.readData[0], vaddr);
memunmap(vaddr);
// printk(KERN_EMERG "set wake up source:%d\n", wakeupsrc.readData[0]);
break;
}
default:
return -EINVAL;
break;
}
return 0;
}
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");