FPGA Intellectual Property
PCI Express*, Networking and Connectivity, Memory Interfaces, DSP IP, and Video IP
6526 Discussions

TSE and scatter-gather dma problem

Altera_Forum
Honored Contributor II
1,553 Views

hi, everyone  

I am recently trying to connect nios II to computor through ethernet , I separately connected a memory to stream scatter gather DMA to TSE's transmit and a stream to memory scatter gather DMA to TSE's receive . But when I sent a packet through scatter gather DMA, the output of TSE was nothing , also ,when I send packet from computor to NIOS, the receiving DMA got nothing. 

I had tried connect the memory to stream DMA to stream to memory DMA, it worked OK.  

Please give me some advice ,thanks. 

https://www.alteraforum.com/forum/attachment.php?attachmentid=5665  

when I runned the code below , I checked ouput signals of TSE through signaltap II,but nothing happened 

# include "sys/alt_stdio.h"# include "altera_avalon_sgdma_regs.h"# include "altera_avalon_sgdma.h"# include "altera_avalon_sgdma_descriptor.h" /* These will gate the data checking near the end of main */ volatile alt_u8 tx_done = 0; volatile alt_u8 rx_done = 0; void tx_callback_function(void * context) { tx_done++; /* main will be polling for this value being 1 */ } void rx_callback_function(void * context) { rx_done++; /* main will be polling for this value being 1 */ } unsigned int * mac_rev = (unsigned int *)TRIPLE_SPEED_ETHERNET_BASE; unsigned int * mac_phy_addr = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x3C); unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200); unsigned int * mac_phy_reg_17 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200+ 17*4); char rx_buf; char tx_buf; int i; void init_phy() { * mac_phy_addr = 1; * mac_phy_reg_addr_base = * mac_phy_reg_addr_base | 0x8000; //*mac_phy_reg_addr_base = *mac_phy_reg_addr_base | 0x1000; } int main() { init_phy(); alt_printf("control register is %x\n", *mac_phy_reg_17); alt_sgdma_dev * pSink = alt_avalon_sgdma_open(HITIC_SINK_NAME); if(pSink == NULL) { alt_putstr("open sink error!\n"); } alt_sgdma_dev * pSource = alt_avalon_sgdma_open(HITIC_SOURCE_NAME); if(pSource == NULL) { alt_putstr("open source error!\n"); } /************************************************************** * Register the ISRs that will get called when each (full) * * transfer completes * ************************************************************/ alt_avalon_sgdma_register_callback(pSource, &tx_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); alt_avalon_sgdma_register_callback(pSink, &rx_callback_function, (ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), NULL); /**************************************************************/ alt_sgdma_descriptor sinkDesc, sourceDesc; alt_sgdma_descriptor nextSinkDesc, nextSourceDesc; nextSinkDesc.control = 0; nextSinkDesc.control = 0; alt_avalon_sgdma_construct_stream_to_mem_desc(&sinkDesc, &nextSinkDesc, (alt_u32 *)rx_buf, 100, 0); alt_avalon_sgdma_construct_mem_to_stream_desc(&sourceDesc, &nextSourceDesc, (alt_u32 *)tx_buf, 100, 0, 0, 0, 0); for(i = 0; i < 6; i ++) { tx_buf=0xff; } for(i = 6; i < 12; i ++) { tx_buf=0x11; } tx_buf = 0; tx_buf = 100; // while(1) // { // alt_avalon_sgdma_do_async_transfer(pSource, &sourceDesc); // while(tx_done == 0) {} // alt_putstr("The transmit SGDMA has completed\n"); // tx_done = 0; // for(i = 0; i < 10000000; i++); // } while(1) { alt_avalon_sgdma_do_async_transfer(pSink, &sinkDesc); while(rx_done == 0) {} alt_putstr("The receive SGDMA has completed\n"); rx_done = 0; }
0 Kudos
16 Replies
Altera_Forum
Honored Contributor II
859 Views

