最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

xilinx PCIE的Linux驱动程序源代码

来源:动视网 责编:小OO 时间:2025-09-30 08:18:14
文档

xilinx PCIE的Linux驱动程序源代码

//--------------------------------------------------------------------------------//--Filename:xbmd.h//--//--Description:Mainheaderfileforkerneldriver//--//--XBMDisanexampleRedHatdevicedriverwhichexercisesXBMDdesign//--DevicedriverhasbeentestedonRed
推荐度:
导读//--------------------------------------------------------------------------------//--Filename:xbmd.h//--//--Description:Mainheaderfileforkerneldriver//--//--XBMDisanexampleRedHatdevicedriverwhichexercisesXBMDdesign//--DevicedriverhasbeentestedonRed
//--------------------------------------------------------------------------------

//-- 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 * 1024)

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,

  RDCFGREG,

  WRCFGREG,

  RDBMDREG,

  WRBMDREG,

  WRDDMACR,

  WRWDMATLPS,

  WRWDMATLPC,

  WRWDMATLPP,

  WRRDMATLPS,

  WRRDMATLPC,

  WRRDMATLPP,

  WRDMISCCONT,

  WRDDLNKC,

  NUMCOMMANDS

};

//--------------------------------------------------------------------------------

//-- Filename: xbmd.c

//--

//-- Description: XBMD device 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.

//--------------------------------------------------------------------------------

#include

#include

#include

#include

#include

//#include

//#include

#include /* copy_to_user */

#include "xbmd.h"

// semaphores

enum  {

        SEM_READ,

        SEM_WRITE,

        SEM_WRITEREG,

        SEM_READREG,

        SEM_WAITFOR,

        SEM_DMA,

        NUM_SEMS

      };

//semaphores

struct semaphore gSem[NUM_SEMS];

MODULE_LICENSE("Dual BSD/GPL");

// Defines the Vendor ID.  Must be changed if core generated did not set the Vendor ID to the same value

#define PCI_VENDOR_ID_XILINX      0x10ee

// Defines the Device ID.  Must be changed if core generated did not set the Device ID to the same value

#define PCI_DEVICE_ID_XILINX_PCIE 0x0007

// Defining

#define XBMD_REGISTER_SIZE        (4*8)    // There are eight registers, and each is 4 bytes wide.

#define HAVE_REGION               0x01     // I/O Memory region

#define HAVE_IRQ                  0x02     // Interupt

//Status Flags: 

//       1 = Resouce successfully acquired

//       0 = Resource not acquired.      

#define HAVE_REGION 0x01                    // I/O Memory region

#define HAVE_IRQ    0x02                    // Interupt

#define HAVE_KREG   0x04                    // Kernel registration

int             gDrvrMajor = 241;           // Major number not dynamic.

unsigned int    gStatFlags = 0x00;          // Status flags used for cleanup.

unsigned long   gBaseHdwr;                  // Base register address (Hardware address)

unsigned long   gBaseLen;                   // Base register address Length

void           *gBaseVirt = NULL;           // Base register address (Virtual address, for I/O).

char            gDrvrName[]= "xbmd";        // Name of driver in proc.

struct pci_dev *gDev = NULL;                // PCI device structure.

int             gIrq;                       // IRQ assigned by PCI system.

char           *gBufferUnaligned = NULL;    // Pointer to Unaligned DMA buffer.

char           *gReadBuffer      = NULL;    // Pointer to dword aligned DMA buffer.

char           *gWriteBuffer     = NULL;    // Pointer to dword aligned DMA buffer.

dma_addr_t      gReadHWAddr;

dma_addr_t      gWriteHWAddr;

unsigned long SA_SHIRQ = 0;

unsigned long SA_SAMPLE_RANDOM = 0;

int pos;

// Struct Used for Writing CFG Register.  Holds value and register to be written

typedef struct cfgwrite {

    int reg;

    int value;

} cfgwr;

// Struct Used for Writing BMD Register.  Holds value and register to be written

typedef struct bmdwrite {

    int reg;

    int value;

} bmdwr;

//-----------------------------------------------------------------------------

// Prototypes

//-----------------------------------------------------------------------------

void  XPCIe_IRQHandler (int irq, void *dev_id, struct pt_regs *regs);

u32   XPCIe_ReadReg (u32 dw_offset);

void  XPCIe_WriteReg (u32 dw_offset, u32 val);

void  XPCIe_InitCard (void);

void  XPCIe_InitiatorReset (void);

u32 XPCIe_ReadCfgReg (u32 byte);

u32 XPCIe_WriteCfgReg (u32 byte, u32 value);

//---------------------------------------------------------------------------

// Name:        XPCIe_Open

//

// Description: Book keeping routine invoked each time the device is opened.             

//

// Arguments: inode :

//            filp  :

//

// Returns: 0 on success, error code on failure.

//

// Modification log:

// Date      Who  Description

//

//---------------------------------------------------------------------------

int XPCIe_Open(struct inode *inode, struct file *filp)

{

  printk(KERN_INFO"%s: Open: module opened\\n",gDrvrName);

  return SUCCESS;

}

//---------------------------------------------------------------------------

// Name:        XPCIe_Release

//

// Description: Book keeping routine invoked each time the device is closed.             

//

// Arguments: inode :

//            filp  :

//

// Returns: 0 on success, error code on failure.

//

// Modification log:

// Date      Who  Description

//

//---------------------------------------------------------------------------

int XPCIe_Release(struct inode *inode, struct file *filp)

{

  printk(KERN_INFO"%s: Release: module released\\n",gDrvrName);

  return(SUCCESS);

}

//---------------------------------------------------------------------------

// Name:        XPCIe_Write

//

// Description: This routine is invoked from user space to write data to

//              the PCIe device. 

//

// Arguments: filp  : file pointer to opened device.

//            buf   : pointer to location in users space, where data is to

//                    be acquired.

//            count : Amount of data in bytes user wishes to send.

//

// Returns: SUCCESS  = Success

//          CRIT_ERR = Critical failure

//

// Modification log:

// Date      Who  Description

//

//---------------------------------------------------------------------------

ssize_t XPCIe_Write(struct file *filp, const char *buf, size_t count,

                       loff_t *f_pos)

{

  int ret = SUCCESS;

  memcpy((char *)gWriteBuffer, buf, count);

  printk(KERN_INFO"%s: XPCIe_Write: %d bytes have been written...\\n", gDrvrName, count);

  memcpy((char *)gReadBuffer, buf, count);

  printk(KERN_INFO"%s: XPCIe_Write: %d bytes have been written...\\n", gDrvrName, count);

  return (ret);

}

//---------------------------------------------------------------------------

// Name:        XPCIe_Read

//

// Description: This routine is invoked from user space to read data from

//              the PCIe device. ***NOTE: This routine returns the entire

//              buffer, (BUF_SIZE), count is ignored!. The user App must

//              do any needed processing on the buffer.

//

// Arguments: filp  : file pointer to opened device.

//            buf   : pointer to location in users space, where data is to

//                    be placed.

//            count : Amount of data in bytes user wishes to read.

//

// Returns: SUCCESS  = Success

//          CRIT_ERR = Critical failure

//

//  Modification log:

//  Date      Who  Description

//----------------------------------------------------------------------------

ssize_t XPCIe_Read(struct file *filp, char *buf, size_t count, loff_t *f_pos)

{

  memcpy(buf, (char *)gWriteBuffer, count);

  printk(KERN_INFO"%s: XPCIe_Read: %d bytes have been read...\\n", gDrvrName, count);

  return (0);

}

//---------------------------------------------------------------------------

// Name:        XPCIe_Ioctl

//

// Description: This routine is invoked from user space to configure the 

//              running driver. 

//

// Arguments: inode : 

//            filp  : File pointer to opened device.

//            cmd   : Ioctl command to execute.

//            arg   : Argument to Ioctl command.

//

// Returns: 0 on success, error code on failure.

//

// Modification log:

// Date      Who  Description

//

//---------------------------------------------------------------------------

int XPCIe_Ioctl(struct inode *inode, 

                struct file *filp, 

                unsigned int cmd,

                unsigned long arg)

