xenomai驱动开发-光纤反射内存卡驱动程序入口driver_entry.c
点击查看代码
#include "rfm2g_driver.h"
#define RFM2G_MEMORY_SPACE 1
#define RFM2G_IO_SPACE 2
/*** Local prototypes ********************************************************/
#ifdef __cplusplus
extern "C" {
#endif
static RFM2G_UINT8 rfm2g_peek( RFM2GCONFIGLINUX *cfg, RFM2G_ADDR rfm2gAddr,
RFM2G_UINT64 *pData, RFM2G_UINT8 width );
static RFM2G_UINT8 rfm2g_poke( RFM2GCONFIGLINUX *cfg, RFM2G_ADDR rfm2gAddr,
RFM2G_UINT64 *pData, RFM2G_UINT8 width );
static int set_lcsr_bit(RFM2GCONFIGLINUX *cfg, unsigned int cmd,
unsigned long arg, unsigned int bit, char* pDescription );
static int get_lcsr_bit(RFM2GCONFIGLINUX *cfg, unsigned int cmd, unsigned long arg,
unsigned int bit, char* pDescription );
static int RFM2gDMA(RFM2GCONFIGLINUX *cfg, RFM2G_UINT32 dmaDesc, RFM2G_UINT64 pciAddress,
RFM2G_UINT32 rfmOffset, RFM2G_UINT32 count, RFM2G_UINT32 addrAdjust);
//james
static int RFM2gDMApolling(RFM2GCONFIGLINUX *cfg, RFM2G_UINT32 dmaDesc, RFM2G_UINT64 pciAddress,
RFM2G_UINT32 rfmOffset, RFM2G_UINT32 count, RFM2G_UINT32 addrAdjust);
// end james
// james & cg (& lb)
static int RFM2gDMApollingwaitend(RFM2GCONFIGLINUX *cfg, RFM2G_UINT32 dmaDesc, RFM2G_UINT64 pciAddress,
RFM2G_UINT32 rfmOffset, RFM2G_UINT32 count, RFM2G_UINT32 addrAdjust);
// end james & cg (& lb)
static int IsReadyForDma(RFM2G_UINT8 unit, char *buf, size_t count, RFM2GDMAINFO *DmaInfo,
RFM2G_UINT32 *addrAdjust);
#ifdef __cplusplus
}
#endif
/******************************************************************************
*
* FUNCTION: rfm2g_open
*
* PURPOSE: Entry point for open(2) call. Maps RFM memory into kernel space.
* PARAMETERS: *inode: (I) Passed in by OS, used for minor number determination
* *filp: (I) Unused, passed in by OS
* RETURNS: 0: Success
* -ENOMEM: Unable to map memory
* GLOBALS: rfm2gDeviceInfo, devname
*
******************************************************************************/
int
rfm2g_open( struct inode *inode, struct file *filp )
{
static char *me = "rfm2g_open()";
RFM2G_UINT8 unit; /*Minor device number, used as index in rfm2gDeviceInfo*/
RFM2G_ADDR BaseAddr = 0;
RFM2G_ADDR MappedAddr = 0;
unsigned long flags;
RFM2GCONFIGLINUX *cfg;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 mapSize; /* How much RFM board memory to map */
/* Extract the minor number so we know which RFM device to access */
unit = MINOR( inode->i_rdev );
cfg = &(rfm2gDeviceInfo[unit].Config );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Entering %s\n", devname,
unit, me);
/* initialize the DMA management structure for this open call */
if ((DmaInfo = kmalloc(sizeof(RFM2GDMAINFO), GFP_KERNEL)) == NULL)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: Allocating kernel memory "
"failed. pid:%d\n", devname, unit, me, current->pid );
}
return( -EFAULT);
}
memset( (void *)DmaInfo, 0, sizeof(RFM2GDMAINFO));
DmaInfo->Threshold = RFM2G_DMA_THRESHOLD_MAX;
filp->private_data = (void *)DmaInfo;
/* Map the RFM board's memory and register spaces */
if( rfm2gDeviceInfo[unit].Instance == 0 )
{
WHENDEBUG(RFM2G_DBOPEN)
{
printk(KERN_ERR"%s%d: %s Enabling interrupts, mapping mem & "
"I/O space. pid:%d\n", devname, unit, me, current->pid );
}
BaseAddr = cfg->PCI.rfm2gBase;
if( BaseAddr != 0 )
{
/* Map the smaller of the two choices: total board memory or memory window */
mapSize = cfg->MemorySize;
if (mapSize > cfg->PCI.rfm2gWindowSize)
{
mapSize = cfg->PCI.rfm2gWindowSize;
WHENDEBUG(RFM2G_DBOPEN)
{
printk(KERN_ERR"%s%d: %s Mapping the smaller Window Size %d bytes. pid:%d\n",
devname, unit, me, cfg->PCI.rfm2gWindowSize, current->pid );
}
}
MappedAddr = (RFM2G_ADDR)ioremap_nocache( BaseAddr, mapSize);
if( MappedAddr == 0 )
{
/* Error */
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Unable to map RFM "
"memory space. pid:%d\n", devname, unit, me, current->pid );
}
return( -ENOMEM );
}
cfg->pBaseAddress = (RFM2G_UINT8 *) MappedAddr;
}
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
devname, unit, me, current->pid);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Count how many times we've been opened */
rfm2gDeviceInfo[unit].Instance++;
rfm2gDeviceInfo[unit].Flags |= RFM2G_OPEN;
WHENDEBUG(RFM2G_DBOPEN)
{
printk(KERN_ERR"%s%d: %s Instance %d Flags = 0x%08X. pid:%d\n",
devname, unit, me, rfm2gDeviceInfo[unit].Instance,
rfm2gDeviceInfo[unit].Flags, current->pid );
}
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock. pid:%d\n", devname, unit, me, current->pid);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Exiting %s. pid:%d\n", devname,
unit, me, current->pid);
return(0);
} /* End of rfm2g_open() */
/******************************************************************************
*
* FUNCTION: rfm2g_release
*
* PURPOSE: Entry point for close(2) call. Unmaps RFM memory.
* PARAMETERS: *inode: (I) Passed in by OS, used for minor number determination
* *filp: Unused, passed in by OS
* RETURNS: void (kernel 2.0.x), or 0 (kernel 2.2.x and higher)
* GLOBALS: devname, rfm2gDeviceInfo
*
******************************************************************************/
int
rfm2g_release( struct inode *inode, struct file *filp )
{
static char *me = "rfm2g_release()";
RFM2GCONFIGLINUX *cfg;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
unsigned long flags;
RFM2GEVENTINFOLINUX event;
int i;
/* Extract the minor number so we know which RFM device to access */
unit = MINOR( inode->i_rdev );
cfg = &(rfm2gDeviceInfo[unit].Config );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Entering %s. pid:%d\n", devname,
unit, me, current->pid);
/* free dma management structure */
if (filp->private_data != NULL)
{
kfree(filp->private_data);
filp->private_data = NULL;
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
devname, unit, me, current->pid);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Count how many times we've been closed */
rfm2gDeviceInfo[unit].Instance--;
if( rfm2gDeviceInfo[unit].Instance == 0 )
{
WHENDEBUG(RFM2G_DBCLOSE)
{
printk(KERN_ERR"%s%d: %s Disabling interrupts, unmapping mem & "
"I/O space. pid:%d\n", devname, unit, me, current->pid );
}
/* Disable interrupts */
for(i=0; i<LINUX_RFM2G_NUM_OF_EVENTS; i++)
{
event.Unit = unit;
event.Event = i;
/* Make sure the interrupt is supported on this board */
switch( event.Event )
{
case RFM2GEVENT_DMADONE: /* Fall thru */
/* These interrupts are disabled during DMA operations */
continue;
break;
case RFM2GEVENT_RESET: /* Fall thru */
case RFM2GEVENT_INTR1: /* Fall thru */
case RFM2GEVENT_INTR2: /* Fall thru */
case RFM2GEVENT_INTR3: /* Fall thru */
case RFM2GEVENT_INTR4: /* Fall thru */
/* These interrupt events are valid for all boards */
break;
case RFM2GEVENT_BAD_DATA: /* Fall thru */
case RFM2GEVENT_RXFIFO_FULL: /* Fall thru */
case RFM2GEVENT_ROGUE_PKT: /* Fall thru */
case RFM2GEVENT_RXFIFO_AFULL: /* Fall thru */
case RFM2GEVENT_SYNC_LOSS: /* Fall thru */
case RFM2GEVENT_MEM_WRITE_INHIBITED: /* Fall thru */
case RFM2GEVENT_LOCAL_MEM_PARITY_ERR: /* Fall thru */
/* These interrupt events shall stay enabled. */
continue;
break;
default:
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock. pid:%d\n", devname, unit, me, current->pid);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR | RFM2G_DBOPEN)
{
printk(KERN_ERR"%s%d: Exiting %s: Interrupt %d is "
"invalid. pid:%d\n", devname, unit, me, event.Event, current->pid );
}
return( -ENOMEM );
break;
}
/* Disable the interrupt */
DisableInterrupt(&event, RFM2G_TRUE);
CancelInterrupt(&event, RFM2G_TRUE);
}
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock. pid:%d\n", devname, unit, me, current->pid);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
/* Unmap the RFM board's memory space */
if( cfg->pBaseAddress != (RFM2G_UINT8 *) NULL )
{
iounmap( (void *) cfg->pBaseAddress );
cfg->pBaseAddress = (RFM2G_UINT8 *) NULL;
}
}
else
{
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock. pid:%d\n", devname, unit, me, current->pid);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Exiting %s. pid:%d\n", devname,
unit, me, current->pid);
return(0);
} /* End of rfm2g_release() */
/******************************************************************************
*
* FUNCTION: rfm2g_llseek
*
* PURPOSE: Entry point for lseek(2) call. Adjusts file pointer to an offset
* into RFM memory.
* PARAMETERS: *filp: (IO) Passed in by OS, contains file pointer to be updated.
* It is also used for minor number
* determination.
* offset: (I) Offset into RFM memory
* whence: (I) Determines relative basis of offset
* RETURNS: 0: Success
* -EINVAL: Indicates invalid offset or whence values.
* GLOBALS: devname, rfm2gDeviceInfo
*
******************************************************************************/
loff_t
rfm2g_llseek( struct file *filp, loff_t offset, int whence )
{
static char *me = "rfm2g_llseek()";
RFM2GCONFIGLINUX *cfg;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
/* Extract the minor number so we know which RFM device to access */
unit = MINOR( filp->f_dentry->d_inode->i_rdev );
cfg = &(rfm2gDeviceInfo[unit].Config );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Entering %s\n", devname,
unit, me);
/* Validate the requested offset */
if( offset > cfg->MemorySize )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: offset %d too big for %d "
"byte board\n", devname, unit, me, (RFM2G_INT32)offset,
(RFM2G_INT32)cfg->MemorySize );
}
return( -EINVAL );
}
/* Now move the file offset */
switch( whence )
{
case 0: /*SEEK_SET*/
filp->f_pos = offset;
break;
case 1: /*SEEK_CUR*/ /* Not supported */
case 2: /*SEEK_END*/ /* Not supported */
default:
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: invalid whence = %d\n",
devname, unit, me, whence );
}
return( -EINVAL );
}
}
WHENDEBUG(RFM2G_DBREAD | RFM2G_DBWRITE)
{
printk(KERN_ERR"%s%d: %s Seeking to Reflective Memory offset 0x%X\n",
devname, unit, me, (int)offset );
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Exiting %s\n", devname,
unit, me);
return( 0 );
} /* End of rfm2g_llseek() */
/******************************************************************************
*
* FUNCTION: rfm2g_read
*
* PURPOSE: Entry point for read(2) call.
* PARAMETERS: *filp: (I) Passed in by OS. Used
* for minor number determination.
* *buf: (O) User space buffer that will receive data from RFM memory
* count: (I) The number of bytes to read
* *offset: (I) Passed in by OS, this is
* the offset into RFM memory.
* RETURNS: The number of bytes successfully read
* -EFAULT Error copying data to user
* space.
* GLOBALS: devname, rfm2gDeviceInfo
*
******************************************************************************/
ssize_t
rfm2g_read( struct file *filp, char *buf, size_t count, loff_t *offset )
{
static char *me = "rfm2g_read()";
RFM2GCONFIGLINUX *cfg;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
void *rfm2gPtr;
RFM2G_UINT32 l_offset;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
l_offset = (RFM2G_UINT32) *offset;
/* Extract the minor number so we know which RFM device to access */
unit = MINOR( filp->f_dentry->d_inode->i_rdev );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Entering %s\n", devname,
unit, me);
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
cfg = &(rfm2gDeviceInfo[unit].Config );
rfm2gPtr = (void *) ( cfg->pBaseAddress + l_offset );
WHENDEBUG(RFM2G_DBREAD)
{
printk(KERN_ERR"%s%d: %s Reading %zu bytes from offset 0x%X to "
"address 0x%p\n", devname, unit, me, count, l_offset, (char *)buf );
}
/* See if DMA needs to be used */
if (IsReadyForDma(unit, buf, count, DmaInfo, &addrAdjust))
{
return (RFM2gDMA(cfg, RFMOR_DMAPTR_TO_PCI, DmaInfo->BuffAddr, l_offset, count, addrAdjust));
}
else /* Not using DMA */
{
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((l_offset + count) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Send the data to the user */
if( copy_to_user(buf, rfm2gPtr, count) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Exiting %s\n", devname,
unit, me);
return( count );
} /* End of rfm2g_read() */
/******************************************************************************
*
* FUNCTION: rfm2g_write
*
* PURPOSE: Entry point for write(2) call.
* PARAMETERS: *filp: (I) Passed in by OS.
* used for minor number determination.
* *buf: (I) User space buffer containing data to be written to RFM
* memory
* count: (I) The number of bytes to written
* *offset: (I) Passed in by OS, this is
* the offset into RFM memory.
* RETURNS: The number of bytes successfully written
* -EFAULT Error copying data from user
* space.
* GLOBALS: devname, rfm2gDeviceInfo
*
******************************************************************************/
ssize_t
rfm2g_write( struct file *filp, const char *buf, size_t count, loff_t *offset )
{
static char *me = "rfm2g_write()";
RFM2GCONFIGLINUX *cfg;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
void *rfm2gPtr;
RFM2G_UINT32 l_offset;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
char *tempBuf = (char *)buf;
l_offset = (RFM2G_UINT32) *offset;
/* Extract the minor number so we know which RFM device to access */
unit = MINOR( filp->f_dentry->d_inode->i_rdev );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Entering %s\n", devname,
unit, me);
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO*)(filp->private_data);
cfg = &(rfm2gDeviceInfo[unit].Config );
rfm2gPtr = (void *) ( cfg->pBaseAddress + l_offset );
WHENDEBUG(RFM2G_DBWRITE)
{
printk(KERN_ERR"%s%d: %s Writing %zu bytes to offset 0x%X from "
"address 0x%p\n", devname, unit, me, count, l_offset, buf );
}
/* See if DMA needs to be used */
if (IsReadyForDma(unit, tempBuf, count, DmaInfo, &addrAdjust))
{
return (RFM2gDMA(cfg, 0x0, DmaInfo->BuffAddr, l_offset, count, addrAdjust));
}
else /* Not using DMA */
{
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((l_offset + count) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Get the data from the user */
if( copy_from_user(rfm2gPtr, (void *)buf, count) != 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Exiting %s\n", devname, unit, me);
return( count );
} /* End of rfm2g_write() */
/******************************************************************************
*
* FUNCTION: rfm2g_peek
*
* PURPOSE: Read one byte, word, or longword from an offset in Reflective
* Memory.
* PARAMETERS: rfm2gAddr: (I) RFM address to read data
* pData: (O) Where to put the data
* width: (I) Byte, word, or long width of data
* RETURNS: 0: Success
* -EINVAL: Invalid data width
* GLOBALS: devname
*
******************************************************************************/
RFM2G_UINT8
rfm2g_peek( RFM2GCONFIGLINUX *cfg, RFM2G_ADDR rfm2gAddr, RFM2G_UINT64 *pData, RFM2G_UINT8 width )
{
static char *me = "rfm2g_peek()";
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s?: Entering %s\n", devname, me);
/* Do the read */
switch( width )
{
case RFM2G_BYTE:
if (cfg->pioByteSwap == RFM2G_FALSE)
{
*pData = (RFM2G_UINT64) readb( (char *)(rfm2gAddr) );
}
else
{
/*
* Read data. PLX Byte Swap is turn on, compensate for 4 byte swap.
* The address is exclusive ored with 3 to produce byte invariant
* addressing.
*/
*pData = (RFM2G_UINT64) readb( (char *)(rfm2gAddr ^ 3) );
}
break;
case RFM2G_WORD:
if (cfg->pioByteSwap == RFM2G_FALSE)
{
/*
* Read Data. readw only Byte Swaps
* if CPU is big endian. Data on PCI Bus is little endian.
* PLX will not byte swap data. Data is little endian
* on RFM2g local bus.
*/
*pData = (RFM2G_UINT64) readw( (char *)(rfm2gAddr) );
/*
* RFM PLX Byte Swap PCI Bus CPU readw Value
* Little OFF Little Little No Swap performed Little
* Little OFF Little Big Swaps after read Big
*/
}
else
{
if ((rfm2gAddr % sizeof(RFM2G_UINT16)) != 0)
{
return (-EINVAL);
}
/*
* Read Data. readw only Byte Swaps
* if CPU is Big Endian, converting the data to little
* endian format. Data on PCI Bus is little endian.
* PLX Byte swap will convert data from little endian on
* RFM2g local bus to big endian on PCI bus. The address is
* exclusive ored with 2 to produce byte invariant addressing.
*/
*pData = (RFM2G_UINT64) readw( (char *)(rfm2gAddr ^ 2) );
/*
* RFM PLX Byte Swap PCI Bus CPU BSPX_PCI_MEM_IN_WORD Value
* Little ON Big Little No Swap performed Big
* Little ON Big Big Swaps after read Little
*/
/*
* PLX byte swap will convert data from little endian on
* RFM2g local bus to big endian on PCI bus. Because
* readw performs a byte swap after read
* for big endian systems and not for little endian systems,
* we must do a unconditional byte swap if PLX byte swap is
* turned on.
*/
*pData = (((*pData)<<8) | ( (*pData) >> 8));
}
/*
* RFM PLX Byte Swap PCI Bus CPU readw LONGSWAP Value
* Little OFF Little Little No Swap performed NO Little
* Little OFF Little Big Swaps after read NO Big
* Little ON Big Little No Swap performed YES Little
* Little ON Big Big Swaps after read YES Big
*/
break;
case RFM2G_LONG:
/* If PIO byte swap is enabled, make sure the offset is aligned. */
if ( (cfg->pioByteSwap == RFM2G_TRUE) && ((rfm2gAddr % sizeof(RFM2G_UINT32)) != 0))
{
return (-EINVAL);
}
/*
* Read Data. readl only Byte Swaps
* if CPU is Big Endian. Data on PCI Bus is little endian
* if PLX byte swap is off, otherwise it is big endian.
* Data is little endian on RFM2g local bus.
*/
*pData = (RFM2G_UINT64) readl( (char *)(rfm2gAddr) );
/*
* RFM PLX Byte Swap PCI Bus CPU BSPX_PCI_MEM_IN_LONG Value
* Little OFF Little Little No Swap performed Little
* Little OFF Little Big Swaps after read Big
* Little ON Big Little No Swap performed Big
* Little ON Big Big Swaps after read Little
*/
if (cfg->pioByteSwap != RFM2G_FALSE)
{
/*
* PLX byte swap will convert data from little endian on
* RFM2g local bus to big endian on PCI bus. Because
* BSPX_PCI_MEM_IN_LONG performs a byte swap after read
* for big endian systems and not for little endian systems,
* we must do a unconditional byte swap if PLX byte swap is
* turned on.
*/
*pData = ( (( *pData & 0x000000ff) << 24) |
(( *pData & 0x0000ff00) << 8) |
(( *pData & 0x00ff0000) >> 8) |
(( *pData & 0xff000000) >> 24)
);
}
/*
* RFM PLX Byte Swap PCI Bus CPU BSPX_PCI_MEM_IN_WORD LONGSWAP Value
* Little OFF Little Little No Swap performed NO Little
* Little OFF Little Big Swaps after read NO Big
* Little ON Big Little No Swap performed YES Little
* Little ON Big Big Swaps after read YES Big
*/
break;
case RFM2G_LONGLONG: /* Not supported */
#ifdef RFM2G_LONGLONG_NOT_SUPPORTED
RFM2G_UINT32 Value0;
RFM2G_UINT32 Value1;
RFM2G_UINT32* pValue = (RFM2G_UINT32*) pData;
/* If PIO byte swap is enabled, make sure the offset is aligned. */
if ( (cfg->pioByteSwap == RFM2G_TRUE) && ((rfm2gAddr % sizeof(RFM2G_UINT64)) != 0))
{
return (-EINVAL);
}
/* Read Data. */
Value0 = readl( (char *)(rfm2gAddr);
Value1 = readl( (char *)(rfm2gAddr + 4);
if (cfg->pioByteSwap != RFM2G_FALSE)
{
/*
* PLX byte swap will convert data from little endian on
* RFM2g local bus to big endian on PCI bus. Because
* BSPX_PCI_MEM_IN_LONG performs a byte swap after read
* for big endian systems and not for little endian systems,
* we must do a unconditional byte swap if PLX byte swap is
* turned on.
*/
Value0 = ( (( Value0 & 0x000000ff) << 24) |
(( Value0 & 0x0000ff00) << 8) |
(( Value0 & 0x00ff0000) >> 8) |
(( Value0 & 0xff000000) >> 24)
);
Value1 = ( (( Value1 & 0x000000ff) << 24) |
(( Value1 & 0x0000ff00) << 8) |
(( Value1 & 0x00ff0000) >> 8) |
(( Value1 & 0xff000000) >> 24)
);
}
pValue[0] = Value0;
pValue[1] = Value1;
break;
#endif
default:
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s?: Exiting %s: Invalid data width %d\n",
devname, me, width );
}
return( -EINVAL );
}
}
WHENDEBUG(RFM2G_DBPEEK)
{
printk(KERN_ERR"%s?: %s Width = %d VirtRfmAddr = 0x%lX Data = 0x%X\n",
devname, me, width, rfm2gAddr, (RFM2G_UINT32) *pData );
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s?: Exiting %s\n", devname, me);
return( 0 );
} /* End of rfm2g_peek() */
/******************************************************************************
*
* FUNCTION: rfm2g_poke
*
* PURPOSE: Write one byte, word, or longword to an offset in Reflective
* Memory.
* PARAMETERS: rfmAddr: (I) RFM address to write data
* pData: (I) Where to get the data
* width: (I) Byte, word, long, or longlong width of data
* RETURNS: 0: Success
* -EINVAL: Invalid data width
* GLOBALS: devname
*
******************************************************************************/
RFM2G_UINT8
rfm2g_poke( RFM2GCONFIGLINUX *cfg, RFM2G_ADDR rfm2gAddr, RFM2G_UINT64 *pData, RFM2G_UINT8 width )
{
static char *me = "rfm2g_poke()";
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s?: Entering %s\n", devname, me);
/* Do the write */
switch( width )
{
case RFM2G_BYTE:
if (cfg->pioByteSwap == RFM2G_FALSE)
{
writeb( (RFM2G_UINT8) *pData, (char *)(rfm2gAddr) );
}
else
{
/*
* Write data. PLX Byte Swap is turn on, compensate for 4 byte swap.
* The address is exclusive or with 3 to produce byte invariant
* addressing.
*/
writeb( (RFM2G_UINT8) *pData, (char *)(rfm2gAddr ^ 3) );
}
break;
case RFM2G_WORD:
if (cfg->pioByteSwap == RFM2G_FALSE)
{
/*
* CPU PLX Byte Swap Value BSPX_PCI_MEM_OUT_LONG PCI Bus RFM
* Little OFF Little No Swap performed Little Little
* Big OFF Big Swaps prior to write Little Little
*/
/*
* Write Data. BSPX_PCI_MEM_OUT_WORD only Byte Swaps
* if CPU is Big Endian. Data on PCI Bus is Little Endian.
* PLX will not byte swap data. Data is Little Endian
* on RFM2g local bus.
*/
writew( (RFM2G_UINT16) *pData, (char *)(rfm2gAddr) );
}
else
{
if ((rfm2gAddr % sizeof(RFM2G_UINT16)) != 0)
{
return (-EINVAL);
}
/*
* If CPU is little endian, swap Value to big endian.
* if CPU is big endian, data is byte swapped to
* little endian.
*/
/*
* CPU PLX Byte Swap Value BSPX_PCI_MEM_OUT_LONG PCI Bus RFM
* Little ON Big No Swap performed Big Little
* Big ON Little Swaps prior to write Big Little
*/
/*
* Write Data. writew only Byte Swaps
* if CPU is Big Endian, converting the data to big
* endian format. Data on PCI Bus is Big Endian.
* PLX Byte swap will convert data to Little Endian on
* RFM2g local bus.
*/
/* Byte swap contents of pData */
writew( (( (RFM2G_UINT16) *pData) << 8) | (( (RFM2G_UINT16) *pData) >> 8),
(char *) (rfm2gAddr ^ 2)
);
}
break;
case RFM2G_LONG:
/* If PIO byte swap is enabled, make sure the offset is aligned. */
if ( (cfg->pioByteSwap == RFM2G_TRUE) && ((rfm2gAddr % sizeof(RFM2G_UINT32)) != 0))
{
return (-EINVAL);
}
/*
* CPU PLX Byte Swap Value BSPX_PCI_MEM_OUT_LONG PCI Bus RFM
* Little OFF Little No Swap performed Little Little
* Big OFF Big Swaps prior to write Little Little
* Little ON Big No Swap performed Big Little
* Big ON Little Swaps prior to write Big Little
*/
if (cfg->pioByteSwap == RFM2G_FALSE)
{
/*
* Write Data. BSPX_PCI_MEM_OUT_LONG only byte swaps
* if CPU is Big Endian. Data is little endian on PCI bus
* if PLX byte swap is off, otherwise data is big endian on
* PCI bus. Data is little endian on RFM2g local bus.
*/
writel( (RFM2G_UINT32) *pData, (char *)(rfm2gAddr) );
}
else
{
/*
* PLX Byte swap will convert data to little endian on
* RFM2g local bus from big endian on PCI bus. If CPU is
* little endian, we need to byte swap to make the value
* a big endian value. If CPU is big endian, we need to
* byte swap to make the value a little endian value because
* BSPX_PCI_MEM_OUT_LONG is going to swap the value prior
* to write.
*/
writel( ( ((( (RFM2G_UINT32) *pData ) & 0x000000ff) << 24) |
((( (RFM2G_UINT32) *pData ) & 0x0000ff00) << 8) |
((( (RFM2G_UINT32) *pData ) & 0x00ff0000) >> 8) |
((( (RFM2G_UINT32) *pData ) & 0xff000000) >> 24)
),
(char *)(rfm2gAddr) );
}
break;
case RFM2G_LONGLONG: /* Not supported */
default:
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s: Exiting %s?: Invalid data width %d\n",
devname, me, width );
}
return( -EINVAL );
}
}
WHENDEBUG(RFM2G_DBPOKE)
{
printk(KERN_ERR"%s?: %s Width = %d VirtRfmAddr = 0x%lx Data = 0x%X\n",
devname, me, width, rfm2gAddr, (RFM2G_UINT32) *pData );
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s: Exiting %s\n", devname, me);
return( 0 );
} /* End of rfm2g_poke() */
/******************************************************************************
*
* FUNCTION: rfm2g_mmap
*
* PURPOSE: Entry point for mmap(2) call. Maps RFM memory into user
* address space.
* PARAMETERS: *filp: (I) Passed in by OS. used
* for minor number determination.
* *vma: (I) Passed in by OS, used to get virtual and physical addresses
* and size, which are passed into remap_page_range()
* RETURNS: 0: Success
* -EAGAIN: Memory mapping failed
* GLOBALS: devname, rfm2gDeviceInfo
*
******************************************************************************/
int
rfm2g_mmap( struct file *filp, struct vm_area_struct *vma )
{
static char *me = "rfm2g_mmap()";
unsigned long virtaddr = 0;
unsigned long physaddr = 0;
unsigned long offset = 0;
unsigned long size = 0;
RFM2GCONFIGLINUX *cfg = NULL;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
int dma = RFM2G_FALSE;
unsigned int pageNumber = 0;
RFM2GDMAINFO *DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
/* Extract the minor number so we know which RFM device to access */
unit = MINOR( filp->f_dentry->d_inode->i_rdev );
cfg = &(rfm2gDeviceInfo[unit].Config );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Entering %s\n", devname,
unit, me);
virtaddr = vma->vm_start;
size = vma->vm_end - vma->vm_start;
offset = vma->vm_pgoff << PAGE_SHIFT; /* convert pages to bytes */
WHENDEBUG(RFM2G_DBMMAP) printk(KERN_ERR"%s: %s offset = 0x%08X\n", devname, me, (unsigned int)offset);
WHENDEBUG(RFM2G_DBTRACE | RFM2G_DBMMAP) printk(KERN_ERR"%s: %s vma->vm_start=0x%X vma->vm_end=0x%X vma->vm_pgoff=0x%X. pid:%d\n",
devname, me, (RFM2G_UINT32) vma->vm_start, (RFM2G_UINT32) vma->vm_end,
(RFM2G_UINT32) vma->vm_pgoff, current->pid);
if (DmaInfo->InUseAction == RFM2G_BAR0_MMAP_OFFSET)
{
DmaInfo->InUseAction = 0;
/* Give the user the BAR0 Register space - Memory Mapped */
physaddr = cfg->PCI.rfm2gOrBase;
WHENDEBUG(RFM2G_DBMMAP)
{
printk(KERN_ERR"%s: %s virtaddr=0x%X physaddr=0x%X size=0x%X offset=0x%X RFM2G_BAR0_MMAP_OFFSET. pid:%d\n",
devname, me, (RFM2G_UINT32)virtaddr, (RFM2G_UINT32)physaddr,
(RFM2G_UINT32)size, (RFM2G_UINT32) offset, current->pid );
}
physaddr &= 0xFFFFF000;
}
else if (DmaInfo->InUseAction == RFM2G_BAR2_MMAP_OFFSET)
{
DmaInfo->InUseAction = 0;
/* Give the user the BAR2 Register space */
physaddr = cfg->PCI.rfm2gCsBase;
WHENDEBUG(RFM2G_DBMMAP)
{
printk(KERN_ERR"%s: %s virtaddr=0x%X physaddr=0x%X size=0x%X offset=0x%X RFM2G_BAR2_MMAP_OFFSET. pid:%d\n",
devname, me, (RFM2G_UINT32)virtaddr, (RFM2G_UINT32)physaddr,
(RFM2G_UINT32)size, (RFM2G_UINT32) offset, current->pid );
}
physaddr &= 0xFFFFF000;
}
else if (DmaInfo->InUseAction == RFM2G_DMA_MMAP_OFFSET)
{
DmaInfo->InUseAction = 0;
/* Map the DMA buffer that was allocated at boot time using 'mem=xxxM' */
dma = RFM2G_TRUE;
if ((DmaInfo->BuffAddr == 0) || (size == 0))
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: DMA buffer address (0x%llX) and/or size (%d) "
"is zero. pid:%d\n", devname, unit, me,
DmaInfo->BuffAddr, (unsigned int) size, current->pid );
}
/* Give the semaphore, which was taken inside rfm2g_ioctl(IOCTL_RFM2G_SET_SPECIAL_MMAP_OFFSET) */
up(rfm2gDeviceInfo[unit].mmapSem);
return( -EAGAIN );
}
DmaInfo->BuffSize = size;
DmaInfo->VirtAddr = virtaddr;
WHENDEBUG(RFM2G_DBMMAP)
{
printk(KERN_ERR"%s: %s virtaddr=0x%X physaddr=0x%llX size=0x%X offset=0x%X RFM2G_DMA_MMAP_OFFSET. pid:%d\n",
devname, me, (RFM2G_UINT32)virtaddr, DmaInfo->BuffAddr,
(RFM2G_UINT32)size, (RFM2G_UINT32) offset, current->pid );
}
}
else if ((offset + size) <= cfg->PCI.rfm2gWindowSize)
{
/* Map reflective memory */
physaddr = cfg->PCI.rfm2gBase + offset;
/* Check for PAGE_SIZE alignment */
if( offset & (PAGE_SIZE-1) )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Offset (0x%X) is not PAGE_SIZE "
"aligned. pid:%d\n", devname, unit, me, (unsigned int) offset, current->pid );
}
return( -EAGAIN );
}
WHENDEBUG(RFM2G_DBMMAP)
{
printk(KERN_ERR"%s: %s virtaddr=0x%X physaddr=0x%X size=0x%X. pid:%d\n",
devname, me, (RFM2G_UINT32)virtaddr, (RFM2G_UINT32)physaddr,
(RFM2G_UINT32)size, current->pid );
}
}
else
{
/* invalid offset */
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Offset (0x%X) and size (%d) "
"are out of range. pid:%d\n", devname, unit, me,
(unsigned int) offset, (unsigned int) size, current->pid );
}
return( -EAGAIN );
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
#else
#ifdef CFG_RFM_KERNEL_DRIVER
{
unsigned long prot;
/* make mapped memory non-cachable */
vma->vm_flags |= VM_RESERVED | VM_LOCKED | VM_IO | VM_SHM;
prot = pgprot_val(vma->vm_page_prot);
prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
vma->vm_page_prot = __pgprot(prot);
}
#else
vma->vm_flags |= VM_RESERVED;
#endif
#endif
/* In kernel 2,6,11 The remap_page_range() function has been replaced with
remap_pfn_range(). The third arg is the page number now. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
if (dma == RFM2G_TRUE)
{
pageNumber = (unsigned int)(DmaInfo->BuffAddr/PAGE_SIZE);
}
else
{
pageNumber = physaddr/PAGE_SIZE;
}
if (remap_pfn_range(vma, virtaddr, pageNumber, size, vma->vm_page_prot))
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: remap_pfn_range() failed. pid:%d\n",
devname, unit, me, current->pid );
}
if (dma == RFM2G_TRUE)
{
DmaInfo->BuffAddr = 0;
DmaInfo->VirtAddr = 0;
/* Give the semaphore, which was taken inside rfm2g_ioctl(IOCTL_RFM2G_SET_SPECIAL_MMAP_OFFSET) */
up(rfm2gDeviceInfo[unit].mmapSem);
}
return( -EAGAIN );
}
#else
/* The remap_page_range() function has a new parameter starting with
the 2.5.3 kernel, and also with Red Hat 9.0 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3) || defined REDHAT9KERNEL
if (dma == RFM2G_TRUE)
{
physaddr = (unsigned int)(DmaInfo->BuffAddr & 0xFFFFFFFF);
}
if( remap_page_range( vma, virtaddr, physaddr, size, vma->vm_page_prot ) )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: remap_page_range() failed\n",
devname, unit, me );
}
if (dma == RFM2G_TRUE)
{
DmaInfo->BuffAddr = 0;
DmaInfo->VirtAddr = 0;
/* Give the semaphore, which was taken inside rfm2g_ioctl(IOCTL_RFM2G_SET_SPECIAL_MMAP_OFFSET) */
up(rfm2gDeviceInfo[unit].mmapSem);
}
return( -EAGAIN );
}
#else
if (dma == RFM2G_TRUE)
{
physaddr = (unsigned int)(DmaInfo->BuffAddr & 0xFFFFFFFF);
}
if( remap_page_range( virtaddr, physaddr, size, vma->vm_page_prot ) )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: remap_page_range() failed\n",
devname, unit, me );
}
if (dma == RFM2G_TRUE)
{
DmaInfo->BuffAddr = 0;
DmaInfo->VirtAddr = 0;
/* Give the semaphore, which was taken inside rfm2g_ioctl(IOCTL_RFM2G_SET_SPECIAL_MMAP_OFFSET) */
up(rfm2gDeviceInfo[unit].mmapSem);
}
return( -EAGAIN );
}
#endif
#endif
if (dma == RFM2G_TRUE)
{
/* Give the semaphore, which was taken inside rfm2g_ioctl(IOCTL_RFM2G_SET_SPECIAL_MMAP_OFFSET) */
up(rfm2gDeviceInfo[unit].mmapSem);
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Exiting %s. pid:%d\n", devname,
unit, me, current->pid);
return(0);
} /* End of rfm2g_mmap() */
/******************************************************************************
*
* FUNCTION: rfm2g_ioctl
*
* PURPOSE: Entry point for ioctl(2) call.
* PARAMETERS: *inode: (I) Passed in by OS, used for minor number determination
* *filp: Passed in by OS, unused.
* cmd: (I) The ioctl command to be processed
* arg: (IO) Argument to cmd, or return value from command
* RETURNS: 0: Success
* -EINVAL: Invalid parameter or command
* -EFAULT: Failure during command execution
* -ETIMEDOUT: Timed out waiting on an interrupt
* -ENOSYS: Interrupt event not supported by board
* GLOBALS: devname, rfm2gDeviceInfo
*
******************************************************************************/
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
int
rfm2g_ioctl( struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg )
#else
long
rfm2g_ioctl(struct file *filp, unsigned int cmd, unsigned long arg )
#endif
{
static char *me = "rfm2g_ioctl()";
RFM2GCONFIGLINUX *cfg;
RFM2G_UINT8 unit; /* Minor device number,used as index in rfm2gDeviceInfo*/
unsigned long flags=0;
int ret_status = 0;
RFM2G_UINT32 stat;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36)
struct inode *inode = filp->f_dentry->d_inode;
#endif
/* Valid Call? */
if (_IOC_TYPE(cmd) != RFM2G_MAGIC)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s: Exiting %s: invalid ioctl magic num = %d expected %d\n",
devname, me, _IOC_TYPE(cmd), RFM2G_MAGIC);
}
return -ENOTTY;
}
/* Extract the minor number so we know which RFM device to access */
unit = MINOR( inode->i_rdev );
cfg = &(rfm2gDeviceInfo[unit].Config );
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Entering %s\n", devname,
unit, me);
/* Process the ioctl command */
switch( cmd )
{
case IOCTL_RFM2G_GET_CONFIG:
{
RFM2GCONFIG Config;
char *myself = "GET_CONFIG";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* Copy the common stuff over */
Config.NodeId = cfg->NodeId;
Config.BoardId = cfg->BoardId;
Config.Unit = cfg->Unit;
Config.PlxRevision = cfg->PlxRevision;
Config.MemorySize = cfg->MemorySize;
strcpy(Config.Device, cfg->Device);
strcpy(Config.Name, RFM2G_PRODUCT_STRING);
strcpy(Config.DriverVersion, RFM2G_PRODUCT_VERSION);
Config.BoardRevision = cfg->RevisionId;
Config.RevisionId = cfg->PCI.revision;
Config.BuildId = cfg->BuildId;
memcpy(&Config.PciConfig, &cfg->PCI, sizeof(RFM2GPCICONFIG));
/* Read LCSR1 */
Config.Lcsr1 = (RFM2G_UINT32) readl( (char *)(( (RFM2G_ADDR) cfg->pCsRegisters + rfm2g_lcsr )));
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&Config,
sizeof(RFM2GCONFIG) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_SET_LED:
{
ret_status = set_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_LED, "SET_LED");
}
break;
case IOCTL_RFM2G_GET_LED:
{
ret_status = get_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_LED, "GET_LED");
}
break;
case IOCTL_RFM2G_ATOMIC_PEEK:
{
char *myself = "ATOMIC_PEEK";
RFM2GATOMIC Data; /* Info necessary to do the access */
RFM2G_ADDR rfm2gAddr; /* RFM address to read data */
RFM2G_ADDR base; /* Base address of RFM I/O or memory space */
RFM2G_UINT32 maxsize; /* Max size of RFM I/O or memory space */
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBPEEK)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
if( copy_from_user( (void *)&Data, (void *)arg,
sizeof(RFM2GATOMIC) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Validate the data width */
switch( Data.width )
{
case RFM2G_BYTE: break;
case RFM2G_WORD: break;
case RFM2G_LONG: break;
case RFM2G_LONGLONG: /* Not supported, fall thru to default */
default:
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Invalid data width %d\n",
devname, unit, me, Data.width );
}
return( -EINVAL );
}
}
base = (RFM2G_ADDR)cfg->pBaseAddress;
maxsize = cfg->PCI.rfm2gWindowSize - Data.width;
/* Point to the desired offset in Reflective Memory */
rfm2gAddr = base + (RFM2G_ADDR)Data.offset;
/* Make sure we are not out of range */
if( rfm2gAddr > (base + maxsize) )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: offset 0x%X is out of range\n",
devname, unit, me, Data.offset );
}
return( -EINVAL );
}
if( rfm2g_peek( cfg, rfm2gAddr, &(Data.data), Data.width ) != 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: rfm2g_peek() failed\n",
devname, unit, me );
}
return( -EINVAL );
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&Data,
sizeof(RFM2GATOMIC) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_ATOMIC_POKE:
{
char *myself = "ATOMIC_POKE";
RFM2GATOMIC Data; /* Info necessary to do the access */
RFM2G_ADDR rfm2gAddr; /* RFM address to write data */
RFM2G_ADDR base; /* Base address of RFM I/O or memory space */
RFM2G_UINT32 maxsize; /* Max size of RFM I/O or memory space */
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBPOKE)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
if( copy_from_user( (void *)&Data, (void *)arg,
sizeof(RFM2GATOMIC) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Validate the data width */
switch( Data.width )
{
case RFM2G_BYTE: break;
case RFM2G_WORD: break;
case RFM2G_LONG: break;
case RFM2G_LONGLONG: /* Not supported, fall thru to default */
default:
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Invalid data width %d\n",
devname, unit, me, Data.width );
}
return( -EINVAL );
}
}
base = (RFM2G_ADDR)cfg->pBaseAddress;
maxsize = cfg->PCI.rfm2gWindowSize - Data.width;
/* Point to the desired offset in Reflective Memory */
rfm2gAddr = base + Data.offset;
/* Make sure we are not out of range */
if( rfm2gAddr > (base + maxsize) )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: offset 0x%X is out of range\n",
devname, unit, me, Data.offset );
}
return( -EINVAL );
}
if( rfm2g_poke( cfg, rfm2gAddr, (void *) &(Data.data), Data.width ) != 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: rfm2g_poke() failed\n",
devname, unit, me );
}
return( -EINVAL );
}
}
break;
case IOCTL_RFM2G_CLEAR_DMA_MMAP_OFFSET:
{
char *myself = "CLEAR_DMA_MMAP_OFFSET";
RFM2GDMAINFO *DmaInfo = (RFM2GDMAINFO*)(filp->private_data);
RFM2G_UINT32 virtAddr = (RFM2G_UINT32) arg;
/* Is this a match for the virtual pointer previously returned by mmap()? */
if (DmaInfo->VirtAddr == virtAddr)
{
DmaInfo->VirtAddr = 0;
DmaInfo->BuffAddr = 0;
WHENDEBUG(RFM2G_DBMMAP)
{
printk(KERN_ERR"%s%d: %s(%s): DMA buffer Virtual Address 0x%0x8 unregistered. pid:%d\n",
devname, unit, me, myself, virtAddr, current->pid );
}
}
else
{
WHENDEBUG(RFM2G_DBMMAP)
{
printk(KERN_ERR"%s%d: %s(%s): DMA buffer Virtual Address 0x%0x8 NOT unregistered. pid:%d\n",
devname, unit, me, myself, virtAddr, current->pid );
}
}
}
break;
case IOCTL_RFM2G_SET_SPECIAL_MMAP_OFFSET:
{
char *myself = "SET_SPECIAL_MMAP_OFFSET";
RFM2GDMAINFO *DmaInfo = (RFM2GDMAINFO*)(filp->private_data);
RFM2G_UINT64 specialOffset = 0;
if( copy_from_user( (void *)&specialOffset, (void *)arg,
sizeof(RFM2G_UINT64) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s(%s): copy_from_user() failed. pid:%d\n",
devname, unit, me, myself, current->pid );
}
return( -EFAULT );
}
/* Which special mmap offset is this? */
if (specialOffset & RFM2G_DMA_MMAP_OFFSET)
{
/* Take the semaphore. This semaphore will normally be given back
inside rfm2g_mmap() */
stat = down_interruptible(rfm2gDeviceInfo[unit].mmapSem);
if (stat != 0)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBMMAP)
{
printk(KERN_ERR"%s%d: Exiting %s:(%s) down interrupted "
"stat %d. pid:%d\n", devname, unit, me, myself, stat, current->pid);
}
return(-EFAULT);
}
DmaInfo->InUseAction = RFM2G_DMA_MMAP_OFFSET;
DmaInfo->BuffAddr = specialOffset & ~((RFM2G_UINT64)RFM2G_DMA_MMAP_OFFSET);
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBMMAP)
{
printk(KERN_ERR"%s%d: %s(%s) Next rfm2g_mmap() will use DMA buffer physaddr 0x%llX. pid:%d\n",
devname, unit, me, myself, DmaInfo->BuffAddr, current->pid);
}
/* Make sure the address is page aligned */
if (DmaInfo->BuffAddr & (PAGE_SIZE-1))
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s(%s): DMA Buffer Physical Address 0x%llX\n",
devname, unit, me, myself, DmaInfo->BuffAddr );
printk(KERN_ERR"%s%d: is not page aligned.. pid:%d\n",
devname, unit, current->pid);
}
/* Give the semaphore */
up(rfm2gDeviceInfo[unit].mmapSem);
return( -EFAULT );
}
}
else if (specialOffset & RFM2G_BAR0_MMAP_OFFSET)
{
DmaInfo->InUseAction = RFM2G_BAR0_MMAP_OFFSET;
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBMMAP)
{
printk(KERN_ERR"%s%d: %s(%s) Next rfm2g_mmap() will use RFM2G_BAR0_MMAP_OFFSET. pid:%d\n",
devname, unit, me, myself, current->pid);
}
}
else if (specialOffset & RFM2G_BAR2_MMAP_OFFSET)
{
DmaInfo->InUseAction = RFM2G_BAR2_MMAP_OFFSET;
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBMMAP)
{
printk(KERN_ERR"%s%d: %s(%s) Next rfm2g_mmap() will use RFM2G_BAR2_MMAP_OFFSET. pid:%d\n",
devname, unit, me, myself, current->pid);
}
}
else
{
DmaInfo->InUseAction = 0;
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s(%s): Unknown special mmap offset flag.. pid:%d\n",
devname, unit, me, myself, current->pid );
}
return( -EFAULT );
}
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s(%s) DMA Buffer Physical Address = 0x%llX. pid:%d\n",
devname, unit, me, myself, DmaInfo->BuffAddr, current->pid );
}
}
break;
case IOCTL_RFM2G_SET_DEBUG_FLAGS:
{
char *myself = "SET_DEBUG_FLAGS";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s, debugflags = 0x%08X\n",
devname, unit, me, myself, (RFM2G_UINT32) arg );
}
rfm2gDebugFlags = (RFM2G_UINT32) arg;
}
break;
case IOCTL_RFM2G_GET_DEBUG_FLAGS:
{
char *myself = "GET_DEBUG_FLAGS";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s, debugflags = 0x%08X\n",
devname, unit, me, myself, rfm2gDebugFlags);
}
/* Copy the debug flags back to the user */
if( copy_to_user( (void *)arg, (void *)&rfm2gDebugFlags,
sizeof(RFM2G_UINT32) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_SEND_EVENT:
{
char *myself = "SEND_EVENT";
RFM2GEVENTINFO event; /* Info needed to send an interrupt */
RFM2G_ADDR rfm2gAddr; /* Base address of RFM memory space */
RFM2G_UINT8 cmd = 0; /* compiled command byte */
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
if( copy_from_user( (void *)&event, (void *)arg,
sizeof(RFM2GEVENTINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Don't allow "self-interrupt", They won't happen */
if( event.NodeId == cfg->NodeId )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s: Exiting %s: self-interrupt attempted\n",
devname, me );
}
return( -EINVAL );
}
rfm2gAddr = (RFM2G_ADDR) cfg->pCsRegisters;
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Write the extended interrupt data */
writel( *( (RFM2G_UINT32 *) &event.ExtendedInfo ), (char *)((rfm2gAddr + rfm2g_ntd)) );
/* Write the target node id */
writeb( (RFM2G_UINT8) event.NodeId, (char *)((rfm2gAddr + rfm2g_ntn)) );
/* Build the interrupt command */
if( event.NodeId == RFM2G_NODE_ALL )
{
cmd = RFM2G_NIC_GLOBAL;
}
switch(event.Event)
{
case RFM2GEVENT_RESET:
cmd |= RFM2G_NIC_RSTREQ;
break;
case RFM2GEVENT_INTR1:
cmd |= RFM2G_NIC_INT1;
break;
case RFM2GEVENT_INTR2:
cmd |= RFM2G_NIC_INT2;
break;
case RFM2GEVENT_INTR3:
cmd |= RFM2G_NIC_INT3;
break;
case RFM2GEVENT_INTR4:
cmd |= RFM2G_NIC_INITINT;
break;
default:
/* Invalid event type */
return( -EINVAL );
}
/* Write the interrupt command */
writeb( *( (RFM2G_UINT8 *) &cmd ), (char *)((rfm2gAddr + rfm2g_nic)) );
mb();
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
}
break;
case IOCTL_RFM2G_ENABLE_EVENT:
{
char *myself = "ENABLE_EVENT";
RFM2GEVENTINFO event;
RFM2GEVENTINFOLINUX eventLinux;
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* See which event the user wants to enable */
if( copy_from_user( (void *)&event, (void *)arg,
sizeof(RFM2GEVENTINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Make sure the interrupt is supported on this board */
switch( event.Event )
{
case RFM2GEVENT_RESET: /* Fall thru */
case RFM2GEVENT_INTR1: /* Fall thru */
case RFM2GEVENT_INTR2: /* Fall thru */
case RFM2GEVENT_INTR3: /* Fall thru */
case RFM2GEVENT_INTR4: /* Fall thru */
case RFM2GEVENT_BAD_DATA: /* Fall thru */
case RFM2GEVENT_RXFIFO_FULL: /* Fall thru */
case RFM2GEVENT_ROGUE_PKT: /* Fall thru */
case RFM2GEVENT_RXFIFO_AFULL: /* Fall thru */
case RFM2GEVENT_SYNC_LOSS: /* Fall thru */
case RFM2GEVENT_MEM_WRITE_INHIBITED: /* Fall thru */
case RFM2GEVENT_LOCAL_MEM_PARITY_ERR: /* Fall thru */
/* These interrupt events are valid for all boards */
break;
default:
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: Interrupt %d is "
"invalid\n", devname, unit, me, event.Event );
}
return( -EINVAL );
break;
}
/* Enable the interrupt */
eventLinux.Unit = unit;
eventLinux.ExtendedInfo = event.ExtendedInfo;
eventLinux.NodeId = event.NodeId;
eventLinux.Timeout = event.Timeout;
eventLinux.Event = event.Event;
switch( EnableInterrupt(&eventLinux, RFM2G_FALSE) )
{
case 0:
/* The interrupt was successfully enabled */
break;
case -1:
/* This interrupt has already been enabled */
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: EnableInterrupt() "
"failed\n", devname, unit, me );
}
return( -EACCES );
break;
default:
/* Some other error occured */
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: EnableInterrupt() "
"failed\n", devname, unit, me );
}
return( -EFAULT );
break;
}
}
break;
case IOCTL_RFM2G_DISABLE_EVENT:
{
char *myself = "DISABLE_EVENT";
RFM2GEVENTINFO event;
RFM2GEVENTINFOLINUX eventLinux;
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* See which event the user wants to disable */
if( copy_from_user( (void *)&event, (void *)arg,
sizeof(RFM2GEVENTINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Make sure the interrupt is supported on this board */
switch( event.Event )
{
case RFM2GEVENT_RESET: /* Fall thru */
case RFM2GEVENT_INTR1: /* Fall thru */
case RFM2GEVENT_INTR2: /* Fall thru */
case RFM2GEVENT_INTR3: /* Fall thru */
case RFM2GEVENT_INTR4: /* Fall thru */
case RFM2GEVENT_BAD_DATA: /* Fall thru */
case RFM2GEVENT_RXFIFO_FULL: /* Fall thru */
case RFM2GEVENT_ROGUE_PKT: /* Fall thru */
case RFM2GEVENT_RXFIFO_AFULL: /* Fall thru */
case RFM2GEVENT_SYNC_LOSS: /* Fall thru */
case RFM2GEVENT_MEM_WRITE_INHIBITED: /* Fall thru */
case RFM2GEVENT_LOCAL_MEM_PARITY_ERR: /* Fall thru */
/* These interrupt events are valid for all boards */
break;
default:
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: Interrupt %d is "
"invalid\n", devname, unit, me, event.Event );
}
return( -EINVAL );
break;
}
/* Disable the interrupt */
eventLinux.Unit = unit;
eventLinux.ExtendedInfo = event.ExtendedInfo;
eventLinux.NodeId = event.NodeId;
eventLinux.Timeout = event.Timeout;
eventLinux.Event = event.Event;
switch( DisableInterrupt(&eventLinux, RFM2G_FALSE) )
{
case 0:
/* The interrupt was successfully disabled */
break;
case -1:
/* This interrupt was not already enabled */
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: DisableInterrupt() "
"failed\n", devname, unit, me );
}
return( -EACCES );
break;
case -2: /* Fall thru */
default:
/* Some other error occured */
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: DisableInterrupt() "
"failed\n", devname, unit, me );
}
return( -EFAULT );
break;
}
}
break;
case IOCTL_RFM2G_GET_EVENT_STATS:
{
char *myself = "GET_EVENT_STATS";
rfm2gEventQueueHeader_t *qhead;
RFM2GQINFO qinfo;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* Read the RFM2GQINFO structure because we need the event number */
if( copy_from_user( (void *)&qinfo, (void *)arg,
sizeof(RFM2GQINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Gather the stats */
qhead = &(rfm2gDeviceInfo[unit].EventQueue[qinfo.Event].req_header);
qinfo.Overflowed = qhead->reqh_flags & QUEUE_OVERFLOW;
qinfo.EventCount = qhead->reqh_counter;
qinfo.EventsQueued = qhead->reqh_size;
qinfo.QueueSize = qhead->reqh_maxSize;
qinfo.MaxQueueSize = qhead->reqh_maxSize;
qinfo.EventTimeout = qhead->reqh_timeout;
qinfo.QueuePeak = qhead->reqh_qpeak;
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&qinfo,
sizeof(RFM2GQINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s: Exiting %s: copy_to_user() failed\n",
devname, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_WAIT_FOR_EVENT:
{
int iStatus = 0;
char *myself = "WAIT_FOR_EVENT";
RFM2GEVENTINFO event; /* Storage for received interrupt info */
RFM2GEVENTINFOLINUX eventLinux;
RFM2G_INT32 status = 0;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
if( copy_from_user( (void *)&event, (void *)arg,
sizeof(RFM2GEVENTINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk( KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
eventLinux.Unit = unit;
eventLinux.ExtendedInfo = event.ExtendedInfo;
eventLinux.NodeId = event.NodeId;
eventLinux.Timeout = event.Timeout;
eventLinux.Event = event.Event;
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
status = WaitForInterrupt( &eventLinux, flags );
switch( status )
{
case -ETIMEDOUT:
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: WaitForInterrupt() "
"Timed out waiting\n", devname, unit, me );
}
/* Timed out waiting for interrupt */
iStatus = -ETIMEDOUT;
break;
case -EALREADY:
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: WaitForInterrupt() "
"Notification already requested\n", devname, unit, me );
}
/* Notification was already requested for this event */
iStatus = -EALREADY;
break;
case -ENOSYS:
/* This interrupt was not already enabled */
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: WaitForInterrupt() "
"failed\n", devname, unit, me );
}
iStatus = -ENOSYS;
break;
case -EIDRM:
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: WaitForInterrupt() "
"canceled\n", devname, unit, me );
}
iStatus = -EIDRM;
break;
case -EINTR:
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: WaitForInterrupt() "
"Signal\n", devname, unit, me );
}
iStatus = -EINTR;
break;
}
/* Leave if any errors returned. */
if (iStatus != 0)
return(iStatus);
/*****************************/
/* We received the interrupt */
/*****************************/
/* Copy info about the received interrupt back to the user */
event.ExtendedInfo = eventLinux.ExtendedInfo;
event.NodeId = eventLinux.NodeId;
event.Timeout = eventLinux.Timeout;
event.Event = eventLinux.Event;
if( copy_to_user( (void *)arg, (void *)&event,
sizeof(RFM2GEVENTINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_CANCEL_EVENT:
{
char *myself = "CANCEL_EVENT";
RFM2GEVENTINFO event;
RFM2GEVENTINFOLINUX eventLinux;
int CancelIntStatus;
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* See which event the user wants to cancel */
if( copy_from_user( (void *)&event, (void *)arg,
sizeof(RFM2GEVENTINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Wake up any sleeping process */
eventLinux.Unit = unit;
eventLinux.ExtendedInfo = event.ExtendedInfo;
eventLinux.NodeId = event.NodeId;
eventLinux.Timeout = event.Timeout;
eventLinux.Event = event.Event;
CancelIntStatus = CancelInterrupt( &eventLinux, RFM2G_FALSE );
switch( CancelIntStatus )
{
case 0: /* No errors */
break;
case -1: /* Interrupt was not already enabled */
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: CancelInterrupt() "
"failed\n", devname, unit, me );
}
return( -ENOSYS );
break;
default: /* Fall thru */
case -2: /* CancelInterrupt() failed for some misc reason */
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: CancelInterrupt() "
"failed\n", devname, unit, me );
}
return( -EFAULT );
break;
}
}
break;
case IOCTL_RFM2G_CLEAR_EVENT_COUNT:
{
char *myself = "CLEAR_EVENT_COUNT";
rfm2gEventQueueHeader_t *qhead;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s, unit = %d, queue = %d\n",
devname, unit, me, myself, unit, (int)arg );
}
/* Validate the interrupt type number */
if( (arg >= RFM2GEVENT_LAST) )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Invalid interrupt queue %d\n",
devname, unit, me, (int)arg );
}
return( -EINVAL );
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Clear the event counter for this unit */
qhead = &( rfm2gDeviceInfo[unit].EventQueue[arg].req_header );
qhead->reqh_counter = 0;
qhead->reqh_qpeak = qhead->reqh_size;
mb();
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
}
break;
case IOCTL_RFM2G_CLEAR_EVENT_STATS:
{
char *myself = "CLEAR_EVENT_STATS";
rfm2gEventQueueHeader_t *qhead;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s, unit = %d, queue = %d\n",
devname, unit, me, myself, unit, (int)arg );
}
/* Validate the interrupt type number */
if( (arg >= RFM2GEVENT_LAST) )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Invalid interrupt queue %d\n",
devname, unit, me, (int)arg );
}
return( -EINVAL );
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Clear the event counter for this unit */
qhead = &( rfm2gDeviceInfo[unit].EventQueue[arg].req_header );
qhead->reqh_counter = 0;
qhead->reqh_qpeak = qhead->reqh_size;
mb();
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
}
break;
case IOCTL_RFM2G_CHECK_RING_CONT:
{
char *myself = "CHECK_RING_CONT";
RFM2G_ADDR csRegs; /* Base address of RFM cs register space */
RFM2G_ADDR temp; /* Value read/written to registers */
RFM2G_BOOL found = RFM2G_FALSE;
int i;
csRegs = (RFM2G_ADDR)cfg->pCsRegisters;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Clear the own data bit */
temp = readl( (char *)(csRegs + rfm2g_lcsr) );
temp &= ~RFM2G_LCSR_OWNDATA;
writel(temp, (char *)(csRegs + rfm2g_lcsr) );
/* Now use one of the "reserved" ints to send a packet around the ring */
/* Write the target node id */
writeb( (RFM2G_UINT8)(cfg->NodeId), (char *)(csRegs + rfm2g_ntn) );
/* Write the interrupt command */
writeb( (RFM2G_UINT8)RFM2G_NIC_RSVD, (char *)(csRegs + rfm2g_nic) );
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
/* Now we wait until the OWNDATA bit is set or we timeout (try for 2 second) */
for (i=200; i>=0; i-=4)
{
/* See if OWNDATA got set */
temp = readl( (char *)(csRegs + rfm2g_lcsr) );
if (temp & RFM2G_LCSR_OWNDATA)
{
/* Got it, get out of here */
found = RFM2G_TRUE;
break;
}
/* Delay for 10000 us */
udelay(10000);
}
/* did our OWNDATA bit get set? */
if (!found)
return( -EFAULT );
}
break;
case IOCTL_RFM2G_GET_DMA_THRESHOLD:
{
char *myself = "GET_DMA_THRESHOLD";
RFM2GDMAINFO *DmaInfo = (RFM2GDMAINFO*)(filp->private_data);
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s, Threshold = %u\n",
devname, unit, me, myself, DmaInfo->Threshold );
}
/* see if DMA is supported for this board */
if (!(cfg->Capabilities & RFM2G_SUPPORTS_DMA))
{
return( -ENOSYS);
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&DmaInfo->Threshold,
sizeof(RFM2G_UINT32) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_SET_DMA_THRESHOLD:
{
char *myself = "SET_DMA_THRESHOLD";
RFM2GDMAINFO *DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname,
unit, me, myself);
}
/* see if DMA is supported for this board */
if (!(cfg->Capabilities & RFM2G_SUPPORTS_DMA))
{
return( -ENOSYS);
}
/* Copy the data back to the user */
if( copy_from_user( (void *)&DmaInfo->Threshold, (void *)arg,
sizeof(RFM2G_UINT32) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s Threshold = %d\n", devname,
unit, me, myself, DmaInfo->Threshold);
}
}
break;
case IOCTL_RFM2G_SET_DARK_ON_DARK:
{
ret_status = set_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_DOD, "SET_DARK_ON_DARK");
}
break;
case IOCTL_RFM2G_GET_DARK_ON_DARK:
{
ret_status = get_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_DOD, "GET_DARK_ON_DARK");
}
break;
case IOCTL_RFM2G_SET_TRANSMIT_DISABLE:
{
ret_status = set_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_XMTDIS, "SET_TRANSMIT_DISABLE");
}
break;
case IOCTL_RFM2G_GET_TRANSMIT_DISABLE:
{
ret_status = get_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_XMTDIS, "GET_TRANSMIT_DISABLE");
}
break;
case IOCTL_RFM2G_SET_LOOPBACK:
{
ret_status = set_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_LOOP, "SET_LOOPBACK");
}
break;
case IOCTL_RFM2G_GET_LOOPBACK:
{
ret_status = get_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_LOOP, "GET_LOOPBACK");
}
break;
case IOCTL_RFM2G_SET_PARITY_ENABLE:
{
ret_status = set_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_PTY, "SET_PARITY_ENABLE");
}
break;
case IOCTL_RFM2G_GET_PARITY_ENABLE:
{
ret_status = get_lcsr_bit(cfg, cmd, arg, RFM2G_LCSR_PTY, "GET_PARITY_ENABLE");
}
break;
case IOCTL_RFM2G_SET_MEMORY_OFFSET:
{
char *myself = "SET_MEMORY_WINDOW";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* Offset 1 and Offset 0 When the host PCI system writes to the on-board
memory and initiates a packet over the network, Offset 1 and Offset 0 will
apply an offset to the network address as it is sent or received over the
network.
Offset 1 Offset 0 Offset Applied
0 0 0
0 1 $4000000
1 0 $8000000
1 1 $C000000
*/
switch(arg)
{
case RFM2G_MEM_OFFSET0:
/* 0 0 0 */
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_FALSE, RFM2G_LCSR_OFF0, "SET_MEMORY_WINDOW");
if (ret_status == 0)
{
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_FALSE, RFM2G_LCSR_OFF1, "SET_MEMORY_WINDOW");
}
break;
case RFM2G_MEM_OFFSET1:
/* 0 1 $4000000 */
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_TRUE, RFM2G_LCSR_OFF0, "SET_MEMORY_WINDOW");
if (ret_status == 0)
{
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_FALSE, RFM2G_LCSR_OFF1, "SET_MEMORY_WINDOW");
}
break;
case RFM2G_MEM_OFFSET2:
/* 1 0 $8000000 */
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_FALSE, RFM2G_LCSR_OFF0, "SET_MEMORY_WINDOW");
if (ret_status == 0)
{
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_TRUE, RFM2G_LCSR_OFF1, "SET_MEMORY_WINDOW");
}
break;
case RFM2G_MEM_OFFSET3:
/* 1 1 $C000000 */
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_TRUE, RFM2G_LCSR_OFF0, "SET_MEMORY_WINDOW");
if (ret_status == 0)
{
ret_status = set_lcsr_bit(cfg, cmd, RFM2G_TRUE, RFM2G_LCSR_OFF1, "SET_MEMORY_WINDOW");
}
break;
default:
return( -EINVAL );
}
}
break;
case IOCTL_RFM2G_GET_MEMORY_OFFSET:
{
RFM2G_MEM_OFFSETTYPE offset;
RFM2G_UINT32 temp; /* Value read from LCSR */
char *myself = "GET_MEMORY_OFFSET";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Get current contents of LCSR */
temp = readl( (char *)((RFM2G_ADDR) ( cfg->pCsRegisters + rfm2g_lcsr )));
switch (temp & (RFM2G_LCSR_OFF0 | RFM2G_LCSR_OFF1))
{
case 0:
offset = RFM2G_MEM_OFFSET0;
break;
case RFM2G_LCSR_OFF0:
offset = RFM2G_MEM_OFFSET1;
break;
case RFM2G_LCSR_OFF1:
offset = RFM2G_MEM_OFFSET2;
break;
case (RFM2G_LCSR_OFF0 | RFM2G_LCSR_OFF1):
offset = RFM2G_MEM_OFFSET3;
break;
default:
return( -EFAULT );
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&offset,
sizeof(RFM2G_MEM_OFFSETTYPE) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, cfg->Unit, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_SET_SLIDING_WINDOW_OFFSET:
{
char *myself = "SET_SLIDING_WINDOW_OFFSET";
RFM2G_UINT32 temp;
RFM2G_ADDR orbase = (RFM2G_ADDR)cfg->pOrRegisters; /* Base address
of RFM's or space */
/* Store the current sliding window offset */
cfg->SlidingWindowOffset = (RFM2G_UINT32) arg;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s, Sliding Window offset = 0x%08X\n",
devname, unit, me, myself, (RFM2G_UINT32) arg );
}
/* Set the current sliding window offset */
writel((cfg->SlidingWindowOffset | RFMOR_LAS1BA_ENABLE_LAS1),
(char *)(orbase + rfmor_las1ba));
/* Read the value back to to flush the previous write */
temp = readl((char *)(orbase + rfmor_las1ba));
}
break;
case IOCTL_RFM2G_CLEAR_OWN_DATA:
{
char *myself = "CLEAR_OWN_DATA";
RFM2G_ADDR csRegs; /* Base address of RFM cs register space */
RFM2G_UINT32 temp; /* Value read/written to registers */
RFM2G_UINT8 found = RFM2G_FALSE;
csRegs = (RFM2G_ADDR)cfg->pCsRegisters;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* See if OWNDATA set */
temp = readl( (char *)(csRegs + rfm2g_lcsr) );
if (temp & RFM2G_LCSR_OWNDATA)
{
found = RFM2G_TRUE;
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&found,
sizeof(RFM2G_UINT8) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Clear the own data bit */
temp = readl( (char *)(csRegs + rfm2g_lcsr) );
temp &= ~RFM2G_LCSR_OWNDATA;
writel(temp, (char *)(csRegs + rfm2g_lcsr) );
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
}
break;
case IOCTL_RFM2G_SET_PCI_COMPATIBILITY:
{
RFM2G_UINT8 *pRfm2g = NULL; /* Temp pointer to RFM control registers */
char *myself = "SET_PCI_COMPATIBILITY";
unsigned int tmp;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Temporarily map the PLX Runtime registers */
pRfm2g = (RFM2G_UINT8 *) ioremap_nocache( cfg->PCI.rfm2gOrBase,
cfg->PCI.rfm2gOrWindowSize );
if( pRfm2g == (RFM2G_UINT8 *) NULL )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk( KERN_ERR"%s:%s ioremap_nocache() failed.\n",
me, devname );
}
return( -ENOMEM );
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
tmp = readl(pRfm2g + rfmor_DmaArb);
tmp &= 0xFEFFFFFF;
writel(tmp, pRfm2g + rfmor_DmaArb);
/* Enable bits 31:28 of LBRD0 register. (Direct Slave Retry Delay Clocks 8*F) */
tmp = readl(pRfm2g + rfmor_lbrd0);
tmp &= 0x0FFFFFFF;
tmp |= 0xF0000000;
writel(tmp, pRfm2g + rfmor_lbrd0);
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
/* Unmap the temporary pointer to the RFM control registers */
if( pRfm2g != (RFM2G_UINT8 *) NULL )
{
iounmap( (void *) pRfm2g );
}
ret_status = 0;
}
break;
//
//james DMA polling mode
//
case IOCTL_RFM2G_WRITE_DMAPOLLING:
{
RFM2GTRANSFER rfm2gTransfer;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
int status;
char *myself = "WRITE";
ret_status = 0;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
if( copy_from_user( (void *)&rfm2gTransfer, (void *)arg,
sizeof(RFM2GTRANSFER) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed \n",
devname, unit, me );
}
return( -EFAULT );
}
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s Length= 0x%X DmaInfo->Threshold = 0x%X DmaInfo->BuffAddr = 0x%llX\n",
devname, unit, me, myself, rfm2gTransfer.Length, DmaInfo->Threshold, DmaInfo->BuffAddr);
}
if (rfm2gTransfer.Length != 0)
{
/* See if DMA needs to be used */
if (IsReadyForDma(unit, (char *)rfm2gTransfer.Buffer, rfm2gTransfer.Length, DmaInfo, &addrAdjust))
{
status = RFM2gDMApolling(cfg, 0x0, DmaInfo->BuffAddr, rfm2gTransfer.Offset,
rfm2gTransfer.Length, addrAdjust);
if (status < 0)
{
return -EFAULT;
}
}
else /* Not using DMA */
{
void *rfm2gPtr;
rfm2gPtr = (void *) ( (RFM2G_ADDR)cfg->pBaseAddress + rfm2gTransfer.Offset );
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((rfm2gTransfer.Offset + rfm2gTransfer.Length) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Get the data from the user */
if( copy_from_user(rfm2gPtr, (void *) rfm2gTransfer.Buffer, rfm2gTransfer.Length) != 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed 1\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
}
}
break;
// james and cg end DMA polling mode, wait for end included
case IOCTL_RFM2G_WRITE_DMAPOLLINGWAIT:
{
RFM2GTRANSFER rfm2gTransfer;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
int status;
char *myself = "WRITE";
ret_status = 0;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
if( copy_from_user( (void *)&rfm2gTransfer, (void *)arg,
sizeof(RFM2GTRANSFER) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed \n",
devname, unit, me );
}
return( -EFAULT );
}
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s Length= 0x%X DmaInfo->Threshold = 0x%X DmaInfo->BuffAddr = 0x%llX\n",
devname, unit, me, myself, rfm2gTransfer.Length, DmaInfo->Threshold, DmaInfo->BuffAddr);
}
if (rfm2gTransfer.Length != 0)
{
/* See if DMA needs to be used */
if (IsReadyForDma(unit, (char *)rfm2gTransfer.Buffer, rfm2gTransfer.Length, DmaInfo, &addrAdjust))
{
status = RFM2gDMApollingwaitend(cfg, 0x0, DmaInfo->BuffAddr, rfm2gTransfer.Offset,
rfm2gTransfer.Length, addrAdjust);
if (status < 0)
{
return -EFAULT;
}
}
else /* Not using DMA */
{
void *rfm2gPtr;
rfm2gPtr = (void *) ( (RFM2G_ADDR)cfg->pBaseAddress + rfm2gTransfer.Offset );
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((rfm2gTransfer.Offset + rfm2gTransfer.Length) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Get the data from the user */
if( copy_from_user(rfm2gPtr, (void *) rfm2gTransfer.Buffer, rfm2gTransfer.Length) != 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed 1\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
}
}
break;
// james end DMA polling mode
case IOCTL_RFM2G_WRITE:
{
RFM2GTRANSFER rfm2gTransfer;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
int status;
char *myself = "WRITE";
ret_status = 0;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
if( copy_from_user( (void *)&rfm2gTransfer, (void *)arg,
sizeof(RFM2GTRANSFER) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed \n",
devname, unit, me );
}
return( -EFAULT );
}
if (rfm2gTransfer.Length != 0)
{
/* See if DMA needs to be used */
if (IsReadyForDma(unit, (char *)rfm2gTransfer.Buffer, rfm2gTransfer.Length, DmaInfo, &addrAdjust))
{
status = RFM2gDMA(cfg, 0x0, DmaInfo->BuffAddr, rfm2gTransfer.Offset,
rfm2gTransfer.Length, addrAdjust);
if (status < 0)
{
return -EFAULT;
}
}
else /* Not using DMA */
{
void *rfm2gPtr;
rfm2gPtr = (void *) ( (RFM2G_ADDR)cfg->pBaseAddress + rfm2gTransfer.Offset );
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((rfm2gTransfer.Offset + rfm2gTransfer.Length) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Get the data from the user */
if( copy_from_user(rfm2gPtr, (void *) rfm2gTransfer.Buffer, rfm2gTransfer.Length) != 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed 1\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
}
}
break;
case IOCTL_RFM2G_WRITE_REG:
{
RFM2GLINUXREGINFO rfm2gLinuxRegInfo;
void* pAddr = NULL;
char *myself = "WRITE_REG";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
ret_status = 0;
if( copy_from_user( (void *)&rfm2gLinuxRegInfo, (void *)arg,
sizeof(RFM2GLINUXREGINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
case RFM2G_WORD:
case RFM2G_LONG:
break;
case RFM2G_LONGLONG: /* Not supported */
default:
return ( -EINVAL );
}
switch(rfm2gLinuxRegInfo.regset)
{
case RFM2GCFGREGIO:
return ( -EINVAL );
break;
case RFM2GCFGREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pOrRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GCTRLREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pCsRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pBaseAddress + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GRESERVED0REG:
return ( -EINVAL );
break;
case RFM2GRESERVED1REG:
return ( -EINVAL );
break;
default:
return ( -EINVAL );
}
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
writeb( (RFM2G_UINT8) rfm2gLinuxRegInfo.Value, (char *)(pAddr) );
break;
case RFM2G_WORD:
writew( (RFM2G_UINT16) rfm2gLinuxRegInfo.Value, (char *)(pAddr) );
break;
case RFM2G_LONG:
writel( (RFM2G_UINT32) rfm2gLinuxRegInfo.Value, (char *)(pAddr) );
break;
case RFM2G_LONGLONG: /* Not supported */
default:
return ( -EINVAL );
}
mb();
}
break;
case IOCTL_RFM2G_SET_REG:
{
RFM2GLINUXREGINFO rfm2gLinuxRegInfo;
void* pAddr = NULL;
char *myself = "SET_REG";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
ret_status = 0;
if( copy_from_user( (void *)&rfm2gLinuxRegInfo, (void *)arg,
sizeof(RFM2GLINUXREGINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
case RFM2G_WORD:
case RFM2G_LONG:
break;
case RFM2G_LONGLONG: /* Not supported */
default:
return ( -EINVAL );
}
switch(rfm2gLinuxRegInfo.regset)
{
case RFM2GCFGREGIO:
return ( -EINVAL );
break;
case RFM2GCFGREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pOrRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GCTRLREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pCsRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pBaseAddress + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GRESERVED0REG:
return ( -EINVAL );
break;
case RFM2GRESERVED1REG:
return ( -EINVAL );
break;
default:
return ( -EINVAL );
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk( KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
{
RFM2G_UINT8 temp;
temp = readb( (char *)(pAddr) );
temp |= (RFM2G_UINT8) rfm2gLinuxRegInfo.Value;
writeb( temp, (char *)(pAddr) );
}
break;
case RFM2G_WORD:
{
RFM2G_UINT16 temp;
temp = readw( (char *)(pAddr) );
temp |= (RFM2G_UINT16) rfm2gLinuxRegInfo.Value;
writew( temp, (char *)(pAddr) );
}
break;
case RFM2G_LONG:
{
RFM2G_UINT32 temp;
temp = readl( (char *)(pAddr) );
temp |= (RFM2G_UINT32) rfm2gLinuxRegInfo.Value;
writel( temp, (char *)(pAddr) );
}
break;
case RFM2G_LONGLONG: /* Not supported */
default:
/* This should have been caught above, but in case we get here,
release the lock */
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, cfg->Unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
return ( -EINVAL );
}
mb();
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, cfg->Unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
}
break;
case IOCTL_RFM2G_CLEAR_REG:
{
RFM2GLINUXREGINFO rfm2gLinuxRegInfo;
void* pAddr = NULL;
char *myself = "CLEAR_REG";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
ret_status = 0;
if( copy_from_user( (void *)&rfm2gLinuxRegInfo, (void *)arg,
sizeof(RFM2GLINUXREGINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
case RFM2G_WORD:
case RFM2G_LONG:
break;
case RFM2G_LONGLONG: /* Not supported */
default:
return ( -EINVAL );
}
switch(rfm2gLinuxRegInfo.regset)
{
case RFM2GCFGREGIO:
return ( -EINVAL );
break;
case RFM2GCFGREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pOrRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GCTRLREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pCsRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pBaseAddress + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GRESERVED0REG:
return ( -EINVAL );
break;
case RFM2GRESERVED1REG:
return ( -EINVAL );
break;
default:
return ( -EINVAL );
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk( KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
{
RFM2G_UINT8 temp;
temp = readb( (char *)(pAddr) );
temp &= ~((RFM2G_UINT8) rfm2gLinuxRegInfo.Value);
writeb( temp, (char *)(pAddr) );
}
break;
case RFM2G_WORD:
{
RFM2G_UINT16 temp;
temp = readw( (char *)(pAddr) );
temp &= ~((RFM2G_UINT16) rfm2gLinuxRegInfo.Value);
writew( temp, (char *)(pAddr) );
}
break;
case RFM2G_LONG:
{
RFM2G_UINT32 temp;
temp = readl( (char *)(pAddr) );
temp &= ~((RFM2G_UINT32) rfm2gLinuxRegInfo.Value);
writel( temp, (char *)(pAddr) );
}
break;
case RFM2G_LONGLONG: /* Not supported */
default:
/* This should have been caught above, but in case we get here,
release the lock */
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, cfg->Unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
return ( -EINVAL );
}
mb();
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, cfg->Unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
}
break;
// james DMA polling
case IOCTL_RFM2G_READ_DMAPOLLING:
{
RFM2GTRANSFER rfm2gTransfer;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
int status;
char *myself = "READ";
ret_status = 0;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
if( copy_from_user( (void *)&rfm2gTransfer, (void *)arg,
sizeof(RFM2GTRANSFER) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed \n",
devname, unit, me );
}
return( -EFAULT );
}
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s Length= 0x%X DmaInfo->Threshold = 0x%X DmaInfo->BuffAddr = 0x%llX\n",
devname, unit, me, myself, rfm2gTransfer.Length, DmaInfo->Threshold, DmaInfo->BuffAddr);
}
if (rfm2gTransfer.Length != 0)
{
/* See if DMA needs to be used */
if (IsReadyForDma(unit, (char *)rfm2gTransfer.Buffer, rfm2gTransfer.Length, DmaInfo, &addrAdjust))
{
status = RFM2gDMApolling(cfg, RFMOR_DMAPTR_TO_PCI, DmaInfo->BuffAddr, rfm2gTransfer.Offset,
rfm2gTransfer.Length, addrAdjust);
if (status < 0)
{
return -EFAULT;
}
}
else /* Not using DMA */
{
void *rfm2gPtr;
rfm2gPtr = (void *) ( (RFM2G_ADDR)cfg->pBaseAddress + rfm2gTransfer.Offset );
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((rfm2gTransfer.Offset + rfm2gTransfer.Length) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Send the data to the user */
if( copy_to_user(rfm2gTransfer.Buffer, rfm2gPtr, rfm2gTransfer.Length) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
}
}
break;
// james end DMA polling
// james and cg DMA polling, waiting for DMA end
case IOCTL_RFM2G_READ_DMAPOLLINGWAIT:
{
RFM2GTRANSFER rfm2gTransfer;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
int status;
char *myself = "READ";
ret_status = 0;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
if( copy_from_user( (void *)&rfm2gTransfer, (void *)arg,
sizeof(RFM2GTRANSFER) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed \n",
devname, unit, me );
}
return( -EFAULT );
}
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s Length= 0x%X DmaInfo->Threshold = 0x%X DmaInfo->BuffAddr = 0x%llX\n",
devname, unit, me, myself, rfm2gTransfer.Length, DmaInfo->Threshold, DmaInfo->BuffAddr);
}
if (rfm2gTransfer.Length != 0)
{
/* See if DMA needs to be used */
if (IsReadyForDma(unit, (char *)rfm2gTransfer.Buffer, rfm2gTransfer.Length, DmaInfo, &addrAdjust))
{
status = RFM2gDMApollingwaitend(cfg, RFMOR_DMAPTR_TO_PCI, DmaInfo->BuffAddr, rfm2gTransfer.Offset,
rfm2gTransfer.Length, addrAdjust);
if (status < 0)
{
return -EFAULT;
}
}
else /* Not using DMA */
{
void *rfm2gPtr;
rfm2gPtr = (void *) ( (RFM2G_ADDR)cfg->pBaseAddress + rfm2gTransfer.Offset );
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((rfm2gTransfer.Offset + rfm2gTransfer.Length) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Send the data to the user */
if( copy_to_user(rfm2gTransfer.Buffer, rfm2gPtr, rfm2gTransfer.Length) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
}
}
break;
// james end DMA polling
case IOCTL_RFM2G_READ:
{
RFM2GTRANSFER rfm2gTransfer;
RFM2GDMAINFO *DmaInfo;
RFM2G_UINT32 addrAdjust = 0;
int status;
char *myself = "READ";
ret_status = 0;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Get a pointer to the specified offset */
DmaInfo = (RFM2GDMAINFO *)(filp->private_data);
if( copy_from_user( (void *)&rfm2gTransfer, (void *)arg,
sizeof(RFM2GTRANSFER) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed \n",
devname, unit, me );
}
return( -EFAULT );
}
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s Length= 0x%X DmaInfo->Threshold = 0x%X DmaInfo->BuffAddr = 0x%llX\n",
devname, unit, me, myself, rfm2gTransfer.Length, DmaInfo->Threshold, DmaInfo->BuffAddr);
}
if (rfm2gTransfer.Length != 0)
{
/* See if DMA needs to be used */
if (IsReadyForDma(unit, (char *)rfm2gTransfer.Buffer, rfm2gTransfer.Length, DmaInfo, &addrAdjust))
{
status = RFM2gDMA(cfg, RFMOR_DMAPTR_TO_PCI, DmaInfo->BuffAddr, rfm2gTransfer.Offset,
rfm2gTransfer.Length, addrAdjust);
if (status < 0)
{
return -EFAULT;
}
}
else /* Not using DMA */
{
void *rfm2gPtr;
rfm2gPtr = (void *) ( (RFM2G_ADDR)cfg->pBaseAddress + rfm2gTransfer.Offset );
/* Make sure the offset is within the window size. We don't want the
offset to go beyond the end of any sliding window. */
if ((rfm2gTransfer.Offset + rfm2gTransfer.Length) > cfg->PCI.rfm2gWindowSize)
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: (RFM offset + count) exceeds WindowSize\n",
devname, unit, me );
}
return( -EFAULT );
}
/* Send the data to the user */
if( copy_to_user(rfm2gTransfer.Buffer, rfm2gPtr, rfm2gTransfer.Length) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
mb();
}
}
}
break;
case IOCTL_RFM2G_READ_REG:
{
RFM2GLINUXREGINFO rfm2gLinuxRegInfo;
void* pAddr = NULL;
char *myself = "READ_REG";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
ret_status = 0;
if( copy_from_user( (void *)&rfm2gLinuxRegInfo, (void *)arg,
sizeof(RFM2GLINUXREGINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_from_user() failed\n",
devname, unit, me );
}
return( -EFAULT );
}
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
case RFM2G_WORD:
case RFM2G_LONG:
break;
case RFM2G_LONGLONG: /* Not supported */
default:
return ( -EINVAL );
}
switch(rfm2gLinuxRegInfo.regset)
{
case RFM2GCFGREGIO:
return ( -EINVAL );
break;
case RFM2GCFGREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pOrRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GCTRLREGMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pCsRegisters + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GMEM:
pAddr = (void*) ( (RFM2G_ADDR) cfg->pBaseAddress + rfm2gLinuxRegInfo.Offset);
break;
case RFM2GRESERVED0REG:
return ( -EINVAL );
break;
case RFM2GRESERVED1REG:
return ( -EINVAL );
break;
default:
return ( -EINVAL );
}
switch( rfm2gLinuxRegInfo.Width )
{
case RFM2G_BYTE:
rfm2gLinuxRegInfo.Value = (RFM2G_ADDR) readb( (char *)(pAddr) );
break;
case RFM2G_WORD:
rfm2gLinuxRegInfo.Value = (RFM2G_ADDR) readw( (char *)(pAddr) );
break;
case RFM2G_LONG:
rfm2gLinuxRegInfo.Value = (RFM2G_ADDR) readl( (char *)(pAddr) );
break;
case RFM2G_LONGLONG: /* Not supported */
default:
return ( -EINVAL );
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&rfm2gLinuxRegInfo,
sizeof(RFM2GLINUXREGINFO) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, cfg->Unit, me );
}
return( -EFAULT );
}
}
break;
case IOCTL_RFM2G_FLUSH_QUEUE:
/* Linux specific, obsolete
Clear event will flush the queue and clear the H/W */
case IOCTL_RFM2G_CLEAR_EVENT:
{
char *myself = "CLEAR_EVENT";
RFM2G_UINT32 saved_lisr;
rfm2gEventQueueHeader_t *qhead;
WHENDEBUG(RFM2G_DBIOCTL | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, unit, me, myself);
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
saved_lisr = readl( (char *)(cfg->pCsRegisters + rfm2g_lisr) );
saved_lisr |= RFM2G_LISR_UNUSED; /* Enable Global Interrupt */
switch (arg)
{
case RFM2GEVENT_RESET:
saved_lisr &= ~RFM2G_LISR_RSTREQ;
break;
case RFM2GEVENT_INTR1:
writeb( 0x00, cfg->pCsRegisters + rfm2g_sid1);
break;
case RFM2GEVENT_INTR2:
writeb( 0x00, cfg->pCsRegisters + rfm2g_sid2);
break;
case RFM2GEVENT_INTR3:
writeb( 0x00, cfg->pCsRegisters + rfm2g_sid3);
break;
case RFM2GEVENT_INTR4:
writeb( 0x00, cfg->pCsRegisters + rfm2g_initn);
break;
case RFM2GEVENT_BAD_DATA:
saved_lisr &= ~RFM2G_LISR_BADDATA;
break;
case RFM2GEVENT_RXFIFO_FULL:
saved_lisr &= ~RFM2G_LISR_RXFULL;
break;
case RFM2GEVENT_ROGUE_PKT:
saved_lisr &= ~RFM2G_LISR_ROGUE_PKT;
break;
case RFM2GEVENT_RXFIFO_AFULL:
saved_lisr &= ~RFM2G_LISR_RXAFULL;
break;
case RFM2GEVENT_SYNC_LOSS:
saved_lisr &= ~RFM2G_LISR_SNCLOST;
break;
case RFM2GEVENT_MEM_WRITE_INHIBITED:
saved_lisr &= ~RFM2G_LISR_WRINIB;
break;
case RFM2GEVENT_LOCAL_MEM_PARITY_ERR:
saved_lisr &= ~RFM2G_LISR_PTYERR;
break;
default:
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: Invalid interrupt queue %d\n",
devname, unit, me, (int)arg );
}
return( -EINVAL );
}
writel( saved_lisr, (char *)(cfg->pCsRegisters + rfm2g_lisr) );
/* Flush this event's queue */
qhead = &( rfm2gDeviceInfo[unit].EventQueue[arg].req_header );
qhead->reqh_size = 0;
qhead->reqh_flags &= ~QUEUE_OVERFLOW;
qhead->reqh_qpeak = 0;
qhead->reqh_head = 0;
qhead->reqh_tail = 0;
mb();
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
ret_status = 0;
}
break;
case IOCTL_RFM2G_GET_DMA_BYTESWAP:
{
RFM2G_UINT8 state = (RFM2G_UINT8) cfg->dmaByteSwap;
char *myself = "GET_DMA_BYTESWAP";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&state,
sizeof(RFM2G_UINT8) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, cfg->Unit, me );
}
return( -EFAULT );
}
ret_status = 0;
}
break;
case IOCTL_RFM2G_SET_DMA_BYTE_SWAP:
{
RFM2G_ADDR orbase; /* Base address of RFM's or space */
RFM2G_ADDR temp_reg32;
char *myself = "SET_DMA_BYTE_SWAP";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
orbase = (RFM2G_ADDR) cfg->pOrRegisters;
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk( KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/*
* Setup PLX chip to Byte Swap, This swap only works for long word (4 byte)
* transfers
*/
temp_reg32 = readl( (char *)(orbase + rfmor_endian_desc) );
/*
* Turn on bit 7 in Big/Little Endian Descriptor: BIGEND, Offset $0C PLX chip
*
* Bit 7
*
* DMA Channel 0 Big Endian Mode (Address Invariance). Writing a one (1)
* specifies use of Big Endian data ordering for DMA Channel 0 accesses to the
* Local Address Space. Writing a zero (0) specifies Little Endian ordering.
*/
if (arg != RFM2G_FALSE)
{
temp_reg32 |= 0x80;
cfg->dmaByteSwap = RFM2G_TRUE;
}
else
{
temp_reg32 &= ~0x80;
cfg->dmaByteSwap = RFM2G_FALSE;
}
writel( temp_reg32, (char *)(orbase + rfmor_endian_desc) );
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, cfg->Unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
ret_status = 0;
}
break;
case IOCTL_RFM2G_GET_PIO_BYTESWAP:
{
RFM2G_UINT8 state = (RFM2G_UINT8) cfg->pioByteSwap;
char *myself = "GET_PIO_BYTESWAP";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&state,
sizeof(RFM2G_UINT8) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, cfg->Unit, me );
}
return( -EFAULT );
}
ret_status = 0;
}
break;
case IOCTL_RFM2G_SET_PIO_BYTE_SWAP:
{
RFM2G_ADDR orbase; /* Base address of RFM's or space */
RFM2G_UINT32 temp_reg32;
char *myself = "SET_PIO_BYTE_SWAP";
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n",
devname, unit, me, myself);
}
orbase = (RFM2G_ADDR) cfg->pOrRegisters;
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk( KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/*
* Setup PLX chip to Byte Swap, This swap only works for long word (4 byte)
* transfers
*/
temp_reg32 = readl( (char *)(orbase + rfmor_endian_desc) );
/*
* Turn on bit 5 in Big/Little Endian Descriptor: BIGEND, Offset $0C PLX chip
*
* Bit 5
*
* Direct Slave Address Space 1 Big Endian Mode (Address Invariance).
* Writing a one (1) specifies use of Big Endian data ordering for Direct
* Slave accesses to Local Address Space 1. Writing a zero (0) specifies
* Little Endian ordering.
*/
if (arg != RFM2G_FALSE)
{
temp_reg32 |= 0x20;
cfg->pioByteSwap = RFM2G_TRUE;
}
else
{
temp_reg32 &= ~0x20;
cfg->pioByteSwap = RFM2G_FALSE;
}
writel( temp_reg32, (char *)(orbase + rfmor_endian_desc) );
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, cfg->Unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
ret_status = 0;
}
break;
default:
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: Exiting %s:Invalid ioctl command 0x%x 0x%zx\n",
devname, unit, me, cmd, IOCTL_RFM2G_GET_CONFIG );
}
return( -EINVAL );
}
}
WHENDEBUG(RFM2G_DBTRACE) printk(KERN_ERR"%s%d: Exiting %s\n", devname,
unit, me);
return( ret_status );
} /* End of rfm2g_ioctl() */
static int
get_lcsr_bit(RFM2GCONFIGLINUX *cfg, unsigned int cmd, unsigned long arg, unsigned int bit, char* pDescription )
{
static char *me = "rfm2g_ioctl()";
RFM2G_UINT8 state; /* Current state of the bit */
RFM2G_ADDR rfm2gAddr; /* Base address of RFM memory space */
RFM2G_UINT32 temp; /* Value read from LCSR */
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, cfg->Unit, me, pDescription);
}
/* Point at the RFM board's LCSR Register */
rfm2gAddr = (RFM2G_ADDR) ( cfg->pCsRegisters + rfm2g_lcsr );
/* Get current contents of LCSR */
temp = readl( (char *)(rfm2gAddr));
if( (temp & bit) == 0 )
{
state = 0; /* bit is off */
}
else
{
state = 1; /* bit is on */
}
/* Copy the data back to the user */
if( copy_to_user( (void *)arg, (void *)&state,
sizeof(RFM2G_UINT8) ) > 0 )
{
WHENDEBUG(RFM2G_DBERROR)
{
printk(KERN_ERR"%s%d: Exiting %s: copy_to_user() failed\n",
devname, cfg->Unit, me );
}
return( -EFAULT );
}
return (0);
}
static int
set_lcsr_bit(RFM2GCONFIGLINUX *cfg, unsigned int cmd, unsigned long arg, unsigned int bit, char* pDescription )
{
static char *me = "rfm2g_ioctl()";
RFM2G_ADDR rfm2gAddr; /* Base address of RFM memory space */
RFM2G_UINT32 temp; /* Value read/written to LCSR */
unsigned long flags;
WHENDEBUG(RFM2G_DBIOCTL)
{
printk(KERN_ERR"%s%d: %s cmd = %s\n", devname, cfg->Unit, me, pDescription);
}
/* Point at the RFM board's LCSR Register */
rfm2gAddr = (RFM2G_ADDR) ( cfg->pCsRegisters + rfm2g_lcsr );
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s About to acquire spinlock\n",
devname, cfg->Unit, me);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Get current contents of CSR2 */
temp = readl( (char *)(rfm2gAddr));
if( arg == RFM2G_FALSE )
{
temp &= ~(bit);
}
else
{
temp |= bit;
}
writel( *( (RFM2G_UINT32 *) &temp ), (char *)(rfm2gAddr) );
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, cfg->Unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
return(0);
}
//
//james polling DMA stuff
//
static int
RFM2gDMApolling(RFM2GCONFIGLINUX *cfg, RFM2G_UINT32 dmaDesc, RFM2G_UINT64 pciAddress,
RFM2G_UINT32 rfmOffset, RFM2G_UINT32 count, RFM2G_UINT32 addrAdjust)
{
static char *me = "RFM2gDMApolling()";
RFM2G_ADDR orbase; /* Base address of RFM's or space */
// RFM2GEVENTINFOLINUX event;
// RFM2GEVENTQUEUE_HEADER qheader;
RFM2G_UINT32 temp_reg32;
// unsigned long flags;
RFM2G_UINT32 ChunkSize;
RFM2G_UINT32 AmountSent;
RFM2G_INT32 stat = 0;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
RFM2G_UINT32 pciAddress_Lower, pciAddress_Upper;
RFM2G_UINT32 DMAendpollingreg;
/* Extract the minor number so we know which RFM device to access */
unit = cfg->Unit;
WHENDEBUG(RFM2G_DBREAD)
{
printk(KERN_CRIT"%s%d: %s(james using DMA in polling mode). pid:%d\n", devname, unit, me, current->pid);
}
/* Add the base offset of the current sliding window to the rfmOffset.
This will make the DMA start at the beginning of the sliding window. */
rfmOffset += cfg->SlidingWindowOffset;
/* Make sure this DMA doesn't go off the end of the rfm board */
if ((rfmOffset + count) > cfg->MemorySize)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: Exiting %s: Offset + SlidingWindowOffset + count > MemorySize\n",
devname, unit, me);
}
return -EINVAL;
}
/* initialize event structure for call to WaitForInterrupt() */
// event.ExtendedInfo = 0;
// event.NodeId = 0;
// event.Event = RFM2GEVENT_DMADONE;
// event.Timeout = 8000; //INFINITE_TIMEOUT;
// event.Unit = unit;
// event.Qflags = 0;
orbase = (RFM2G_ADDR)cfg->pOrRegisters;
/* Get a pointer to this interrupt queue header */
// qheader = &rfm2gDeviceInfo[unit].EventQueue[RFM2GEVENT_DMADONE].req_header;
/* See if we have to deal with the PLX errata */
if ( (cfg->PlxRevision < 0xAD) && (count > 0x100) )
{
ChunkSize = 0x100;
}
else
{
ChunkSize = 0x7fff80;
}
// semaphore to enable exclusive access to device
stat = down_interruptible(rfm2gDeviceInfo[unit].DMASem);
if (stat != 0)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: down interrupted, "
"stat %d, pid:%d\n", devname, unit, me, stat, current->pid);
}
return(-2);
}
for ( AmountSent = 0; (AmountSent < count) && (stat==0); AmountSent += ChunkSize)
{
/* Check for short remainder */
if ( ChunkSize > (count - AmountSent) )
{
ChunkSize = count - AmountSent;
}
// /* Acquire lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk( KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
// devname, unit, me, current->pid);
// }
// spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
// /* Stop now if this interrupt is already enabled */
// if( qheader->reqh_flags & EVENT_ENABLED )
// {
// /* Release lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
// }
// spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
//
// WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
// {
// printk(KERN_ERR"%s%d: Exiting %s: Interrupt already enabled, "
// "event %d\n", devname, unit, me, event.Event);
// }
// up(rfm2gDeviceInfo[unit].DMASem);
// return(-2);
// }
/* Set PCI Address */
pciAddress_Lower = (RFM2G_UINT32)((pciAddress + addrAdjust + AmountSent) & 0xFFFFFFFF);
pciAddress_Upper = (RFM2G_UINT32)((pciAddress + addrAdjust + AmountSent) >> 32);
writel( pciAddress_Lower, (char *)(orbase + rfmor_DmaPciAddr0) );
writel( pciAddress_Upper, (char *)(orbase + rfmor_DmaDac0) );
/* James verify previous transfer is complete */
temp_reg32 = readl( (char *)(orbase + rfmor_Dma0Csr) );
if (!((temp_reg32 & 0x10) >> 4))
{
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s Previous transfer NOT Co\n", devname, unit, me);
}
return(-2);
}
// james clear transfer complete reg
writel( RFMOR_DMACSR_CLEAR_INT, (char *)(orbase + rfmor_Dma0Csr) );
wmb(); // james.. linux kernel function. insert hardware memory barrier. guarantees ordering in write memory operations.
/* PCI registers */
/* Setup DMA Mode register */
writel( (RFMOR_DMAMODE_32BIT_BUS |
RFMOR_DMAMODE_TA_READY |
RFMOR_DMAMODE_BTERM |
RFMOR_DMAMODE_LOCAL_BURST |
RFMOR_DMAMODE_DONE_INT_OFF |
RFMOR_DMAMODE_INT_TO_PCI_OFF), (char *)(orbase + rfmor_DmaMode0) );
/* Set Transfer Byte Count */
writel( ChunkSize, (char *)(orbase + rfmor_DmaCount0) );
/* Set initiator address */
writel( (rfmOffset + AmountSent), (char *)(orbase + rfmor_DmaLocAddr0) );
/* Enable from RFM to PC or PC to RFM based on value in dmaDesc */
writel( dmaDesc, (char *)(orbase + rfmor_DmaPtr0) );
/* Enable DMA Done Interrupt */
/* Now enable the interrupt */
// temp_reg32 = readl( (char *)(orbase + rfmor_intcsr) );
// temp_reg32 |= RFMOR_INTCSR_ENABLEDMA0INT;
// temp_reg32 |= RFMOR_INTCSR_ENABLEINT;
// writel( temp_reg32, (char *)(orbase + rfmor_intcsr) );
///
// qheader->reqh_flags |= EVENT_ENABLED;
// (cfg->IntrCount)++;
wmb(); // james.. linux kernel function. insert hardware memory barrier. guarantees ordering in write memory operations.
/* Definitions of the rfmor_DmaCsr register */
//#define RFMOR_DMACSR_ENABLE (1<<0)
//#define RFMOR_DMACSR_START (1<<1)
//#define RFMOR_DMACSR_CLEAR_INT (1<<3)
/* Initiate DMA transfer */
writeb( (RFMOR_DMACSR_ENABLE | RFMOR_DMACSR_START),
(char *)(orbase + rfmor_Dma0Csr) );
//WHENDEBUG(RFM2G_DBREAD)
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_CRIT"%s%d: %s DMA started! pid:%d\n",
devname, unit, me , current->pid );
}
// /* Wait here until interrupt occurs */
// stat = WaitForInterrupt( &event, flags );
/* Acquire lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk( KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
// devname, unit, me, current->pid);
// }
// spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
//
// qheader->reqh_flags = 0;
// (cfg->IntrCount)--;
// /* Release lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk(KERN_ERR"%s%d: %s Releasing lock. pid:%d\n", devname, unit, me, current->pid);
// }
// spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
// if(stat !=0 )
// {
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk(KERN_ERR"%s%d: %s Aborted. pid:%d\n", devname, unit, me, current->pid);
// }
// up(rfm2gDeviceInfo[unit].DMASem);
// return( -EINTR);
// }
}
up(rfm2gDeviceInfo[unit].DMASem);
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_CRIT"%s%d: %s(james just finished DMA function). pid:%d\n", devname, unit, me, current->pid);
}
return (count);
}
// end james polling DMA stuff
//
//james polling DMA stuff, LucaB DMA end register polling code added
//
static int
RFM2gDMApollingwaitend(RFM2GCONFIGLINUX *cfg, RFM2G_UINT32 dmaDesc, RFM2G_UINT64 pciAddress,
RFM2G_UINT32 rfmOffset, RFM2G_UINT32 count, RFM2G_UINT32 addrAdjust)
{
static char *me = "RFM2gDMApollingwaitend()";
RFM2G_ADDR orbase; /* Base address of RFM's or space */
// RFM2GEVENTINFOLINUX event;
// RFM2GEVENTQUEUE_HEADER qheader;
RFM2G_UINT32 temp_reg32;
// unsigned long flags;
RFM2G_UINT32 ChunkSize;
RFM2G_UINT32 AmountSent;
RFM2G_INT32 stat = 0;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
RFM2G_UINT32 pciAddress_Lower, pciAddress_Upper;
RFM2G_UINT32 DMAendpollingreg;
/* Extract the minor number so we know which RFM device to access */
unit = cfg->Unit;
WHENDEBUG(RFM2G_DBREAD)
{
printk(KERN_CRIT"%s%d: %s(james using DMA in polling mode). pid:%d\n", devname, unit, me, current->pid);
}
/* Add the base offset of the current sliding window to the rfmOffset.
This will make the DMA start at the beginning of the sliding window. */
rfmOffset += cfg->SlidingWindowOffset;
/* Make sure this DMA doesn't go off the end of the rfm board */
if ((rfmOffset + count) > cfg->MemorySize)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: Exiting %s: Offset + SlidingWindowOffset + count > MemorySize\n",
devname, unit, me);
}
return -EINVAL;
}
/* initialize event structure for call to WaitForInterrupt() */
// event.ExtendedInfo = 0;
// event.NodeId = 0;
// event.Event = RFM2GEVENT_DMADONE;
// event.Timeout = 8000; //INFINITE_TIMEOUT;
// event.Unit = unit;
// event.Qflags = 0;
orbase = (RFM2G_ADDR)cfg->pOrRegisters;
/* Get a pointer to this interrupt queue header */
// qheader = &rfm2gDeviceInfo[unit].EventQueue[RFM2GEVENT_DMADONE].req_header;
/* See if we have to deal with the PLX errata */
if ( (cfg->PlxRevision < 0xAD) && (count > 0x100) )
{
ChunkSize = 0x100;
}
else
{
ChunkSize = 0x7fff80;
}
// semaphore to enable exclusive access to device
stat = down_interruptible(rfm2gDeviceInfo[unit].DMASem);
if (stat != 0)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: down interrupted, "
"stat %d, pid:%d\n", devname, unit, me, stat, current->pid);
}
return(-2);
}
for ( AmountSent = 0; (AmountSent < count) && (stat==0); AmountSent += ChunkSize)
{
/* Check for short remainder */
if ( ChunkSize > (count - AmountSent) )
{
ChunkSize = count - AmountSent;
}
// /* Acquire lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk( KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
// devname, unit, me, current->pid);
// }
// spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
// /* Stop now if this interrupt is already enabled */
// if( qheader->reqh_flags & EVENT_ENABLED )
// {
// /* Release lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
// }
// spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
//
// WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
// {
// printk(KERN_ERR"%s%d: Exiting %s: Interrupt already enabled, "
// "event %d\n", devname, unit, me, event.Event);
// }
// up(rfm2gDeviceInfo[unit].DMASem);
// return(-2);
// }
/* Set PCI Address */
pciAddress_Lower = (RFM2G_UINT32)((pciAddress + addrAdjust + AmountSent) & 0xFFFFFFFF);
pciAddress_Upper = (RFM2G_UINT32)((pciAddress + addrAdjust + AmountSent) >> 32);
writel( pciAddress_Lower, (char *)(orbase + rfmor_DmaPciAddr0) );
writel( pciAddress_Upper, (char *)(orbase + rfmor_DmaDac0) );
/* James verify previous transfer is complete */
temp_reg32 = readl( (char *)(orbase + rfmor_Dma0Csr) );
if (!((temp_reg32 & 0x10) >> 4))
{
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s Previous transfer NOT Co\n", devname, unit, me);
}
return(-2);
}
// james clear transfer complete reg
writel( RFMOR_DMACSR_CLEAR_INT, (char *)(orbase + rfmor_Dma0Csr) );
wmb(); // james.. linux kernel function. insert hardware memory barrier. guarantees ordering in write memory operations.
/* PCI registers */
/* Setup DMA Mode register */
writel( (RFMOR_DMAMODE_32BIT_BUS |
RFMOR_DMAMODE_TA_READY |
RFMOR_DMAMODE_BTERM |
RFMOR_DMAMODE_LOCAL_BURST |
RFMOR_DMAMODE_DONE_INT_OFF |
RFMOR_DMAMODE_INT_TO_PCI_OFF), (char *)(orbase + rfmor_DmaMode0) );
/* Set Transfer Byte Count */
writel( ChunkSize, (char *)(orbase + rfmor_DmaCount0) );
/* Set initiator address */
writel( (rfmOffset + AmountSent), (char *)(orbase + rfmor_DmaLocAddr0) );
/* Enable from RFM to PC or PC to RFM based on value in dmaDesc */
writel( dmaDesc, (char *)(orbase + rfmor_DmaPtr0) );
/* Enable DMA Done Interrupt */
/* Now enable the interrupt */
// temp_reg32 = readl( (char *)(orbase + rfmor_intcsr) );
// temp_reg32 |= RFMOR_INTCSR_ENABLEDMA0INT;
// temp_reg32 |= RFMOR_INTCSR_ENABLEINT;
// writel( temp_reg32, (char *)(orbase + rfmor_intcsr) );
///
// qheader->reqh_flags |= EVENT_ENABLED;
// (cfg->IntrCount)++;
wmb(); // james.. linux kernel function. insert hardware memory barrier. guarantees ordering in write memory operations.
/* Definitions of the rfmor_DmaCsr register */
//#define RFMOR_DMACSR_ENABLE (1<<0)
//#define RFMOR_DMACSR_START (1<<1)
//#define RFMOR_DMACSR_CLEAR_INT (1<<3)
/* Initiate DMA transfer */
writeb( (RFMOR_DMACSR_ENABLE | RFMOR_DMACSR_START),
(char *)(orbase + rfmor_Dma0Csr) );
//WHENDEBUG(RFM2G_DBREAD)
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_CRIT"%s%d: %s DMA started! pid:%d\n",
devname, unit, me , current->pid );
}
// LucaB polling code,
// Warning: the manual says that polling registers has the priority
// over DMA transfers, so an aggressive polling can slow the DMA
// it must be checked.
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_CRIT"%s%d: %s Polling for DMA end. pid:%d\n", devname, unit, me , current->pid );
}
// RFM2g hardware manual says that upon DMA completion flag
// DMACSR0 register's bit 4 becomes high, so we poll for anything
// different from the start DMA command (0x11)
do
{
DMAendpollingreg = readl(orbase + rfmor_Dma0Csr) & 0x000000FF;
} while (DMAendpollingreg!=0x11);
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_CRIT"%s%d: %s DMA ended! pid:%d\n", devname, unit, me , current->pid );
}
// /* Wait here until interrupt occurs */
// stat = WaitForInterrupt( &event, flags );
/* Acquire lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk( KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
// devname, unit, me, current->pid);
// }
// spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
//
// qheader->reqh_flags = 0;
// (cfg->IntrCount)--;
// /* Release lock */
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk(KERN_ERR"%s%d: %s Releasing lock. pid:%d\n", devname, unit, me, current->pid);
// }
// spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
// if(stat !=0 )
// {
// WHENDEBUG(RFM2G_DBMUTEX)
// {
// printk(KERN_ERR"%s%d: %s Aborted. pid:%d\n", devname, unit, me, current->pid);
// }
// up(rfm2gDeviceInfo[unit].DMASem);
// return( -EINTR);
// }
}
up(rfm2gDeviceInfo[unit].DMASem);
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_CRIT"%s%d: %s(james just finished DMA function). pid:%d\n", devname, unit, me, current->pid);
}
return (count);
}
// end james polling DMA stuff
static int
RFM2gDMA(RFM2GCONFIGLINUX *cfg, RFM2G_UINT32 dmaDesc, RFM2G_UINT64 pciAddress,
RFM2G_UINT32 rfmOffset, RFM2G_UINT32 count, RFM2G_UINT32 addrAdjust)
{
static char *me = "RFM2gDMA()";
RFM2G_ADDR orbase; /* Base address of RFM's or space */
RFM2GEVENTINFOLINUX event;
RFM2GEVENTQUEUE_HEADER qheader;
RFM2G_UINT32 temp_reg32;
unsigned long flags;
RFM2G_UINT32 ChunkSize;
RFM2G_UINT32 AmountSent;
RFM2G_INT32 stat = 0;
RFM2G_UINT8 unit; /* Minor device number, used as index in rfm2gDeviceInfo */
RFM2G_UINT32 pciAddress_Lower, pciAddress_Upper;
/* Extract the minor number so we know which RFM device to access */
unit = cfg->Unit;
WHENDEBUG(RFM2G_DBREAD)
{
printk(KERN_ERR"%s%d: %s(using DMA). pid:%d\n", devname, unit, me, current->pid);
}
/* Add the base offset of the current sliding window to the rfmOffset.
This will make the DMA start at the beginning of the sliding window. */
rfmOffset += cfg->SlidingWindowOffset;
/* Make sure this DMA doesn't go off the end of the rfm board */
if ((rfmOffset + count) > cfg->MemorySize)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: Exiting %s: Offset + SlidingWindowOffset + count > MemorySize\n",
devname, unit, me);
}
return -EINVAL;
}
/* initialize event structure for call to WaitForInterrupt() */
event.ExtendedInfo = 0;
event.NodeId = 0;
event.Event = RFM2GEVENT_DMADONE;
event.Timeout = 8000; //INFINITE_TIMEOUT;
event.Unit = unit;
event.Qflags = 0;
orbase = (RFM2G_ADDR)cfg->pOrRegisters;
/* Get a pointer to this interrupt queue header */
qheader = &rfm2gDeviceInfo[unit].EventQueue[RFM2GEVENT_DMADONE].req_header;
/* See if we have to deal with the PLX errata */
if ( (cfg->PlxRevision < 0xAD) && (count > 0x100) )
{
ChunkSize = 0x100;
}
else
{
ChunkSize = 0x7fff80;
}
stat = down_interruptible(rfm2gDeviceInfo[unit].DMASem);
if (stat != 0)
{
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: down interrupted, "
"stat %d, pid:%d\n", devname, unit, me, stat, current->pid);
}
return(-2);
}
for ( AmountSent = 0; (AmountSent < count) && (stat==0); AmountSent += ChunkSize)
{
/* Check for short remainder */
if ( ChunkSize > (count - AmountSent) )
{
ChunkSize = count - AmountSent;
}
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk( KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
devname, unit, me, current->pid);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
/* Stop now if this interrupt is already enabled */
if( qheader->reqh_flags & EVENT_ENABLED )
{
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock\n", devname, unit, me);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
WHENDEBUG(RFM2G_DBERROR | RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: Exiting %s: Interrupt already enabled, "
"event %d\n", devname, unit, me, event.Event);
}
up(rfm2gDeviceInfo[unit].DMASem);
return(-2);
}
/* Set PCI Address */
pciAddress_Lower = (RFM2G_UINT32)((pciAddress + addrAdjust + AmountSent) & 0xFFFFFFFF);
pciAddress_Upper = (RFM2G_UINT32)((pciAddress + addrAdjust + AmountSent) >> 32);
writel( pciAddress_Lower, (char *)(orbase + rfmor_DmaPciAddr0) );
writel( pciAddress_Upper, (char *)(orbase + rfmor_DmaDac0) );
/* PCI registers */
/* Setup DMA Mode register */
writel( (RFMOR_DMAMODE_32BIT_BUS |
RFMOR_DMAMODE_TA_READY |
RFMOR_DMAMODE_BTERM |
RFMOR_DMAMODE_LOCAL_BURST |
RFMOR_DMAMODE_DONE_INT |
RFMOR_DMAMODE_INT_TO_PCI), (char *)(orbase + rfmor_DmaMode0) );
/* Set Transfer Byte Count */
writel( ChunkSize, (char *)(orbase + rfmor_DmaCount0) );
/* Set initiator address */
writel( (rfmOffset + AmountSent), (char *)(orbase + rfmor_DmaLocAddr0) );
/* Enable from RFM to PC or PC to RFM based on value in dmaDesc */
writel( dmaDesc, (char *)(orbase + rfmor_DmaPtr0) );
/* Enable DMA Done Interrupt */
/* Now enable the interrupt */
temp_reg32 = readl( (char *)(orbase + rfmor_intcsr) );
temp_reg32 |= RFMOR_INTCSR_ENABLEDMA0INT;
temp_reg32 |= RFMOR_INTCSR_ENABLEINT;
writel( temp_reg32, (char *)(orbase + rfmor_intcsr) );
/* flush PCI write fifo */
readl( (char*)(orbase + rfmor_intcsr));
qheader->reqh_flags |= EVENT_ENABLED;
(cfg->IntrCount)++;
wmb();
WHENDEBUG(RFM2G_DBINTR)
{
printk(KERN_ERR"%s%d: %s Enabled interrupt event %d. pid:%d\n",
devname, unit, me, event.Event, current->pid );
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
/* Do DMA and Wait here until interrupt occurs */
stat = DoDMAWithWaitForInt( &event, flags );
/* Acquire lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk( KERN_ERR"%s%d: %s About to acquire spinlock. pid:%d\n",
devname, unit, me, current->pid);
}
spin_lock_irqsave( (spinlock_t*)(cfg->SpinLock), flags );
qheader->reqh_flags = 0;
(cfg->IntrCount)--;
/* Release lock */
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Releasing lock. pid:%d\n", devname, unit, me, current->pid);
}
spin_unlock_irqrestore( (spinlock_t*)(cfg->SpinLock), flags );
if(stat !=0 )
{
WHENDEBUG(RFM2G_DBMUTEX)
{
printk(KERN_ERR"%s%d: %s Aborted. pid:%d\n", devname, unit, me, current->pid);
}
up(rfm2gDeviceInfo[unit].DMASem);
return( -EINTR);
}
}
up(rfm2gDeviceInfo[unit].DMASem);
return (count);
}
static int
IsReadyForDma(RFM2G_UINT8 unit, char *buf, size_t count, RFM2GDMAINFO *DmaInfo, RFM2G_UINT32 *addrAdjust)
{
static char *me = "IsReadyForDma()";
#ifdef __x86_64__
RFM2G_UINT32 virtaddr = (RFM2G_UINT32)((RFM2G_UINT64)buf);
#else
RFM2G_UINT32 virtaddr = (RFM2G_UINT32)buf;
#endif
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s virtaddr 0x%08X, count %d. pid:%d\n", devname, unit, me, virtaddr, (int) count, current->pid);
}
/* Don't DMA if there hasn't been a DMA buffer preallocated with mem=xxxM */
if (DmaInfo->BuffAddr == 0)
{
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s Don't DMA because there is no preallocated DMA buffer.. pid:%d\n", devname, unit, me, current->pid);
}
return 0;
}
/* Don't DMA if the data size is below the DMA threshold */
if (count < DmaInfo->Threshold)
{
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s Don't DMA because the data size is below the DMA threshold.. pid:%d\n", devname, unit, me, current->pid);
}
return 0;
}
/* Make sure the virtaddr is not outside of the mmap'ed region used for DMA */
*addrAdjust = virtaddr - DmaInfo->VirtAddr;
if (*addrAdjust > DmaInfo->BuffSize)
{
*addrAdjust = 0;
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s Don't DMA because the virtual buffer address is outside of the mmap'ed region used for DMA.. pid:%d\n", devname, unit, me, current->pid);
}
return 0;
}
/* Make sure the amount of data doesn't exceed the mmap'ed region used for DMA */
// james adding more debig stuff
/*
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s . Count %d, BuffSize %x, addrAdjust %x\n", devname, unit, me, count, (int)DmaInfo->BuffSize, *addrAdjust);
}
*/
if (count > (DmaInfo->BuffSize - *addrAdjust))
{
*addrAdjust = 0;
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s Don't DMA because the amount of data exceeds the mmap'ed region used for DMA. pid:%d\n", devname, unit, me, current->pid);
}
return 0;
}
WHENDEBUG(RFM2G_DBDMA)
{
printk(KERN_ERR"%s%d: %s Okay to DMA.. pid:%d\n", devname, unit, me, current->pid);
}
/* Perform DMA */
return 1;
}
本文来自博客园,作者:相对维度,转载请注明原文链接:https://www.cnblogs.com/wangjirui/p/16491866.html

浙公网安备 33010602011771号