#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DMA_ADDR_OFFSET 32 #define PRINT(A) printk(KERN_ALERT ">>>>> #A %x\n", A); MODULE_AUTHOR("Talaie"); MODULE_LICENSE("Dual BSD/GPL"); static struct pci_device_id pcie_ids[] = { {PCI_DEVICE(0x10ee, 0x7024)}, {0, }, }; MODULE_DEVICE_TABLE(pci, pcie_ids); static irqreturn_t interrupt_handler(int irq, void *p); static struct pci_dev *pcidev = NULL; static unsigned int chrdev_major = 0; static unsigned int chrdev_minor = 0; static unsigned int ioctl_alloc_dma = 0; static unsigned int ioctl_refresh_link = 1; static unsigned long bar0_addr; static unsigned long bar0_size = 4*1024; //TODO ask about size. 4KB static void* bar0_ptr; static unsigned int irq; struct page** dma_pages = NULL; unsigned int dma_pages_count = 0; void* dma_addr = NULL; unsigned long mmap_buffersize = 4 * 1024; //4KB /*************************************************************************************************/ static int __init pcie_init(void); static int chrdev_init(void); static int usd_open(struct inode *inode, struct file *flip); static int usd_mmap(struct file *filp, struct vm_area_struct *vma); static unsigned int usd_poll (struct file *filp, poll_table *wait); static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *id); static void pcie_remove(struct pci_dev *dev); static void __exit pcie_exit(void); /*************************************************************************************************/ static dev_t chrdev; static struct cdev cdev; static struct class *class = NULL; #define DEV_NAME "usd_reg" struct file_operations chrdev_fops = { .owner = THIS_MODULE, .open = usd_open, .mmap = usd_mmap, .poll = usd_poll }; /*************************************************************************************************/ static struct pci_driver pci_driver = { .name = "usdpci", .id_table = pcie_ids, .probe = pcie_probe, .remove = __exit_p(pcie_remove), }; /*************************************************************************************************/ #define PRINT_PREFIX "USDriver PCIe" #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 = chrdev_init(); if ( res ) { PRINT_ALERT("character device file creation failed"); return res; } PRINT_ALERT("driver loaded"); return res; } /*************************************************************************************************/ static int chrdev_init(void) { PRINT_ALERT("chrdev_init"); int res = 0; struct device *device = NULL; res = alloc_chrdev_region(&chrdev, 0, 1, DEV_NAME); if(res < 0) { return -1; } cdev_init(&cdev, &chrdev_fops); res = cdev_add(&cdev, chrdev, 1); if (res) { unregister_chrdev_region(chrdev, 1); return res; } class = class_create(THIS_MODULE, "usdpci"); device = device_create(class, NULL, 0, NULL, "usd_regs0"); return 0; } /*************************************************************************************************/ static int usd_open(struct inode *inode, struct file *flip) { return 0; } /*************************************************************************************************/ static int usd_mmap(struct file *filp, struct vm_area_struct *vma) { return 0; } /*************************************************************************************************/ static unsigned int usd_poll (struct file *filp, poll_table *wait) { return 0; } /*************************************************************************************************/ static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *id) { bar0_ptr = pci_iomap(dev, 0, 64 * 1024);//4KB u8* bar0_data = (u8*)bar0_ptr; int rc = 0; if(bar0_data == 0) { PRINT_ALERT("driver failed to map BAR 0"); rc = 1; goto probe_fail_release_region; } pci_set_master(dev); // int i = 0; // for( i = 0; i < 1; i++) // { // int r32 = ioread32(&bar0_data[i*4]); // printk(KERN_ALERT "Read: %x (%d)\n", r32, i); // } iowrite32(0x45670000, &bar0_data[0x8018]); int r32 = ioread32(&bar0_data[0x8018]); printk(KERN_ALERT "Read: %x\n", r32); 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"); int i; u8* bar0_data; bar0_data = (u8*)bar0_ptr; for ( i = 0; i < dma_pages_count; i++ ) { pci_unmap_single(pcidev, bar0_data[DMA_ADDR_OFFSET + 4*i], PAGE_SIZE, DMA_BIDIRECTIONAL); __free_page(dma_pages[i]); } if (dma_pages != NULL) kfree(dma_pages); printk(KERN_ALERT "Freed DMA pages\n"); pci_clear_master(dev); printk(KERN_ALERT "Cleared PCIe master\n"); pci_iounmap(dev, bar0_ptr); printk(KERN_ALERT "IOunmap\n"); pci_release_regions(dev); printk(KERN_ALERT "pci_release_regions\n"); pci_disable_device(dev); printk(KERN_ALERT "pci_disable_device\n"); } /*************************************************************************************************/ static void __exit pcie_exit(void) { int i; u8* bar0_data; bar0_data = (u8*)bar0_ptr; printk(KERN_ALERT "USDriver PCIe driver unloading\n"); printk(KERN_ALERT "USDriver PCIe driver unregistering\n"); pci_unregister_driver(&pci_driver); printk(KERN_ALERT "USDriver PCIe unregister_chrdev_region\n"); unregister_chrdev_region(chrdev, 1); printk(KERN_ALERT "USDriver PCIe cdev_del\n"); cdev_del(&cdev); printk(KERN_ALERT "USDriver PCIe device_destroy\n"); device_destroy(class, chrdev); printk(KERN_ALERT "USDriver PCIe class_destroy\n"); class_destroy(class); printk(KERN_ALERT "USDriver PCIe driver unloaded\n"); } module_init(pcie_init); module_exit(pcie_exit); /*************************************************************************************************/ static int create_dma_buffer(unsigned int bufcount) { int i; int bufidx = 0; unsigned int gfp_mask = GFP_KERNEL | __GFP_DMA; dma_addr_t bus_addr; u8* bar0_data; bar0_data = (u8*)bar0_ptr; printk(KERN_ALERT "USDriver DMA buffer alloc request: %d pages\n", bufcount); if( dma_pages != NULL) { printk(KERN_ALERT "USDriver DMA buffer already exist! Strange!\n"); } dma_pages = kmalloc(4*1024*1024 * bufcount, GFP_KERNEL); if(dma_pages == NULL) { printk(KERN_ERR "USDriver DMA dma_pages alloc failed! \n" ); return 1; } for(bufidx = 0; bufidx < bufcount; bufidx++) { void __iomem *maddr = NULL; struct page *pages = alloc_pages(gfp_mask, 10); if(pages == NULL) { printk(KERN_ERR "USDriver DMA buffer alloc failed! \n" ); return 1; } maddr = page_address(pages); dma_pages[bufidx] = pages; bus_addr = pci_map_single(pcidev, maddr, 1024 * PAGE_SIZE, DMA_BIDIRECTIONAL); printk(KERN_ALERT ">>>>>[%d] 0x%x\n", bufidx, bus_addr); iowrite32(bus_addr, &bar0_data[DMA_ADDR_OFFSET + (4 * bufidx)]); wmb(); if(pci_dma_mapping_error(pcidev, bus_addr)) { return 1; } } dma_pages_count = bufcount; printk(KERN_ALERT "USDriver DMA buffer alloc successful\n"); return 0; } /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/ /*************************************************************************************************/