{

  

  u32 regx;

  int ret = SUCCESS;

  switch (cmd) {

    case INITCARD:                    // Initailizes XBMD application

      XPCIe_InitCard();

      break;

    case INITRST:                     // Resets XBMD applications

      XPCIe_InitiatorReset();

      break;

    case DISPREGS:

      break;

    case RDDCSR:                     // Read: Device Control Status Register

      regx = XPCIe_ReadReg(0);  

      *((u32 *)arg) = regx; 

      break;

    case RDDDMACR:                   // Read: DMA Control Status Register

      regx = XPCIe_ReadReg(1);  

      *((u32 *)arg) = regx; 

      break;

    case RDWDMATLPA:                 // Read: Write DMA TLP Address Register

      regx = XPCIe_ReadReg(2);  

      *((u32 *)arg) = regx; 

      break;

    case RDWDMATLPS:                 // Read: Write DMA TLP Size Register

      regx = XPCIe_ReadReg(3);  

      *((u32 *)arg) = regx; 

      break;

    case RDWDMATLPC:                 // Read: Write DMA TLP Count Register

      regx = XPCIe_ReadReg(4);  

      *((u32 *)arg) = regx; 

      break;

    case RDWDMATLPP:                 // Read: Write DMA TLP Pattern Register

      regx = XPCIe_ReadReg(5);  

      *((u32 *)arg) = regx; 

      break;

    case RDRDMATLPP:                 // Read: Read DMA TLP Pattern Register

      regx = XPCIe_ReadReg(6);  

      *((u32 *)arg) = regx; 

      break;

    case RDRDMATLPA:                 // Read: Read DMA TLP Address Register

      regx = XPCIe_ReadReg(7);  

      *((u32 *)arg) = regx; 

      break;

    case RDRDMATLPS:                 // Read: Read DMA TLP Size Register

      regx = XPCIe_ReadReg(8);  

      *((u32 *)arg) = regx; 

      break;

    case RDRDMATLPC:                 // Read: Read DMA TLP Count Register

      regx = XPCIe_ReadReg(9);  

      *((u32 *)arg) = regx; 

      break;

    case RDWDMAPERF:                 // Read: Write DMA Performance Register

      regx = XPCIe_ReadReg(10);  

      *((u32 *)arg) = regx; 

      break;

    case RDRDMAPERF:                 // Read: Read DMA Performance Register

      regx = XPCIe_ReadReg(11);  

      *((u32 *)arg) = regx; 

      break;

    case RDRDMASTAT:                 // Read: Read DMA Status Register

      regx = XPCIe_ReadReg(12);  

      *((u32 *)arg) = regx; 

      break;

    case RDNRDCOMP:                  // Read: Number of Read Completion w/ Data Register

      regx = XPCIe_ReadReg(13);  

      *((u32 *)arg) = regx; 

      break;

    case RDRCOMPDSIZE:               // Read: Read Completion Size Register

      regx = XPCIe_ReadReg(14);  

      *((u32 *)arg) = regx; 

      break;

    case RDDLWSTAT:                  // Read: Device Link Width Status Register

      regx = XPCIe_ReadReg(15);  

      *((u32 *)arg) = regx; 

      break;

    case RDDLTRSSTAT:                // Read: Device Link Transaction Size Status Register

      regx = XPCIe_ReadReg(16);  

      *((u32 *)arg) = regx; 

      break;

    case RDDMISCCONT:                // Read: Device Miscellaneous Control Register

      regx = XPCIe_ReadReg(17);  

      *((u32 *)arg) = regx; 

      break;

    case RDDMISCONT:                // Read: Device MSI Control

      regx = XPCIe_ReadReg(18);  

      *((u32 *)arg) = regx; 

      break;

    case RDDLNKC:                   // Read: Device Directed Link Change Register

      regx = XPCIe_ReadReg(19);  

      *((u32 *)arg) = regx; 

      break;

    case DFCCTL:                    // Read: Device FC Control Register

      regx = XPCIe_ReadReg(20);  

      *((u32 *)arg) = regx; 

      break;

    case DFCPINFO:                  // Read: Device FC Posted Information

      regx = XPCIe_ReadReg(21);  

      *((u32 *)arg) = regx; 

      break;

    case DFCNPINFO:                 // Read: Device FC Non Posted Information

      regx = XPCIe_ReadReg(22);  

      *((u32 *)arg) = regx; 

      break;

    case DFCINFO:                  // Read: Device FC Completion Information

      regx = XPCIe_ReadReg(23);  

      *((u32 *)arg) = regx; 

      break;

    case WRDDMACR:                 // Write: DMA Control Status Register

      XPCIe_WriteReg(1, arg);

      break;

    case WRWDMATLPS:               // Write: Write DMA TLP Size Register

      XPCIe_WriteReg(3, arg);

      break;

    case WRWDMATLPC:               // Write: Write DMA TLP Count Register

      XPCIe_WriteReg(4, arg);

      break;

    case WRWDMATLPP:               // Write: Write DMA TLP Pattern Register

      XPCIe_WriteReg(5, arg);

      break;

    case WRRDMATLPS:               // Write: Read DMA TLP Size Register

      XPCIe_WriteReg(8, arg);

      break;

    case WRRDMATLPC:               // Write: Read DMA TLP Count Register

      XPCIe_WriteReg(9, arg);

      break;

    case WRRDMATLPP:               // Write: Read DMA TLP Pattern Register

      XPCIe_WriteReg(6, arg);

      break;

    case WRDMISCCONT:              // Write: Device Miscellaneous Control Register

      XPCIe_WriteReg(18, arg);

      break;

    case WRDDLNKC:                 // Write: Device Directed Link Change Register

      XPCIe_WriteReg(19, arg);

      break;

    case RDBMDREG:                 // Read: Any XBMD Reg.  Added generic functionality so all register can be read

      regx = XPCIe_ReadReg(*(u32 *)arg);  

      *((u32 *)arg) = regx; 

      break; 

    case RDCFGREG:                 // Read: Any CFG Reg.  Added generic functionality so all register can be read

      regx = XPCIe_ReadCfgReg(*(u32 *)arg);  

      *((u32 *)arg) = regx; 

      break;

   case WRBMDREG:                 // Write: Any BMD Reg.  Added generic functionality so all register can be read

          XPCIe_WriteReg((*(bmdwr *)arg).reg,(*(bmdwr *)arg).value);

    printk(KERN_WARNING"%d: Write Register.\\n", (*(bmdwr *)arg).reg);

    printk(KERN_WARNING"%d: Write Value\\n", (*(bmdwr *)arg).value);

    break;

   case WRCFGREG:                 // Write: Any CFG Reg.  Added generic functionality so all register can be read

          regx = XPCIe_WriteCfgReg((*(cfgwr *)arg).reg,(*(cfgwr *)arg).value);

    printk(KERN_WARNING"%d: Write Register.\\n", (*(cfgwr *)arg).reg);

    printk(KERN_WARNING"%d: Write Value\\n", (*(cfgwr *)arg).value);

    break;

    default:

      break;

  }

  return ret;

}