Transmit should always work. CHeck with signal tap both the avalon stream interface and the PHY side signals, to check where the transfer is stopped. 

For reception you should configure the MAC with a MAC address, or set it in promiscuous mode, or most of the packets will be filtered and never transmitted to the DMA. 

You should also check if the PHY needs any initialization. 

Is there any reason why you don't use an OS with a tcp/ip stack?
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

I can only use the on chip mem ,so I have not enough space to run os, an I alse need not to use a tcp/ip. 

I just found that only when I unchecked the Aligned packet headers to 32-bit boundary and check SG DMA's Allow unaligned transfers ,I could send data to computor. When received data from computor , after the first packet TSE's start of packet signal always high and sink in ready was always low. The first packet 's data also was not correctly all . 

what's the problem maybe, please give me some advice ,thanks.
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

if the sink ready signal is low it means that the DMA can't receive more data. Check all the signals around the DMA to verify that it got its descriptor and isn't stuck in a memory operation.

0 Kudos
Altera_Forum
Honored Contributor II
859 Views

I have got the problem ,and it works OK now. there are three problem : 

1. I didn't initial the TSE properly ,command_config needed to configure and enable sending and receiving . 

2. I used the asynchronous transfer of sgdma, I find the synchronized transfer works OK, but the asynchronous transfer would encounter some error after just less ten transfers. I don't know why . 

3. If I checked the Align packet headers to 32-bit boundaries in sopc builder ,It did not work at all. 

 

For the problems above ,would you give me some advices, thanks 

sincerely  

hjh
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

2) it depends on your code. When using asynchronous transfers you must be very careful with synchronization, you mustn't modify the descriptor before the transfer is finished. 

3) it should work also without the alignment. Just check that you are sending a correct Ethernet packet when you don't use the alignment (i.e. without the two padding bytes before the Ethernet header).
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

Hello, hujianhua (http://www.alteraforum.com/forum/member.php?u=35796

First of all I tryied to use TSE with InterNich tcp/ip stack (SSS example). And I found that tse_mac_init was called somewhere inside alt_iniche_init() and netmain(): I can see link, speed and other information in console, and all works fine. 

 

But I do not really need OS + tcp/ip stack using for some reasons. So I tryied to use TSE and SGDMA in the same way as you did. 

I unchecked the Aligned packet headers to 32-bit boundary and checked SGDMA's Allow unaligned transfers in SOPC builder. 

When I runned code you posted above, nothing happened.  

I tryied to use async and sync transmitt also... I didn't see any TSE output (trying to observe mdio_out signal of tse with SignaltapII).  

The only message in console was "Control register is ffff". Is it correct value? 

How can I configure command_config to enable send/receive of TSE?
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

 

--- Quote Start ---  

Hello, hujianhua (http://www.alteraforum.com/forum/member.php?u=35796

First of all I tryied to use TSE with InterNich tcp/ip stack (SSS example). And I found that tse_mac_init was called somewhere inside alt_iniche_init() and netmain(): I can see link, speed and other information in console, and all works fine. 

 

But I do not really need OS + tcp/ip stack using for some reasons. So I tryied to use TSE and SGDMA in the same way as you did. 

I unchecked the Aligned packet headers to 32-bit boundary and checked SGDMA's Allow unaligned transfers in SOPC builder. 

When I runned code you posted above, nothing happened.  

I tryied to use async and sync transmitt also... I didn't see any TSE output (trying to observe mdio_out signal of tse with SignaltapII).  

The only message in console was "Control register is ffff". Is it correct value? 

How can I configure command_config to enable send/receive of TSE? 

--- Quote End ---  

 

 

hi, Forester, 

I configured the TSE as : 

unsigned int * mac_addr0 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x00C); 

unsigned int * mac_addr1 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x0010); 

unsigned int * mac_phy_addr = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x3C); 

unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200); 

unsigned int * mac_command_configure = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x008); 

* mac_addr0 = 0x17231c00;//the mac address 

