Forum Discussion
Altera_Forum
Honored Contributor
14 years agoIgor,
Building your program (changing it to NO_SYS=1 and no RTOS) doesn't download - some debugger complaint about running 2 programs? Anyway, adding echo.c to my version of the example does run and I can confirm your finding. This is pretty bad - I don't know why I don't find this problem in real applications - even those using telnet. Anyway, you cannot send more bytes than required to meet the minimum 4 quantity. The only option is to copy the pbuf chains to a single pbuf. I think this sucks! But so it is. This works:
/* @Function Description - TSE transmit API to send data to the MAC
*
*
* @API TYPE - Public
* @param net - NET structure associated with the TSE MAC instance
* @param data - pointer to the data payload
* @param data_bytes - number of bytes of the data payload to be sent to the MAC
* @return SUCCESS if success, else a negative value
*/
err_t tse_mac_raw_send(struct netif *netif, struct pbuf *pkt)
{
int tx_length;
unsigned len;
struct pbuf *p, *q = NULL;
alt_u32 *data;
tse_mac_trans_info *mi;
lwip_tse_info *tse_ptr;
struct ethernetif *ethernetif;
unsigned int *ActualData;
/* Intermediate buffers used for temporary copy of frames that cannot be directrly DMA'ed*/
char buf2;
ethernetif = netif->state;
tse_ptr = ethernetif->tse_info;
mi = &tse_ptr->mi;
if(pkt->next != NULL) // Unwind pbuf chains
{
q = pbuf_alloc(PBUF_RAW, pkt->tot_len, pkt->type);
for(len = 0, p = pkt; p != NULL; p = p->next)
{
memcpy(q->payload + len, p->payload, p->len);
len += p->len;
}
pkt = q;
}
for(p = pkt; p != NULL; p = p->next)
{
data = p->payload;
len = p->len;
if(((unsigned long)data & 0x03) != 0)
{
/*
* Copy data to temporary buffer <buf2>. This is done because of allignment
* issues. The SGDMA cannot copy the data directly from (data + ETH_PAD_SIZE)
* because it needs a 32-bit alligned address space.
*/
memcpy(buf2,data,len);
data = (alt_u32 *)buf2;
}
ActualData = (void *)alt_remap_uncached (data, len<4 ? 4 : len);
printf("<%d @ 0x%08X/0x%08X>", len, (unsigned int)p->payload, (unsigned int)ActualData);
if(len<4)
len=4;
/* Write data to Tx FIFO using the DMA */
alt_avalon_sgdma_construct_mem_to_stream_desc(
(alt_sgdma_descriptor *) &tse_ptr->desc, // descriptor I want to work with
(alt_sgdma_descriptor *) &tse_ptr->desc,// pointer to "next"
(alt_u32*)ActualData, // starting read address
(len), //# bytes
0, // don't read from constant address
p == pkt, // generate sop
p->next == NULL, // generate endofpacket signal
0); // atlantic channel (don't know/don't care: set to 0)
tx_length = tse_mac_sTxWrite(mi,&tse_ptr->desc);
ethernetif->bytes_sent += tx_length;
}
if(q != NULL)
pbuf_free(q);
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
You could optimize it by first checking if any chains are less than 4 and doing this addition only when one or more is, but I kept it simple - just do it if there are chains. Maybe it's risky but I intend to not change my lwIP-based products. They don't show the problem which I don't know why. Maybe I could add this code and it would never be called??? [Update: Probably should check for q != NULL and exit if so. Of course this will result in errors as well!] Bill