This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to use DMA copy on IPNC

Hi all:

        As we know "wis-streamer" will call GetAVData() to get frame from AV_SERVER,  and in "wis-streamer" will use memory copy the frame data to it own buffer, now i want to change to use DMA copy solution in "wis-streamer".

       AV_SERVER will call API in drv_dma.h to do DMA copy internal, but when I try to call these API in "wis-streamer", the camera crashed, anyone who can help on this?

       Could we use DMA copy solution in other process(not in AV_SERVER)?

       Thanks.

  • Tracy,

    The DMA driver in IPNC reference design can be used in different processes. Now, i need to understand what all APIs are you calling from your other process to use DMA instead of memcpy().

     

    Can you please let me know more details about the function calls and also the failure condition?

    If you just do the following, it should work:

    1. DRV_dmaOpen

    2. DRV_dmaCopy2D

    3. DRV_dmaClose

    Other things that you should worry about is the alignment details. In network cases, many times the data transfers are non-aligned.

    Regards,

    Anshuman

  • Hi Anshuman:

          Appreciate for you help firstly!

          I had build a sample application which will call call GetAVData() to get frame from AV_SERVER, here is my code detail for you reference(DMA copy part):

          int status = 0;

          DRV_DmaCopy1D copy1D;

          status = CMEM_init();
          if (status < 0)
          {
                fprintf (stderr, "DRV: ERROR: CMEM_init()\n"); 
                return status;
          }

          status = DRV_dmaInit();
          if (status < 0)
          {
                fprintf (stderr, "DRV: ERROR: DRV_dmaInit()\n");
                return status;
          }

          status = DRV_dmaOpen(&Me->encoded.dmaHndl, DRV_DMA_MODE_NORMAL, 1);
          if (status < 0)
          {
                fprintf (stderr, "DRV: ERROR: DRV_dmaOpen()\n");
                return status;
          }

          copy1D.srcPhysAddr = (unsigned long)DRV_dmaGetPhysAddr((unsigned long)av_data.ptr);
          copy1D.dstPhysAddr = (unsigned long)DRV_dmaGetPhysAddr((unsigned long)dest_addr);
          copy1D.size        = av_data.size - 1;
          DRV_dmaCopy1D(&Me->encoded.dmaHndl, &copy1D, 1);

          DRV_dmaClose(&Me->encoded.dmaHndl); 
          DRV_dmaExit();
          CMEM_exit();

  • Tracy,

    Your code looks ok. I dont see a problem there. I have few debug points though:

     

    1. Check if you are getting a EDMa channel allocated after DRV_dmaOpen() is called. You can check it in the Me->encoded.dmaHndl

    2. Check if you are able to get correct SrcPhyAddr and DstPhyAddr from DRV_dmaGetPhysAddr()

    3. Check the copy1D.size that is being passed to DMA copy routine.

     

    BTW, i still did not get the hang condition. Do you mean that DRV_dmaCopy() does not complete and never comes out in your code?

    If any of the above does not give any clue, please enable #define DMA_DEBUG in dev_dma.h. This will tell us if there is any problem in channel allocation of the DMA driver

    Regards,

    Anshuman

  • Hi Anshuman:

                 I found that the crash happend when call DRV_dmaClose() and DRV_dmaExit(). When I call these API in my application, the av_server seems crashed, here list some debug for you reference:

     ERROR  (drv_frameCopy.c DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 53)
    |DRV_frameCopy|2 DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 6)
    24): DRV_dmaCopy DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 6)
    Fill2D() (chId = 6)
     ERROR  (videoFaceDetectThr.c|VIDEO_fdCopyRun|71): DRV_frameCopy(srcOffset:640x480 dstOffse DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 53)
    t:320x480 wxh:640x480)
     ERROR   DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 6)
    (drv_frameCopy.c DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 6)
    |DRV_frameCopy|224): DRV_dmaCopyFill2D() (chId = 6)
     ERROR  (videoDisplayThr.c|VIDEO_displayCopyRun|77): DRV_frameCopy()
     ERROR  (drv_frameCopy.c|DRV_frameCopy|224): DRV_dmaCopyFill2D() (chId = 6)
     ERROR   DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 6)
    (videoFaceDetect DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 53)
    Thr.c|VIDEO_fdCo DRV ERR :DMA_copyFillRun:250: Illegal parameter (chId = 6)

    IN function DRV_dmaExit(), it will close the globle FD gDRV_dmaCtrl.fd, it may impact the av_server, but it comfused me that the API DRV_dmaClose()  will impact the av_server too.

    Could you help explain this?

    Thanks.

  • Tracy,

    Let me clarify a few things:

    1. DRV_dmaInit() and DRV_dmaExit() should be called only once in the overall process context. So in your wis_streamer process case, please call it only once. I assume from your description, that it is getting called inside GetAVData() function, which is getting called multiple times.

    2. DRV_dmaExit() is actually going through all the channels and clearing them. It does not depend upon process. So calling DRV_dmaExit() from wis_streamer should be a problem for av_server process.

    I would suggest making the folloing change in the dev_dma.c file DMA_devRelease() function:

    int DMA_devRelease(struct inode *inode, struct file *filp)
    {
      int i;
      DMA_OpenClosePrm openClosePrm;
     
    #ifdef DMA_DEBUG
      printk(KERN_INFO "DMA: DMA_devRelease()\n");
    #endif

    #if 0

      for(i=0; i<DMA_DEV_MAX_CH; i++)
      {
        if(gDMA_dev.pObj[i]!=NULL)
        {
          openClosePrm.chId = i;
          openClosePrm.mode = gDMA_dev.pObj[i]->dmaMode;          
          openClosePrm.maxTransfers = 0;
          if(openClosePrm.mode==DRV_DMA_MODE_NORMAL) {
            DMA_copyFillDelete(&openClosePrm);       
          } else
          if(openClosePrm.mode==DRV_DMA_MODE_DEMUX) {
            DMA_demuxDelete(&openClosePrm);
          } else {
            FUNCERR( "Illegal parameter (chId = %d)\n", openClosePrm.chId);                               
          }
        }
      }

    #endif

      return 0;
    }

    This way, you are not going to do any cleaning up of EDMA channels in the DRV_dmaExit() routine. But you still need to call DRV_dmaClose() in both wis_streamer and av_server.

    The other option is that you dont call DRV_dmaExit() in wis_streamer at all and let av_server do the cleaning up of the EDMA.

     

    Regards,

    Anshuman

  • Hi Anshuman:

    I know ApproDrvInit() will call CMEM_init(), here is the test code for you reference:

     int qid = 0;
     int status = 0;

     if (ApproDrvInit(2))
     {
      SURE_PRINTF("ApproDrvInit error\n");
      exit(1);
     }
     SURE_PRINTF("%s(%d): ApproDrvInit end\n",__FUNCTION__,__LINE__);
     
     if (func_get_mem(&qid))
     {
      SURE_PRINTF("func_get_mem error\n");
      ApproDrvExit();
      exit(1);
     }
     SURE_PRINTF("%s(%d): func_get_mem end\n",__FUNCTION__,__LINE__);

     status = DRV_dmaInit();
     if (status < 0)
     {
      X_FPRINTF (stderr, "DRV: ERROR: DRV_dmaInit()\n");
      return status;
     }
     SURE_PRINTF("%s(%d): DRV_dmaInit end\n",__FUNCTION__,__LINE__);

     status = DRV_dmaOpen(&Me->encoded.dmaHndl, DRV_DMA_MODE_NORMAL, 1);
     if (status < 0)
     {
      X_FPRINTF (stderr, "DRV: ERROR: DRV_dmaOpen()\n");
      return status;
     }
     SURE_PRINTF("%s(%d): Request DMA Channel ID %d\n", __FUNCTION__, __LINE__, Me->encoded.dmaHndl.chId);

    while (term_flag)

    {

    ...

    GetAVData();

    do_DMA_copy()

    ....

    }


     DRV_dmaClose(&Me->encoded.dmaHndl);
     ApproInterfaceExit();

    The DMA copy can work well, but when I try to kill this process in comand line, I will meet the error which list above.

  • Tracy,

    Now your problem makes more sense. So DRV_dmaClose() is not causing the problem. The problem is coming only when you kill this wis_streamer process from command line. Isnt it?

    Did you change the code like i showed in DMA_devRelease()? This routine is called even if you kill the process from command line as linux goes and closes all open file handle and execute their exit function. It is equivalent of calling DRV_DMAExit().

    So if you remove the piece of code as i mentioned and ensure that you have a called DRV_dmaClose() for all channels, then it should be fine.

    Everytime you do a CTRL+C or kill the av_server process, please make sure to load edmak.ko module again to start the DMA from a clean state.

    Regards,

    Anshuman

     

  • Tracy,

    Any updates on this? Could you get DMA copy working across two processes?

    Regards,

    Anshuman

  • Hi Anshuman:

    Appreciate for you help, the solution you provided is worked in my source code.

    We can note the source in driver if user call the DRV_dmaClose() correctly, right? We SHOULD have closed the channel before we close the driver fd.

    But i think we can update the solution to cover more case, the driver should remember the channel opened by which process, and when this process exit, the driver will close the related channel, right?

  • Tracy,

    Thanks for confirmation. Please mark the answer as verified if it works for you.

    I agree with your idea. We need to do the tracking of channels at process level instead of making it static allocation. Similar fixes have been done in framework components (part of DVSDK), but it need to go in our DMA drivers also. It is not planned currently, but we would surely take this task up in next release.

    Regards,

    Anshuman