@@ -66,7 +66,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)
@@ -80,6 +84,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;
@@ -87,6 +92,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
};
@@ -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
@@ -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;
Signed-off-by: Maxim Uvarov <maxim.uvarov@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(-)