* mac_addr1 = 0x0000cb4a;//the mac address 

* mac_command_configure = *mac_command_configure | 0x2000; //reset TSE 

for(i = 0; i < 10000000; i++); 

* mac_command_configure = *mac_command_configure | 0x00800233;//configure 

 

use the configure above can enable the TSE trans, you can look up the detail information from Triple speed ehternet user guide. 

 

you can contact me by hujianhua.jianhua@163.com 

 

 

0 Kudos
Altera_Forum
Honored Contributor II
859 Views

unsigned int * mac_rev = (unsigned int *)TRIPLE_SPEED_ETHERNET_BASE; 

unsigned int * mac_command_configure = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x008); 

unsigned int * mac_addr0 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x00C); 

unsigned int * mac_addr1 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+ 0x0010); 

unsigned int * mac_phy_addr = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x3C); 

unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200); 

unsigned int * mac_phy_reg_17 = (unsigned int *)(TRIPLE_SPEED_ETHERNET_BASE+0x200+ 17*4); 

 

* mac_addr0 = 0x17231c00; 

* mac_addr1 = 0x0000cb4a; 

* mac_command_configure = *mac_command_configure | 0x2000; //reset TSE 

for(i = 0; i < 10000000; i++); 

* mac_command_configure = *mac_command_configure | 0x00800233;
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

Hello, 

Here is test code: 

 

 

/* These will gate the data checking near the end of main */ 

volatile alt_u8 tx_done = 0; 

volatile alt_u8 rx_done = 0; 

 

void tx_callback_function(void * context) 

tx_done++; /* main will be polling for this value being 1 */ 

 

void rx_callback_function(void * context) 

rx_done++; /* main will be polling for this value being 1 */ 

 

// Base configuration register 

unsigned int * mac_addr0 = (unsigned int *)(TSE_BASE + 0x00C); // mac0 

unsigned int * mac_addr1 = (unsigned int *)(TSE_BASE + 0x010); // mac1 

 

// mdio_addr0 register 

unsigned int * mac_phy_addr = (unsigned int *)(TSE_BASE + 0x03C); 

 

// Command configuration register 

unsigned int * mac_command_configure = (unsigned int *)(TSE_BASE + 0x008); 

 

// MDIO Space 0 (map to PHY device 0) 

unsigned int * mac_phy_reg_addr_base = (unsigned int *)(TSE_BASE + 0x200); 

 

// ( PHY = DP8384I ) 

// PHY basic mode control register 

unsigned int * mac_phy_reg_0 = (unsigned int *)(TSE_BASE + 0x200); 

 

// PHY mode status register 

unsigned int * mac_phy_reg_1 = (unsigned int *)(TSE_BASE + 0x200 + 1 * 4); 

 

// PHY status register 

unsigned int * mac_phy_reg_10 = (unsigned int *)(TSE_BASE + 0x200 + 10 * 4); 

 

// PHY control register 

unsigned int * mac_phy_reg_19 = (unsigned int *)(TSE_BASE + 0x200 + 19 * 4); 

 

char rx_buf[1800]; 

char tx_buf[1800]; 

 

void init_phy() 

# define PHY_RESET 0x8000 

# define PHY_AUTONEG_ENA 0x1000 

 

long i; 

 

*mac_phy_addr = 0x01; // associate MAC with with PHY addr = 0x01 

*mac_phy_reg_0 = *mac_phy_reg_0 | PHY_AUTONEG_ENA; 

 

 

# define AUTO_MDIX 0x8000 

 

*mac_phy_reg_19 = *mac_phy_reg_19 | AUTO_MDIX; 

 

void init_tse() 

*mac_addr0 = 0x17231c00; // set MAC = 

*mac_addr1 = 0x0000cb4a; // 00-1c-23-17-4a-cb 

 

# define TX_ENA 0x00000001 

# define RX_ENA 0x00000002 

# define PROMIS_EN 0x00000010 

# define PAD_EN 0x00000020 

