在GITHUB上搜PCIE驱动找到这个最简单的,也可以编译过的。
https://github.com/ahmedshakill/PCIeDriver
下载下来直接make就可以编译过。
里面只有一个C文件和一个makefile。我分别贴出来:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
// These have to match a physical device attached to a PCIe slot
#define PCITTL32IO_VENDOR_ID 0x8086
#define PCITTL32IO_DEVICE_ID 0x09ab
/* Meta Information */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shakil Ahmed");
MODULE_DESCRIPTION("A PCIe LKM");
static struct pci_device_id pcittl32io_ids[]={
{PCI_DEVICE(PCITTL32IO_VENDOR_ID, PCITTL32IO_DEVICE_ID)},
{ }
};
MODULE_DEVICE_TABLE(pci, pcittl32io_ids);
/* @brief This function is called, when a pci device is registered into the kernel
*
*@param dev
*@param id
*@return
*/
static int pcittl32io_probe(struct pci_dev *dev, const struct pci_device_id *id){
printk("pcittl32io - Now in the probe function");
return 0;
}
/* @brief This function is called, when a pci device is unregistered from the kernel
*
*@param dev
*/
static void pcittl32io_remove(struct pci_dev *dev){
printk("pcittl32io - Now in the remove function");
}
/*PCI driver struct*/
static struct pci_driver pcittl32io_driver = {
.name = "pcittl32io",
.id_table = pcittl32io_ids,
.probe = pcittl32io_probe,
.remove = pcittl32io_remove
};
/*This function is called when the module is loaded into the kernel*/
static int __init my_init(void){
printk("pcittl32io - Registering the PCI device \n");
return pci_register_driver(&pcittl32io_driver);
}
/*This function is called when the module is removed from the kernel*/
static void __exit my_exit(void){
printk("pcittl32io - Unregistering the PCI device \n");
pci_unregister_driver(&pcittl32io_driver);
}
module_init(my_init);
module_exit(my_exit);
obj-m += mymodule.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
使用insmod后也可以看到正常加载:
可以基于这个驱动做些练习
以下代码加入了对BAR0和BAR1的映射:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/device.h>
#include <linux/time.h>
#include <linux/pps_kernel.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
// These have to match a physical device attached to a PCIe slot
#define PCITTL32IO_VENDOR_ID 0x10EE
#define PCITTL32IO_DEVICE_ID 0x7012
#define DRV_NAME "pcittl32io"
#define PFX DRV_NAME ": "
#ifndef PCI_EXP_DEVCTL_READRQ_4096B
#define PCI_EXP_DEVCTL_READRQ_4096B 0x5000
/* Meta Information */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shakil Ahmed");
MODULE_DESCRIPTION("A PCIe LKM");
static struct pci_device_id pcittl32io_ids[]={
{PCI_DEVICE(PCITTL32IO_VENDOR_ID, PCITTL32IO_DEVICE_ID)},
{ }
};
/*
static struct pci_device_id xtrx_pci_table[] = {
{ PCI_DEVICE(0x10EE, 0xFAE3),
.driver_data = 0 },
{ PCI_DEVICE(0x10EE, 0x7011),
.driver_data = 1 },
{ PCI_DEVICE(0x10EE, 0x7012),
.driver_data = 2 },
{ 0, }
};
*/
MODULE_DEVICE_TABLE(pci, pcittl32io_ids);
/* @brief This function is called, when a pci device is registered into the kernel
*
*@param dev
*@param id
*@return
*/
#endif
#define BAR0_WR(a,o,v ) iowrite32(cpu_to_be32(v), (void __iomem *)((unsigned long)a + 4*o))
#define BAR0_RD(a,o) be32_to_cpu(ioread32((void __iomem *)((unsigned long)a + 4*o)))
void __iomem* bar0_addr;
void __iomem* bar1_addr;
static int pcittl32io_probe(struct pci_dev *pdev, const struct pci_device_id *id){
printk("pcittl32io - Now in the probe function");
int err ;
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Cannot enable PCI device, "
"aborting.\n");
return err;
}
printk(KERN_INFO PFX "liwei: pcittl32io_probe [%d] \n", __LINE__ );
/* Reconfigure MaxReadReq to 4KB */
pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_4096B);
pci_set_master(pdev);
if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
dev_err(&pdev->dev,"No suitable consistent DMA available.\n");
goto err_disable_pdev;
}
/*
* Check for BARs. We expect 0: 4KB
*/
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
pci_resource_len(pdev, 0) < 1 << 10) {
dev_err(&pdev->dev, "Missing UL BAR, aborting.\n");
err = -ENODEV;
goto err_disable_pdev;
} //获取bar0
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
dev_err(&pdev->dev, "Cannot obtain PCI resources, "
"aborting.\n");
goto err_disable_pdev;
}//开始获取资源
bar0_addr = pci_iomap(pdev, 0, 1 << 12);
if (!bar0_addr) {
dev_err(&pdev->dev, "Failed to map BAR 0.\n");
goto err_free_res;
}
bar1_addr = pci_iomap(pdev, 1, 1 << 16);
if (!bar0_addr) {
dev_err(&pdev->dev, "Failed to map BAR 1.\n");
goto err_unmap0;
}
int i , r ;
///for(i=0;i<100;++i) BAR0_WR( bar0_addr , i , i ) ;
for(i=0;i<16;++i) {
BAR0_WR( bar0_addr , i , i ) ;
r = BAR0_RD( bar0_addr , i ) ; // BAR0_WR( bar0_addr , i , i ) ;
printk(KERN_INFO PFX "read%d = %08d \n" , i , r );
}
printk(KERN_INFO PFX "liwei: bar0 bar1 now ready [%d] \n", __LINE__ );
return 0 ;
err_unmap1:
pci_iounmap(pdev, bar1_addr);
err_unmap0:
pci_iounmap(pdev, bar0_addr);
err_free_res:
pci_release_regions(pdev);
err_disable_pdev:
pci_clear_master(pdev); /* Nobody seems to do this */
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
return err;
}
/* @brief This function is called, when a pci device is unregistered from the kernel
*
*@param dev
*/
static void pcittl32io_remove(struct pci_dev *pdev){
printk("pcittl32io - Now in the remove function");
// struct xtrx_dev* xtrxdev = pci_get_drvdata(pdev);
printk(KERN_INFO PFX "liwei: pcittl32io_remove [%d] \n", __LINE__ );
/printk(KERN_INFO PFX "Removing device %s\n", pci_name(pdev));
/* Disable interrupts */
//xtrx_writel(xtrxdev, GP_PORT_WR_INT_PCIE, (1U << INT_PCIE_I_FLAG));
/* Clear pending interrupts */
//xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS);
//cdev_del(&xtrxdev->cdev);
//device_destroy(xtrx_class, MKDEV(MAJOR(dev_first), MINOR(xtrxdev->devno)));
//err_unmap1:
pci_iounmap(pdev, bar1_addr);
//err_unmap0:
pci_iounmap(pdev, bar0_addr);
//err_free_res:
pci_release_regions(pdev);
//err_disable_pdev:
pci_clear_master(pdev); /* Nobody seems to do this */
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
/*PCI driver struct*/
static struct pci_driver pcittl32io_driver = {
.name = "pcittl32io",
.id_table = pcittl32io_ids,
.probe = pcittl32io_probe,
.remove = pcittl32io_remove
};
/*This function is called when the module is loaded into the kernel*/
static int __init my_init(void){
printk("pcittl32io - Registering the PCI device \n");
return pci_register_driver(&pcittl32io_driver);
}
/*This function is called when the module is removed from the kernel*/
static void __exit my_exit(void){
printk("pcittl32io - Unregistering the PCI device \n");
pci_unregister_driver(&pcittl32io_driver);
}
module_init(my_init);
module_exit(my_exit);
vivado 项目以及linux驱动打包文件如下:
链接:https://pan.baidu.com/s/1zpBpLLttvSIBMPxnCmAgAQ
提取码:1asm
vivado版本是2019.1 在XC7A35T的XTRX硬件上运行通过。