@@ -478,13 +478,18 @@ static inline odp_packet_hdr_t *add_segments(odp_packet_hdr_t *pkt_hdr,
static inline void free_bufs(odp_packet_hdr_t *pkt_hdr, int first, int num)
{
- int i;
+ int i, nfree;
odp_buffer_t buf[num];
- for (i = 0; i < num; i++)
- buf[i] = buffer_handle(pkt_hdr->buf_hdr.seg[first + i].hdr);
+ for (i = 0, nfree = 0; i < num; i++) {
+ odp_packet_hdr_t *hdr = pkt_hdr->buf_hdr.seg[first + i].hdr;
+
+ if (packet_ref_count(hdr) == 1 || packet_ref_dec(hdr) == 1)
+ buf[nfree++] = buffer_handle(hdr);
+ }
- buffer_free_multi(buf, num);
+ if (nfree > 0)
+ buffer_free_multi(buf, nfree);
}
static inline odp_packet_hdr_t *free_segments(odp_packet_hdr_t *pkt_hdr,
@@ -495,11 +500,16 @@ static inline odp_packet_hdr_t *free_segments(odp_packet_hdr_t *pkt_hdr,
if (head) {
odp_packet_hdr_t *new_hdr;
- int i;
+ int i, nfree;
odp_buffer_t buf[num];
- for (i = 0; i < num; i++)
- buf[i] = buffer_handle(pkt_hdr->buf_hdr.seg[i].hdr);
+ for (i = 0, nfree = 0; i < num; i++) {
+ new_hdr = pkt_hdr->buf_hdr.seg[i].hdr;
+
+ if (packet_ref_count(new_hdr) == 1 ||
+ packet_ref_dec(new_hdr) == 1)
+ buf[nfree++] = buffer_handle(new_hdr);
+ }
/* First remaining segment is the new packet descriptor */
new_hdr = pkt_hdr->buf_hdr.seg[num].hdr;
@@ -517,7 +527,8 @@ static inline odp_packet_hdr_t *free_segments(odp_packet_hdr_t *pkt_hdr,
pkt_hdr = new_hdr;
- buffer_free_multi(buf, num);
+ if (nfree > 0)
+ buffer_free_multi(buf, nfree);
} else {
/* Free last 'num' bufs */
free_bufs(pkt_hdr, num_remain, num);
@@ -630,47 +641,109 @@ int odp_packet_alloc_multi(odp_pool_t pool_hdl, uint32_t len,
return num;
}
-void odp_packet_free(odp_packet_t pkt)
+static inline odp_packet_hdr_t *packet_free_to_list(odp_packet_hdr_t *pkt_hdr,
+ odp_buffer_t buf[],
+ int nbufs,
+ int *nfree)
{
- odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt);
- odp_buffer_t hdl = buffer_handle(pkt_hdr);
+ odp_packet_hdr_t *ref_hdr;
+ uint32_t ref_count;
+ int num_seg, i;
- int num_seg = pkt_hdr->buf_hdr.segcount;
+ do {
+ ref_count = packet_ref_count(pkt_hdr);
+ num_seg = pkt_hdr->buf_hdr.segcount;
+ ref_hdr = pkt_hdr->ref_hdr;
- if (odp_likely(CONFIG_PACKET_MAX_SEGS == 1 || num_seg == 1))
- buffer_free_multi(&hdl, 1);
- else
- free_bufs(pkt_hdr, 0, num_seg);
+ if (odp_likely((CONFIG_PACKET_MAX_SEGS == 1 || num_seg == 1) &&
+ ref_count == 1)) {
+ if (*nfree >= nbufs)
+ break;
+
+ buf[(*nfree)++] = buffer_handle(pkt_hdr);
+ } else {
+ if (*nfree + num_seg >= nbufs)
+ break;
+
+ for (i = 0; i < num_seg; i++) {
+ odp_packet_hdr_t *hdr =
+ pkt_hdr->buf_hdr.seg[i].hdr;
+
+ if (packet_ref_count(hdr) == 1 ||
+ packet_ref_dec(hdr) == 1)
+ buf[(*nfree)++] = buffer_handle(hdr);
+ }
+ }
+
+ pkt_hdr = ref_hdr;
+ } while (pkt_hdr);
+
+ return pkt_hdr;
+}
+
+static inline void packet_free(odp_packet_hdr_t *pkt_hdr)
+{
+ odp_packet_hdr_t *ref_hdr;
+ uint32_t ref_count;
+ int num_seg;
+
+ do {
+ ref_count = packet_ref_count(pkt_hdr);
+ num_seg = pkt_hdr->buf_hdr.segcount;
+ ref_hdr = pkt_hdr->ref_hdr;
+
+ if (odp_likely((CONFIG_PACKET_MAX_SEGS == 1 || num_seg == 1) &&
+ ref_count == 1))
+ buffer_free_multi((odp_buffer_t *)
+ &pkt_hdr->buf_hdr.handle.handle, 1);
+ else
+ free_bufs(pkt_hdr, 0, num_seg);
+
+ pkt_hdr = ref_hdr;
+ } while (pkt_hdr);
+}
+
+void odp_packet_free(odp_packet_t pkt)
+{
+ packet_free(packet_hdr(pkt));
}
void odp_packet_free_multi(const odp_packet_t pkt[], int num)
{
- if (CONFIG_PACKET_MAX_SEGS == 1) {
- buffer_free_multi((const odp_buffer_t * const)pkt, num);
- } else {
- odp_buffer_t buf[num * CONFIG_PACKET_MAX_SEGS];
- int i, j;
- int bufs = 0;
+ int nbufs = num * CONFIG_PACKET_MAX_SEGS * 2;
+ odp_buffer_t buf[nbufs];
+ int nfree = 0;
+ int i = 0;
+ odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt[0]);
+ uint32_t pool_id = pool_id_from_buf(pkt_hdr->buf_hdr.handle.handle);
+ uint32_t next_pool;
+
+ while (1) {
+ pkt_hdr = packet_free_to_list(pkt_hdr, buf, nbufs, &nfree);
- for (i = 0; i < num; i++) {
- odp_packet_hdr_t *pkt_hdr = packet_hdr(pkt[i]);
- int num_seg = pkt_hdr->buf_hdr.segcount;
- odp_buffer_hdr_t *buf_hdr = &pkt_hdr->buf_hdr;
+ if (pkt_hdr) {
+ buffer_free_to_pool(pool_id, buf, nfree);
+ nfree = 0;
+ continue;
+ }
- buf[bufs] = buffer_handle(pkt_hdr);
- bufs++;
+ if (++i == num)
+ break;
- if (odp_likely(num_seg == 1))
- continue;
+ pkt_hdr = packet_hdr(pkt[i]);
+ next_pool = pool_id_from_buf(pkt_hdr->buf_hdr.handle.handle);
- for (j = 1; j < num_seg; j++) {
- buf[bufs] = buffer_handle(buf_hdr->seg[j].hdr);
- bufs++;
+ if (odp_unlikely(next_pool != pool_id)) {
+ if (nfree > 0) {
+ buffer_free_to_pool(pool_id, buf, nfree);
+ nfree = 0;
}
+ pool_id = next_pool;
}
-
- buffer_free_multi(buf, bufs);
}
+
+ if (nfree > 0)
+ buffer_free_to_pool(pool_id, buf, nfree);
}
int odp_packet_reset(odp_packet_t pkt, uint32_t len)
@@ -681,6 +754,9 @@ int odp_packet_reset(odp_packet_t pkt, uint32_t len)
if (len > pool->headroom + pool->data_size + pool->tailroom)
return -1;
+ if (pkt_hdr->ref_hdr)
+ packet_free(pkt_hdr->ref_hdr);
+
packet_init(pkt_hdr, len, 0);
return 0;
Restructure the various packet/segment free routines to support references. Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> --- platform/linux-generic/odp_packet.c | 146 +++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 35 deletions(-) -- 2.5.0