# define TX_ADDR_INS 0x00000200 

# define SW_RESET 0x00002000 

# define CTR_FRM_ENA 0x00800000 

 

 

*mac_command_configure = *mac_command_configure | SW_RESET; // Reset 

 

while ( *mac_command_configure & SW_RESET ) // wait for reset complete 

alt_putstr("reset in progress\n"); 

 

*mac_command_configure = *mac_command_configure | PROMIS_EN; 

*mac_command_configure = *mac_command_configure | PAD_EN; 

*mac_command_configure = *mac_command_configure | TX_ADDR_INS; 

*mac_command_configure = *mac_command_configure | CTR_FRM_ENA; 

*mac_command_configure = *mac_command_configure | RX_ENA; 

*mac_command_configure = *mac_command_configure | TX_ENA; 

 

int main() 

int i; 

 

init_tse(); 

alt_printf("command_cfg register is %x\n", *mac_command_configure); 

 

init_phy(); 

for(i = 0; i < 10000000; i++); 

 

alt_printf("PHY mode status is %x\n", *mac_phy_reg_1); 

alt_printf("PHY status is %x\n", *mac_phy_reg_10); 

alt_printf("PHY control is %x\n", *mac_phy_reg_19); 

 

 

alt_sgdma_dev * pSink = alt_avalon_sgdma_open(SGDMA_RX_NAME); 

if(pSink == NULL) 

alt_putstr("open sink error!\n"); 

else 

alt_putstr("sink was opened\n"); 

 

alt_sgdma_dev * pSource = alt_avalon_sgdma_open(SGDMA_TX_NAME); 

if(pSource == NULL) 

alt_putstr("open source error!\n"); 

else 

alt_putstr("source was opened\n"); 

 

/************************************************************** 

* Register the ISRs that will get called when each (full) * 

* transfer completes * 

************************************************************/ 

alt_avalon_sgdma_register_callback(pSource, &tx_callback_function, 

(ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), 

NULL); 

alt_avalon_sgdma_register_callback(pSink, &rx_callback_function, 

(ALTERA_AVALON_SGDMA_CONTROL_IE_GLOBAL_MSK | ALTERA_AVALON_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK), 

NULL); 

/**************************************************************/ 

 

alt_sgdma_descriptor sinkDesc, sourceDesc; 

alt_sgdma_descriptor nextSinkDesc, nextSourceDesc; 

nextSinkDesc.control = 0; 

nextSourceDesc.control = 0; 

 

alt_avalon_sgdma_construct_stream_to_mem_desc(&sinkDesc, &nextSinkDesc, 

(alt_u32 *)rx_buf, 100, 0); 

alt_avalon_sgdma_construct_mem_to_stream_desc(&sourceDesc, &nextSourceDesc, 

(alt_u32 *)tx_buf, 100, 0, 0, 0, 0); 

for(i = 0; i < 6; i ++) 

tx_buf = 0xff; 

for(i = 6; i < 12; i ++) 

tx_buf = 0x11; 

tx_buf[12] = 0; 

tx_buf[13] = 100; 

 

 

while(1) 

//alt_avalon_sgdma_do_async_transfer(pSource, &sourceDesc); 

alt_avalon_sgdma_do_sync_transfer(pSource, &sourceDesc); 

while(tx_done == 0) {} 

alt_putstr("The transmit SGDMA has completed\n"); 

tx_done = 0; 

 

As a result, I see only 

 

command_cfg register is 800233 

PHY mode status is 7869 

PHY status is 0 

PHY control is 0 

sink was opened 

source was opened 

 

and nothing is transmitted via tse. 

Is it important, tse or phy is inited earlier?
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

Does the Nios CPU have a data cache? If yes, then it is possible that the values you set aren't written to the TSE, but just in the data cache instead. You can try and disable the data cache, use some IOWR/IORD macros to write the TSE registers, use uncached pointers (set bit 31 in the address) or flush the data cache once you are done configuring the TSE, and invalidating it before reading the PHY registers.