// Aliasing write, read, ioctl, etc...

struct file_operations XPCIe_Intf = {

    read:       XPCIe_Read,

    write:      XPCIe_Write,

    ioctl:      XPCIe_Ioctl,

    open:       XPCIe_Open,

    release:    XPCIe_Release,

};

static int XPCIe_init(void)

{

  // Find the Xilinx EP device.  The device is found by matching device and vendor ID's which is defined

  // at the top of this file.  Be default, the driver will look for 10EE & 0007.  If the core is generated 

  // with other settings, the defines at the top must be changed or the driver will not load

  gDev = pci_find_device (PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX_PCIE, gDev);

  if (NULL == gDev) {

    // If a matching device or vendor ID is not found, return failure and update kernel log. 

    // NOTE: In fedora systems, the kernel log is located at: /var/log/messages

    printk(KERN_WARNING"%s: Init: Hardware not found.\\n", gDrvrName);

    return (CRIT_ERR);

  }

  // Get Base Address of registers from pci structure. Should come from pci_dev

  // structure, but that element seems to be missing on the development system.

  gBaseHdwr = pci_resource_start (gDev, 0);

if (0 > gBaseHdwr) {

    printk(KERN_WARNING"%s: Init: Base Address not set.\\n", gDrvrName);

    return (CRIT_ERR);

  } 

  // Print Base Address to kernel log

  printk(KERN_INFO"%s: Init: Base hw val %X\\n", gDrvrName, (unsigned int)gBaseHdwr);

  // Get the Base Address Length

  gBaseLen = pci_resource_len (gDev, 0);

  // Print the Base Address Length to Kernel Log

  printk(KERN_INFO"%s: Init: Base hw len %d\\n", gDrvrName, (unsigned int)gBaseLen);

  // Remap the I/O register block so that it can be safely accessed.

  // I/O register block starts at gBaseHdwr and is 32 bytes long.

  // It is cast to char because that is the way Linus does it.

  // Reference "/usr/src/Linux-2.4/Documentation/IO-mapping.txt".

  gBaseVirt = ioremap(gBaseHdwr, gBaseLen);

  if (!gBaseVirt) {

    printk(KERN_WARNING"%s: Init: Could not remap memory.\\n", gDrvrName);

    return (CRIT_ERR);

  } 

  // Print out the aquired virtual base addresss

  printk(KERN_INFO"%s: Init: Virt HW address %X\\n", gDrvrName, (unsigned int)gBaseVirt);

  // Get IRQ from pci_dev structure. It may have been remapped by the kernel,

  // and this value will be the correct one.

gIrq = gDev->irq;

  printk(KERN_INFO"%s: Init: Device IRQ: %X\\n",gDrvrName, gIrq);

  //---START: Initialize Hardware

  // Check the memory region to see if it is in use

if (0 > check_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE)) {

    printk(KERN_WARNING"%s: Init: Memory in use.\\n", gDrvrName);

    return (CRIT_ERR);

  }

  // Try to gain exclusive control of memory for demo hardware.

  request_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE, "3GIO_Demo_Drv");

  // Update flags

  gStatFlags = gStatFlags | HAVE_REGION;

  printk(KERN_INFO"%s: Init: Initialize Hardware Done..\\n",gDrvrName);

  // Request IRQ from OS.

  // In past architectures, the SHARED and SAMPLE_RANDOM flags were called: SA_SHIRQ and SA_SAMPLE_RANDOM

  // respectively.  In older Fedora core installations, the request arguments may need to be reverted back.

  // SA_SHIRQ | SA_SAMPLE_RANDOM

  printk(KERN_INFO"%s: ISR Setup..\\n", gDrvrName);

