Topic
3 replies Latest Post - ‏2012-05-25T18:55:39Z by rakuraku
rakuraku
rakuraku
4 Posts
ACCEPTED ANSWER

Pinned topic More than one DMA transfer to SPU program - SPU is not receiving

‏2012-05-24T21:36:46Z |
Hello, i'm using one of examples from IBM - simple_DMA example.

Code is pretty simple:


/* we allocate one control block, to correspond to one SPE */ control_block cb __attribute__ ((aligned (128)));   
/* this is the pointer to the SPE code, to be used at thread creation time */ extern spe_program_handle_t hello_spu;   
/* this is the handle which will be returned by "spe_context_create."  */ spe_context_ptr_t speid;   
/* this variable is the SPU entry point address which is initially set to the default */ unsigned 

int entry = SPE_DEFAULT_ENTRY;   
/* this variable is used to return data regarding an abnormal return from the SPE */ spe_stop_info_t stop_info;   
/* here is the variable to hold the address returned by the malloc() call. */ 

float *data;       
// NOW THE TRANSFER, WHICH WORKS!!!!!   rc = posix_memalign ((void*)(&data), 128, DATA_BUFFER_SIZE); 

if (rc != 0) 
{ fprintf (stderr, 
"Failed allocating space for data array\n"); exit (1); 
}   
/* Fill the data array */   

for (i=0; i<DATA_BUFFER_ENTRIES; i++) 
{ data[i] = 0.5; printf(
"table PPE: %f\n", data[i]); 
}   

if (spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1) < 1) 
{ fprintf(stderr, 
"System doesn't have a working SPE.  I'm leaving.\n"); 

return -1; 
}   printf(
"Address being sent in control block: %p\n", data);   
/* load the address into the control block */ cb.addr = (unsigned 

long 

long)((uintptr_t)data); 
/* create the SPE context */ 

