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

198 lines
5.3 KiB
C
Raw Normal View History

2025-02-21 09:38:33 +00:00
#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>
2025-02-21 09:38:33 +00:00
#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)
2025-02-21 09:38:33 +00:00
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;
2025-02-21 09:38:33 +00:00
static long mem_operation_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
wakeup_src_t wakeupsrc = {.readData[0] = 0};
2025-02-21 09:38:33 +00:00
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;
}
2025-02-21 09:38:33 +00:00
default:
return -EINVAL;
2025-02-21 09:38:33 +00:00
break;
}
return 0;
2025-02-21 09:38:33 +00:00
}
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");