admin管理员组

文章数量:1530518

2024年6月17日发(作者:)

// (c) Copyright 2009 聳2009 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.

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

//-- 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

};

#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, // 0

INITRST,

DISPREGS,

RDDCSR,

RDDDMACR,

RDWDMATLPA, // 5

RDWDMATLPS,

RDWDMATLPC,

RDWDMATLPP,

RDRDMATLPP,

RDRDMATLPA, // 10

RDRDMATLPS,

RDRDMATLPC,

RDWDMAPERF,

RDRDMAPERF,

RDRDMASTAT, // 15

RDNRDCOMP,

RDRCOMPDSIZE,

RDDLWSTAT,

RDDLTRSSTAT,

RDDMISCCONT, // 20

RDDMISCONT,

RDDLNKC,

DFCCTL,

DFCPINFO,

DFCNPINFO, // 25

DFCINFO,

RDCFGREG,

WRCFGREG,

RDBMDREG,

WRBMDREG, // 30

WRDDMACR,

WRWDMATLPS,

WRWDMATLPC,

WRWDMATLPP,

WRRDMATLPS,

WRRDMATLPC,

WRRDMATLPP,

WRDMISCCONT,

WRDDLNKC,

NUMCOMMANDS

};

//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 openedn",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 releasedn",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 ", gDrvrName, count);

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

printk(KERN_INFO"%s: XPCIe_Write: %d bytes have ", 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 ", 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:

regx = XPCIe_ReadReg(2);

*((u32 *)arg) = regx;

break;

case RDWDMATLPS:

regx = XPCIe_ReadReg(3);

*((u32 *)arg) = regx;

break;

case RDWDMATLPC:

regx = XPCIe_ReadReg(4);

*((u32 *)arg) = regx;

break;

case RDWDMATLPP:

regx = XPCIe_ReadReg(5);

*((u32 *)arg) = regx;

break;

case RDRDMATLPP:

regx = XPCIe_ReadReg(6);

*((u32 *)arg) = regx;

break;

case RDRDMATLPA:

regx = XPCIe_ReadReg(7);

*((u32 *)arg) = regx;

break;

case RDRDMATLPS:

regx = XPCIe_ReadReg(8);

*((u32 *)arg) = regx;

break;

case RDRDMATLPC:

regx = XPCIe_ReadReg(9);

*((u32 *)arg) = regx;

break;

case RDWDMAPERF:

regx = XPCIe_ReadReg(10);

*((u32 *)arg) = regx;

break;

case RDRDMAPERF:

regx = XPCIe_ReadReg(11);

*((u32 *)arg) = regx;

break;

case RDRDMASTAT:

regx = XPCIe_ReadReg(12);

// Read: Write DMA TLP Address Register

// Read: Write DMA TLP Size Register

// Read: Write DMA TLP Count Register

// Read: Write DMA TLP Pattern Register

// Read: Read DMA TLP Pattern Register

// Read: Read DMA TLP Address Register

// Read: Read DMA TLP Size Register

// Read: Read DMA TLP Count Register

// Read: Write DMA Performance Register

// Read: Read DMA Performance Register

// Read: Read DMA Status Register

*((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:

regx = XPCIe_ReadReg(16);

*((u32 *)arg) = regx;

break;

case RDDMISCCONT:

regx = XPCIe_ReadReg(17);

*((u32 *)arg) = regx;

break;

case RDDMISCONT:

regx = XPCIe_ReadReg(18);

*((u32 *)arg) = regx;

break;

case RDDLNKC:

regx = XPCIe_ReadReg(19);

*((u32 *)arg) = regx;

break;

case DFCCTL:

regx = XPCIe_ReadReg(20);

*((u32 *)arg) = regx;

break;

case DFCPINFO:

regx = XPCIe_ReadReg(21);

*((u32 *)arg) = regx;

break;

case DFCNPINFO:

regx = XPCIe_ReadReg(22);

*((u32 *)arg) = regx;

break;

case DFCINFO:

regx = XPCIe_ReadReg(23);

*((u32 *)arg) = regx;

break;

case WRDDMACR:

XPCIe_WriteReg(1, arg);

break;

case WRWDMATLPS:

XPCIe_WriteReg(3, arg);

break;

case WRWDMATLPC:

XPCIe_WriteReg(4, arg);

break;

// Read: Device Link Transaction Size Status Register

// Read: Device Miscellaneous Control Register

// Read: Device MSI Control

// Read: Device Directed Link Change Register

// Read: Device FC Control Register

// Read: Device FC Posted Information

// Read: Device FC Non Posted Information

// Read: Device FC Completion Information

// Write: DMA Control Status Register

// Write: Write DMA TLP Size Register

// Write: Write DMA TLP Count Register

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 Valuen", (*(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 Valuen", (*(cfgwr *)arg).value);

break;

default:

break;

}

return ret;

}

// Aliasing write, read, ioctl,

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 (gBaseHdwr < 0)

{

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 %Xn", 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 %dn", 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/".

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 %Xn", 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;// 这个中断号是怎么来的,难道是pci_find_device函数分配的?

printk(KERN_INFO"%s: Init: Device IRQ: %Xn",gDrvrName, gIrq);

//---START: Initialize Hardware

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

if (check_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE) < 0)

{

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

if (request_irq(gIrq, &XPCIe_IRQHandler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, gDrvrName, gDev) <

0)

{

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 (pci_enable_device(gDev) < 0)

{

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->%Xn", 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->%Xn", gDrvrName, (unsigned int)gWriteBuffer,

(unsigned int)gWriteHWAddr);

//--- END: Allocate Buffers

//--- START: Register Driver

// Register with the kernel as a character device.

if (register_chrdev(gDrvrMajor, gDrvrName, &XPCIe_Intf) < 0)

{

printk(KERN_WARNING"%s: Init: will not registern", gDrvrName);

return (CRIT_ERR);

}

printk(KERN_INFO"%s: Init: module registeredn", 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 loadedn", 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 unloadedn", 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%Xn", 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;

return ret;

//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总线地址,底层调用的是pci_map_single

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;

up(&gSem[SEM_DMA]);

return ret;

//goto exit; // return 之前要释放互斥量,不能直接return

}

// 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

// 直接调用read write 函数进行传输?

// 宋宝华第页流程图

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;

return ret;

//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);

return ret;

//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;

up(&gSem[SEM_DMA]);

return ret;

//goto exit; // return 之前要释放互斥量,不能直接return

}

// 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

// 直接调用read write 函数进行传输?

// 宋宝华第页流程图

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;

}

本文标签: 函数总线地址说明相关