• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

llif26.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * File:
00004  *
00005  * $RCSfile: llif26.c,v $
00006  * 
00007  * Copyright (C) 2001 D-TACQ Solutions Ltd
00008  * not to be used without owner's permission
00009  *
00010  * Description: implmentation of device driver interface for LLC
00011  *
00012  * $Id: llif26.c,v 1.4 2010/08/26 16:25:52 pgm Exp $
00013  * $Log: llif26.c,v $
00014  * Revision 1.4  2010/08/26 16:25:52  pgm
00015  * more switchable instrumentation
00016  *
00017  * Revision 1.3  2007/05/01 19:22:04  pgm
00018  * linux26 device index from 0
00019  *
00020  * Revision 1.2  2007/02/19 15:22:23  pgm
00021  * *** empty log message ***
00022  *
00023  * Revision 1.1  2006/06/19 13:13:30  pgm
00024  * *** empty log message ***
00025  *
00026  * Revision 1.18.4.17  2006/02/22 10:25:47  pgm
00027  * fix dbg snafu
00028  *
00029  *
00030  *
00031 \*****************************************************************************/
00032 
00033 /** @file llif26.c  implementation of device driver interface 
00034  * for LLC for kernel .2.6x.
00035  */
00036 
00037 
00038 
00039 #include "local.h"
00040 
00041 
00042 #include <assert.h>
00043 #include "llif.h"
00044 
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 
00048 #include <errno.h>
00049 #include <fcntl.h>
00050 #include <sys/ioctl.h>
00051 #include <sys/mman.h>
00052 #include <sys/stat.h>
00053 #include <sys/types.h>
00054 #include <stdio.h>
00055 #include <unistd.h>
00056 
00057 
00058 #include "acq32ioctl.h"
00059 
00060 
00061 
00062 
00063 
00064 #ifndef dbg
00065 #define dbg(level, fmt, arg...)  fprintf(stderr, fmt, ## arg)
00066 #endif
00067 
00068 typedef volatile u32 r32;
00069 
00070 struct MU {
00071         int fd;                         // alternate - use ioctl to access
00072         r32* mailboxes;                 // or mapping (x86 only)
00073         u32 mailboxes_shadow[4];        // up to dat cache of write values
00074         u32 mailboxes_lastwrite[4];     // what did we write last ??
00075         r32 *inbound_q_port;            /* inbound on target */
00076         r32 *outbound_q_port;
00077 
00078         int poll_count;
00079 };
00080 
00081 #define FNAME_FMT        "/dev/acq32/acq32.%d."
00082 #define FNAME_FMT_MBOX   FNAME_FMT "raw"
00083 #define FNAME_FMT_DMABUF FNAME_FMT "01"    // don't ask - this is a convenience
00084 
00085 #define FNAME_FMT_HOST   FNAME_FMT "host"
00086 
00087 #define FMT_SYS_PARAMS  "/sys/module/acq200_hostdrv/parameters/"
00088 #define FMT_SYS_SLOTS           FMT_SYS_PARAMS "slots"
00089 
00090 #define FMT_SYS_DEV "/sys/class/acqX00/acq200.%d/device/"
00091 #define FMT_SYS_DEV_HOST_PA     FMT_SYS_DEV "host_pa"
00092 #define FMT_SYS_DEV_HOST_LEN    FMT_SYS_DEV "host_len"
00093 
00094 
00095 static int lookup_device_index(int slot)
00096 {
00097         static int mapping[16];
00098         static int valid;
00099         int rc;
00100         
00101         if (!valid){
00102                 char slotdef[128];              
00103                 int ii;
00104                 FILE *fp;               
00105                 
00106                 fp = fopen(FMT_SYS_SLOTS, "r");
00107                 if (!fp){
00108                         fprintf(stderr, "Failed to open slot mapping:\"%s\"", 
00109                                 FMT_SYS_SLOTS); 
00110                         exit(errno);
00111                 }
00112                                 
00113                 for (ii = 0; ii < 16; ++ii){
00114                         mapping[ii] = -1;       
00115                 }
00116                 if (fgets(slotdef, 128, fp)){
00117                         char *cp;
00118                         for (cp = slotdef, ii = 0; 
00119                                 ii < 16 && (cp = strtok(cp, ",")) != 0; 
00120                                 cp = 0, ++ii){
00121                                         
00122                                 int slot_num = atoi(cp);
00123                                 assert(IN_RANGE(slot_num, 0, 15));
00124                                 if (slot_num != 0){
00125                                         mapping[slot_num] = ii;         
00126                                 }       
00127                         }
00128                 }                               
00129                 valid = 1;      
00130         }
00131         
00132         rc = mapping[slot];
00133         if (rc == -1){
00134                 fprintf(stderr, "No device found for slot %d", slot);
00135                 exit(-1);       
00136         }
00137         return rc;
00138 }
00139 static unsigned host_len(int iboard) {
00140         char fname[80];
00141         char line[80];
00142         char *my_line;
00143         unsigned len = 0;
00144         int rc;
00145         
00146         sprintf(fname, FMT_SYS_DEV_HOST_LEN, lookup_device_index(iboard));
00147         FILE *fp = fopen(fname, "r");
00148         assert(fp);
00149 
00150         my_line = fgets(line, sizeof(line), fp);
00151         assert(my_line);
00152         
00153         rc = sscanf(my_line, "%u", &len);
00154         assert(rc);
00155         return len;
00156 }
00157 static unsigned host_pa(int iboard) {
00158         char fname[80];
00159         char line[80];
00160         char *my_line;
00161         unsigned pa = 0;
00162         int rc;
00163 
00164         sprintf(fname, FMT_SYS_DEV_HOST_PA, lookup_device_index(iboard));
00165         FILE *fp = fopen(fname, "r");
00166         assert(fp);
00167 
00168         my_line = fgets(line, sizeof(line), fp);
00169         assert(my_line);
00170         
00171         rc = sscanf(my_line, "0x%x", &pa);
00172         assert(rc);
00173         return pa;
00174 }
00175 
00176 int setMbox( struct MU* m, int ibox, u32 value )      
00177 // set a mail mbox register: ibox {0..3}. return 0 on success
00178 {
00179         assert( IN_RANGE( ibox, 0, 3 ) );
00180 
00181     
00182         PRINTF(3)( "setMbox( %d, 0x%08x )\n", ibox, value );
00183         m->mailboxes[ibox] = 
00184                 m->mailboxes_shadow[ibox] = 
00185                 m->mailboxes_lastwrite[ibox] = value;    
00186 
00187         return 0;   
00188 }    
00189 
00190 void showLastWrites( struct MU* m )
00191 {
00192         fprintf( stderr, "lastWrites()\n" );
00193         fprintf( stderr, "0x%08x  0x%08x  0x%08x  0x%08x\n",
00194                  m->mailboxes_lastwrite[0],
00195                  m->mailboxes_lastwrite[1],
00196                  m->mailboxes_lastwrite[2],
00197                  m->mailboxes_lastwrite[3] );
00198 }
00199 int setMboxBits( struct MU* m, int ibox, u32 bits_to_set )
00200 {
00201         assert( IN_RANGE( ibox, 0, 3 ) );
00202     
00203         m->mailboxes[ibox] = m->mailboxes_shadow[ibox] |= bits_to_set;
00204         return 0;
00205 }
00206 
00207 int clrMboxBits( struct MU* m, int ibox, u32 bits_to_clr )
00208 {
00209         assert( IN_RANGE( ibox, 0, 3 ) );
00210     
00211         m->mailboxes[ibox] = m->mailboxes_shadow[ibox] &= ~bits_to_clr;
00212         return 0;
00213 }
00214 
00215 int setMboxField( struct MU* m, 
00216                   int ibox, u32 field_mask, u32 field_value )
00217 {
00218         assert( IN_RANGE( ibox, 0, 3 ) );
00219     
00220         m->mailboxes_shadow[ibox] &= ~field_mask;
00221         m->mailboxes_shadow[ibox] |= field_value;
00222         m->mailboxes[ibox] = m->mailboxes_shadow[ibox];
00223         return 0;
00224 }
00225 
00226 u32 getMbox( struct MU* m, int ibox )      
00227 // get contents of mailbox register: ibox {0..3}
00228 {
00229         u32 newval;
00230     
00231         assert( IN_RANGE( ibox, 0, 3 ) );
00232 
00233         newval = m->mailboxes[ibox];
00234     
00235         if ( newval != m->mailboxes_shadow[ibox] ){
00236                 PRINTF(4)( "getMbox( %d ) was:0x%08x now:0x%08x\n", 
00237                            ibox, m->mailboxes_shadow[ibox],
00238                            newval);
00239         }
00240     
00241         m->mailboxes_shadow[ibox] = newval;
00242         return m->mailboxes_shadow[ibox];
00243 }
00244 
00245 u32 getMboxShadow(struct MU* m, int ibox)
00246 {
00247         assert( IN_RANGE( ibox, 0, 3 ) );
00248         return m->mailboxes_shadow[ibox];
00249 }
00250 
00251 u32 pollMboxBits( struct MU* m, int ibox, u32 mask, u32 goal )
00252 {
00253         int ipoll = 0;
00254         u32 mbtemp;
00255     
00256         while( ( (mbtemp = getMbox( m, ibox ))&mask ) == 0 ){
00257                 if ( (++ipoll&0x3ffff) == 0 ){
00258                         fprintf( stderr, 
00259                                  "pollMboxBits() mask:0x%08x goal:0x%08x got:0x%08x\n",
00260                                  mask, goal, mbtemp       );
00261                 }
00262         }
00263     
00264         PRINTF(4)( "pollMboxBits() returning 0x%08x\n", mbtemp );
00265         return mbtemp;
00266 }
00267 
00268 
00269 void setMboxPollcount(struct MU* m, int poll_count)
00270 {
00271         m->poll_count = poll_count;
00272 }
00273 int getMboxPollcount(struct MU* m)
00274 {
00275         return m->poll_count;
00276 }
00277 
00278 
00279 struct MU* mmapMbox( int iboard )   
00280 // iboard {1..3}. return 0 on success
00281 {
00282         char fname[80];
00283 
00284         void* region;
00285         struct MU* m = malloc( sizeof(struct MU) );
00286         unsigned offset;
00287 
00288         assert( m != 0 );    
00289         assert( IN_RANGE( iboard, 1, 8 ) );
00290     
00291         sprintf( fname, FNAME_FMT_MBOX, iboard );
00292 
00293         if ( (m->fd = open( fname, O_RDWR )) < 0 ){
00294                 fprintf( stderr, "mmap: failed to open device \"%s\" - ", fname );
00295                 perror( "" );
00296                 exit( 1 );
00297         }
00298 
00299         region = mmap( NULL, 0x400, PROT_READ|PROT_WRITE, MAP_SHARED, m->fd, 0 );
00300 
00301         if ( region == (void*)-1 ){
00302                 char errbuf[256];
00303                 sprintf(errbuf, "%s %s", "mmap", fname);
00304                 perror(errbuf);
00305                 exit( 1 );
00306         }
00307     
00308 #if 0
00309         // IO not on page boundary - get the offset to adjust
00310     
00311         if ( ioctl( m->fd, ACQ32_IOG_PCIREGS_OFFSET, &offset ) != 0 ){
00312                 perror( "ioctl ACQ32_IOG_PCIREGS_OFFSET" );
00313                 exit( 1 );
00314         }
00315 #else
00316         offset = 16;
00317 #endif
00318 
00319         PRINTF(1)("mmap %p offset %d\n", region, offset);
00320         PRINTF(2)("data: %08x %08x %08x %08x\n",
00321                   ((unsigned*)(region+offset))[0],
00322                   ((unsigned*)(region+offset))[1],
00323                   ((unsigned*)(region+offset))[2],
00324                   ((unsigned*)(region+offset))[3] );
00325 
00326 #ifndef __ACQ196__
00327         m->mailboxes = (r32*)((char*)region+offset+MAILBOX_0);
00328 #else
00329         m->mailboxes = (r32*)((char*)region+offset);
00330         m->inbound_q_port = (r32*)((char*)region+offset+0x30);
00331         m->outbound_q_port = (r32*)((char*)region+offset+0x34);
00332 #endif
00333         getMbox( m, 0 );
00334         getMbox( m, 1 );
00335         getMbox( m, 2 );
00336         getMbox( m, 3 );
00337 
00338         return m;
00339 }
00340 
00341 
00342 /*
00343  * mmapDmaBuffer obtains a user space buffer
00344  * in virtual memory, this is mapped linearly
00345  * in physical memory, this is a series of 128K blocks
00346  *
00347  * if the allocated length < 128K, no problem, it's just linear memory
00348  *
00349  * clients should use getBusAddr to get the appropriate bus address for offset
00350  */
00351  
00352 #define MAX_MAPPING 0x00100000        // 1MB is a handy # to play with
00353 #define MAX_SEG     0x00020000        // Linux maps 128k segments
00354 
00355 #define MAX_SEGMENTS    (MAX_MAPPING/MAX_SEG)
00356  
00357 struct SegmentMap {
00358         int offset;
00359         int length;
00360         u32 physaddr;
00361         int pad;
00362 };
00363 
00364 
00365 struct DmaBuffer {
00366         u32* vaddr;
00367         int nbytes;
00368         struct SegmentMap seg_map[MAX_SEGMENTS];
00369 };
00370 
00371 int getDmaBufferLen(struct DmaBuffer* buffer)
00372 {
00373         return buffer->nbytes;
00374 }
00375 
00376 struct DmaBuffer* mmapDmaBuffer( int iboard, unsigned nbytes )
00377 // maps dma buffer, nbytes long. ret 0 on success
00378 // iboard {1..4}
00379 {
00380         char fname[80];
00381         int fd_in;
00382         caddr_t* region;
00383         u32* phys_defs;
00384         int idef;
00385         u32 offset;
00386         int rc;
00387         struct DmaBuffer* d = malloc( sizeof( struct DmaBuffer ) );
00388     
00389         PRINTF(1)("mmapDmaBuffer 01\n");
00390 
00391         assert( d != 0 );
00392     
00393         sprintf( fname, FNAME_FMT_DMABUF, iboard );
00394 /*
00395  * (1)open() a path to the device
00396  */
00397         if ( (fd_in = open( fname, O_RDWR )) < 0 ){
00398                 fprintf( stderr, "mmap: failed to open device \"%s\" - ", fname );
00399                 perror( "" );
00400                 exit( 1 );
00401         }
00402 
00403 /*
00404  * (2) mmap() a buffer
00405  */
00406  
00407         region = mmap( NULL, nbytes, PROT_READ|PROT_WRITE, MAP_SHARED, fd_in, 0 );
00408 
00409         if ( region == (caddr_t*)-1 ){
00410                 perror( "mmap" );
00411                 exit( 1 );
00412         }
00413 
00414 /*
00415  * (3) ioctl() - fetch the phys defs
00416  */
00417  
00418         PRINTF(3)( "region is %p\n", region );
00419      
00420         rc = ioctl( fd_in, ACQ32_IOREAD_GETPHYSICAL, region );
00421 
00422         if ( rc < 0 ){
00423                 perror( "ioctl ACQ32_IOREAD_GETPHYSICAL failed" );
00424                 exit( 1 );
00425         }
00426     
00427 /*
00428  * now decode the physical mem defs in buffer.
00429  */
00430         phys_defs = (u32*)region;
00431      
00432         for ( idef = 0, offset = 0; idef != MAX_SEGMENTS; idef += 1 ){
00433                 if ( phys_defs[idef*2] == 0 ){
00434                         PRINTF(3)( "quitting after %d segments\n", idef );
00435                         break;
00436                 }else{
00437                         PRINTF(3)( "adding segment %d at offset 0x%08x phys 0x%08x"
00438                                    " len 0x%08x\n",
00439                                    idef, offset, phys_defs[idef*2], phys_defs[idef*2+1] );
00440                         d->seg_map[idef].offset = offset;
00441                         d->seg_map[idef].physaddr = phys_defs[idef*2];
00442                         d->seg_map[idef].length = phys_defs[idef*2+1];                   
00443                         offset += phys_defs[idef*2+1];
00444                 }
00445         }
00446     
00447         d->vaddr = (u32*)region;
00448         d->nbytes = nbytes;
00449         return d;
00450 }
00451 
00452 u32 getBusAddr( struct DmaBuffer* d, u32 offset ) 
00453 // returns mapped bus address for offset (bytes) 
00454 // warning: client is assumed not to go over the end of a segment
00455 // BUT client has no way of knowng where the end is ...
00456 {
00457         int idef;
00458     
00459         for ( idef = 0; idef != MAX_SEGMENTS; ++idef ){
00460                 if ( offset >= d->seg_map[idef].offset && 
00461                      offset < d->seg_map[idef].offset + d->seg_map[idef].length ){
00462                         return d->seg_map[idef].physaddr + offset - 
00463                                 d->seg_map[idef].offset;
00464                 }
00465         }
00466     
00467         return 0;
00468 }
00469 
00470 u32* getVaddr( struct DmaBuffer* db, u32 offset )
00471 {
00472         if ( offset < db->nbytes ){
00473                 PRINTF(4)( "getVaddr %p %d %p\n", db->vaddr, offset, 
00474                            &db->vaddr[offset/sizeof(u32)] );
00475         
00476                 return &db->vaddr[offset/sizeof(u32)];
00477         }else{
00478                 return 0;
00479         }
00480 }
00481 
00482 void acq32_enableInts( struct MU* mbx, unsigned mask )
00483 {
00484         if ( ioctl( mbx->fd, ACQ32_IOS_INTS_ENABLE, mask ) != 0 ){
00485                 perror( "ioctl ACQ32_IOS_INTS_ENABLE" );
00486                 exit( 1 );
00487         }
00488 }
00489 void acq32_maskInts( struct MU* mbx, unsigned mask )
00490 {
00491         if ( ioctl( mbx->fd, ACQ32_IOS_INTS_DISABLE, mask ) != 0 ){
00492                 perror( "ioctl ACQ32_IOS_INTS_DISABLE" );
00493                 exit( 1 );
00494         }
00495 }
00496 
00497 
00498 
00499 struct DmaBuffer* mmapBigBuffer( int iboard, unsigned nbytes )
00500 // maps dma buffer, nbytes long. ret 0 on success
00501 // iboard {1..4}
00502 {
00503 #define FN "mmapDmaBuffer() "
00504         char fname[80];
00505         int fd_in;
00506         caddr_t* region;
00507         struct DmaBuffer* d = malloc( sizeof( struct DmaBuffer ) );
00508     
00509         assert( d != 0 );
00510 
00511 
00512 
00513         sprintf(fname, FNAME_FMT_HOST, iboard );
00514 
00515         PRINTF(1)(FN"01: open %s\n", fname);
00516 /*
00517  * (1)open() a path to the device
00518  */
00519         if ( (fd_in = open( fname, O_RDWR )) < 0 ){
00520                 fprintf(stderr, "mmap:failed to open device \"%s\" - ", fname);
00521                 perror( "" );
00522                 exit( 1 );
00523         }
00524 
00525 /*
00526  * (2) mmap() a buffer
00527  */
00528 #ifdef __ACQ196__
00529         nbytes = host_len(iboard);
00530         PRINTF(1)(FN"ask for full bigbuf portion %x\n", nbytes);
00531 #endif
00532  
00533         PRINTF(1)( FN"map at most %d bytes\n", nbytes );
00534 
00535         region = mmap( NULL, nbytes, PROT_READ|PROT_WRITE, MAP_SHARED, fd_in, 0 );
00536 
00537         if ( region == (caddr_t*)-1 ){
00538                 perror( "mmap" );
00539                 exit( 1 );
00540         }
00541 
00542         /* fill in a single segment .. 
00543          * @todo remove over complex segmented design hang over
00544          */
00545         d->seg_map[0].physaddr = host_pa(iboard);
00546         d->seg_map[0].offset = 0;
00547         d->seg_map[0].length = nbytes;
00548         d->vaddr = (u32*)region;
00549         d->nbytes = nbytes;
00550 
00551         PRINTF(1)( FN "physaddr 0x%08x vaddr 0x%08x\n", 
00552                    d->seg_map[0].physaddr, (u32)d->vaddr );
00553 
00554         return d;
00555 #undef FN    
00556 }
00557 
00558 
00559 void mmapValidateDmaBuffer( struct MU* m, int nsamples )
00560 {
00561 
00562 }
00563 
00564 #define INITBUF_MARKER 0x1100c0de   /* chances of 4 channels all having this val => 0*/
00565 
00566 
00567 
00568 static void udelay(int usecs)
00569 /* a wild guess at a microsecond delay. aim is to "rest" memory to let 
00570  * external DMA have accesss. We assume this code runs from cache ...
00571  */
00572 {
00573         volatile int ii;
00574 
00575         while(usecs--){
00576                 for(ii = 0x10; --ii;){
00577                         ;
00578                 }
00579         }
00580 }
00581 
00582 void hbPrimeBuffer(struct DmaBuffer *buf)
00583 /* one shot buffer priming pre run */
00584 {
00585         int len = buf->nbytes - 0x100000;
00586 
00587         assert(len > 0);
00588 
00589         memset32(buf->vaddr, INITBUF_MARKER, len/sizeof(u32));
00590 }
00591 
00592 void hbPrimePoll(struct DmaBuffer *buf, int offset, int sample_len)
00593 {
00594         int end32 = (offset + sample_len)/sizeof(u32);
00595         volatile u32* marker = &buf->vaddr[end32-2];
00596 
00597         marker[0] = INITBUF_MARKER;
00598         marker[1] = INITBUF_MARKER;
00599 }
00600 int hbPoll(
00601         struct DmaBuffer *buf, int offset, int sample_len,
00602         volatile int *user_abort)
00603 {
00604         int end32 = (offset + sample_len)/sizeof(u32);
00605         volatile u32* marker = &buf->vaddr[end32-2];
00606         int ipoll = 1;
00607         int reported = 0;
00608 
00609         while (marker[0] == INITBUF_MARKER && marker[1] == INITBUF_MARKER){
00610                 udelay(1);
00611                 ++ipoll;
00612                 if (ipoll > 10000 && !reported){
00613                         PRINTF(1)("hbPoll looking at %p\n", marker);
00614                         reported = 1;
00615                 }
00616                 if (*user_abort){
00617                         break;
00618                 }
00619         }
00620 
00621         return ipoll;
00622 }
00623 
00624 
00625 MFA mu_reserveOutbound(struct MU* mu)
00626 {
00627         return *mu->inbound_q_port;
00628 }
00629 int mu_putOutbound(struct MU* mu, MFA mfa)
00630 /* return 0 on success */
00631 {
00632         *mu->inbound_q_port = mfa;
00633         return 0;
00634 }
00635 
00636 
00637 MFA mu_getInbound(struct MU* mu)
00638 {
00639         return *mu->outbound_q_port;
00640 }
00641 int mu_returnInbound(struct MU* mu, MFA mfa)
00642 {
00643         *mu->outbound_q_port = mfa;
00644         return 0;
00645 }
00646 

Generated on Wed Jan 5 2011 for llcontrol by  doxygen 1.7.1