Signed-off-by: Maxim Uvarov <maxim.uva...@linaro.org>
---
 .../linux-generic/include/odp_buffer_internal.h    |  8 ++-
 .../linux-generic/include/odp_packet_internal.h    | 18 ++++++
 platform/linux-generic/odp_packet.c                | 65 ++++++++++++++++++++--
 3 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/platform/linux-generic/include/odp_buffer_internal.h 
b/platform/linux-generic/include/odp_buffer_internal.h
index 4cacca1..7ab53c6 100644
--- a/platform/linux-generic/include/odp_buffer_internal.h
+++ b/platform/linux-generic/include/odp_buffer_internal.h
@@ -65,7 +65,11 @@ _ODP_STATIC_ASSERT((ODP_CONFIG_PACKET_BUF_LEN_MAX %
 
 #define ODP_BUFFER_POOL_BITS   ODP_BITSIZE(ODP_CONFIG_POOLS)
 #define ODP_BUFFER_SEG_BITS    ODP_BITSIZE(ODP_BUFFER_MAX_SEG)
-#define ODP_BUFFER_INDEX_BITS  (32 - ODP_BUFFER_POOL_BITS - 
ODP_BUFFER_SEG_BITS)
+#define ODP_PACKET_REFS_BITS  ODP_BITSIZE(ODP_CONFIG_PACKET_REFS)
+
+#define ODP_BUFFER_INDEX_BITS  (32 - ODP_BUFFER_POOL_BITS - \
+                                    ODP_BUFFER_SEG_BITS - \
+                                    ODP_PACKET_REFS_BITS)
 #define ODP_BUFFER_PREFIX_BITS (ODP_BUFFER_POOL_BITS + ODP_BUFFER_INDEX_BITS)
 #define ODP_BUFFER_MAX_POOLS   (1 << ODP_BUFFER_POOL_BITS)
 #define ODP_BUFFER_MAX_BUFFERS (1 << ODP_BUFFER_INDEX_BITS)
