From 3e9f48137205070cf8ad1b20a9b9d4699db9d2bb Mon Sep 17 00:00:00 2001 From: h-4nd-h Date: Sat, 19 Dec 2020 14:07:27 +0330 Subject: [PATCH] Work --- .gitignore | 12 + Makefile | 21 ++ scripts/drvMake.sh | 8 + scripts/modInstall.sh | 4 + scripts/modRemove.sh | 4 + scripts/unloadReinstallLoad.sh | 5 + sonoPciDrv.c | 402 +++++++++++++++++++++++++++++++++ sonoPciDrv.rules | 1 + 8 files changed, 457 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 scripts/drvMake.sh create mode 100755 scripts/modInstall.sh create mode 100755 scripts/modRemove.sh create mode 100755 scripts/unloadReinstallLoad.sh create mode 100644 sonoPciDrv.c create mode 100644 sonoPciDrv.rules diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e64cf53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ + GNU nano 4.8 .gitignore +test +*.order +*.symvers +*.ko +*.mod +*.mod.* +*.o +*.cmd +.vscode/ + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f243a11 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +# Otherwise we were called directly from the command +# line; invoke the kernel build system. + +ifneq ($(KERNELRELEASE),) + obj-m := sonoPciDrv.o +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + $(MAKE) -C $(KERNELDIR) M=$(PWD) clean +endif + +install: + sudo cp ./sonoPciDrv.ko /lib/modules/`uname -r`/ + sudo depmod -a + sudo cp ./sonoPciDrv.rules /etc/udev/rules.d/ diff --git a/scripts/drvMake.sh b/scripts/drvMake.sh new file mode 100755 index 0000000..fa134aa --- /dev/null +++ b/scripts/drvMake.sh @@ -0,0 +1,8 @@ +cd .. +echo ***Cleaning workspace*** +make clean +echo ***Making driver*** +make +echo ***Installing driver workspace*** +sudo make install +cd scripts \ No newline at end of file diff --git a/scripts/modInstall.sh b/scripts/modInstall.sh new file mode 100755 index 0000000..6aacb93 --- /dev/null +++ b/scripts/modInstall.sh @@ -0,0 +1,4 @@ +echo ***Installing kernel module*** +cd .. +sudo insmod sonoPciDrv.ko +cd scripts \ No newline at end of file diff --git a/scripts/modRemove.sh b/scripts/modRemove.sh new file mode 100755 index 0000000..2089664 --- /dev/null +++ b/scripts/modRemove.sh @@ -0,0 +1,4 @@ +echo ***Removing kernel module*** +cd .. +sudo rmmod sonoPciDrv +cd scripts \ No newline at end of file diff --git a/scripts/unloadReinstallLoad.sh b/scripts/unloadReinstallLoad.sh new file mode 100755 index 0000000..9f6f22c --- /dev/null +++ b/scripts/unloadReinstallLoad.sh @@ -0,0 +1,5 @@ +./modRemove.sh +./drvMake.sh +./modInstall.sh +dmesg +echo ***Done*** \ No newline at end of file diff --git a/sonoPciDrv.c b/sonoPciDrv.c new file mode 100644 index 0000000..ddf16f3 --- /dev/null +++ b/sonoPciDrv.c @@ -0,0 +1,402 @@ +#include +#include +#include +#include + +/*************************************************************************************************/ +MODULE_AUTHOR("h4ndh"); //hessamoddin hediyehloo +MODULE_LICENSE("Dual BSD/GPL"); + +/*************************************************************************************************/ +#define VENDOR_ID 0x10EE +#define DEVICE_ID 0x7024 + +struct pci_device_id pcie_ids[] = +{ + {PCI_DEVICE(VENDOR_ID, DEVICE_ID)}, + {0, } +}; + +MODULE_DEVICE_TABLE(pci, pcie_ids); + +/*************************************************************************************************/ +static struct pci_dev *pcidev = NULL; + +/*************************************************************************************************/ +static int pcie_init(void); +static void pcie_exit(void); +static int pcie_probe (struct pci_dev *dev, const struct pci_device_id *id); +static void pcie_remove(struct pci_dev *dev); + +static int proc_init(void); + +static int sono_bar_open(struct inode *inode, struct file *flip); +static int sono_bar_close(struct inode *inode, struct file *filp); +static int sono_bar_mmap(struct file *filp, struct vm_area_struct *vma); + +static int sono_buffer_open(struct inode *inode, struct file *flip); +static int sono_buffer_close(struct inode *inode, struct file *filp); +static int sono_buffer_mmap(struct file *filp, struct vm_area_struct *vma); + +static int create_dma_buffer(void); + +static void release_dma_buffer(int num); +static void unmap_bar_buffer(int num); + +static void pass_dma_address_to_hw(void); + +/*************************************************************************************************/ +#define DEV_NAME "sonoDevice" +#define CLASS_NAME "sonoClass" + +/*************************************************************************************************/ +#define TOTAL_BAR_NUM 3 + +struct bar_t { + resource_size_t start_addr; + resource_size_t end_addr; + resource_size_t length; + unsigned long flags; + void* bar_ptr; +}; + +struct bar_t bars[TOTAL_BAR_NUM]; + +/*************************************************************************************************/ +#define TOTAL_BUFFER_NUM 16 + +struct buffer_t { + void * ptr; + dma_addr_t address; +}; + +struct buffer_t buffers[TOTAL_BUFFER_NUM]; + +/*************************************************************************************************/ +#define DMA_SIZE 4*1024*1024 + +/*************************************************************************************************/ +static struct pci_driver pci_driver = +{ + .name = CLASS_NAME, + .id_table = pcie_ids, + .probe = pcie_probe, + .remove = __exit_p(pcie_remove), +}; + +/*************************************************************************************************/ +static struct file_operations bar_fops = +{ + .owner = THIS_MODULE, + .open = sono_bar_open, + .release = sono_bar_close, + .mmap = sono_bar_mmap +}; + +static struct file_operations buffer_fops = +{ + .owner = THIS_MODULE, + .open = sono_buffer_open, + .release = sono_buffer_close, + .mmap = sono_buffer_mmap +}; + +/*************************************************************************************************/ +#define PRINT_PREFIX "Sono pcie driver" +#define PRINT_ALERT(STR) printk(KERN_ALERT "%s %s\n", PRINT_PREFIX, STR) +#define PRINT_WARN(STR) printk(KERN_WARN "%s %s\n", PRINT_PREFIX, STR) + +/*************************************************************************************************/ +static int __init pcie_init(void) +{ + int res = 0; + PRINT_ALERT("driver initializing"); + + res = pci_register_driver(&pci_driver); + if ( res ) { + PRINT_ALERT("device not found"); + return res; + } + + PRINT_ALERT("register driver success" ); + + res = proc_init(); + if ( res ) { + PRINT_ALERT("proc file creation failed"); + return res; + } + + PRINT_ALERT("driver loaded"); + return res; +} + +/*************************************************************************************************/ +static int proc_init(void) +{ + PRINT_ALERT("proc_init"); + + proc_create("sono_bars", 0, NULL, &bar_fops); + proc_create("sono_buffers", 0, NULL, &buffer_fops); + + return 0; +} + +/*************************************************************************************************/ +static int sono_bar_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +/*************************************************************************************************/ +static int sono_buffer_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +/*************************************************************************************************/ +static int sono_bar_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +/*************************************************************************************************/ +static int sono_buffer_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +/*************************************************************************************************/ +static int sono_bar_mmap(struct file *filp, struct vm_area_struct *vma) +{ + PRINT_ALERT("BAR MMAP"); + + unsigned long offset = vma->vm_pgoff; + int bar_num = offset; + + unsigned long physical = bars[bar_num].start_addr; + unsigned long bar_size = bars[bar_num].length; + unsigned long vsize = vma->vm_end - vma->vm_start; + + if(vsize > bar_size) + return -EINVAL; + + vma->vm_flags |= VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + int res = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, vsize, vma->vm_page_prot); + if(res) + { + printk(KERN_ERR "Failed to map bar @ %d\n", bar_num); + } + + return res; +} + +/*************************************************************************************************/ +static int sono_buffer_mmap(struct file *filp, struct vm_area_struct *vma) +{ + PRINT_ALERT("BUFFER MMAP"); + + unsigned long offset = vma->vm_pgoff; + int buffer_num = offset; + + unsigned long physical = virt_to_phys(buffers[buffer_num].ptr); + unsigned long vsize = vma->vm_end - vma->vm_start; + + if(vsize > DMA_SIZE) + return -EINVAL; + + int res = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, vsize, vma->vm_page_prot); + if(res) + { + printk(KERN_ERR "failed to map mapped DMA buffer at phys: %p\n", buffers[buffer_num].address); + } + + return res; +} + +/*************************************************************************************************/ +static int create_dma_buffer() +{ + int i = 0; + for(; i < TOTAL_BUFFER_NUM; i++) + { + buffers[i].ptr = dma_alloc_coherent(&pcidev->dev, DMA_SIZE, &buffers[i].address, GFP_USER); + if(buffers[i].ptr == NULL) + { + PRINT_ALERT("I can't allocate the DMA buffer"); + while(--i >= 0) + { + release_dma_buffer(i); + } + return 1; + } + } + + return 0; +} + +/*************************************************************************************************/ +static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + int rc = 0; + + if(pcidev) + { + PRINT_ALERT("Cant handle more than one device at a time"); + + return -EINVAL; + } + + pcidev = dev; + + rc = pci_enable_device(dev); + if(rc) + { + PRINT_ALERT("driver pci_enable_device() failed"); + goto probe_fail_enable; + } + + if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) + { + if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) + { + printk(KERN_ERR "Unable to obtain 64bit DMA for consistent allocations\n"); + rc = 1; + goto probe_fail; + } + } + + create_dma_buffer(); + + rc = pci_request_regions(pcidev, DEV_NAME); + if(rc) + { + PRINT_ALERT("Failed to request regoins"); + goto probe_fail; + } + + int i = 0; + for(; i < TOTAL_BAR_NUM; i++) + { + bars[i].flags = pci_resource_flags(pcidev, i); + if (!(bars[i].flags & IORESOURCE_MEM)) { + printk(KERN_ERR "Sono pcie driver incorrect BAR configuration\n" ); + rc = 1; + goto probe_fail_release_region; + } + + bars[i].start_addr = pci_resource_start(pcidev, i); + bars[i].end_addr = pci_resource_end(pcidev, i); + bars[i].length = pci_resource_len(pcidev, i); + + bars[i].bar_ptr = pci_iomap(pcidev, i, bars[i].length); + + u32* temp = (u32*)bars[i].bar_ptr; + + if(temp == 0) + { + printk(KERN_ERR "driver failed to map BAR %d\n", i); + rc = 1; + while(--i >= 0) + { + unmap_bar_buffer(i); + } + for(; i < TOTAL_BUFFER_NUM; i++) + { + release_dma_buffer(i); + } + goto probe_fail_release_region; + } + } + + pci_set_master(dev); + + pass_dma_address_to_hw(); + + return 0; + + probe_fail_release_region: + pci_release_regions(dev); + probe_fail: + pci_disable_device(dev); + probe_fail_enable: + return rc; +} + +/*************************************************************************************************/ +static void pcie_remove(struct pci_dev *dev) +{ + PRINT_ALERT("remove driver"); + + pci_clear_master(dev); + PRINT_ALERT("Cleared PCIe master"); + + int i = 0; + for(; i < TOTAL_BAR_NUM ; i++) + { + unmap_bar_buffer(i); + } + + for(; i < TOTAL_BUFFER_NUM ; i++) + { + release_dma_buffer(i); + } + + PRINT_ALERT("IOunmap"); + + pci_release_regions(dev); + PRINT_ALERT("pci_release_regions"); + + pci_disable_device(dev); + PRINT_ALERT("pci_disable_device"); +} + +/*************************************************************************************************/ +static void __exit pcie_exit(void) +{ + PRINT_ALERT("driver unloading"); + + PRINT_ALERT("driver unregistering"); + pci_unregister_driver(&pci_driver); + + remove_proc_entry("sono_bars", NULL); + remove_proc_entry("sono_buffers", NULL); + + PRINT_ALERT("driver unloaded"); +} + +module_init(pcie_init); +module_exit(pcie_exit); +/*************************************************************************************************/ +void release_dma_buffer(int num) +{ + dma_free_coherent(&pcidev->dev, DMA_SIZE, buffers[num].ptr, buffers[num].address); +} +/*************************************************************************************************/ +void unmap_bar_buffer(int num) +{ + pci_iounmap(pcidev, bars[num].bar_ptr); +} +/*************************************************************************************************/ +//This function is tightly coupled with hw def +void pass_dma_address_to_hw(void) +{ + int index = 0x00002060; + + u32* temp = (u32*)bars[2].bar_ptr; + + int i; + for(i = 0; i < TOTAL_BUFFER_NUM; i++) + { + dma_addr_t address = buffers[i].address; + + temp[index / 4] = address >> 32; + index += 4; + + temp[index / 4] = (address & 0xFFFFFFFF); + index += 4; + } +} +/*************************************************************************************************/ +/*************************************************************************************************/ +/*************************************************************************************************/ diff --git a/sonoPciDrv.rules b/sonoPciDrv.rules new file mode 100644 index 0000000..a820aa5 --- /dev/null +++ b/sonoPciDrv.rules @@ -0,0 +1 @@ +ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10ee", ATTR{device}="0x7024", MODE="666", RUN+="/sbin/modprobe sonoPciDrv"