PCIE開發(fā)流程_第1頁
PCIE開發(fā)流程_第2頁
PCIE開發(fā)流程_第3頁
PCIE開發(fā)流程_第4頁
PCIE開發(fā)流程_第5頁
已閱讀5頁,還剩12頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、PCIE開發(fā)流程前言:對于USB、PCIE設備這種掛接在總線上的設備而言,USB、PCI只是它們的”工作單位”,它們需要向”工作單位”注冊(使用usb_driver,pci_driver),并接收”工作單位”的管理(被調入probe()、調出disconnect/remove()、放假suspend()/shutdown()、繼續(xù)上班resume()等),但設備本身可能是一個工程師、一個前臺或者一個經理,因此做好工程師,前臺或者經理是其主題工作,這部分對應于字符設備驅動,tty設備驅動,網絡設備驅動等。第一節(jié) 整體構成整個驅動程序的開發(fā)應該包括三個大的部分1.1 驅動模塊的加載與卸載xxx_i

2、nit_module()注冊pci_driver設備。xxx_cleanup_module()注銷pci_driver設備。1.2 pci_driver成員函數的初始化xxx_probe()完成PCI設備初始化,注冊字符設備xxx_remove()完成PCI設備釋放,注銷字符設備1.3 字符設備file_operations成員函數用于實現上層應用程序對下層驅動程序調用時的調用函數。xxx_open()xxx_release()xxx_ioctl()xxx_read()xxx_write()第二節(jié) PCIE設備實現細節(jié)由于PCIE設備的驅動的開發(fā)都是按照一個統(tǒng)一規(guī)范的框架進行的。因此以一個字符

3、設備為例說明這個框架的實現機制。在所有PCIE驅動開發(fā)的過程中2.1 驅動程序的初始化和注銷涉及的函數為module_init(xxx_init_module),并在init中完成的功能為注冊PCIE設備,具體函數內容如下所示:注銷涉及的函數為module_exit(xxx_cleanup_module)在exit中完成的功能為注銷PCIE設備,具體函數內容如下所示:2.2 PCIE設備的注冊在模塊的初始化過程中,首先是注冊PCIE設備,使用函數為pci_register_driver(&xxx_pci_driver),輸入變量指明了PCIE結構體,如下所示:#define XXX_M

4、ODULE_NAME "xxx_audio"static struct pci_driver xxx_pci_driver = .name= XXX_MODULE_NAME,.id_table= xxx_pci_tbl,.probe= xxx_probe,.remove= _devexit_p(xxx_remove),#ifdef CONFIG_PM.suspend= xxx_pm_suspend,.resume= xxx_pm_resume,#endif /* CONFIG_PM */;結構體中name指明PCIE模塊的名稱,id_table指明了PCIE的設備驅動號也就

5、是為哪個設備進行驅動等。其中probe函數完成PCI設備的初始化以及其設備本身身份(字符,TTY,網絡等)的驅動注冊。也是驅動注冊中最重要的函數。probe函數講解1、 首先使能pci設備,pci_enable_device(pci_dev),該函數主要作用是調用底層代碼初始化PCI配置空間命令寄存器的I/O位和memory位。2、 設置成總線主DMA模式,pci_set_dma_mask(pci_dev, XXX_DMA_MASK)用于實現對dma設備的設置。3、 讀取PCI的配置信息,使用的函數是pci_resource_start (pci_dev, 1)獲取設備的內存基地址和所有BAR

6、的長度,4、調用ioremap完成配置信息的映射,可以配置PCI定義的寄存器BAR設置的空間用于映射DMA的寄存器。4、 申請I/O資源,request_region(card->ac97base, 256, card_namespci_id->driver_data)5、 注冊字符/網絡設備涉及到的函數為cdev_init(xxx_cdev,&xxx_fops);/*注冊驅動*/register_chrdev_region(xxx_dev_no,1,XXX);/*申請設備號*/cdev_add(xxx_cdev);/*添加字符設備*/request_irq(card-&g

7、t;irq, &xxx_interrupt, SA_SHIRQ, card_namespci_id->driver_data, card)/*申請中斷以及注冊中斷處理程序*/remove函數講解1、 釋放I/O資源 pci_release_regions(pdev)2、 禁止PCI設備 pci_disable_device(pdev)釋放占用的設備號register_chrdev_region(xxx_dev_no,1,XXX);3、 注銷字符設備cdev_del(&xxx_dev.cdev)。2.3 設備的file_operations操作在probe中需要注冊字符設備