0 Kudos
Altera_Forum
Honored Contributor II
859 Views

Hello, Daixiwen. 

Thank you so much for clarifications. 

I tried to use uncached pointers (with 31 bit set). Now after TSE and PHY initialization complete, I read PHY mode status register, and bits "Auto-Negotiation Complete" and "Link Status" are both 1. So, PHY is configurated correctly and evidently must work. 

However, I can't see any data on TSE output, and code never comes to 'tx_done = 1'.  

I think that sgdma in my project is not configurated properly, or some changes are needed in software functions where I try to send data... 

 

Is there any other simple way to test TSE sending/receiving without sgdma?  

Actually I need to receive raw ethernet frames in my project, but first of all I try to send data as I think it should be easier to make it work. 

I looked through some threads in altera forums, but unfortunately didn't find any thread about how to receive ethernet frames with TSE and NOT using interNiche stack and OS.
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

Some data was transmitted via ethernet now: as I said in previous post, sgdma was initialized incorrectly. 

But while catching the packets with Wireshark, I see that packets content isn't correct. 

Besides that the packet was transmitted only twice (instead of infinite sending), after 2 transmissions code never comes to tx_done++, so it is looped in while(tx_done == 0); 

I have attached zip-code of source files. 

 

The only correct information is the source mac (00-11-22-33-44-55) 

All other bytes should be 0xA5 (as initialized), but in fact I see such packet: 

 

CC CC A5 A5 CC CC 00 11 22 33 44 55 CC CC A5 A5 CC CC A5 A5 CC CC A5 A5 CC CC  

and so on... 

Total length is also correct (128 bytes). 

I have no ideas, what happens...
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

 

--- Quote Start ---  

Some data was transmitted via ethernet now: as I said in previous post, sgdma was initialized incorrectly. 

But while catching the packets with Wireshark, I see that packets content isn't correct. 

Besides that the packet was transmitted only twice (instead of infinite sending), after 2 transmissions code never comes to tx_done++, so it is looped in while(tx_done == 0); 

I have attached zip-code of source files. 

 

The only correct information is the source mac (00-11-22-33-44-55) 

All other bytes should be 0xA5 (as initialized), but in fact I see such packet: 

 

CC CC A5 A5 CC CC 00 11 22 33 44 55 CC CC A5 A5 CC CC A5 A5 CC CC A5 A5 CC CC  

and so on... 

Total length is also correct (128 bytes). 

I have no ideas, what happens... 

--- Quote End ---  

 

 

One of the problem is that sgdma descriptor should be constructed before every cycle of transmitting. 

So, now I achieved stable tramsmitting of packets by TSE ( in while(1) loop ). The only issue is that packet content is incorrect (only MAC of source is OK )...
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

I'd look carefully at the write cycles into the tx fifo.

0 Kudos
Altera_Forum
Honored Contributor II
859 Views

It could be a problem with the data cache again, although it is rather odd that it would only get the high (or low) 16 bits of every 32-bit word correctly. 

I'd suggest to use signaltap to monitor what the SGDMA is doing, on both the TX fifo (as dsl suggests) and the Avalon master mread interface, to check what address the DMA is using and what it is reading there.
0 Kudos
Altera_Forum
Honored Contributor II
859 Views

The issue was very simple: 

 

alt_avalon_sgdma_construct_mem_to_stream_desc( 

&sourceDesc[0], // descriptor I want to work with 

&nextSourceDesc[0], // pointer to "next" 

(alt_u32 *)ActualData, // starting read address 

(length), //# bytes 

0, // don't read from constant address 

1, // generate sop 

1, // generate endofpacket signal 

0);  

 

Parameter 5 should be 0 (zero) - don't read from constant address. Now all eth packets are transmitted correctly. 

So, thanks, everyone, for clarifications and suggestions. 

As actually I need to receive raw ethernet frames, I'll try to modificate the project for such a purpose.
0 Kudos
Reply