task #7013: Added option LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only one pbuf to help MACs that don't support scatter-gather DMA.

This commit is contained in:
goldsimon 2009-05-10 17:07:25 +00:00
parent 105d72a3c2
commit 22d6558f13
6 changed files with 110 additions and 8 deletions

View File

@ -19,6 +19,11 @@ HISTORY
++ New features:
2009-05-10 Simon Goldschmidt
* opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option
LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only
one pbuf to help MACs that don't support scatter-gather DMA.
2009-05-09 Simon Goldschmidt
* icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming
ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN

View File

@ -668,7 +668,7 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
{
struct lwip_socket *sock;
struct ip_addr remote_addr;
int err;
err_t err;
u16_t short_size;
#if !LWIP_TCPIP_CORE_LOCKING
struct netbuf buf;
@ -738,17 +738,25 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
s, data, short_size, flags));
ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
/* make the buffer point to the data that should be sent */
if ((err = netbuf_ref(&buf, data, short_size)) == ERR_OK) {
#if LWIP_NETIF_TX_SINGLE_PBUF
/* Allocate a new netbuf and copy the data into it. */
if (netbuf_alloc(&buf, short_size) == NULL) {
err = ERR_MEM;
} else {
err = netbuf_take(&buf, data, short_size);
}
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
err = netbuf_ref(&buf, data, short_size);
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
if (err == ERR_OK) {
/* send the data */
err = netconn_send(sock->conn, &buf);
}
/* deallocated the buffer */
if (buf.p != NULL) {
pbuf_free(buf.p);
}
netbuf_free(&buf);
#endif /* LWIP_TCPIP_CORE_LOCKING */
sock_set_errno(sock, err_to_errno(err));
return (err == ERR_OK ? short_size : -1);

View File

@ -790,8 +790,8 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
u16_t buf_copy_len;
u16_t copied_total = 0;
LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
left = 0;
@ -819,3 +819,76 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
}
return copied_total;
}
/**
* Copy application supplied data into a pbuf.
* This function can only be used to copy the equivalent of buf->tot_len data.
*
* @param buf pbuf to fill with data
* @param dataptr application supplied data buffer
* @param len length of the application supplied data buffer
*
* @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
*/
err_t
pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
{
struct pbuf *p;
u16_t buf_copy_len;
u16_t total_copy_len = len;
u16_t copied_total = 0;
LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
return ERR_ARG;
}
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
for(p = buf; total_copy_len != 0; p = p->next) {
LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
buf_copy_len = total_copy_len;
if (buf_copy_len > p->len) {
/* this pbuf cannot hold all remaining data */
buf_copy_len = p->len;
}
/* copy the necessary parts of the buffer */
MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
total_copy_len -= buf_copy_len;
copied_total += buf_copy_len;
}
LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
return ERR_OK;
}
/**
* Creates a single pbuf out of a queue of pbufs.
*
* @remark: The source pbuf 'p' is not freed by this function because that can
* be illegal in some places!
*
* @param p the source pbuf
* @param layer pbuf_layer of the new pbuf
*
* @return a new, single pbuf (p->next is NULL)
* or the old pbuf if allocation fails
*/
struct pbuf*
pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
{
struct pbuf *q;
err_t err;
if (p->next == NULL) {
return p;
}
q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
if (q == NULL) {
/* @todo: what do we do now? */
return p;
}
err = pbuf_copy(q, p);
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
pbuf_free(p);
return q;
}

View File

@ -65,6 +65,7 @@ void netbuf_first (struct netbuf *buf);
#define netbuf_copy_partial(buf, dataptr, len, offset) \
pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))
#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
#define netbuf_len(buf) ((buf)->p->tot_len)
#define netbuf_fromaddr(buf) ((buf)->addr)
#define netbuf_fromport(buf) ((buf)->port)

View File

@ -965,6 +965,19 @@
#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS)
#endif
/**
* LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data
* to be sent into one single pbuf. This is for compatibility with DMA-enabled
* MACs that do not support scatter-gather.
* Beware that this might involve CPU-memcpy before transmitting that would not
* be needed without this flag! Use this only if you need to!
*
* @todo: TCP and IP-frag do not work with this, yet:
*/
#ifndef LWIP_NETIF_TX_SINGLE_PBUF
#define LWIP_NETIF_TX_SINGLE_PBUF 0
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
/*
------------------------------------
---------- LOOPIF options ----------

View File

@ -110,6 +110,8 @@ void pbuf_chain(struct pbuf *head, struct pbuf *tail);
struct pbuf *pbuf_dechain(struct pbuf *p);
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
#ifdef __cplusplus
}