8、,實現應用程序對PCIE設備的調用,例如打開,讀取,控制等。這些功能都是通過file_operations操作接口實現。例如用戶使用該設備完成讀取操作,那么用戶的過程為open(),read()。而用戶調用的這些函數對于linux來說這些調用都會變成系統(tǒng)調用,并指向改設備對應的open(),read()函數,對于該設備來說,指向了xxx_open和xxx_read。static struct file_operations xxx_fops = .owner= THIS_MODULE,.llseek= no_llseek,.read= sgma_read,.write= xxx_write,.

9、poll= xxx_poll,.ioctl= xxx_ioctl,.mmap= xxx_mmap,.open= xxx_open,.release= xxx_release,;接下來,需要實現上面的這些操作,然后就能實現用戶對設備的調用。static int i810_open(struct inode *inode, struct file *file)2.4 其他說明a)、中斷在PCIE中可以使用request_irq共享中斷或者pci_enable_msi消息告知申請中斷,不同之處在于前者在掃描PCI的時候自動為設備分配好中斷號,這樣存在多個設備共享中斷號的情況。MSI中斷是在調用初始化

10、函數pci_enable_msi()才分配中斷號,可以保證設備的中斷號不會與其他設備共用,從而避免了中斷共享能夠提高整體性能,但是MSI中斷的使用需要Linux操作系統(tǒng)特殊的支持,不具有普遍的適用性。傳統(tǒng)的中斷,由于資源號是有限的,常常涉及到多個設備共享同一個中斷號,在中斷的處理過程中要依次調用每個中斷處理函數來判斷中斷是不是目標設備發(fā)出,這會消耗系統(tǒng)性能。第三節(jié) 示例程序#include "card.h"#include <linux/time.h>#include <linux/spinlock.h>#define DMA_MASK 0xffff

11、ffff#define test_dri_major 249 / 主設備號/#define INT_ASSERT_W 0x02 / DMA Write Complete/#define INT_ASSERT_R 0x10 / DMA Read Complete/* PCI 驅動基本框架 ,為下面的設備進行驅動*/static struct pci_device_id card_ids = PCI_DEVICE(PCI_VENDOR_ID_XILINX,PCI_DEVICE_ID_EP_PIPE), 0,;MODULE_DEVICE_TABLE(pci,card_ids);/*probe和rem

12、ove基本函數*/static int card_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);static void card_remove(struct pci_dev *pdev);/*pci_driver 結構體*/static struct pci_driver card_driver = .name = DEV_NAME, .id_table = card_ids, .probe = card_probe, .remove = card_remove,;static int _init card_ini

13、t(void) int result; result = pci_register_driver(&card_driver); return result;static void _exit card_exit(void) pci_unregister_driver(&card_driver);module_init(card_init);module_exit(card_exit);/* PCI 驅動基本框架 */* 特定設備私有數據結構 */struct card_private struct pci_dev* pci_dev; void* pci_bar0; /wait_

14、queue_head_t * dma_write_wait; /wait_queue_head_t * dma_read_wait;/* 特定設備私有數據結構 */static struct card_private *adapter;/static DECLARE_WAIT_QUEUE_HEAD(dma_write_wait);/static int flag = 1;/ 將文件操作與分配的設備號相連static const struct file_operations card_fops = .owner = THIS_MODULE, /.ioctl = card_ioctl, .open

