|
|
@ -12,6 +12,7 @@ |
|
|
|
#include <linux/spinlock_types.h> |
|
|
|
|
|
|
|
#include <linux/fs.h> |
|
|
|
#include <linux/proc_fs.h> |
|
|
|
#include <linux/cdev.h> |
|
|
|
|
|
|
|
#include <linux/sched.h> |
|
|
@ -19,13 +20,14 @@ |
|
|
|
#include <linux/delay.h> |
|
|
|
#include <linux/poll.h> |
|
|
|
|
|
|
|
|
|
|
|
#define DMA_ADDR_OFFSET 32 |
|
|
|
/*************************************************************************************************/ |
|
|
|
#define PRINT(A) printk(KERN_ALERT ">>>>> #A %x\n", A); |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
MODULE_AUTHOR("h4ndh"); //hediyehloo based on Talaee works
|
|
|
|
MODULE_LICENSE("Dual BSD/GPL"); |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static struct pci_device_id pcie_ids[] = |
|
|
|
{ |
|
|
|
{PCI_DEVICE(0x10ee, 0x7024)}, |
|
|
@ -33,43 +35,28 @@ static struct pci_device_id pcie_ids[] = |
|
|
|
}; |
|
|
|
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 = 64 * 1024; |
|
|
|
static void* bar0_ptr; |
|
|
|
|
|
|
|
static unsigned long bar1_addr; |
|
|
|
static unsigned long bar1_size = 128 * 1024 * 1024; |
|
|
|
static void* bar1_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 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 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 void pcie_exit(void); |
|
|
|
|
|
|
|
static int chrdev_init(void); |
|
|
|
|
|
|
|
static int usd_open_0(struct inode *inode, struct file *flip); |
|
|
|
static int usd_close_0(struct inode *inode, struct file *filp); |
|
|
|
static int usd_mmap_0(struct file *filp, struct vm_area_struct *vma); |
|
|
|
|
|
|
|
static int usd_open_1(struct inode *inode, struct file *flip); |
|
|
|
static int usd_close_1(struct inode *inode, struct file *filp); |
|
|
|
static int usd_mmap_1(struct file *filp, struct vm_area_struct *vma); |
|
|
|
|
|
|
|
static int usd_open_2(struct inode *inode, struct file *flip); |
|
|
|
static int usd_close_2(struct inode *inode, struct file *filp); |
|
|
|
static int usd_mmap_2(struct file *filp, struct vm_area_struct *vma); |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static dev_t chrdev; |
|
|
@ -78,16 +65,19 @@ static struct class *class = NULL; |
|
|
|
|
|
|
|
#define DEV_NAME "usd_reg" |
|
|
|
#define CLASS_NAME "usdpci" |
|
|
|
#define NODE_0_NAME "usd_reg0" |
|
|
|
|
|
|
|
struct file_operations chrdev_fops = |
|
|
|
{ |
|
|
|
.owner = THIS_MODULE, |
|
|
|
.open = usd_open, |
|
|
|
.mmap = usd_mmap, |
|
|
|
.poll = usd_poll |
|
|
|
/*************************************************************************************************/ |
|
|
|
#define TOTAL_BAR_NUM 2 |
|
|
|
|
|
|
|
struct bar_t{ |
|
|
|
unsigned long bar_addr; |
|
|
|
unsigned long bar_size; |
|
|
|
void* bar_ptr; |
|
|
|
struct file_operations chrdev_fops; |
|
|
|
}; |
|
|
|
|
|
|
|
struct bar_t bars[TOTAL_BAR_NUM]; |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static struct pci_driver pci_driver = |
|
|
|
{ |
|
|
@ -114,6 +104,27 @@ static int __init pcie_init(void) |
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
//gone have 3 bar for now
|
|
|
|
bars[0].chrdev_fops.owner = THIS_MODULE; |
|
|
|
bars[0].chrdev_fops.open = usd_open_0; |
|
|
|
bars[0].chrdev_fops.mmap = usd_mmap_0; |
|
|
|
bars[0].chrdev_fops.release = usd_close_0; |
|
|
|
bars[0].bar_size = 4 * 1024; |
|
|
|
|
|
|
|
bars[1].chrdev_fops.owner = THIS_MODULE; |
|
|
|
bars[1].chrdev_fops.open = usd_open_1; |
|
|
|
bars[1].chrdev_fops.mmap = usd_mmap_1; |
|
|
|
bars[1].chrdev_fops.release = usd_close_1; |
|
|
|
bars[1].bar_size = 128 * 1024 * 1024; |
|
|
|
|
|
|
|
// bars[2].chrdev_fops = {
|
|
|
|
// .owner = THIS_MODULE,
|
|
|
|
// .open = usd_open_2,
|
|
|
|
// .mmap = usd_mmap_2,
|
|
|
|
// .release = usd_close_2
|
|
|
|
// };
|
|
|
|
// bars[2].bar_size = 4 * 1024;
|
|
|
|
|
|
|
|
PRINT_ALERT("register driver success" ); |
|
|
|
|
|
|
|
res = chrdev_init(); |
|
|
@ -131,44 +142,113 @@ 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) |
|
|
|
char name[16]; |
|
|
|
int i = 0; |
|
|
|
for( ;i < TOTAL_BAR_NUM; i++) |
|
|
|
{ |
|
|
|
return -1; |
|
|
|
sprintf(name, "%s_%d", DEV_NAME, i); |
|
|
|
proc_create(name, 0, NULL, &bars[i].chrdev_fops); |
|
|
|
} |
|
|
|
|
|
|
|
cdev_init(&cdev, &chrdev_fops); |
|
|
|
res = cdev_add(&cdev, chrdev, 1); |
|
|
|
if (res) |
|
|
|
{ |
|
|
|
unregister_chrdev_region(chrdev, 1); |
|
|
|
return res; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_open_0(struct inode *inode, struct file *filp) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
class = class_create(THIS_MODULE, CLASS_NAME); |
|
|
|
device = device_create(class, NULL, chrdev, NULL, NODE_0_NAME); |
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_open_1(struct inode *inode, struct file *filp) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_open_2(struct inode *inode, struct file *filp) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_close_0(struct inode *inode, struct file *filp) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_close_1(struct inode *inode, struct file *filp) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_close_2(struct inode *inode, struct file *filp) |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_open(struct inode *inode, struct file *flip) |
|
|
|
static int usd_mmap_0(struct file *filp, struct vm_area_struct *vma) |
|
|
|
{ |
|
|
|
PRINT_ALERT("MMAP"); |
|
|
|
|
|
|
|
unsigned long off = vma->vm_pgoff << PAGE_SHIFT; |
|
|
|
unsigned long vsize = vma->vm_end - vma->vm_start; |
|
|
|
|
|
|
|
unsigned long physical = bars[0].bar_addr + off; |
|
|
|
|
|
|
|
unsigned int intvsize = bars[0].bar_size - off; |
|
|
|
// these are required for io maps, but is it okay for the buffer as well?
|
|
|
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
|
|
|
vma->vm_flags |= VM_IO; |
|
|
|
if ( vsize < intvsize ) |
|
|
|
intvsize = vsize; |
|
|
|
remap_pfn_range(vma, vma->vm_start, physical>>PAGE_SHIFT, intvsize, vma->vm_page_prot); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static int usd_mmap(struct file *filp, struct vm_area_struct *vma) |
|
|
|
static int usd_mmap_1(struct file *filp, struct vm_area_struct *vma) |
|
|
|
{ |
|
|
|
PRINT_ALERT("MMAP"); |
|
|
|
|
|
|
|
unsigned long off = vma->vm_pgoff << PAGE_SHIFT; |
|
|
|
unsigned long vsize = vma->vm_end - vma->vm_start; |
|
|
|
|
|
|
|
unsigned long physical = bars[1].bar_addr + off; |
|
|
|
|
|
|
|
unsigned int intvsize = bars[1].bar_size - off; |
|
|
|
// these are required for io maps, but is it okay for the buffer as well?
|
|
|
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
|
|
|
vma->vm_flags |= VM_IO; |
|
|
|
if ( vsize < intvsize ) |
|
|
|
intvsize = vsize; |
|
|
|
remap_pfn_range(vma, vma->vm_start, physical>>PAGE_SHIFT, intvsize, vma->vm_page_prot); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/*************************************************************************************************/ |
|
|
|
static unsigned int usd_poll (struct file *filp, poll_table *wait) |
|
|
|
static int usd_mmap_2(struct file *filp, struct vm_area_struct *vma) |
|
|
|
{ |
|
|
|
PRINT_ALERT("MMAP"); |
|
|
|
|
|
|
|
unsigned long off = vma->vm_pgoff << PAGE_SHIFT; |
|
|
|
unsigned long vsize = vma->vm_end - vma->vm_start; |
|
|
|
|
|
|
|
unsigned long physical = bars[2].bar_addr + off; |
|
|
|
|
|
|
|
unsigned int intvsize = bars[2].bar_size - off; |
|
|
|
// these are required for io maps, but is it okay for the buffer as well?
|
|
|
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
|
|
|
vma->vm_flags |= VM_IO; |
|
|
|
if ( vsize < intvsize ) |
|
|
|
intvsize = vsize; |
|
|
|
remap_pfn_range(vma, vma->vm_start, physical>>PAGE_SHIFT, intvsize, vma->vm_page_prot); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -184,6 +264,7 @@ static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *i |
|
|
|
goto probe_fail_enable; |
|
|
|
} |
|
|
|
|
|
|
|
/***************BAR 0***********************/ |
|
|
|
if(!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) |
|
|
|
{ |
|
|
|
printk(KERN_ERR "USDriver PCIe driver incorrect BAR configuration\n" ); |
|
|
@ -191,7 +272,7 @@ static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *i |
|
|
|
goto probe_fail; |
|
|
|
} |
|
|
|
|
|
|
|
bar0_addr = pci_resource_start(dev, 0); |
|
|
|
bars[0].bar_addr = pci_resource_start(dev, 0); |
|
|
|
rc = pci_request_region(dev, 0, "bar0"); |
|
|
|
if(rc) |
|
|
|
{ |
|
|
@ -199,8 +280,8 @@ static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *i |
|
|
|
goto probe_fail; |
|
|
|
} |
|
|
|
|
|
|
|
bar0_ptr = pci_iomap(dev, 0, bar0_size); |
|
|
|
u32* bar0_data = (u32*)bar0_ptr; |
|
|
|
bars[0].bar_ptr = pci_iomap(dev, 0, bars[0].bar_size); |
|
|
|
u32* bar0_data = (u32*)bars[0].bar_ptr; |
|
|
|
|
|
|
|
if(bar0_data == 0) |
|
|
|
{ |
|
|
@ -216,7 +297,7 @@ static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *i |
|
|
|
goto probe_fail; |
|
|
|
} |
|
|
|
|
|
|
|
bar1_addr = pci_resource_start(dev, 1); |
|
|
|
bars[1].bar_addr = pci_resource_start(dev, 1); |
|
|
|
rc = pci_request_region(dev, 1, "bar1"); |
|
|
|
if(rc) |
|
|
|
{ |
|
|
@ -224,8 +305,8 @@ static int __init pcie_probe (struct pci_dev *dev, const struct pci_device_id *i |
|
|
|
goto probe_fail; |
|
|
|
} |
|
|
|
|
|
|
|
bar1_ptr = pci_iomap(dev, 1, bar1_size); |
|
|
|
u32* bar1_data = (u32*)bar1_ptr; |
|
|
|
bars[1].bar_ptr = pci_iomap(dev, 1, bars[1].bar_size); |
|
|
|
u32* bar1_data = (u32*)bars[1].bar_ptr; |
|
|
|
|
|
|
|
if(bar1_data == 0) |
|
|
|
{ |
|
|
@ -257,21 +338,11 @@ 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); |
|
|
|
PRINT_ALERT("Freed DMA pages"); |
|
|
|
|
|
|
|
pci_clear_master(dev); |
|
|
|
PRINT_ALERT("Cleared PCIe master"); |
|
|
|
|
|
|
|
pci_iounmap(dev, bar0_ptr); |
|
|
|
pci_iounmap(dev, bar1_ptr); |
|
|
|
pci_iounmap(dev, bars[0].bar_ptr); |
|
|
|
pci_iounmap(dev, bars[1].bar_ptr); |
|
|
|
PRINT_ALERT("IOunmap"); |
|
|
|
|
|
|
|
pci_release_regions(dev); |
|
|
@ -289,17 +360,13 @@ static void __exit pcie_exit(void) |
|
|
|
PRINT_ALERT("driver unregistering"); |
|
|
|
pci_unregister_driver(&pci_driver); |
|
|
|
|
|
|
|
PRINT_ALERT("unregister_chrdev_region"); |
|
|
|
unregister_chrdev_region(chrdev, 1); |
|
|
|
|
|
|
|
PRINT_ALERT("cdev_del"); |
|
|
|
cdev_del(&cdev); |
|
|
|
|
|
|
|
PRINT_ALERT("device_destroy"); |
|
|
|
device_destroy(class, chrdev); |
|
|
|
|
|
|
|
PRINT_ALERT("class_destroy"); |
|
|
|
class_destroy(class); |
|
|
|
char name[16]; |
|
|
|
int i = 0; |
|
|
|
for( ; i < TOTAL_BAR_NUM; i++) |
|
|
|
{ |
|
|
|
snprintf(name, 8, "%s%d", DEV_NAME, i); |
|
|
|
remove_proc_entry(name, NULL); |
|
|
|
} |
|
|
|
|
|
|
|
PRINT_ALERT("driver unloaded"); |
|
|
|
} |
|
|
|