if (0 > request_irq(gIrq, &XPCIe_IRQHandler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, gDrvrName, gDev)) {

    printk(KERN_WARNING"%s: Init: Unable to allocate IRQ",gDrvrName);

    return (CRIT_ERR);

  }

  // Update flags stating IRQ was successfully obtained

  gStatFlags = gStatFlags | HAVE_IRQ;

  // Bus Master Enable

if (0 > pci_enable_device(gDev)) {

    printk(KERN_WARNING"%s: Init: Device not enabled.\\n", gDrvrName);

    return (CRIT_ERR);

  }

  //--- END: Initialize Hardware

  //--- START: Allocate Buffers

  // Allocate the read buffer with size BUF_SIZE and return the starting address

  gReadBuffer = pci_alloc_consistent(gDev, BUF_SIZE, &gReadHWAddr);

  if (NULL == gReadBuffer) {

    printk(KERN_CRIT"%s: Init: Unable to allocate gBuffer.\\n",gDrvrName);

    return (CRIT_ERR);

  }

  // Print Read buffer size and address to kernel log

printk(KERN_INFO"%s: Read Buffer Allocation: %X->%X\\n", gDrvrName, (unsigned int)gReadBuffer, (unsigned int)gReadHWAddr);

  // Allocate the write buffer with size BUF_SIZE and return the starting address

  gWriteBuffer = pci_alloc_consistent(gDev, BUF_SIZE, &gWriteHWAddr);

  if (NULL == gWriteBuffer) {

    printk(KERN_CRIT"%s: Init: Unable to allocate gBuffer.\\n",gDrvrName);

    return (CRIT_ERR);

  }

  // Print Write buffer size and address to kernel log  

printk(KERN_INFO"%s: Write Buffer Allocation: %X->%X\\n", gDrvrName, (unsigned int)gWriteBuffer, (unsigned int)gWriteHWAddr);

  //--- END: Allocate Buffers

  //--- START: Register Driver

  // Register with the kernel as a character device.