@@ -79,6 +83,7 @@ typedef union odp_buffer_bits_t {
                uint32_t     u32;
                struct {
 #if ODP_BYTE_ORDER == ODP_BIG_ENDIAN
+                       uint32_t ref:ODP_PACKET_REFS_BITS;
                        uint32_t pool_id:ODP_BUFFER_POOL_BITS;
                        uint32_t index:ODP_BUFFER_INDEX_BITS;
                        uint32_t seg:ODP_BUFFER_SEG_BITS;
@@ -86,6 +91,7 @@ typedef union odp_buffer_bits_t {
                        uint32_t seg:ODP_BUFFER_SEG_BITS;
                        uint32_t index:ODP_BUFFER_INDEX_BITS;
                        uint32_t pool_id:ODP_BUFFER_POOL_BITS;
+                       uint32_t ref:ODP_PACKET_REFS_BITS;
 #endif
                };
 
diff --git a/platform/linux-generic/include/odp_packet_internal.h 
b/platform/linux-generic/include/odp_packet_internal.h
index ba2cd7e..2d6b58f 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -272,12 +272,30 @@ odp_packet_t _odp_packet_alloc(odp_pool_t pool_hdl);
 
 int _odp_packet_parse(odp_packet_hdr_t *pkt_hdr);
 
+void _odp_packet_init(odp_packet_t pkt);
+void _odp_packet_get(odp_packet_t pkt);
+uint32_t _odp_packet_put(odp_packet_t pkt);
+
 /* Convert a packet handle to a buffer handle */
 odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt);
 
 /* Convert a buffer handle to a packet handle */
 odp_packet_t _odp_packet_from_buffer(odp_buffer_t buf);
 
+/*  Internal debug function to check if packet has references
+ *
+ * @param pkt  Packet handle
+ * @retval 0   Packet does not have references
+ * @retval 1   Packet has references
+*/
+static inline int _odp_packet_refcheck(odp_packet_t pkt)
+{
+       odp_buffer_t buf = _odp_packet_to_buffer(pkt);
+       odp_buffer_hdr_t *hdr = odp_buf_to_hdr(buf);
+
+       return odp_atomic_load_u32(&hdr->ref_count) - 1;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/platform/linux-generic/odp_packet.c 
b/platform/linux-generic/odp_packet.c
index 209a6e6..f6c5509 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -28,28 +28,34 @@
 odp_packet_t odp_packet_alloc(odp_pool_t pool_hdl, uint32_t len)
 {
        pool_entry_t *pool = odp_pool_to_entry(pool_hdl);
+       odp_packet_t pkt = ODP_PACKET_INVALID;
 
        if (pool->s.params.type != ODP_POOL_PACKET)
                return ODP_PACKET_INVALID;
 
        /* Handle special case for zero-length packets */
        if (len == 0) {
-               odp_packet_t pkt =
+               pkt =
                        (odp_packet_t)buffer_alloc(pool_hdl,
                                                   pool->s.params.buf.size);
-               if (pkt != ODP_PACKET_INVALID)
+               if (pkt != ODP_PACKET_INVALID) {
                        pull_tail(odp_packet_hdr(pkt),
                                  pool->s.params.buf.size);
-
+                       _odp_packet_init(pkt);
+               }
                return pkt;
        }
 
-       return (odp_packet_t)buffer_alloc(pool_hdl, len);
+       pkt = (odp_packet_t)buffer_alloc(pool_hdl, len);
+       if (pkt != ODP_PACKET_INVALID)
+               _odp_packet_init(pkt);
+       return pkt;
 }
 
 void odp_packet_free(odp_packet_t pkt)
 {
-       odp_buffer_free((odp_buffer_t)pkt);
+       if (!_odp_packet_put(pkt))
+               odp_buffer_free((odp_buffer_t)pkt);
 }
 
 int odp_packet_reset(odp_packet_t pkt, uint32_t len)
@@ -85,6 +91,46 @@ odp_event_t odp_packet_to_event(odp_packet_t pkt)
        return (odp_event_t)pkt;
 }
 
+void _odp_packet_init(odp_packet_t pkt)
+{
+       odp_buffer_t buf = _odp_packet_to_buffer(pkt);
+       odp_buffer_hdr_t *hdr = odp_buf_to_hdr(buf);
+
+       odp_atomic_store_u32(&hdr->ref_count, 1);
+}
+
+void _odp_packet_get(odp_packet_t pkt)
+{
+       odp_buffer_t buf = _odp_packet_to_buffer(pkt);
+       odp_buffer_hdr_t *hdr = odp_buf_to_hdr(buf);
+
+       odp_atomic_inc_u32(&hdr->ref_count);
+}
+
+uint32_t _odp_packet_put(odp_packet_t pkt)
+{
+       odp_buffer_t buf = _odp_packet_to_buffer(pkt);
+       odp_buffer_hdr_t *hdr = odp_buf_to_hdr(buf);
+
+       return odp_atomic_fetch_dec_u32(&hdr->ref_count) - 1;
+}
+
+odp_packet_t odp_packet_create_ref(odp_packet_t pkt)
+{
+       odp_buffer_t buf = _odp_packet_to_buffer(pkt);
+       odp_buffer_bits_t handle;
+
+       _odp_packet_get(pkt);
+
+       handle.handle = buf;
+       if (handle.ref > ODP_CONFIG_PACKET_REFS)
+               ODP_ABORT("Maximum %d refs exceeded.\n",
+                         ODP_CONFIG_PACKET_REFS);
+       handle.ref += 1;
+
+       return _odp_packet_from_buffer(handle.handle);
+}
+
 /*
  *
  * Pointers and lengths
@@ -472,6 +518,9 @@ odp_packet_t odp_packet_rem_data(odp_packet_t pkt, uint32_t 
offset,
        uint32_t pktlen = pkt_hdr->frame_len;
        odp_packet_t newpkt;
 
+       if (_odp_packet_refcheck(pkt))
+               ODP_ABORT("modifying with refcounters is prohibited\n");
+
        if (offset > pktlen || offset + len > pktlen)
                return ODP_PACKET_INVALID;
 
@@ -577,6 +626,9 @@ int odp_packet_copydata_in(odp_packet_t pkt, uint32_t 
offset,
        const uint8_t *srcaddr = (const uint8_t *)src;
        odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
 
+       if (_odp_packet_refcheck(pkt))
+               ODP_ABORT("modifying with refcounters is prohibited\n");
+
        if (offset + len > pkt_hdr->frame_len)
                return -1;
 
@@ -679,6 +731,9 @@ int _odp_packet_copy_to_packet(odp_packet_t srcpkt, 
uint32_t srcoffset,
        uint32_t srcseglen = 0; /* GCC */
        uint32_t dstseglen = 0; /* GCC */
 
+       if (_odp_packet_refcheck(dstpkt))
+               ODP_ABORT("copiyng to packet with refcounters is prohibited\n");
+
        if (srcoffset + len > srchdr->frame_len ||
            dstoffset + len > dsthdr->frame_len)
                return -1;
-- 
1.9.1

_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to