diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.cpp b/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.cpp index a97a576692..6490965702 100644 --- a/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.cpp +++ b/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.cpp @@ -63,6 +63,16 @@ void LWIPMemoryManager::copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_ pbuf_copy(static_cast(to_buf), static_cast(from_buf)); } +void LWIPMemoryManager::copy_to_buf(emac_mem_buf_t *to_buf, const void *ptr, uint32_t len) +{ + pbuf_take(static_cast(to_buf), ptr, len); +} + +uint32_t LWIPMemoryManager::copy_from_buf(void *ptr, uint32_t len, const emac_mem_buf_t *from_buf) const +{ + return pbuf_copy_partial(static_cast(from_buf), ptr, len, 0); +} + void LWIPMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf) { pbuf_cat(static_cast(to_buf), static_cast(cat_buf)); diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.h b/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.h index 7a7d8e3a39..5ecf98b4d4 100644 --- a/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.h +++ b/features/FEATURE_LWIP/lwip-interface/LWIPMemoryManager.h @@ -86,6 +86,31 @@ public: */ virtual void copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf); + /** + * Copy to a memory buffer chain + * + * Copies data to a buffer chain. Copy operation does not adjust the lengths + * of the copied-to memory buffer chain, so chain total length must match the + * copied length. + * + * @param to_buf Memory buffer chain to copy to + * @param ptr Pointer to data + * @param len Data length + */ + virtual void copy_to_buf(emac_mem_buf_t *to_buf, const void *ptr, uint32_t len); + + /** + * Copy from a memory buffer chain + * + * Copies data from a memory buffer chain. + * + * @param len Data length + * @param ptr Pointer to data + * @param from_buf Memory buffer chain to copy from + * @return Length of the data that was copied + */ + virtual uint32_t copy_from_buf(void *ptr, uint32_t len, const emac_mem_buf_t *from_buf) const; + /** * Concatenate two memory buffer chains * diff --git a/features/netsocket/EMAC.h b/features/netsocket/EMAC.h index 5af593cc09..bc63b79b38 100644 --- a/features/netsocket/EMAC.h +++ b/features/netsocket/EMAC.h @@ -62,6 +62,16 @@ public: */ virtual uint32_t get_mtu_size() const = 0; + /** + * Gets memory buffer alignment preference + * + * Gets preferred memory buffer alignment of the Emac device. IP stack may or may not + * align link out memory buffer chains using the alignment. + * + * @return Memory alignment requirement in bytes + */ + virtual uint32_t get_align_preference() const = 0; + /** * Return interface name * diff --git a/features/netsocket/EMACMemoryManager.cpp b/features/netsocket/EMACMemoryManager.cpp new file mode 100644 index 0000000000..1e6c5da20f --- /dev/null +++ b/features/netsocket/EMACMemoryManager.cpp @@ -0,0 +1,62 @@ +/* Copyright (c) 2018 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EMACMemoryManager.h" + +void EMACMemoryManager::copy_to_buf(emac_mem_buf_t *to_buf, const void *ptr, uint32_t len) +{ + while (to_buf && len) { + void *copy_to_ptr = get_ptr(to_buf); + uint32_t copy_to_len = get_len(to_buf); + + if (copy_to_len > len) { + copy_to_len = len; + len = 0; + } else { + len -= copy_to_len; + } + + memcpy(copy_to_ptr, ptr, copy_to_len); + ptr = static_cast(ptr) + copy_to_len; + + to_buf = get_next(to_buf); + } +} + +uint32_t EMACMemoryManager::copy_from_buf(void *ptr, uint32_t len, const emac_mem_buf_t *from_buf) const +{ + uint32_t copied_len = 0; + + while (from_buf && len) { + void *copy_from_ptr = get_ptr(from_buf); + uint32_t copy_from_len = get_len(from_buf); + + if (copy_from_len > len) { + copy_from_len = len; + len = 0; + } else { + len -= copy_from_len; + } + + memcpy(ptr, copy_from_ptr, copy_from_len); + ptr = static_cast(ptr) + copy_from_len; + copied_len += copy_from_len; + + from_buf = get_next(from_buf); + } + + return copied_len; +} + diff --git a/features/netsocket/EMACMemoryManager.h b/features/netsocket/EMACMemoryManager.h index 112b0c5bda..ad97d6675c 100644 --- a/features/netsocket/EMACMemoryManager.h +++ b/features/netsocket/EMACMemoryManager.h @@ -36,6 +36,8 @@ * */ +#include "nsapi.h" + typedef void emac_mem_buf_t; // Memory buffer class EMACMemoryManager { @@ -106,6 +108,31 @@ public: */ virtual void copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *from_buf) = 0; + /** + * Copy to a memory buffer chain + * + * Copies data to a buffer chain. Copy operation does not adjust the lengths + * of the copied-to memory buffer chain, so chain total length must match the + * copied length. + * + * @param to_buf Memory buffer chain to copy to + * @param ptr Pointer to data + * @param len Data length + */ + virtual void copy_to_buf(emac_mem_buf_t *to_buf, const void *ptr, uint32_t len); + + /** + * Copy from a memory buffer chain + * + * Copies data from a memory buffer chain. + * + * @param len Data length + * @param ptr Pointer to data + * @param from_buf Memory buffer chain to copy from + * @return Length of the data that was copied + */ + virtual uint32_t copy_from_buf(void *ptr, uint32_t len, const emac_mem_buf_t *from_buf) const; + /** * Concatenate two memory buffer chains * diff --git a/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp index aed46772ac..6b7979c1bc 100644 --- a/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp +++ b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp @@ -412,13 +412,19 @@ bool K64F_EMAC::link_out(emac_mem_buf_t *buf) { emac_mem_buf_t *temp_pbuf; - temp_pbuf = memory_manager->alloc_heap(memory_manager->get_total_len(buf), ENET_BUFF_ALIGNMENT); - if (NULL == temp_pbuf) - return false; + // If buffer is chained or not aligned then make a contiguous aligned copy of it + if (memory_manager->get_next(buf) || + reinterpret_cast(memory_manager->get_ptr(buf)) % ENET_BUFF_ALIGNMENT) { + temp_pbuf = memory_manager->alloc_heap(memory_manager->get_total_len(buf), ENET_BUFF_ALIGNMENT); + if (NULL == temp_pbuf) + return false; - // Copy to new buffer and free original - memory_manager->copy(temp_pbuf, buf); - memory_manager->free(buf); + // Copy to new buffer and free original + memory_manager->copy(temp_pbuf, buf); + memory_manager->free(buf); + } else { + temp_pbuf = buf; + } /* Check if a descriptor is available for the transfer. */ if (xTXDCountSem.wait(0) == 0) @@ -525,6 +531,11 @@ uint32_t K64F_EMAC::get_mtu_size() const return K64_ETH_MTU_SIZE; } +uint32_t K64F_EMAC::get_align_preference() const +{ + return ENET_BUFF_ALIGNMENT; +} + void K64F_EMAC::get_ifname(char *name, uint8_t size) const { memcpy(name, K64_ETH_IF_NAME, (size < sizeof(K64_ETH_IF_NAME)) ? size : sizeof(K64_ETH_IF_NAME)); diff --git a/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h index d9bda83235..fee1028f32 100644 --- a/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h +++ b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h @@ -22,6 +22,16 @@ public: */ virtual uint32_t get_mtu_size() const; + /** + * Gets memory buffer alignment preference + * + * Gets preferred memory buffer alignment of the Emac device. IP stack may or may not + * align link out memory buffer chains using the alignment. + * + * @return Memory alignment requirement in bytes + */ + virtual uint32_t get_align_preference() const; + /** * Return interface name * diff --git a/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.cpp b/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.cpp index f6338978d6..6c53628324 100644 --- a/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.cpp +++ b/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.cpp @@ -480,6 +480,11 @@ uint32_t STM32_EMAC::get_mtu_size() const return STM_ETH_MTU_SIZE; } +uint32_t STM32_EMAC::get_align_preference() const +{ + return 0; +} + void STM32_EMAC::get_ifname(char *name, uint8_t size) const { memcpy(name, STM_ETH_IF_NAME, (size < sizeof(STM_ETH_IF_NAME)) ? size : sizeof(STM_ETH_IF_NAME)); diff --git a/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.h b/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.h index 657fdeb0d1..c7c03918ac 100644 --- a/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.h +++ b/features/netsocket/emac-drivers/TARGET_STM/stm32xx_emac.h @@ -33,6 +33,16 @@ public: */ virtual uint32_t get_mtu_size() const; + /** + * Gets memory buffer alignment preference + * + * Gets preferred memory buffer alignment of the Emac device. IP stack may or may not + * align link out memory buffer chains using the alignment. + * + * @return Memory alignment requirement in bytes + */ + virtual uint32_t get_align_preference() const; + /** * Return interface name *