15、 = card_open, .release= card_release, .read = card_read, .write = card_write,;static int card_probe(struct pci_dev *pdev, const struct pci_device_id *id) unsigned long phymem; void _iomem *mem; u_int8_t csz; u32 val; int result;/*配置PCI設備*/ if (pci_enable_device(pdev) return -EIO; /* XXX 32-bit addre

16、ssing only */ if (pci_set_dma_mask(pdev, 0xffffffff) printk(KERN_ERR "ath_pci: 32-bit DMA not availablen"); goto bad; /pci_write_config_word(pdev, 0x04, 0x0007); /*配置PCI寄存器,首先調用pci_read_config_byte進行讀取PCI配置空間,并將值返回給csz * Cache line size is used to size and align various * structures used t

17、o communicate with the hardware. */ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); if (csz = 0) /* * Linux 2.4.18 (at least) writes the cache line size * register as a 16-bit wide register which is wrong. * We must have this setup properly for rx buffer * DMA to work so force a reasonabl

18、e value here if it * comes up zero. */ csz = L1_CACHE_BYTES / sizeof(u_int32_t); pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); /* * The default setting of latency timer yields poor results, * set it to the value used by other systems. It may be worth * tweaking this setting more. *配置PCI配置空間

19、 */ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);/*設置成總線主模式*/ pci_set_master(pdev); /*讀取寄存器信息 * Disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state. * * Code taken from ipw2100 driver - jg */ pci_read_config_dword(pdev, 0x40, &val); if (v

20、al & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); / 獲得BAR0空間的基地址,該地址為存儲器域的物理地址; phymem = pci_resource_start(pdev, 0); if (!request_mem_region(phymem, pci_resource_len(pdev, 0), DEV_NAME) printk(KERN_ERR "card_driver: cannot reserve PCI memory regionn"); g

21、oto bad; / 將存儲器域的物理地址映射為虛擬地址; mem = ioremap(phymem, pci_resource_len(pdev, 0); if (!mem) printk(KERN_ERR "card_driver: cannot remap PCI memory regionn") ; goto bad1; adapter = kmalloc(sizeof(struct card_private), GFP_KERNEL); if (unlikely(!adapter) return -ENOMEM; adapter -> pci_dev = p

22、dev; adapter -> pci_bar0 = mem; / 注冊設備驅動程序 result = register_chrdev(test_dri_major, DEV_NAME, &card_fops); if (unlikely(result) printk(KERN_ERR "card_driver: no memory for device staten"); goto bad2; /* /init_waitqueue_head(adapter->dma_write_wait); /init_waitqueue_head(adapter-&

23、gt;dma_read_wait); result = pci_enable_msi(pdev); if (unlikely(result) /PDEBUG("cannot enable msi . n"); goto bad3; result = request_irq(pdev -> irq, card_interrupt, 0, DEV_NAME, NULL); if (unlikely(result) /PDEBUG("request interrupt failed . n"); goto bad3; printk(KERN_DEBUG

24、"request_irq(pdev -> irq, card_interrupt, 0, DEV_NAME, NULL);"); */ return 0;/bad3:/ unregister_chrdev(test_dri_major, DEV_NAME); bad2: iounmap(mem);bad1: release_mem_region(phymem, pci_resource_len(pdev, 0);bad: pci_disable_device(pdev); return (-ENODEV);static void card_remove(struct

25、pci_dev *pdev) /pci_disable_msi(pdev); /if(pdev->irq) / free_irq(pdev->irq, pdev); iounmap(adapter -> pci_bar0); release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0); pci_disable_device(pdev); unregister_chrdev(test_dri_major, DEV_NAME);/打開設備文件系統(tǒng)調用對應的操作static int card_o

26、pen(struct inode *inode, struct file *filp) return 0;/關閉設備文件系統(tǒng)調用對應的操作static int card_release(struct inode *inode, struct file *filp) return 0;/讀取設備信息static ssize_t card_read(struct file *file, char _user *buf, size_t count, loff_t *f_pos) void* virt_addr = NULL; dma_addr_t dma_write_addr; u32 base,

27、w_ddr2, w_addr,w_size,cst_32,w_counter,dma_cst; u32 ddr2; int i; i = 0;/*讀取寄存器的值,0x10的位置也就是BAR的初始地址*/ pci_read_config_dword(adapter->pci_dev, 0x10, &base); printk(KERN_DEBUG " pci_read_config_dword, base:%xn",base); printk(KERN_DEBUG "adater -> pci_bar0 %lxn",(unsigned

28、long)(adapter -> pci_bar0); /*Request virt_addr(kernel) for Read(DMA write)*/ virt_addr = kmalloc(count, GFP_KERNEL|_GFP_DMA); if(unlikely(!virt_addr) /PDEBUG("cannot alloc rx memory you want . n"); return -EIO; printk(KERN_DEBUG " virt_addr(kernel):%xn",(u32)virt_addr); /*Req

29、uest virt_addr(kernel) for Read(DMA write)*/ /*dma_write_addr*/ /將存儲器域的虛擬地址virt_addr轉化為pci總線域的物理地址dma_write_addr,供card的DMA控制器使用。 dma_write_addr = pci_map_single(adapter->pci_dev, virt_addr, count, PCI_DMA_FROMDEVICE); if(unlikely(pci_dma_mapping_error(adapter->pci_dev, dma_write_addr) /PDEBUG(

30、"RX DMA MAPPING FAIL.n"); goto err_kmalloc; printk(KERN_DEBUG " dma_write_addr:%xn",dma_write_addr); /*dma_write_addr*/ /*BAR0 kong jian */ / START, w_counter讀取BAR0空間 w_counter = ioread32(adapter -> pci_bar0+WRITE_DMA_COUNTER_OFFSET); printk(KERN_DEBUG " START, w_counter:

31、 %x",w_counter); / w_ddr2 DMA寫的原地址 iowrite32(*f_pos,(adapter -> pci_bar0 + WRITE_DDR2_SA_OFFSET); ddr2 = ioread32(adapter -> pci_bar0 + WRITE_DDR2_SA_OFFSET); printk(KERN_DEBUG " WRITE_DDR2_SA_OFFSET: %x",ddr2); / w_addr / Lower 32-bit address of system memory buffer for DMA wri

32、te operation. iowrite32(dma_write_addr,(adapter -> pci_bar0 + WRITE_HOST_DA_L_OFFSET); / w_size / Write DMA TLP Size Register(from DDR2 to mm). iowrite32(count,(adapter -> pci_bar0 + WRITE_SIZE_OFFSET); / Write DMA Control && Status Register dma_cst = 0; dma_cst = ioread32(adapter ->

33、; pci_bar0 + DMA_CST_OFFSET); printk(KERN_DEBUG "dma_cst1: %x",dma_cst); dma_cst = dma_cst | 0x1; printk(KERN_DEBUG "dma_cst2: %x",dma_cst); / dma_cst /writel(dma_cst,(void _iomem *) (unsigned long) (adapter -> pci_bar0 + DMA_CST_OFFSET); iowrite32(dma_cst,(adapter -> pci_b

34、ar0 + DMA_CST_OFFSET); dma_cst = ioread32(adapter -> pci_bar0+DMA_CST_OFFSET); printk(KERN_DEBUG "dma_cst3: %x",dma_cst); while( (!(dma_cst & 0x2)&&(i<1000) ) dma_cst = ioread8(adapter -> pci_bar0 + DMA_CST_OFFSET); i+; printk(KERN_DEBUG "#"); i = 0; dma_cst

35、= dma_cst | 0x2; iowrite32(dma_cst,(adapter -> pci_bar0 + DMA_CST_OFFSET); dma_cst = ioread8(adapter -> pci_bar0 + DMA_CST_OFFSET); printk(KERN_DEBUG "dma_cst4: %x",dma_cst); /interruptible_sleep_on(adapter->dma_write_wait); /wait_event_interruptible(dma_write_wait,flag); /flag =

36、0; /test (w_ddr2, w_addr,w_size,cst_32,w_counter) w_ddr2 = ioread32(adapter -> pci_bar0 + WRITE_DDR2_SA_OFFSET); w_addr = ioread32(adapter -> pci_bar0 + WRITE_HOST_DA_L_OFFSET); w_size = ioread32(adapter -> pci_bar0 + WRITE_SIZE_OFFSET); cst_32 = ioread32(adapter -> pci_bar0 + DMA_CST_OF

37、FSET); printk(KERN_DEBUG "w_ddr2: %x; w_addr: %x; w_size: %u; w_cst:%x n",w_ddr2,w_addr,w_size,cst_32); /END, w_counter w_counter = ioread32(adapter -> pci_bar0+WRITE_DMA_COUNTER_OFFSET); printk(KERN_DEBUG "END, w_counter: %xn",w_counter); /*BAR0 kong jian */ /*copy_to_user*/

38、if(unlikely(copy_to_user(buf,virt_addr,count) goto err_pci_map; /*copy_to_user*/ pci_unmap_single(adapter->pci_dev, dma_write_addr, count, PCI_DMA_FROMDEVICE); kfree(virt_addr); printk(KERN_DEBUG "Here I am: %s:%in",_FILE_,_LINE_); return count;err_pci_map: /wake_up_interruptible(&a

39、dapter->dma_write_wait); return -1;err_kmalloc: return -1;/*file_operation中的write函數。*/static ssize_t card_write(struct file *file, const char _user *buf, size_t count, loff_t *f_pos) /unsigned int dma_cst = 0; int err = -EINVAL; void * virt_addr = NULL; dma_addr_t dma_read_addr; u32 base, r_addr,

40、 r_ddr2, r_size, cst_32, r_counter,dma_cst; struct timeval tv1; struct timeval tv2; spinlock_t write_lock; int i; i = 0; /*BAR0*/ pci_read_config_dword(adapter->pci_dev, 0x10, &base); printk(KERN_DEBUG " pci_read_config_dword, base:%xn",base); printk(KERN_DEBUG "adater -> pc

41、i_bar0 %lxn",(unsigned long)(adapter -> pci_bar0); /*BAR0*/ /*Request virt_addr(kernel) for Write(DMA Read)*/ virt_addr = kmalloc(count, GFP_KERNEL|_GFP_DMA); if(unlikely(copy_from_user(virt_addr, buf, count) return err; printk(KERN_DEBUG " virt_addr(kernel):%xn",(u32)virt_addr); /

42、*Request virt_addr(kernel) for Write(DMA Read)*/ /*dma_read_addr*/ dma_read_addr = pci_map_single(adapter->pci_dev, virt_addr, count, PCI_DMA_TODEVICE); if(unlikely(pci_dma_mapping_error(adapter->pci_dev, dma_read_addr) /PDEBUG("RX DMA MAPPING FAIL.n"); goto err_kmalloc; printk(KERN_

43、DEBUG " dma_read_addr:%xn", dma_read_addr); /*dma_read_addr*/ spin_lock_init(&write_lock); /*BAR0 kong jian */ spin_lock(&write_lock); / START, r_counter r_counter = ioread32(adapter -> pci_bar0 + READ_DMA_COUNTER_OFFSET); printk(KERN_DEBUG " START, r_counter: %x",r_co

44、unter); / r_addr / Lower 32-bit address of system memory buffer for DMA READ operation. iowrite32(dma_read_addr, (adapter -> pci_bar0 + READ_HOST_SA_L_OFFSET); / r_ddr2 iowrite32(*f_pos,(adapter -> pci_bar0 + READ_DDR2_DA_OFFSET); / r_size / Read DMA TLP Size Register(from mm to DDR2). iowrite

45、32(count, (adapter -> pci_bar0 + READ_SIZE_OFFSET); / dma_cst / Read DMA Control and Status Register dma_cst = ioread8(adapter -> pci_bar0 + DMA_CST_OFFSET); printk(KERN_DEBUG "dma_cst1: %x",dma_cst); dma_cst = dma_cst | 0x4; iowrite8(dma_cst,(adapter -> pci_bar0 + DMA_CST_OFFSET)

46、; dma_cst = ioread8(adapter -> pci_bar0 + DMA_CST_OFFSET); printk(KERN_DEBUG "dma_cst2: %x",dma_cst); do_gettimeofday(&tv1); while( (!(dma_cst & 0x8) && (i < 1000) ) dma_cst = ioread8(adapter -> pci_bar0 + DMA_CST_OFFSET); i+; /printk(KERN_DEBUG "*%d n",i

47、); do_gettimeofday(&tv2); printk(KERN_DEBUG "time_time: %ld",(tv2.tv_usec-tv1.tv_usec); i = 0; dma_cst = ioread8(adapter -> pci_bar0 + DMA_CST_OFFSET); printk(KERN_DEBUG "dma_cst3: %x",dma_cst); dma_cst = dma_cst | 0x8; iowrite8(dma_cst,(adapter -> pci_bar0 + DMA_CST_OF

48、FSET); dma_cst = ioread8(adapter -> pci_bar0 + DMA_CST_OFFSET); printk(KERN_DEBUG "dma_cst4: %x",dma_cst); /adapter->dma_read_done = 0; /if(unlikely(interruptible_sleep_on(adapter->dma_read_wait) / goto err_pci_map; /interruptible_sleep_on(adapter->dma_read_wait); /test (r_addr

49、,r_ddr2,r_size,cst_32, r_counter) r_ddr2 = ioread32(adapter -> pci_bar0 + READ_DDR2_DA_OFFSET); r_addr = ioread32(adapter -> pci_bar0 + READ_HOST_SA_L_OFFSET); r_size = ioread32(adapter -> pci_bar0 + READ_SIZE_OFFSET); cst_32 = ioread32(adapter -> pci_bar0 + DMA_CST_OFFSET); printk(KERN_DEBUG "r_ddr2: %x; r_addr: %x; r_size: %u; r_cst:%x n",r_ddr2,r_addr,r_size,cst_32); /END, w_counter r_counter = ioread32(adapter -> pci_bar0 + READ_DMA_COUNTER_OFFSET); printk(KERN_DEBU

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論