Forum Discussion
Altera_Forum
Honored Contributor
14 years agoBill,
Thank you for the confirmation and for the patch. With modified tse_mac_raw_send() both raw_api- and netconn-based tests work fine in my configuration. I think that your simple solution should be OK for TCP, but may severely impact performance of udp applications if someone tries to achieve zero-copy by chaining headers-only pbuf with ROM- or REF-type payload-only pbuf. The both pbufs could be properly aligned and unnecessary and expensive unwinding may become a bottleneck. I don’t use this approach in my code currently, but advertised it earlier in this thread. Below is my implementation of chain scanning as you suggested. I changed also to do unwinding in buf2[]. Is it ok, or you had good reasons to allocate separate pbuf for this purpose?err_t tse_mac_raw_send(struct netif *netif, struct pbuf *pkt)
{
int tx_length;
unsigned len;
struct pbuf *p;
alt_u32 *data;
tse_mac_trans_info *mi;
lwip_tse_info *tse_ptr;
struct ethernetif *ethernetif;
unsigned int *ActualData;
int unwind;
/* Intermediate buffers used for temporary copy of frames that cannot be directrly DMA'ed*/
struct pbuf unwind_pbuf;
char buf2;
ethernetif = netif->state;
tse_ptr = ethernetif->tse_info;
mi = &tse_ptr->mi;
unwind = 0;
for(p = pkt; p != NULL; p = p->next) {
if (((unsigned long)p->payload & 0x03) != 0 || p->len < 4 || ((p->len & 3) != 0 && p->next)) {
unwind = 1;
break;
}
}
if (unwind) {
// Unwind pbuf chains
if (pkt->tot_len > sizeof(buf2)) {
// no space for unwinding; drop the packet
return ERR_OK;
}
for(len = 0, p = pkt; p != NULL; p = p->next)
{
/*
* 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 + len, p->payload, p->len);
len += p->len;
}
unwind_pbuf.len = unwind_pbuf.tot_len = len;
unwind_pbuf.payload = buf2;
unwind_pbuf.next = NULL;
pkt = &unwind_pbuf;
}
for(p = pkt; p != NULL; p = p->next)
{
data = p->payload;
len = p->len;
// No need for re-alignment and length-checking here
ActualData = (void *)alt_remap_uncached (data, len);
//printf("<%d @ 0x%08X/0x%08X>", len, (unsigned int)p->payload, (unsigned int)ActualData);
/* 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;
}
LINK_STATS_INC(link.xmit);
return ERR_OK;
}