我正在PCIe
和FPGA (ML605)
之间进行PC
通信。
我遇到的问题是:
一旦我发送INTA
assert packet
然后INTA de-assert packet
,我就会发信息,所以我的预期行为是interrupt handler
应调用一次,
但正在发生的事情是interrupt handler
被连续调用不止一次。
request_irq function
如下:
request_irq(gIrq, &XPCIe_IRQHandler, IRQF_SHARED, gDrvrName, gDev)
在handler
的结尾处,我提供了一个返回类型IRQ_HANDLED
。
cat /proc/interrupts
我的handler
registered
为IO-APIC fasteoi type
所以有人可以说可能是什么问题吗?
还需要进一步澄清。
当我第二次insmod
我的模块时,interrupt handler
正在运行而没有给出interrupt
。
在PCI
的内核文档中
在section 3.5 Initialize device registers
它被编写为在调用pending interrupts
之前清除request_irq
。
那么有人可以说怎么做吗?
我的代码是
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
//#include <linux/pci-aspm.h>
//#include <linux/pci_regs.h>
#include <asm/uaccess.h> /* 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 0x6018 //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);
int XPCIe_Open(struct inode *inode, struct file *filp)
{
printk(KERN_INFO"%s: Open: module opened\n",gDrvrName);
return SUCCESS;
}
int XPCIe_Release(struct inode *inode, struct file *filp)
{
printk(KERN_INFO"%s: Release: module released\n",gDrvrName);
return(SUCCESS);
}
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);
}
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);
}
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,
unlocked_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_get_device (PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX_PCIE, gDev);
// 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, (irq_handler_t)XPCIe_IRQHandler, IRQF_SHARED, gDrvrName, gDev)) {
// 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)
{
printk("N_TEST:in exit\n");
// Check if we have a memory region and free it
if (gStatFlags & HAVE_REGION) {
(void) release_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE);}
printk("N_TEST:rel reg cmp\n");
// Check if we have an IRQ and free it
if (gStatFlags & HAVE_IRQ) {
(void) free_irq(gIrq, gDev);
}
printk("N_TEST:free irq cmp\n");
// Free Write and Read buffers allocated to use
// if (NULL != gReadBuffer)
// (void) kfree(gReadBuffer);
// if (NULL != gWriteBuffer)
// (void) kfree(gWriteBuffer);
// printk("N_TEST:free buff cmp\n");
// Free memory allocated to our Endpoint
pci_free_consistent(gDev, BUF_SIZE, gReadBuffer, gReadHWAddr);
pci_free_consistent(gDev, BUF_SIZE, gWriteBuffer, gWriteHWAddr);
printk("N_TEST:free consitent mem\n");
gReadBuffer = NULL;
gWriteBuffer = NULL;
// Free up memory pointed to by virtual address
if (gBaseVirt != NULL) {
iounmap(gBaseVirt);
}
printk("N_TEST:io unmap cmp\n");
gBaseVirt = NULL;
// Unregister Device Driver
if (gStatFlags & HAVE_KREG) {
unregister_chrdev(gDrvrMajor, gDrvrName);
}
printk("N_TEST:un reg chr dev cmp\n");
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);
static irq_return_t 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);
返回IRQ_HANDLED;
}
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)
{printk("Nag:offset=%d\tval=%x\n",dw_offset,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;
}