if ((speid = spe_context_create(0, NULL)) == NULL) 
{ fprintf (stderr, 
"FAILED: spe_context_create(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
} 
/* load the SPE program into the SPE context */ 

if (spe_program_load(speid, &hello_spu) != 0) 
{ fprintf (stderr, 
"FAILED: spe_program_load(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* run the SPE context */ 

if (spe_context_run(speid, &entry, 0, &cb, NULL, &stop_info) < 0) 
{ fprintf (stderr, 
"FAILED: spe_context_run(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
} 
/* destroy the SPE context */ 

if (spe_context_destroy(speid) != 0) 
{ fprintf (stderr, 
"FAILED: spe_context_destroy(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* check the SPE status */ 

if (stop_info.stop_reason == SPE_EXIT) 
{ 

if (stop_info.result.spe_exit_code != 0) 
{ fprintf(stderr, 
"FAILED: SPE returned a non-zero exit status\n"); exit(1); 
} 
} 

else 
{ fprintf(stderr, 
"FAILED: SPE abnormally terminated\n"); exit(1); 
}       
//AFTER THAT I;M FREEING THE MEMORY FROM DATA HERE:   free(data);       
//TRANSFER 2 - WHICH DOESN'T WORK BUT IT'S THE SAME PIECE OF CODE   

for (i=0; i<DATA_BUFFER_ENTRIES; i++) 
{ data[i] = 0.5; printf(
"table PPE: %f\n", data[i]); 
}     rc = posix_memalign ((void*)(&data), 128, DATA_BUFFER_SIZE); 

if (rc != 0) 
{ fprintf (stderr, 
"Failed allocating space for data array\n"); exit (1); 
}     

if (spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1) < 1) 
{ fprintf(stderr, 
"System doesn't have a working SPE.  I'm leaving.\n"); 

return -1; 
}   printf(
"Address being sent in control block: %p\n", data);   
/* load the address into the control block */ cb.addr = (unsigned 

long 

long)((uintptr_t)data); 
/* create the SPE context */ 

if ((speid = spe_context_create(0, NULL)) == NULL) 
{ fprintf (stderr, 
"FAILED: spe_context_create(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
} 
/* load the SPE program into the SPE context */ 

if (spe_program_load(speid, &hello_spu) != 0) 
{ fprintf (stderr, 
"FAILED: spe_program_load(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* run the SPE context */ 

if (spe_context_run(speid, &entry, 0, &cb, NULL, &stop_info) < 0) 
{ fprintf (stderr, 
"FAILED: spe_context_run(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}     
/* destroy the SPE context */ 

if (spe_context_destroy(speid) != 0) 
{ fprintf (stderr, 
"FAILED: spe_context_destroy(errno=%d strerror=%s)\n", errno, strerror(errno)); exit (1); 
}   
/* check the SPE status */ 

if (stop_info.stop_reason == SPE_EXIT) 
{ 

if (stop_info.result.spe_exit_code != 0) 
{ fprintf(stderr, 
"FAILED: SPE returned a non-zero exit status\n"); exit(1); 
} 
} 

else 
{ fprintf(stderr, 
"FAILED: SPE abnormally terminated\n"); exit(1); 
}


SPE code is just mfc_get, displaying the table and giving it back by mfc_put and my problem is, that first transfer works well, and then it's just shows that second transfer has been sent in memory block and program can't move on.

What am i doing wrong? Thanks!
Updated on 2012-05-25T18:55:39Z at 2012-05-25T18:55:39Z by rakuraku
  • jk-
    jk-
    43 Posts
    ACCEPTED ANSWER

    Re: More than one DMA transfer to SPU program - SPU is not receiving

    ‏2012-05-25T02:38:35Z  in response to rakuraku
    Does the program fail to run completely the second time? Or do you still see the output from the SPE program from the second invocation, but the data is wrong?

    If it's the former, then your problem is probably due to re-using the old value of the SPE entry point (the `entry` var in your code). This will cause the SPE program to be started from the instruction that the previous invocation ended at. This is probably not what you want.

    Try resetting the entry var to SPE_DEFAULT_ENTRY before calling the second spe_context_run().
    • rakuraku
      rakuraku
      4 Posts
      ACCEPTED ANSWER

      Re: More than one DMA transfer to SPU program - SPU is not receiving

      ‏2012-05-25T08:35:05Z  in response to jk-
      Thank you for your attention!

      My output is OK for the first transfer, but for the second transfer I see only that the data was sent, and program can't move on then.

      The entry issue is possible, I'll try to do it today, and post the results here - thanks!
    • rakuraku
      rakuraku
      4 Posts
      ACCEPTED ANSWER

      Re: More than one DMA transfer to SPU program - SPU is not receiving

      ‏2012-05-25T18:55:39Z  in response to jk-
      Hey! That's amazing! it worked just when I added the
      
      entry = SPE_DEFAULT_ENTRY;
      
      : )

      Can you tell me how can i synchronize these transfers? I've tried to do that via mailboxes but it doesn't work for me. Now I can only do the same operation with the data sent to my program, how can I make it a way, that my SPU will make another operations to another blocks of data?

      I.e it will changing the values of the first block to 5, it will will chaning the second block to 12 etc.

      Because now it's only can change values of every block to 5 : )

      That's my SPE code:

      
      
      /* Here's the local copy of the control block, to be filled by the DMA */ 
      
      volatile control_block cb __attribute__ ((aligned (128)));   
      /* Here's the local copy of the data array, to be filled by the DMA */ 
      
      float data[DATA_BUFFER_ENTRIES] __attribute__ ((aligned (128)));     
      
      int main(unsigned 
      
      long 
      
      long speid __attribute__ ((unused)), unsigned 
      
      long 
      
      long argp, unsigned 
      
      long 
      
      long envp __attribute__ ((unused))) 
      { 
      
      int i; unsigned 
      
      int tag_id;   
      /* Reserve a tag for application usage */ 
      
      if ((tag_id = mfc_tag_reserve()) == MFC_TAG_INVALID) 
      { printf(
      "ERROR: unable to reserve a tag\n"); 
      
      return 1; 
      }   
      /* Here is the actual DMA call */ 
      /* the first parameter is the address in local store to place the data */ 
      /* the second parameter holds the main memory address                  */ 
      /* the third parameter holds the number of bytes to DMA                */ 
      /* the fourth parameter identifies a "tag" to associate with this DMA */ 
      /* (this should be a number between 0 and 31, inclusive)               */ 
      /* the last two parameters are only useful if you've implemented your  */ 
      /* own cache replacement management policy.  Otherwise set them to 0.  */   mfc_get(&cb, argp, sizeof(cb), tag_id, 0, 0);   
      /* Now, we set the "tag bit" into the correct channel on the hardware  */ 
      /* this is always 1 left-shifted by the tag specified with the DMA     */ 
      /* for whose completion you wish to wait.                              */ mfc_write_tag_mask(1<<tag_id);   
      /* Now, issue the read and wait to guarantee DMA completion before we  */ 
      /* continue. */ mfc_read_tag_status_all();   
      /* DMA the data from system memory to our local store buffer. */ mfc_get(data, cb.addr, DATA_BUFFER_SIZE, tag_id, 0, 0);     printf(
      "Address received through control block = 0x%llx\n", cb.addr);     
      /* Wait for the data array DMA to complete. */ mfc_read_tag_status_all();   
      // CHANGING DATA TABLE CONTENT TO 5!!!   
      
      for (i=2; i<DATA_BUFFER_ENTRIES; i++) 
      {   data[i] = 5.; 
      } 
      //giving it back to the ppu   mfc_put(data, cb.addr, DATA_BUFFER_SIZE, tag_id, 0, 0); printf(
      " \n"); 
      
      return 0; 
      }