Skip to content
Snippets Groups Projects
Commit b89dff08 authored by Rolf Bork's avatar Rolf Bork
Browse files

Changes to moduleLoadIop.c:

  - Prematurely ran clang, so unfortunately looks like lots of diffs.
  - Added module initialization for card model numbers being passed to user apps.
    - Without this, user model could mistake a zero as an ADC if IOP does not have the
      right number of cards, such as in a test stand.
  - Added 2msec delay before starting core locked thread to allow time for printk
    buffers to be flushed.
parent 492dd8fa
No related branches found
No related tags found
No related merge requests found
......@@ -7,276 +7,300 @@
#include <proc.h>
// These externs and "16" need to go to a header file (mbuf.h)
extern void *kmalloc_area[16];
extern int mbuf_allocate_area(char *name, int size, struct file *file);
extern void *fe_start_iop(void *arg);
extern char daqArea[2*DAQ_DCU_SIZE]; // Space allocation for daqLib buffers
struct task_struct *sthread;
// MAIN routine: Code starting point ****************************************************************
extern void* kmalloc_area[ 16 ];
extern int mbuf_allocate_area( char* name, int size, struct file* file );
extern void* fe_start_iop( void* arg );
extern char daqArea[ 2 * DAQ_DCU_SIZE ]; // Space allocation for daqLib buffers
struct task_struct* sthread;
// MAIN routine: Code starting point
// ****************************************************************
int need_to_load_IOP_first;
EXPORT_SYMBOL(need_to_load_IOP_first);
EXPORT_SYMBOL( need_to_load_IOP_first );
extern void set_fe_code_idle(void *(*ptr)(void *), unsigned int cpu);
extern void msleep(unsigned int);
extern void set_fe_code_idle( void* ( *ptr )(void*), unsigned int cpu );
extern void msleep( unsigned int );
#include "moduleLoadCommon.c"
/// Startup function for initialization of kernel module.
int rt_iop_init (void)
int
rt_iop_init( void )
{
int status;
int ii,jj,kk; /// @param ii,jj,kk default loop counters
char fname[128]; /// @param fname[128] Name of shared mem area to allocate for DAQ data
int cards; /// @param cards Number of PCIe cards found on bus
int ret; /// @param ret Return value from various Malloc calls to allocate memory.
int cnt;
extern int cpu_down(unsigned int); /// @param cpu_down CPU shutdown call.
extern int is_cpu_taken_by_rcg_model(unsigned int cpu); /// @param is_cpu_taken_by_rcg_model Check to verify CPU availability for shutdown.
kk = 0;
int status;
int ii, jj, kk; /// @param ii,jj,kk default loop counters
char fname[ 128 ]; /// @param fname[128] Name of shared mem area to allocate
/// for DAQ data
int cards; /// @param cards Number of PCIe cards found on bus
int ret; /// @param ret Return value from various Malloc calls to allocate
/// memory.
int cnt;
extern int cpu_down( unsigned int ); /// @param cpu_down CPU shutdown call.
extern int is_cpu_taken_by_rcg_model(
unsigned int cpu ); /// @param is_cpu_taken_by_rcg_model Check to verify
/// CPU availability for shutdown.
kk = 0;
#ifdef SPECIFIC_CPU
#define CPUID SPECIFIC_CPU
#else
#define CPUID 1
#else
#define CPUID 1
#endif
#ifndef NO_CPU_SHUTDOWN
/// Verify requested core is free.
if (is_cpu_taken_by_rcg_model(CPUID)) {
printk(KERN_ALERT "Error: CPU %d already taken\n", CPUID);
return -1;
}
if ( is_cpu_taken_by_rcg_model( CPUID ) )
{
printk( KERN_ALERT "Error: CPU %d already taken\n", CPUID );
return -1;
}
#endif
#ifdef DOLPHIN_TEST
/// Initialize the Dolphin interface
status = init_dolphin(2);
if (status != 0) {
return -1;
}
status = init_dolphin( 2 );
if ( status != 0 )
{
return -1;
}
#endif
jj = 0;
jj = 0;
/// Allocate EPICS memory area
ret = mbuf_allocate_area(SYSTEM_NAME_STRING_LOWER, 64*1024*1024, 0);
if (ret < 0) {
printk("mbuf_allocate_area() failed; ret = %d\n", ret);
ret = mbuf_allocate_area( SYSTEM_NAME_STRING_LOWER, 64 * 1024 * 1024, 0 );
if ( ret < 0 )
{
printk( "mbuf_allocate_area() failed; ret = %d\n", ret );
return -1;
}
_epics_shm = (unsigned char *)(kmalloc_area[ret]);
// Set pointer to EPICS area
pLocalEpics = (CDS_EPICS *)&((RFM_FE_COMMS *)_epics_shm)->epicsSpace;
_epics_shm = (unsigned char*)( kmalloc_area[ ret ] );
// Set pointer to EPICS area
pLocalEpics = (CDS_EPICS*)&( (RFM_FE_COMMS*)_epics_shm )->epicsSpace;
pLocalEpics->epicsOutput.fe_status = 0;
/// Allocate IPC memory area
ret = mbuf_allocate_area("ipc", 16*1024*1024, 0);
if (ret < 0) {
printk("mbuf_allocate_area(ipc) failed; ret = %d\n", ret);
/// Allocate IPC memory area
ret = mbuf_allocate_area( "ipc", 16 * 1024 * 1024, 0 );
if ( ret < 0 )
{
printk( "mbuf_allocate_area(ipc) failed; ret = %d\n", ret );
return -1;
}
_ipc_shm = (unsigned char *)(kmalloc_area[ret]);
}
_ipc_shm = (unsigned char*)( kmalloc_area[ ret ] );
// Assign pointer to IOP/USER app comms space
ioMemData = (IO_MEM_DATA *)(_ipc_shm+ 0x4000);
ioMemData = (IO_MEM_DATA*)( _ipc_shm + 0x4000 );
/// Allocate DAQ memory area
sprintf(fname, "%s_daq", SYSTEM_NAME_STRING_LOWER);
ret = mbuf_allocate_area(fname, 64*1024*1024, 0);
if (ret < 0) {
printk("mbuf_allocate_area() failed; ret = %d\n", ret);
sprintf( fname, "%s_daq", SYSTEM_NAME_STRING_LOWER );
ret = mbuf_allocate_area( fname, 64 * 1024 * 1024, 0 );
if ( ret < 0 )
{
printk( "mbuf_allocate_area() failed; ret = %d\n", ret );
return -1;
}
_daq_shm = (unsigned char *)(kmalloc_area[ret]);
daqPtr = (struct rmIpcStr *) _daq_shm;
}
_daq_shm = (unsigned char*)( kmalloc_area[ ret ] );
daqPtr = (struct rmIpcStr*)_daq_shm;
pLocalEpics->epicsOutput.fe_status = 1;
/// Find and initialize all PCIe I/O modules
// Following I/O card info is from feCode
cards = sizeof(cards_used)/sizeof(cards_used[0]);
cdsPciModules.cards = cards;
cdsPciModules.cards_used = cards_used;
cdsPciModules.adcCount = 0;
cdsPciModules.dacCount = 0;
cdsPciModules.dioCount = 0;
cdsPciModules.doCount = 0;
/// Call PCI initialization routine in map.c file.
status = mapPciModules(&cdsPciModules);
if(status < cards)
{
printk(" ERROR **** Did not find correct number of cards! Expected %d and Found %d\n",cards,status);
cardCountErr = 1;
}
/// Master send module counts to SLAVE via ipc shm
ioMemData->totalCards = status;
ioMemData->adcCount = cdsPciModules.adcCount;
ioMemData->dacCount = cdsPciModules.dacCount;
ioMemData->bioCount = cdsPciModules.doCount;
// kk will act as ioMem location counter for mapping modules
kk = cdsPciModules.adcCount;
for(ii=0;ii<cdsPciModules.adcCount;ii++)
{
// MASTER maps ADC modules first in ipc shm for SLAVES
ioMemData->model[ii] = cdsPciModules.adcType[ii];
ioMemData->ipc[ii] = ii; // ioData memory buffer location for SLAVE to use
// Following I/O card info is from feCode
cards = sizeof( cards_used ) / sizeof( cards_used[ 0 ] );
cdsPciModules.cards = cards;
cdsPciModules.cards_used = cards_used;
cdsPciModules.adcCount = 0;
cdsPciModules.dacCount = 0;
cdsPciModules.dioCount = 0;
cdsPciModules.doCount = 0;
/// Call PCI initialization routine in map.c file.
status = mapPciModules( &cdsPciModules );
if ( status < cards )
{
printk( " ERROR **** Did not find correct number of cards! Expected %d "
"and Found %d\n",
cards,
status );
cardCountErr = 1;
}
for(ii=0;ii<cdsPciModules.dacCount;ii++)
// Clear out card model info in IO_MEM
for ( ii = 0; ii < MAX_IO_MODULES; ii++ )
{
ioMemData->model[ ii ] = -1;
}
/// Master send module counts to SLAVE via ipc shm
ioMemData->totalCards = status;
ioMemData->adcCount = cdsPciModules.adcCount;
ioMemData->dacCount = cdsPciModules.dacCount;
ioMemData->bioCount = cdsPciModules.doCount;
// kk will act as ioMem location counter for mapping modules
kk = cdsPciModules.adcCount;
for ( ii = 0; ii < cdsPciModules.adcCount; ii++ )
{
// Pass DAC info to SLAVE processes
ioMemData->model[kk] = cdsPciModules.dacType[ii];
ioMemData->ipc[kk] = kk;
// Following used by MASTER to point to ipc memory for inputting DAC data from SLAVES
cdsPciModules.dacConfig[ii] = kk;
kk ++;
}
// MASTER sends DIO module information to SLAVES
// Note that for DIO, SLAVE modules will perform the I/O directly and therefore need to
// know the PCIe address of these modules.
ioMemData->bioCount = cdsPciModules.doCount;
for(ii=0;ii<cdsPciModules.doCount;ii++)
// MASTER maps ADC modules first in ipc shm for SLAVES
ioMemData->model[ ii ] = cdsPciModules.adcType[ ii ];
ioMemData->ipc[ ii ] =
ii; // ioData memory buffer location for SLAVE to use
}
for ( ii = 0; ii < cdsPciModules.dacCount; ii++ )
{
// Pass DAC info to SLAVE processes
ioMemData->model[ kk ] = cdsPciModules.dacType[ ii ];
ioMemData->ipc[ kk ] = kk;
// Following used by MASTER to point to ipc memory for inputting DAC
// data from SLAVES
cdsPciModules.dacConfig[ ii ] = kk;
kk++;
}
// MASTER sends DIO module information to SLAVES
// Note that for DIO, SLAVE modules will perform the I/O directly and
// therefore need to know the PCIe address of these modules.
ioMemData->bioCount = cdsPciModules.doCount;
for ( ii = 0; ii < cdsPciModules.doCount; ii++ )
{
// MASTER needs to find Contec 1616 I/O card to control timing slave.
if ( cdsPciModules.doType[ ii ] == CON_1616DIO )
{
// MASTER needs to find Contec 1616 I/O card to control timing slave.
if(cdsPciModules.doType[ii] == CON_1616DIO)
{
tdsControl[tdsCount] = ii;
tdsCount ++;
}
ioMemData->model[kk] = cdsPciModules.doType[ii];
// Unlike ADC and DAC, where a memory buffer number is passed, a PCIe address is passed
// for DIO cards.
ioMemData->ipc[kk] = cdsPciModules.pci_do[ii];
kk ++;
}
// Following section maps Reflected Memory, both VMIC hardware style and Dolphin PCIe network style.
// Slave units will perform I/O transactions with RFM directly ie MASTER does not do RFM I/O.
// Master unit only maps the RFM I/O space and passes pointers to SLAVES.
tdsControl[ tdsCount ] = ii;
tdsCount++;
}
ioMemData->model[ kk ] = cdsPciModules.doType[ ii ];
// Unlike ADC and DAC, where a memory buffer number is passed, a PCIe
// address is passed for DIO cards.
ioMemData->ipc[ kk ] = cdsPciModules.pci_do[ ii ];
kk++;
}
// Following section maps Reflected Memory, both VMIC hardware style and
// Dolphin PCIe network style. Slave units will perform I/O transactions
// with RFM directly ie MASTER does not do RFM I/O. Master unit only maps
// the RFM I/O space and passes pointers to SLAVES.
/// Map VMIC RFM cards, if any
ioMemData->rfmCount = cdsPciModules.rfmCount;
for(ii=0;ii<cdsPciModules.rfmCount;ii++)
{
// Master sends RFM memory pointers to SLAVES
ioMemData->pci_rfm[ii] = cdsPciModules.pci_rfm[ii];
ioMemData->pci_rfm_dma[ii] = cdsPciModules.pci_rfm_dma[ii];
}
ioMemData->rfmCount = cdsPciModules.rfmCount;
for ( ii = 0; ii < cdsPciModules.rfmCount; ii++ )
{
// Master sends RFM memory pointers to SLAVES
ioMemData->pci_rfm[ ii ] = cdsPciModules.pci_rfm[ ii ];
ioMemData->pci_rfm_dma[ ii ] = cdsPciModules.pci_rfm_dma[ ii ];
}
#ifdef DOLPHIN_TEST
/// Send Dolphin addresses to user app processes
// dolphinCount is number of segments
ioMemData->dolphinCount = cdsPciModules.dolphinCount;
// dolphin read/write 0 is for local PCIe network traffic
ioMemData->dolphinRead[0] = cdsPciModules.dolphinRead[0];
ioMemData->dolphinWrite[0] = cdsPciModules.dolphinWrite[0];
// dolphin read/write 1 is for long range PCIe (RFM) traffic
ioMemData->dolphinRead[1] = cdsPciModules.dolphinRead[1];
ioMemData->dolphinWrite[1] = cdsPciModules.dolphinWrite[1];
// dolphinCount is number of segments
ioMemData->dolphinCount = cdsPciModules.dolphinCount;
// dolphin read/write 0 is for local PCIe network traffic
ioMemData->dolphinRead[ 0 ] = cdsPciModules.dolphinRead[ 0 ];
ioMemData->dolphinWrite[ 0 ] = cdsPciModules.dolphinWrite[ 0 ];
// dolphin read/write 1 is for long range PCIe (RFM) traffic
ioMemData->dolphinRead[ 1 ] = cdsPciModules.dolphinRead[ 1 ];
ioMemData->dolphinWrite[ 1 ] = cdsPciModules.dolphinWrite[ 1 ];
#else
// Clear Dolphin pointers so the slave sees NULLs
ioMemData->dolphinCount = 0;
ioMemData->dolphinRead[0] = 0;
ioMemData->dolphinWrite[0] = 0;
ioMemData->dolphinRead[1] = 0;
ioMemData->dolphinWrite[1] = 0;
// Clear Dolphin pointers so the slave sees NULLs
ioMemData->dolphinCount = 0;
ioMemData->dolphinRead[ 0 ] = 0;
ioMemData->dolphinWrite[ 0 ] = 0;
ioMemData->dolphinRead[ 1 ] = 0;
ioMemData->dolphinWrite[ 1 ] = 0;
#endif
/// Print out all the I/O information to dmesg
print_io_info(&cdsPciModules);
/// Print out all the I/O information to dmesg
print_io_info( &cdsPciModules );
// Initialize buffer for daqLib.c code
daqBuffer = (long)&daqArea[ 0 ];
// Initialize buffer for daqLib.c code
daqBuffer = (long)&daqArea[0];
pLocalEpics->epicsOutput.fe_status = 2;
printk("Waiting for EPICS BURT Restore = %d\n", pLocalEpics->epicsInput.burtRestore);
/// Ensure EPICS running else exit
for (cnt = 0; cnt < 10 && pLocalEpics->epicsInput.burtRestore == 0; cnt++) {
msleep(1000);
}
if (cnt == 10 || cdsPciModules.adcCount == 0) {
// Cleanup
printk( "Waiting for EPICS BURT Restore = %d\n",
pLocalEpics->epicsInput.burtRestore );
/// Ensure EPICS running else exit
for ( cnt = 0; cnt < 10 && pLocalEpics->epicsInput.burtRestore == 0; cnt++ )
{
msleep( 1000 );
}
if ( cnt == 10 || cdsPciModules.adcCount == 0 )
{
// Cleanup
#ifdef DOLPHIN_TEST
finish_dolphin();
finish_dolphin( );
#endif
return -1;
}
printk("BURT Restore Complete\n");
return -1;
}
printk( "BURT Restore Complete\n" );
pLocalEpics->epicsInput.vmeReset = 0;
pLocalEpics->epicsInput.vmeReset = 0;
udelay( 2000 );
/// Start the controller thread
#ifdef NO_CPU_SHUTDOWN
sthread = kthread_create(fe_start_iop, 0, "fe_start_iop/%d", CPUID);
if (IS_ERR(sthread)){
printk("Failed to kthread_create()\n");
return -1;
}
kthread_bind(sthread, CPUID);
wake_up_process(sthread);
sthread = kthread_create( fe_start_iop, 0, "fe_start_iop/%d", CPUID );
if ( IS_ERR( sthread ) )
{
printk( "Failed to kthread_create()\n" );
return -1;
}
kthread_bind( sthread, CPUID );
wake_up_process( sthread );
#endif
#ifndef NO_CPU_SHUTDOWN
pLocalEpics->epicsOutput.fe_status = 3;
printk("" SYSTEM_NAME_STRING_LOWER ": Locking CPU core %d\n", CPUID);
// The code runs on the disabled CPU
set_fe_code_idle(fe_start_iop, CPUID);
msleep(100);
cpu_down(CPUID);
printk( "" SYSTEM_NAME_STRING_LOWER ": Locking CPU core %d\n", CPUID );
// The code runs on the disabled CPU
set_fe_code_idle( fe_start_iop, CPUID );
msleep( 100 );
cpu_down( CPUID );
#endif
return 0;
return 0;
}
/// Kernel module cleanup function
void rt_iop_cleanup(void) {
void
rt_iop_cleanup( void )
{
#ifndef NO_CPU_SHUTDOWN
extern int cpu_up(unsigned int cpu);
extern int cpu_up( unsigned int cpu );
/// Unset the code callback
set_fe_code_idle(0, CPUID);
/// Unset the code callback
set_fe_code_idle( 0, CPUID );
#endif
// printk("Setting stop_working_threads to 1\n");
// Stop the code and wait
// printk("Setting stop_working_threads to 1\n");
// Stop the code and wait
#ifdef NO_CPU_SHUTDOWN
int ret;
ret = kthread_stop(sthread);
int ret;
ret = kthread_stop( sthread );
#endif
stop_working_threads = 1;
msleep(1000);
stop_working_threads = 1;
msleep( 1000 );
#ifdef DOLPHIN_TEST
/// Cleanup Dolphin card connections
finish_dolphin();
finish_dolphin( );
#endif
#ifndef NO_CPU_SHUTDOWN
/// Bring the CPU core back on line
// Unset the code callback
set_fe_code_idle(0, CPUID);
// printkl("Will bring back CPU %d\n", CPUID);
msleep(1000);
// Bring the CPU back up
cpu_up(CPUID);
msleep(1000);
printk("Brought the CPU back up\n");
// Unset the code callback
set_fe_code_idle( 0, CPUID );
// printkl("Will bring back CPU %d\n", CPUID);
msleep( 1000 );
// Bring the CPU back up
cpu_up( CPUID );
msleep( 1000 );
printk( "Brought the CPU back up\n" );
#endif
printk("Just before returning from cleanup_module for " SYSTEM_NAME_STRING_LOWER "\n");
printk( "Just before returning from cleanup_module "
"for " SYSTEM_NAME_STRING_LOWER "\n" );
}
module_init(rt_iop_init);
module_exit(rt_iop_cleanup);
module_init( rt_iop_init );
module_exit( rt_iop_cleanup );
MODULE_DESCRIPTION("Control system");
MODULE_AUTHOR("LIGO");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION( "Control system" );
MODULE_AUTHOR( "LIGO" );
MODULE_LICENSE( "Dual BSD/GPL" );
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment