From: Matias Elo <matias....@nokia.com> When packet pool memory page size is >= CONT_PAGE_SIZE, leave those memory buffers unused which cross a page boundary. This is required by zero-copy dpdk pktio (NIC drivers don't support buffers which cross page boundaries).
Signed-off-by: Matias Elo <matias....@nokia.com> --- /** Email created from pull request 223 (matiaselo:fix/pool_create) ** https://github.com/Linaro/odp/pull/223 ** Patch: https://github.com/Linaro/odp/pull/223.patch ** Base sha: a63f25ff2994b2df78c24f1f8b63d0e06628eb68 ** Merge commit sha: e4415d4c413122c020cf42e3c287a237e800f606 **/ platform/linux-generic/odp_pool.c | 43 ++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/platform/linux-generic/odp_pool.c b/platform/linux-generic/odp_pool.c index 2a0a35e40..70b79be11 100644 --- a/platform/linux-generic/odp_pool.c +++ b/platform/linux-generic/odp_pool.c @@ -32,6 +32,10 @@ #define CACHE_BURST 32 #define RING_SIZE_MIN (2 * CACHE_BURST) +/* Make sure packet buffers don't cross page boundaries starting from this page + * size. */ +#define CONT_PAGE_SIZE (2 * 1024 * 1024) + /* Define a practical limit for contiguous memory allocations */ #define MAX_SIZE (10 * 1024 * 1024) @@ -224,6 +228,7 @@ static void init_buffers(pool_t *pool) uint32_t i; odp_buffer_hdr_t *buf_hdr; odp_packet_hdr_t *pkt_hdr; + odp_shm_info_t shm_info; void *addr; void *uarea = NULL; uint8_t *data; @@ -232,19 +237,40 @@ static void init_buffers(pool_t *pool) uint32_t mask; int type; uint32_t seg_size; + uint64_t page_size = 0; + int skipped_blocks = 0; + + if (odp_shm_info(pool->shm, &shm_info) == 0) + page_size = shm_info.page_size; ring = &pool->ring->hdr; mask = pool->ring_mask; type = pool->params.type; - for (i = 0; i < pool->num; i++) { + for (i = 0; i < pool->num + skipped_blocks ; i++) { addr = &pool->base_addr[i * pool->block_size]; buf_hdr = addr; pkt_hdr = addr; - + /* Skip packet buffers which cross page boundaries. Some NICs + * cannot handle buffers which cross page boundaries. */ + if (pool->params.type == ODP_POOL_PACKET && + page_size >= CONT_PAGE_SIZE) { + uint64_t first_page; + uint64_t last_page; + + first_page = ((uint64_t)(uintptr_t)addr & + ~(page_size - 1)); + last_page = (((uint64_t)(uintptr_t)addr + + pool->block_size - 1) & + ~(page_size - 1)); + if (last_page != first_page) { + skipped_blocks++; + continue; + } + } if (pool->uarea_size) - uarea = &pool->uarea_base_addr[i * pool->uarea_size]; - + uarea = &pool->uarea_base_addr[(i - skipped_blocks) * + pool->uarea_size]; data = buf_hdr->data; if (type == ODP_POOL_PACKET) @@ -317,6 +343,7 @@ static odp_pool_t pool_create(const char *name, odp_pool_param_t *params, uint32_t data_size, align, num, hdr_size, block_size; uint32_t max_len, max_seg_len; uint32_t ring_size; + uint32_t num_extra = 0; int name_len; const char *postfix = "_uarea"; char uarea_name[ODP_POOL_NAME_LEN + sizeof(postfix)]; @@ -403,6 +430,12 @@ static odp_pool_t pool_create(const char *name, odp_pool_param_t *params, block_size = ROUNDUP_CACHE_LINE(hdr_size + align + headroom + data_size + tailroom); + /* Allocate extra memory for skipping packet buffers which cross page + * boundaries. */ + if (params->type == ODP_POOL_PACKET) + num_extra = 2 * (((uint64_t)(num * block_size) + + CONT_PAGE_SIZE - 1) / CONT_PAGE_SIZE); + if (num <= RING_SIZE_MIN) ring_size = RING_SIZE_MIN; else @@ -418,7 +451,7 @@ static odp_pool_t pool_create(const char *name, odp_pool_param_t *params, pool->tailroom = tailroom; pool->block_size = block_size; pool->uarea_size = uarea_size; - pool->shm_size = num * block_size; + pool->shm_size = (num + num_extra) * block_size; pool->uarea_shm_size = num * uarea_size; pool->ext_desc = NULL; pool->ext_destroy = NULL;