在LC480T上部署xapp1052
实验环境:LC480T加速卡
开发环境:windows11+vivado2020
运行环境:ubuntu22.04
硬件电路:LC480T加速卡(xc7k480tffg1156-2)
vivado工程文件下载:https://download.csdn.net/download/xiaolangyangyang/91349686
驱动及应用代码下载:https://download.csdn.net/download/xiaolangyangyang/91349692
LC480T引脚说明下载:https://download.csdn.net/download/xiaolangyangyang/91350582
xapp1052_xbmd寄存器说明下载:https://download.csdn.net/download/xiaolangyangyang/91350584
一、说明
xilinx官网xapp1052例程是基于Kintex-7 KC705 Evaluation Platform (xc7k325tffg900-2)开发板,使用7 Series FPGAs Integrated Block for PCI Express ip核,如果直接将项目修改成device为xc7k480tffg1156-2生成bit文件过程会报错,所以重新构建工程,将官网xapp1052例程的xbmd文件夹拷贝到工程,修改顶层文件及约束文件,生成bit文件。
xilinx官网xapp1052例程软件基于Fedora-10操作系统,内核很旧,代码在ubuntu22.04上编译不过,所以考虑从新编写驱动及应用代码。
二、构建vivado项目并生成bin文件
打开工程,生成bit即可,约束文件如下:
##-----------------------------------------------------------------------------
##
## (c) Copyright 2010-2011 Xilinx, Inc. All rights reserved.
##
## This file contains confidential and proprietary information
## of Xilinx, Inc. and is protected under U.S. and
## international copyright and other intellectual property
## laws.
##
## DISCLAIMER
## This disclaimer is not a license and does not grant any
## rights to the materials distributed herewith. Except as
## otherwise provided in a valid license issued to you by
## Xilinx, and to the maximum extent permitted by applicable
## law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
## WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
## AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
## BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
## INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
## (2) Xilinx shall not be liable (whether in contract or tort,
## including negligence, or under any other theory of
## liability) for any loss or damage of any kind or nature
## related to, arising under or in connection with these
## materials, including for any direct, or any indirect,
## special, incidental, or consequential loss or damage
## (including loss of data, profits, goodwill, or any type of
## loss or damage suffered as a result of any action brought
## by a third party) even if such damage or loss was
## reasonably foreseeable or Xilinx had been advised of the
## possibility of the same.
##
## CRITICAL APPLICATIONS
## Xilinx products are not designed or intended to be fail-
## safe, or for use in any application requiring fail-safe
## performance, such as life-support or safety devices or
## systems, Class III medical devices, nuclear facilities,
## applications related to the deployment of airbags, or any
## other applications that could lead to death, personal
## injury, or severe property or environmental damage
## (individually and collectively, "Critical
## Applications"). Customer assumes the sole risk and
## liability of any use of Xilinx products in Critical
## Applications, subject only to applicable laws and
## regulations governing limitations on product liability.
##
## THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
## PART OF THIS FILE AT ALL TIMES.
##
##-----------------------------------------------------------------------------
## Project : Series-7 Integrated Block for PCI Express
## File : xilinx_pcie_7x_ep_x8g2.xdc
## Version : 3.3
#
###############################################################################
# User Configuration
# Link Width - x8
# Link Speed - gen2
# Family - kintex7
# Part - xc7k480t
# Package - ffg1156
# Speed grade - -2
# PCIe Block - X0Y0
###############################################################################
#
###############################################################################
# User Time Names / User Time Groups / Time Specs
##############################################################################################################################################################
# User Physical Constraints
##############################################################################################################################################################
# Pinout and Related I/O Constraints
################################################################################
# SYS reset (input) signal. The sys_reset_n signal should be
# obtained from the PCI Express interface if possible. For
# slot based form factors, a system reset signal is usually
# present on the connector. For cable based form factors, a
# system reset signal may not be available. In this case, the
# system reset signal must be generated locally by some form of
# supervisory circuit. You may change the IOSTANDARD and LOC
# to suit your requirements and VCCO voltage banking rules.
# Some 7 series devices do not have 3.3 V I/Os available.
# Therefore the appropriate level shift is required to operate
# with these devices that contain only 1.8 V banks.
#set_property PULLUP true [get_ports sys_rst_n]###############################################################################
# Physical Constraints
###############################################################################
#
# SYS clock 100 MHz (input) signal. The sys_clk_p and sys_clk_n
# signals are the PCI Express reference clock. Virtex-7 GT
# Transceiver architecture requires the use of a dedicated clock
# resources (FPGA input pins) associated with each GT Transceiver.
# To use these pins an IBUFDS primitive (refclk_ibuf) is
# instantiated in user's design.
# Please refer to the Virtex-7 GT Transceiver User Guide
# (UG) for guidelines regarding clock resource selection.
#set_property LOC IBUFDS_GTE2_X0Y9 [get_cells refclk_ibuf]###############################################################################
# Timing Constraints
###############################################################################
#
create_clock -name sys_clk -period 10 [get_ports sys_clk_p]
#
#
set_false_path -to [get_pins {pcie_7x_0_support_i/pipe_clock_i/pclk_i1_bufgctrl.pclk_i1/S0}]
set_false_path -to [get_pins {pcie_7x_0_support_i/pipe_clock_i/pclk_i1_bufgctrl.pclk_i1/S1}]
#
#
create_generated_clock -name clk_125mhz_x0y0 [get_pins pcie_7x_0_support_i/pipe_clock_i/mmcm_i/CLKOUT0]
create_generated_clock -name clk_250mhz_x0y0 [get_pins pcie_7x_0_support_i/pipe_clock_i/mmcm_i/CLKOUT1]
create_generated_clock -name clk_125mhz_mux_x0y0 \ -source [get_pins pcie_7x_0_support_i/pipe_clock_i/pclk_i1_bufgctrl.pclk_i1/I0] \-divide_by 1 \[get_pins pcie_7x_0_support_i/pipe_clock_i/pclk_i1_bufgctrl.pclk_i1/O]
#
create_generated_clock -name clk_250mhz_mux_x0y0 \ -source [get_pins pcie_7x_0_support_i/pipe_clock_i/pclk_i1_bufgctrl.pclk_i1/I1] \-divide_by 1 -add -master_clock [get_clocks -of [get_pins pcie_7x_0_support_i/pipe_clock_i/pclk_i1_bufgctrl.pclk_i1/I1]] \[get_pins pcie_7x_0_support_i/pipe_clock_i/pclk_i1_bufgctrl.pclk_i1/O]
#
set_clock_groups -name pcieclkmux -physically_exclusive -group clk_125mhz_mux_x0y0 -group clk_250mhz_mux_x0y0#
# Timing ignoring the below pins to avoid CDC analysis, but care has been taken in RTL to sync properly to other clock domain.
#
#
##############################################################################
# Tandem Configuration Constraints
###############################################################################set_false_path -from [get_ports sys_rst_n]set_property PACKAGE_PIN J8 [get_ports sys_clk_p]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst_n]
set_property PACKAGE_PIN Y26 [get_ports sys_rst_n]set_property LOC GTXE2_CHANNEL_X0Y23 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[0].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN F2 [get_ports {pci_exp_txp[0]}]
set_property LOC GTXE2_CHANNEL_X0Y22 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[1].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN H2 [get_ports {pci_exp_txp[1]}]
set_property LOC GTXE2_CHANNEL_X0Y21 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[2].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN K2 [get_ports {pci_exp_txp[2]}]
set_property LOC GTXE2_CHANNEL_X0Y20 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[3].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN M2 [get_ports {pci_exp_txp[3]}]
set_property LOC GTXE2_CHANNEL_X0Y19 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[4].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN N4 [get_ports {pci_exp_txp[4]}]
set_property LOC GTXE2_CHANNEL_X0Y18 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[5].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN P2 [get_ports {pci_exp_txp[5]}]
set_property LOC GTXE2_CHANNEL_X0Y17 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[6].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN T2 [get_ports {pci_exp_txp[6]}]
set_property LOC GTXE2_CHANNEL_X0Y16 [get_cells {pcie_7x_1_support_i/pcie_7x_1_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[7].gt_wrapper_i/gtx_channel.gtxe2_channel_i}]
set_property PACKAGE_PIN U4 [get_ports {pci_exp_txp[7]}]###############################################################################
# End
###############################################################################
三、代码列表
头文件:
//--------------------------------------------------------------------------------
//-- Filename: xbmd.h
//--
//-- Description: Main header file for kernel driver
//--
//-- XBMD is an example Red Hat device driver which exercises XBMD design
//-- Device driver has been tested on Red Hat Fedora FC9 2.6.15.
//--------------------------------------------------------------------------------
// Define Result values
#define SUCCESS 0
#define CRIT_ERR -1// Debug - define will output more info
#define Verbose 1// Max DMA Buffer Size
#define BUF_SIZE (4096 * 2)enum {INITCARD,INITRST,DISPREGS,RDDCSR,RDDDMACR,RDWDMATLPA,RDWDMATLPS,RDWDMATLPC,RDWDMATLPP,RDRDMATLPP,RDRDMATLPA,RDRDMATLPS,RDRDMATLPC,RDWDMAPERF,RDRDMAPERF,RDRDMASTAT,RDNRDCOMP,RDRCOMPDSIZE,RDDLWSTAT,RDDLTRSSTAT,RDDMISCCONT,RDDMISCONT,RDDLNKC,DFCCTL,DFCPINFO,DFCNPINFO,DFCINFO,WRDDMACR,WRWDMATLPS,WRWDMATLPC,WRWDMATLPP,WRRDMATLPS,WRRDMATLPC,WRRDMATLPP,WRDMISCCONT,WRDDLNKC,NUMCOMMANDS};
linux驱动代码:
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/device.h>#include "xbmd.h"#define CLASS_NAME "xbmd"
#define DEVICE_NAME "xbmd"static int major_number = 530;
static struct cdev *xbmd_cdev;
void __iomem *regs;
struct pci_dev *gDev = NULL;
static struct class *xbmd_class = NULL;
static struct device *xbmd_device = NULL;
char *gReadBuffer = NULL;
char *gWriteBuffer = NULL;
dma_addr_t gReadHWAddr;
dma_addr_t gWriteHWAddr;
int gIrq;static const struct pci_device_id xbmd_ids[] = {{ PCI_DEVICE(0x10ee, 0x7028) },{ 0, }
};dev_t devno = MKDEV(295, 0);MODULE_DEVICE_TABLE(pci, xbmd_ids);u32 XPCIe_ReadReg (u32 dw_offset)
{u32 ret = 0;ret = ioread32(regs + (4 * dw_offset));printk("XPCIe_ReadReg @0x%x = 0x%x", regs + (4 * dw_offset), ret);return ret;
}void XPCIe_WriteReg (u32 dw_offset, u32 val)
{printk("XPCIe_WriteReg @0x%x = 0x%x", regs + (4 * dw_offset), val);iowrite32(val, (regs + (4 * dw_offset)));
}u32 XPCIe_ReadCfgReg (u32 byte)
{u32 pciReg;if (pci_read_config_dword(gDev, byte, &pciReg) < 0) {printk("%s: XPCIe_ReadCfgReg: Reading PCI interface failed.", DEVICE_NAME);return (-1);}return (pciReg);
}u32 XPCIe_WriteCfgReg (u32 byte, u32 val)
{if (pci_write_config_dword(gDev, byte, val) < 0) {printk("%s: XPCIe_Read Device Control: Reading PCI interface failed.", DEVICE_NAME);return (-1);}return 1;
}void XPCIe_InitCard(void)
{XPCIe_WriteReg(0, 1); // Write: DCSR (offset 0) with value of 1 (Reset Device)XPCIe_WriteReg(0, 0); // Write: DCSR (offset 0) with value of 0 (Make Active)XPCIe_WriteReg(1, 0);XPCIe_WriteReg(2, gWriteHWAddr); // Write: Write DMA TLP Address register with starting addressXPCIe_WriteReg(3, 0x20); // Write: Write DMA TLP Size register with default value (32dwords)XPCIe_WriteReg(4, 0x2000); // Write: Write DMA TLP Count register with default value (2000)XPCIe_WriteReg(5, 0x00000000); // Write: Write DMA TLP Pattern register with default value (0x0)XPCIe_WriteReg(6, 0xfeedbeef); // Write: Read DMA Expected Data Pattern with default value (feedbeef)XPCIe_WriteReg(7, gReadHWAddr); // Write: Read DMA TLP Address register with starting address.XPCIe_WriteReg(8, 0x20); // Write: Read DMA TLP Size register with default value (32dwords)XPCIe_WriteReg(9, 0x2000); // Write: Read DMA TLP Count register with default value (2000)printk("XPCIe_InitCard ok");
}void XPCIe_InitiatorReset(void)
{XPCIe_WriteReg(0, 1); // Write: DCSR (offset 0) with value of 1 (Reset Device)XPCIe_WriteReg(0, 0); // Write: DCSR (offset 0) with value of 0 (Make Active)printk("XPCIe_InitiatorReset ok");
}static int xbmd_open(struct inode *inode, struct file *file)
{printk(KERN_INFO "Device opened\n");return 0;
}static int xbmd_release(struct inode *inode, struct file *file)
{printk(KERN_INFO "Device released\n");return 0;
}static ssize_t xbmd_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{copy_to_user(buffer, gWriteBuffer, length);printk(KERN_INFO "%s: XPCIe_Read: %d bytes have been read...\n", DEVICE_NAME, length);return 0;
}static ssize_t xbmd_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
{int ret = SUCCESS;copy_from_user(gReadBuffer, buffer, length);printk(KERN_INFO "%s: XPCIe_Write: %d bytes have been written...\n", DEVICE_NAME, length);return ret;
}long xbmd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{u32 regx;long ret = SUCCESS;switch (cmd) {case INITCARD: // Initailizes XBMD applicationXPCIe_InitCard();memset(gReadBuffer, 0x0, sizeof(gReadBuffer));memset(gWriteBuffer, 0x0, sizeof(gWriteBuffer));break;case INITRST: // Resets XBMD applicationsXPCIe_InitiatorReset();break;case DISPREGS:break;case RDDCSR: // Read: Device Control Status Registerregx = XPCIe_ReadReg(0);__put_user(regx, (int *)arg);break;case RDDDMACR: // Read: DMA Control Status Registerregx = XPCIe_ReadReg(1);__put_user(regx, (int *)arg);break;case RDWDMATLPA: // Read: Write DMA TLP Address Registerregx = XPCIe_ReadReg(2);__put_user(regx, (int *)arg);break;case RDWDMATLPS: // Read: Write DMA TLP Size Registerregx = XPCIe_ReadReg(3);__put_user(regx, (int *)arg);break;case RDWDMATLPC: // Read: Write DMA TLP Count Registerregx = XPCIe_ReadReg(4);__put_user(regx, (int *)arg);break;case RDWDMATLPP: // Read: Write DMA TLP Pattern Registerregx = XPCIe_ReadReg(5);__put_user(regx, (int *)arg);break;case RDRDMATLPP: // Read: Read DMA TLP Pattern Registerregx = XPCIe_ReadReg(6);__put_user(regx, (int *)arg);break;case RDRDMATLPA: // Read: Read DMA TLP Address Registerregx = XPCIe_ReadReg(7); __put_user(regx, (int *)arg);break;case RDRDMATLPS: // Read: Read DMA TLP Size Registerregx = XPCIe_ReadReg(8);__put_user(regx, (int *)arg);break;case RDRDMATLPC: // Read: Read DMA TLP Count Registerregx = XPCIe_ReadReg(9);__put_user(regx, (int *)arg);break;case RDWDMAPERF: // Read: Write DMA Performance Registerregx = XPCIe_ReadReg(10);__put_user(regx, (int *)arg);break;case RDRDMAPERF: // Read: Read DMA Performance Registerregx = XPCIe_ReadReg(11);__put_user(regx, (int *)arg);break;case RDRDMASTAT: // Read: Read DMA Status Registerregx = XPCIe_ReadReg(12);__put_user(regx, (int *)arg);break;case RDNRDCOMP: // Read: Number of Read Completion w/ Data Registerregx = XPCIe_ReadReg(13);__put_user(regx, (int *)arg);break;case RDRCOMPDSIZE: // Read: Read Completion Size Registerregx = XPCIe_ReadReg(14);__put_user(regx, (int *)arg);break;case RDDLWSTAT: // Read: Device Link Width Status Registerregx = XPCIe_ReadReg(15);__put_user(regx, (int *)arg);break;case RDDLTRSSTAT: // Read: Device Link Transaction Size Status Registerregx = XPCIe_ReadReg(16);__put_user(regx, (int *)arg);break;case RDDMISCCONT: // Read: Device Miscellaneous Control Registerregx = XPCIe_ReadReg(17);__put_user(regx, (int *)arg);break;case RDDMISCONT: // Read: Device MSI Controlregx = XPCIe_ReadReg(18);__put_user(regx, (int *)arg);break;case RDDLNKC: // Read: Device Directed Link Change Registerregx = XPCIe_ReadReg(19);__put_user(regx, (int *)arg);break;case DFCCTL: // Read: Device FC Control Registerregx = XPCIe_ReadReg(20);__put_user(regx, (int *)arg);break;case DFCPINFO: // Read: Device FC Posted Informationregx = XPCIe_ReadReg(21);__put_user(regx, (int *)arg);break;case DFCNPINFO: // Read: Device FC Non Posted Informationregx = XPCIe_ReadReg(22);__put_user(regx, (int *)arg);break;case DFCINFO: // Read: Device FC Completion Informationregx = XPCIe_ReadReg(23);__put_user(regx, (int *)arg);break;case WRDDMACR: // Write: DMA Control Status Register__get_user(regx, (int *)arg);XPCIe_WriteReg(1, regx);break;case WRWDMATLPS: // Write: Write DMA TLP Size Register__get_user(regx, (int *)arg);XPCIe_WriteReg(3, regx);break;case WRWDMATLPC: // Write: Write DMA TLP Count Register__get_user(regx, (int *)arg);XPCIe_WriteReg(4, regx);break;case WRWDMATLPP: // Write: Write DMA TLP Pattern Register__get_user(regx, (int *)arg);XPCIe_WriteReg(5, regx);break;case WRRDMATLPS: // Write: Read DMA TLP Size Register__get_user(regx, (int *)arg);XPCIe_WriteReg(8, regx);break;case WRRDMATLPC: // Write: Read DMA TLP Count Register__get_user(regx, (int *)arg);XPCIe_WriteReg(9, regx);break;case WRRDMATLPP: // Write: Read DMA TLP Pattern Register__get_user(regx, (int *)arg);XPCIe_WriteReg(6, regx);break;case WRDMISCCONT: // Write: Device Miscellaneous Control Register__get_user(regx, (int *)arg);XPCIe_WriteReg(18, regx);break;case WRDDLNKC: // Write: Device Directed Link Change Register__get_user(regx, (int *)arg);XPCIe_WriteReg(19, regx);break;default:break;}return ret;
}static struct file_operations xbmd_fops = {.owner = THIS_MODULE,.open = xbmd_open,.release = xbmd_release,.read = xbmd_read,.write = xbmd_write,.unlocked_ioctl = xbmd_ioctl,
};irqreturn_t XPCIe_IRQHandler(int irq, void *dev_id)
{u32 i, regx;printk(KERN_WARNING"%s: Interrupt Handler Start ..", DEVICE_NAME);for (i = 0; i < 32; i++) {regx = XPCIe_ReadReg(i);printk(KERN_WARNING"%s : REG<%d> : 0x%X\n", DEVICE_NAME, i, regx);}printk(KERN_WARNING"%s Interrupt Handler End ..\n", DEVICE_NAME);return IRQ_NONE;
}static int xbmd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{int ret;gDev = pdev;ret = pci_enable_device(pdev);if (ret) {printk(KERN_ERR "Failed to enable PCI device\n");return ret;}ret = pci_request_regions(pdev, "xbmd_driver");if (ret) {printk(KERN_ERR "Failed to request regions\n");goto err_disable;}regs = pci_ioremap_bar(pdev, 0); // BAR0if (!regs) {printk(KERN_ERR "Failed to map BAR0\n");ret = -ENOMEM;goto err_release;}//u32 value = ioread32(regs);//printk(KERN_INFO "Register @0x%x value: 0x%x\n", regs, value);gIrq = gDev->irq;printk(KERN_INFO"%s: Init: Device IRQ: %d\n",DEVICE_NAME, gIrq);printk(KERN_INFO"%s: ISR Setup..\n", DEVICE_NAME);if (0 > request_irq(gIrq, XPCIe_IRQHandler, IRQF_SHARED, DEVICE_NAME, gDev)) {printk(KERN_INFO"%s: Init: Unable to allocate IRQ",DEVICE_NAME);return (CRIT_ERR);}gReadBuffer = dma_alloc_coherent(&pdev->dev, BUF_SIZE, &gReadHWAddr, GFP_KERNEL);if (NULL == gReadBuffer) {printk(KERN_INFO"%s: Init: Unable to allocate gBuffer.\n", DEVICE_NAME);return (CRIT_ERR);}printk(KERN_INFO"%s: Read Buffer Allocation: %X->%X\n", DEVICE_NAME, (u32)gReadBuffer, (u32)gReadHWAddr);gWriteBuffer = dma_alloc_coherent(&pdev->dev, BUF_SIZE, &gWriteHWAddr, GFP_KERNEL);if (NULL == gWriteBuffer) {printk(KERN_INFO"%s: Init: Unable to allocate gBuffer.\n", DEVICE_NAME);return (CRIT_ERR);}printk(KERN_INFO"%s: Write Buffer Allocation: %X->%X\n", DEVICE_NAME, (u32)gWriteBuffer, (u32)gWriteHWAddr);XPCIe_InitCard();printk("xbmd_probe ok\n");return 0;err_release:pci_release_regions(pdev);
err_disable:pci_disable_device(pdev);return ret;
}static void xbmd_remove(struct pci_dev *pdev)
{free_irq(gIrq, gDev);pci_release_regions(pdev);pci_disable_device(pdev);dma_free_coherent(&gDev->dev, BUF_SIZE, gReadBuffer, gReadHWAddr);dma_free_coherent(&gDev->dev, BUF_SIZE, gWriteBuffer, gWriteHWAddr);if (NULL != gReadBuffer)(void) kfree(gReadBuffer);if (NULL != gWriteBuffer)(void) kfree(gWriteBuffer);gReadBuffer = NULL;gWriteBuffer = NULL;if (regs) {printk("Iounmap\n");iounmap(regs);}printk("xbmd_remove ok\n");
}static struct pci_driver xbmd_driver = {.name = "xbmd_driver",.id_table = xbmd_ids,.probe = xbmd_probe,.remove = xbmd_remove,
};#if 1
static int __init xbmd_init(void)
{int ret;ret = pci_register_driver(&xbmd_driver);if (ret < 0)return ret;major_number = register_chrdev(0, DEVICE_NAME, &xbmd_fops);if (major_number < 0) {printk(KERN_ALERT "Registering char device failed with %d\n", major_number);goto out_pci_unregister_driver;}printk(KERN_INFO "Char device registered with major number %d\n", major_number);xbmd_class = class_create(CLASS_NAME);if (IS_ERR(xbmd_class)) {ret = PTR_ERR(xbmd_class);goto out_unregister_chedev;} xbmd_device = device_create(xbmd_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME);if (IS_ERR(xbmd_device)) {ret = PTR_ERR(xbmd_device);goto out_device_destroy;}printk("xbmd_init ok\n");return 0;out_device_destroy:class_destroy(xbmd_class);
out_unregister_chedev:unregister_chrdev(major_number, DEVICE_NAME);
out_pci_unregister_driver:pci_unregister_driver(&xbmd_driver);exit:return ret;
}
#else
static int __init xbmd_init(void)
{int ret;ret = pci_register_driver(&xbmd_driver);if (ret < 0)return ret;#if 0ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);if (ret < 0) goto out_pci_unregister_driver;
#elseret = register_chrdev_region(devno, 1, DEVICE_NAME);if (ret < 0) goto out_pci_unregister_driver;
#endifxbmd_cdev = cdev_alloc();if (IS_ERR(xbmd_cdev)) {ret = PTR_ERR(xbmd_cdev);goto out_unregister_dev;}cdev_init(xbmd_cdev, &xbmd_fops);xbmd_cdev->owner = THIS_MODULE;ret = cdev_add(xbmd_cdev, devno, 1); if (ret) goto out_free_cdev;xbmd_class = class_create(CLASS_NAME);if (IS_ERR(xbmd_class)) {ret = PTR_ERR(xbmd_class);goto out_unregister_cdev;} xbmd_device = device_create(xbmd_class, NULL, devno, NULL, DEVICE_NAME);if (IS_ERR(xbmd_device)) {ret = PTR_ERR(xbmd_device);goto out_del_class;}return 0;out_del_class:class_destroy(xbmd_class);
out_unregister_cdev:cdev_del(xbmd_cdev);
out_free_cdev:kfree(xbmd_cdev);
out_unregister_dev:unregister_chrdev_region(devno, 1);
out_pci_unregister_driver:pci_unregister_driver(&xbmd_driver);return ret;
}
#endif#if 1
static void __exit xbmd_exit(void)
{if (xbmd_class) {printk("Destroy device and class\n");device_destroy(xbmd_class, MKDEV(major_number, 0));class_destroy(xbmd_class);}unregister_chrdev(major_number, DEVICE_NAME);pci_unregister_driver(&xbmd_driver);printk("xbmd_exit ok\n");
}
#else
static void __exit xbmd_exit(void)
{if (xbmd_class) {printk("Destroy device and class\n");device_destroy(xbmd_class, devno);class_destroy(xbmd_class);}cdev_del(xbmd_cdev);kfree(xbmd_cdev);unregister_chrdev_region(devno, 1);pci_unregister_driver(&xbmd_driver);printk("xbmd_exit ok\n");
}
#endifmodule_init(xbmd_init);
module_exit(xbmd_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Charley Zhang");
MODULE_DESCRIPTION("Xilinx xbmd");
linux应用层代码
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "xbmd.h"unsigned int rxBuffer[1024];
unsigned int txBuffer[1024];int main(int)
{int ret = 0;int devFd = 0;int i;for (i = 0; i < 1024; i++) {rxBuffer[i] = 0x0;txBuffer[i] = 0xfeedbeef;}devFd = open("/dev/xbmd", O_RDWR);if ( devFd < 0 ) {printf("Open /dev/xbmd failed!\n");return -1;}// initcardioctl(devFd, INITCARD, &ret);write(devFd, txBuffer, sizeof(txBuffer));// enable irq & start dmaret = 0x00810081;ioctl(devFd, WRDDMACR, &ret);// wait dma completeusleep(1000);ioctl(devFd, RDDDMACR, &ret);printf("RDDDMACR = 0x%x\n", ret);// check dataret = read(devFd, rxBuffer, sizeof(rxBuffer));printf("rxBuffer[0] = 0x%x\n", rxBuffer[0]);printf("rxBuffer[1] = 0x%x\n", rxBuffer[1]);return 0;
}
Makefile
obj-m += xbmd.oall:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) cleanrm -rf app
测试脚本
dmesg -cmake clean
makegcc-12 -o app app.crmmod xbmd.ko
dmesg -c
insmod xbmd.ko
dmesg -c./app
dmesg -c
四、测试
# ./run_bmd.csh
五、测试结果
实际运行dma没有启动,原因待分析。
六、固化bit文件
使用BPI Flash,待研究。
七、疑问
7 Series FPGAs Integrated Block for PCI Express 实现了CfgRd0 CfgRd1 CfgWr0 CfgWr1等配置TLP吗?还是xbmd代码实现的,如下的BMD_CFG_CTRL.v文件有什么作用?
FPGA再入门-1-480T板卡试用
YPCB-00338-1P1 FPGA 板卡 逆向 – TiferKing的学习笔记
PCIe应用实战