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 @@ ...@@ -7,276 +7,300 @@
#include <proc.h> #include <proc.h>
// These externs and "16" need to go to a header file (mbuf.h) // These externs and "16" need to go to a header file (mbuf.h)
extern void *kmalloc_area[16]; extern void* kmalloc_area[ 16 ];
extern int mbuf_allocate_area(char *name, int size, struct file *file); extern int mbuf_allocate_area( char* name, int size, struct file* file );
extern void *fe_start_iop(void *arg); extern void* fe_start_iop( void* arg );
extern char daqArea[2*DAQ_DCU_SIZE]; // Space allocation for daqLib buffers extern char daqArea[ 2 * DAQ_DCU_SIZE ]; // Space allocation for daqLib buffers
struct task_struct *sthread; struct task_struct* sthread;
// MAIN routine: Code starting point
// ****************************************************************
// MAIN routine: Code starting point ****************************************************************
int need_to_load_IOP_first; 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 set_fe_code_idle( void* ( *ptr )(void*), unsigned int cpu );
extern void msleep(unsigned int); extern void msleep( unsigned int );
#include "moduleLoadCommon.c" #include "moduleLoadCommon.c"
/// Startup function for initialization of kernel module. /// Startup function for initialization of kernel module.
int rt_iop_init (void) int
rt_iop_init( void )
{ {
int status; int status;
int ii,jj,kk; /// @param ii,jj,kk default loop counters 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 char fname[ 128 ]; /// @param fname[128] Name of shared mem area to allocate
int cards; /// @param cards Number of PCIe cards found on bus /// for DAQ data
int ret; /// @param ret Return value from various Malloc calls to allocate memory. int cards; /// @param cards Number of PCIe cards found on bus
int cnt; int ret; /// @param ret Return value from various Malloc calls to allocate
extern int cpu_down(unsigned int); /// @param cpu_down CPU shutdown call. /// memory.
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. int cnt;
extern int cpu_down( unsigned int ); /// @param cpu_down CPU shutdown call.
kk = 0; 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 #ifdef SPECIFIC_CPU
#define CPUID SPECIFIC_CPU #define CPUID SPECIFIC_CPU
#else #else
#define CPUID 1 #define CPUID 1
#endif #endif
#ifndef NO_CPU_SHUTDOWN #ifndef NO_CPU_SHUTDOWN
/// Verify requested core is free. /// Verify requested core is free.
if (is_cpu_taken_by_rcg_model(CPUID)) { if ( is_cpu_taken_by_rcg_model( CPUID ) )
printk(KERN_ALERT "Error: CPU %d already taken\n", CPUID); {
return -1; printk( KERN_ALERT "Error: CPU %d already taken\n", CPUID );
} return -1;
}
#endif #endif
#ifdef DOLPHIN_TEST #ifdef DOLPHIN_TEST
/// Initialize the Dolphin interface /// Initialize the Dolphin interface
status = init_dolphin(2); status = init_dolphin( 2 );
if (status != 0) { if ( status != 0 )
return -1; {
} return -1;
}
#endif #endif
jj = 0; jj = 0;
/// Allocate EPICS memory area /// Allocate EPICS memory area
ret = mbuf_allocate_area(SYSTEM_NAME_STRING_LOWER, 64*1024*1024, 0); ret = mbuf_allocate_area( SYSTEM_NAME_STRING_LOWER, 64 * 1024 * 1024, 0 );
if (ret < 0) { if ( ret < 0 )
printk("mbuf_allocate_area() failed; ret = %d\n", ret); {
printk( "mbuf_allocate_area() failed; ret = %d\n", ret );
return -1; return -1;
} }
_epics_shm = (unsigned char *)(kmalloc_area[ret]); _epics_shm = (unsigned char*)( kmalloc_area[ ret ] );
// Set pointer to EPICS area // Set pointer to EPICS area
pLocalEpics = (CDS_EPICS *)&((RFM_FE_COMMS *)_epics_shm)->epicsSpace; pLocalEpics = (CDS_EPICS*)&( (RFM_FE_COMMS*)_epics_shm )->epicsSpace;
pLocalEpics->epicsOutput.fe_status = 0; pLocalEpics->epicsOutput.fe_status = 0;
/// Allocate IPC memory area /// Allocate IPC memory area
ret = mbuf_allocate_area("ipc", 16*1024*1024, 0); ret = mbuf_allocate_area( "ipc", 16 * 1024 * 1024, 0 );
if (ret < 0) { if ( ret < 0 )
printk("mbuf_allocate_area(ipc) failed; ret = %d\n", ret); {
printk( "mbuf_allocate_area(ipc) failed; ret = %d\n", ret );
return -1; return -1;
} }
_ipc_shm = (unsigned char *)(kmalloc_area[ret]); _ipc_shm = (unsigned char*)( kmalloc_area[ ret ] );
// Assign pointer to IOP/USER app comms space // 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 /// Allocate DAQ memory area
sprintf(fname, "%s_daq", SYSTEM_NAME_STRING_LOWER); sprintf( fname, "%s_daq", SYSTEM_NAME_STRING_LOWER );
ret = mbuf_allocate_area(fname, 64*1024*1024, 0); ret = mbuf_allocate_area( fname, 64 * 1024 * 1024, 0 );
if (ret < 0) { if ( ret < 0 )
printk("mbuf_allocate_area() failed; ret = %d\n", ret); {
printk( "mbuf_allocate_area() failed; ret = %d\n", ret );
return -1; return -1;
} }
_daq_shm = (unsigned char *)(kmalloc_area[ret]); _daq_shm = (unsigned char*)( kmalloc_area[ ret ] );
daqPtr = (struct rmIpcStr *) _daq_shm; daqPtr = (struct rmIpcStr*)_daq_shm;
pLocalEpics->epicsOutput.fe_status = 1; pLocalEpics->epicsOutput.fe_status = 1;
/// Find and initialize all PCIe I/O modules /// Find and initialize all PCIe I/O modules
// Following I/O card info is from feCode // Following I/O card info is from feCode
cards = sizeof(cards_used)/sizeof(cards_used[0]); cards = sizeof( cards_used ) / sizeof( cards_used[ 0 ] );
cdsPciModules.cards = cards; cdsPciModules.cards = cards;
cdsPciModules.cards_used = cards_used; cdsPciModules.cards_used = cards_used;
cdsPciModules.adcCount = 0; cdsPciModules.adcCount = 0;
cdsPciModules.dacCount = 0; cdsPciModules.dacCount = 0;
cdsPciModules.dioCount = 0; cdsPciModules.dioCount = 0;
cdsPciModules.doCount = 0; cdsPciModules.doCount = 0;
/// Call PCI initialization routine in map.c file. /// Call PCI initialization routine in map.c file.
status = mapPciModules(&cdsPciModules); status = mapPciModules( &cdsPciModules );
if(status < cards) if ( status < cards )
{ {
printk(" ERROR **** Did not find correct number of cards! Expected %d and Found %d\n",cards,status); printk( " ERROR **** Did not find correct number of cards! Expected %d "
cardCountErr = 1; "and Found %d\n",
} cards,
status );
/// Master send module counts to SLAVE via ipc shm cardCountErr = 1;
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
} }
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 // MASTER maps ADC modules first in ipc shm for SLAVES
ioMemData->model[kk] = cdsPciModules.dacType[ii]; ioMemData->model[ ii ] = cdsPciModules.adcType[ ii ];
ioMemData->ipc[kk] = kk; ioMemData->ipc[ ii ] =
// Following used by MASTER to point to ipc memory for inputting DAC data from SLAVES ii; // ioData memory buffer location for SLAVE to use
cdsPciModules.dacConfig[ii] = kk; }
kk ++; for ( ii = 0; ii < cdsPciModules.dacCount; ii++ )
} {
// MASTER sends DIO module information to SLAVES // Pass DAC info to SLAVE processes
// Note that for DIO, SLAVE modules will perform the I/O directly and therefore need to ioMemData->model[ kk ] = cdsPciModules.dacType[ ii ];
// know the PCIe address of these modules. ioMemData->ipc[ kk ] = kk;
ioMemData->bioCount = cdsPciModules.doCount; // Following used by MASTER to point to ipc memory for inputting DAC
for(ii=0;ii<cdsPciModules.doCount;ii++) // 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. tdsControl[ tdsCount ] = ii;
if(cdsPciModules.doType[ii] == CON_1616DIO) tdsCount++;
{ }
tdsControl[tdsCount] = ii; ioMemData->model[ kk ] = cdsPciModules.doType[ ii ];
tdsCount ++; // Unlike ADC and DAC, where a memory buffer number is passed, a PCIe
} // address is passed for DIO cards.
ioMemData->model[kk] = cdsPciModules.doType[ii]; ioMemData->ipc[ kk ] = cdsPciModules.pci_do[ ii ];
// Unlike ADC and DAC, where a memory buffer number is passed, a PCIe address is passed kk++;
// for DIO cards. }
ioMemData->ipc[kk] = cdsPciModules.pci_do[ii]; // Following section maps Reflected Memory, both VMIC hardware style and
kk ++; // 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
// Following section maps Reflected Memory, both VMIC hardware style and Dolphin PCIe network style. // the RFM I/O space and passes pointers to SLAVES.
// 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 /// Map VMIC RFM cards, if any
ioMemData->rfmCount = cdsPciModules.rfmCount; ioMemData->rfmCount = cdsPciModules.rfmCount;
for(ii=0;ii<cdsPciModules.rfmCount;ii++) for ( ii = 0; ii < cdsPciModules.rfmCount; ii++ )
{ {
// Master sends RFM memory pointers to SLAVES // Master sends RFM memory pointers to SLAVES
ioMemData->pci_rfm[ii] = cdsPciModules.pci_rfm[ii]; ioMemData->pci_rfm[ ii ] = cdsPciModules.pci_rfm[ ii ];
ioMemData->pci_rfm_dma[ii] = cdsPciModules.pci_rfm_dma[ii]; ioMemData->pci_rfm_dma[ ii ] = cdsPciModules.pci_rfm_dma[ ii ];
} }
#ifdef DOLPHIN_TEST #ifdef DOLPHIN_TEST
/// Send Dolphin addresses to user app processes /// Send Dolphin addresses to user app processes
// dolphinCount is number of segments // dolphinCount is number of segments
ioMemData->dolphinCount = cdsPciModules.dolphinCount; ioMemData->dolphinCount = cdsPciModules.dolphinCount;
// dolphin read/write 0 is for local PCIe network traffic // dolphin read/write 0 is for local PCIe network traffic
ioMemData->dolphinRead[0] = cdsPciModules.dolphinRead[0]; ioMemData->dolphinRead[ 0 ] = cdsPciModules.dolphinRead[ 0 ];
ioMemData->dolphinWrite[0] = cdsPciModules.dolphinWrite[0]; ioMemData->dolphinWrite[ 0 ] = cdsPciModules.dolphinWrite[ 0 ];
// dolphin read/write 1 is for long range PCIe (RFM) traffic // dolphin read/write 1 is for long range PCIe (RFM) traffic
ioMemData->dolphinRead[1] = cdsPciModules.dolphinRead[1]; ioMemData->dolphinRead[ 1 ] = cdsPciModules.dolphinRead[ 1 ];
ioMemData->dolphinWrite[1] = cdsPciModules.dolphinWrite[1]; ioMemData->dolphinWrite[ 1 ] = cdsPciModules.dolphinWrite[ 1 ];
#else #else
// Clear Dolphin pointers so the slave sees NULLs // Clear Dolphin pointers so the slave sees NULLs
ioMemData->dolphinCount = 0; ioMemData->dolphinCount = 0;
ioMemData->dolphinRead[0] = 0; ioMemData->dolphinRead[ 0 ] = 0;
ioMemData->dolphinWrite[0] = 0; ioMemData->dolphinWrite[ 0 ] = 0;
ioMemData->dolphinRead[1] = 0; ioMemData->dolphinRead[ 1 ] = 0;
ioMemData->dolphinWrite[1] = 0; ioMemData->dolphinWrite[ 1 ] = 0;
#endif #endif
/// Print out all the I/O information to dmesg /// Print out all the I/O information to dmesg
print_io_info(&cdsPciModules); 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; pLocalEpics->epicsOutput.fe_status = 2;
printk("Waiting for EPICS BURT Restore = %d\n", pLocalEpics->epicsInput.burtRestore); printk( "Waiting for EPICS BURT Restore = %d\n",
/// Ensure EPICS running else exit pLocalEpics->epicsInput.burtRestore );
for (cnt = 0; cnt < 10 && pLocalEpics->epicsInput.burtRestore == 0; cnt++) { /// Ensure EPICS running else exit
msleep(1000); for ( cnt = 0; cnt < 10 && pLocalEpics->epicsInput.burtRestore == 0; cnt++ )
} {
if (cnt == 10 || cdsPciModules.adcCount == 0) { msleep( 1000 );
// Cleanup }
if ( cnt == 10 || cdsPciModules.adcCount == 0 )
{
// Cleanup
#ifdef DOLPHIN_TEST #ifdef DOLPHIN_TEST
finish_dolphin(); finish_dolphin( );
#endif #endif
return -1; return -1;
} }
printk("BURT Restore Complete\n"); printk( "BURT Restore Complete\n" );
pLocalEpics->epicsInput.vmeReset = 0; pLocalEpics->epicsInput.vmeReset = 0;
udelay( 2000 );
/// Start the controller thread /// Start the controller thread
#ifdef NO_CPU_SHUTDOWN #ifdef NO_CPU_SHUTDOWN
sthread = kthread_create(fe_start_iop, 0, "fe_start_iop/%d", CPUID); sthread = kthread_create( fe_start_iop, 0, "fe_start_iop/%d", CPUID );
if (IS_ERR(sthread)){ if ( IS_ERR( sthread ) )
printk("Failed to kthread_create()\n"); {
return -1; printk( "Failed to kthread_create()\n" );
} return -1;
kthread_bind(sthread, CPUID); }
wake_up_process(sthread); kthread_bind( sthread, CPUID );
wake_up_process( sthread );
#endif #endif
#ifndef NO_CPU_SHUTDOWN #ifndef NO_CPU_SHUTDOWN
pLocalEpics->epicsOutput.fe_status = 3; pLocalEpics->epicsOutput.fe_status = 3;
printk("" SYSTEM_NAME_STRING_LOWER ": Locking CPU core %d\n", CPUID); printk( "" SYSTEM_NAME_STRING_LOWER ": Locking CPU core %d\n", CPUID );
// The code runs on the disabled CPU // The code runs on the disabled CPU
set_fe_code_idle(fe_start_iop, CPUID); set_fe_code_idle( fe_start_iop, CPUID );
msleep(100); msleep( 100 );
cpu_down(CPUID); cpu_down( CPUID );
#endif #endif
return 0; return 0;
} }
/// Kernel module cleanup function /// Kernel module cleanup function
void rt_iop_cleanup(void) { void
rt_iop_cleanup( void )
{
#ifndef NO_CPU_SHUTDOWN #ifndef NO_CPU_SHUTDOWN
extern int cpu_up(unsigned int cpu); extern int cpu_up( unsigned int cpu );
/// Unset the code callback /// Unset the code callback
set_fe_code_idle(0, CPUID); set_fe_code_idle( 0, CPUID );
#endif #endif
// printk("Setting stop_working_threads to 1\n"); // printk("Setting stop_working_threads to 1\n");
// Stop the code and wait // Stop the code and wait
#ifdef NO_CPU_SHUTDOWN #ifdef NO_CPU_SHUTDOWN
int ret; int ret;
ret = kthread_stop(sthread); ret = kthread_stop( sthread );
#endif #endif
stop_working_threads = 1; stop_working_threads = 1;
msleep(1000); msleep( 1000 );
#ifdef DOLPHIN_TEST #ifdef DOLPHIN_TEST
/// Cleanup Dolphin card connections /// Cleanup Dolphin card connections
finish_dolphin(); finish_dolphin( );
#endif #endif
#ifndef NO_CPU_SHUTDOWN #ifndef NO_CPU_SHUTDOWN
/// Bring the CPU core back on line /// Bring the CPU core back on line
// Unset the code callback // Unset the code callback
set_fe_code_idle(0, CPUID); set_fe_code_idle( 0, CPUID );
// printkl("Will bring back CPU %d\n", CPUID); // printkl("Will bring back CPU %d\n", CPUID);
msleep(1000); msleep( 1000 );
// Bring the CPU back up // Bring the CPU back up
cpu_up(CPUID); cpu_up( CPUID );
msleep(1000); msleep( 1000 );
printk("Brought the CPU back up\n"); printk( "Brought the CPU back up\n" );
#endif #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_init( rt_iop_init );
module_exit(rt_iop_cleanup); module_exit( rt_iop_cleanup );
MODULE_DESCRIPTION("Control system"); MODULE_DESCRIPTION( "Control system" );
MODULE_AUTHOR("LIGO"); MODULE_AUTHOR( "LIGO" );
MODULE_LICENSE("Dual BSD/GPL"); 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