if (0 > register_chrdev(gDrvrMajor, gDrvrName, &XPCIe_Intf)) {

    printk(KERN_WARNING"%s: Init: will not register\\n", gDrvrName);

    return (CRIT_ERR);

  }

  printk(KERN_INFO"%s: Init: module registered\\n", gDrvrName);

  gStatFlags = gStatFlags | HAVE_KREG;

  //--- END: Register Driver

  // The driver is now successfully loaded.  All HW is initialized, IRQ's assigned, and buffers allocated

  printk("%s driver is loaded\\n", gDrvrName);

  // Initializing card registers

  XPCIe_InitCard();

  return 0;

}

//--- XPCIe_InitiatorReset(): Resets the XBMD reference design

//--- Arguments: None

//--- Return Value: None

//--- Detailed Description: Writes a 1 to the DCSR register which resets the XBMD design

void XPCIe_InitiatorReset()

{

  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_InitCard(): Initializes XBMD descriptor registers to default values

//--- Arguments: None

//--- Return Value: None

//--- Detailed Description: 1) Resets device

//---                       2) Writes specific values into the XBMD registers inside the EP 

void XPCIe_InitCard()

{

  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(2, gWriteHWAddr);        // Write: Write DMA TLP Address register with starting address

  XPCIe_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)

}

//--- XPCIe_exit(): Performs any cleanup required before releasing the device

//--- Arguments: None

//--- Return Value: None

//--- Detailed Description: Performs all cleanup functions required before releasing device

static void XPCIe_exit(void)

{

  // Check if we have a memory region and free it

  if (gStatFlags & HAVE_REGION) {

     (void) release_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE);}

    // Check if we have an IRQ and free it

    if (gStatFlags & HAVE_IRQ) {

        (void) free_irq(gIrq, gDev);

    }

    // Free Write and Read buffers allocated to use

    if (NULL != gReadBuffer)

        (void) kfree(gReadBuffer);

    if (NULL != gWriteBuffer)

        (void) kfree(gWriteBuffer);

    // Free memory allocated to our Endpoint

    pci_free_consistent(gDev, BUF_SIZE, gReadBuffer, gReadHWAddr);

    pci_free_consistent(gDev, BUF_SIZE, gWriteBuffer, gWriteHWAddr);

    gReadBuffer = NULL;

    gWriteBuffer = NULL;

    // Free up memory pointed to by virtual address

    if (gBaseVirt != NULL) {

        iounmap(gBaseVirt);

     }

    

    gBaseVirt = NULL;

    // Unregister Device Driver

    if (gStatFlags & HAVE_KREG) {

      unregister_chrdev(gDrvrMajor, gDrvrName);

    }

    gStatFlags = 0;

    // Update Kernel log stating driver is unloaded

    printk(KERN_ALERT"%s driver is unloaded\\n", gDrvrName);

}

// Driver Entry Point

module_init(XPCIe_init);

// Driver Exit Point

module_exit(XPCIe_exit);

void XPCIe_IRQHandler(int irq, void *dev_id, struct pt_regs *regs)

{

  u32 i, regx;

  printk(KERN_WARNING"%s: Interrupt Handler Start ..",gDrvrName);

  

for (i = 0; i < 32; i++) {

     regx = XPCIe_ReadReg(i);

printk(KERN_WARNING"%s : REG<%d> : 0x%X\\n", gDrvrName, i, regx);

  }

  printk(KERN_WARNING"%s Interrupt Handler End ..\\n", gDrvrName);

}

u32 XPCIe_ReadReg (u32 dw_offset)

{

        u32 ret = 0;

        //u32 reg_addr = (u32)(gBaseVirt + (4 * dw_offset));

        //ret = readl(reg_addr);  

        ret = readl(gBaseVirt + (4 * dw_offset));  

        return ret; 

}

void XPCIe_WriteReg (u32 dw_offset, u32 val)

{

        //u32 reg_addr = (u32)(gBaseVirt + (4 * dw_offset));

        writel(val, (gBaseVirt + (4 * dw_offset)));

}

ssize_t* XPCIe_ReadMem(char *buf, size_t count)

{

    int ret = 0;

    dma_addr_t dma_addr;

                                                                                

    //make sure passed in buffer is large enough

if ( count < BUF_SIZE ) {

      printk("%s: XPCIe_Read: passed in buffer too small.\\n", gDrvrName);

      ret = -1;

      goto exit;

    }

    down(&gSem[SEM_DMA]);

    // pci_map_single return the physical address corresponding to 

    // the virtual address passed to it as the 2nd parameter

    dma_addr = pci_map_single(gDev, gReadBuffer, BUF_SIZE, PCI_DMA_FROMDEVICE);

    if ( 0 == dma_addr )  {

        printk("%s: XPCIe_Read: Map error.\\n",gDrvrName);

        ret = -1;

        goto exit;

    }

    // Now pass the physical address to the device hardware. This is now

    // the destination physical address for the DMA and hence the to be

    // put on Memory Transactions

    // Do DMA transfer here....

    printk("%s: XPCIe_Read: ReadBuf Virt Addr = %x Phy Addr = %x.\\n", 

            gDrvrName, (unsigned int)gReadBuffer, (unsigned int)dma_addr);

                                                                   

    // Unmap the DMA buffer so it is safe for normal access again.

    pci_unmap_single(gDev, dma_addr, BUF_SIZE, PCI_DMA_FROMDEVICE);

                                                                                

    up(&gSem[SEM_DMA]);

    // Now it is safe to copy the data to user space.

    if ( copy_to_user(buf, gReadBuffer, BUF_SIZE) )  {

        ret = -1;

        printk("%s: XPCIe_Read: Failed copy to user.\\n",gDrvrName);

        goto exit;

    }

    exit:

      return ret;

}

ssize_t XPCIe_WriteMem(const char *buf, size_t count) {

    int ret = 0;

    dma_addr_t dma_addr;

    if ( (count % 4) != 0 )  {

       printk("%s: XPCIe_Write: Buffer length not dword aligned.\\n",gDrvrName);

       ret = -1;

       goto exit;

    }

    // Now it is safe to copy the data from user space.

    if ( copy_from_user(gWriteBuffer, buf, count) )  {

        ret = -1;

        printk("%s: XPCIe_Write: Failed copy to user.\\n",gDrvrName);

        goto exit;

    }

    //set DMA semaphore if in loopback

    down(&gSem[SEM_DMA]);

    // pci_map_single return the physical address corresponding to 

    // the virtual address passed to it as the 2nd parameter

    dma_addr = pci_map_single(gDev, gWriteBuffer, BUF_SIZE, PCI_DMA_FROMDEVICE);

    if ( 0 == dma_addr )  {

        printk("%s: XPCIe_Write: Map error.\\n",gDrvrName);

        ret = -1;

        goto exit;

    }

    // Now pass the physical address to the device hardware. This is now

    // the source physical address for the DMA and hence the to be

// put on Memory Transactions

    // Do DMA transfer here....

    printk("%s: XPCIe_Write: WriteBuf Virt Addr = %x Phy Addr = %x.\\n",  

           gDrvrName, (unsigned int)gReadBuffer, (unsigned int)dma_addr);

                                                                   

    // Unmap the DMA buffer so it is safe for normal access again.

    pci_unmap_single(gDev, dma_addr, BUF_SIZE, PCI_DMA_FROMDEVICE);

                                                                                

    up(&gSem[SEM_DMA]);

    exit:

      return (ret);

}

u32 XPCIe_ReadCfgReg (u32 byte) {

   u32 pciReg;

if (pci_read_config_dword(gDev, byte, &pciReg) < 0) {

        printk("%s: XPCIe_ReadCfgReg: Reading PCI interface failed.",gDrvrName);

        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.",gDrvrName);

        return (-1);

   }

   return 1;

}

文档

xilinx PCIE的Linux驱动程序源代码

//--------------------------------------------------------------------------------//--Filename:xbmd.h//--//--Description:Mainheaderfileforkerneldriver//--//--XBMDisanexampleRedHatdevicedriverwhichexercisesXBMDdesign//--DevicedriverhasbeentestedonRed
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top