From 22d6558f1363610596c8a2000df8450a68adab44 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 10 May 2009 17:07:25 +0000 Subject: [PATCH] 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. --- CHANGELOG | 5 +++ src/api/sockets.c | 20 +++++++--- src/core/pbuf.c | 77 ++++++++++++++++++++++++++++++++++++++- src/include/lwip/netbuf.h | 1 + src/include/lwip/opt.h | 13 +++++++ src/include/lwip/pbuf.h | 2 + 6 files changed, 110 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee4a27b3..4239dcad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/src/api/sockets.c b/src/api/sockets.c index 1711ea18..6b745af0 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -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); diff --git a/src/core/pbuf.c b/src/core/pbuf.c index e860f69b..55a0bf01 100644 --- a/src/core/pbuf.c +++ b/src/core/pbuf.c @@ -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; +} diff --git a/src/include/lwip/netbuf.h b/src/include/lwip/netbuf.h index f6de3a4f..6d84dd07 100644 --- a/src/include/lwip/netbuf.h +++ b/src/include/lwip/netbuf.h @@ -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) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 0f518889..e8bd8b89 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -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 ---------- diff --git a/src/include/lwip/pbuf.h b/src/include/lwip/pbuf.h index 57a1e999..8380f65d 100644 --- a/src/include/lwip/pbuf.h +++ b/src/include/lwip/pbuf.h @@ -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 }