Browse Source

qcacmn: Add QDF wrapper for frag ops

Introduce qdf wrapper API

1. frag is added to nbuf fragment array. If frag can't be fit in that nbuf
a new nbuf is allocated and frag is added to the new nbuf. Once added
nbuf is added as a fraglist to head nbuf. On a subsequent call, frag is
added to the last nbuf in a fraglist.

2. get reference for fragment.

Change-Id: Ia4ccbc48e54b08d6b9d4f0cf5089fbf43ee8b496
nobelj 3 years ago
parent
commit
85dca44878
3 changed files with 241 additions and 0 deletions
  1. 59 0
      qdf/inc/qdf_nbuf.h
  2. 39 0
      qdf/linux/src/i_qdf_nbuf.h
  3. 143 0
      qdf/linux/src/qdf_nbuf.c

+ 59 - 0
qdf/inc/qdf_nbuf.h

@@ -4071,6 +4071,19 @@ void qdf_nbuf_add_rx_frag_debug(qdf_frag_t buf, qdf_nbuf_t nbuf,
 				unsigned int truesize, bool take_frag_ref,
 				const char *func, uint32_t line);
 
+#define qdf_nbuf_ref_frag(f) \
+	qdf_nbuf_ref_frag_debug(f, __func__, __LINE__)
+
+/**
+ * qdf_nbuf_ref_frag_debug() - get frag reference
+ * @buf: Frag pointer needs to be taken reference.
+ * @func: Caller function name
+ * @line: Caller function line no.
+ *
+ * Return: none
+ */
+void qdf_nbuf_ref_frag_debug(qdf_frag_t buf, const char *func, uint32_t line);
+
 /**
  * qdf_net_buf_debug_acquire_frag() - Add frag nodes to frag debug tracker
  *	when nbuf is received from network stack
@@ -4154,6 +4167,17 @@ static inline void qdf_nbuf_add_rx_frag(qdf_frag_t buf, qdf_nbuf_t nbuf,
 			       frag_len, truesize, take_frag_ref);
 }
 
+/**
+ * qdf_nbuf_ref_frag() - get frag reference
+ * @buf: Frag pointer needs to be taken reference.
+ *
+ * Return: void
+ */
+static inline void qdf_nbuf_ref_frag(qdf_frag_t buf)
+{
+	__qdf_nbuf_ref_frag(buf);
+}
+
 static inline void qdf_net_buf_debug_acquire_frag(qdf_nbuf_t buf,
 						  const char *func,
 						  uint32_t line)
@@ -4176,6 +4200,41 @@ static inline void qdf_nbuf_frag_count_dec(qdf_nbuf_t buf)
 
 #endif /* NBUF_FRAG_MEMORY_DEBUG */
 
+#define qdf_nbuf_add_frag(dev, f, n, o, f_l, t_sz, f_r, sz) \
+	qdf_nbuf_add_frag_debug(dev, f, n, o, f_l, t_sz,	\
+				f_r, sz, __func__, __LINE__)
+
+/**
+ * qdf_nbuf_add_frag_debug() - Add frag to nbuf
+ * @osdev: Device handle
+ * @buf: Frag pointer needs to be added in nbuf frag
+ * @nbuf: qdf_nbuf_t where frag will be added
+ * @offset: Offset in frag to be added to nbuf_frags
+ * @frag_len: Frag length
+ * @truesize: truesize
+ * @take_frag_ref: Whether to take ref for frag or not
+ *      This bool must be set as per below comdition:
+ *      1. False: If this frag is being added in any nbuf
+ *              for the first time after allocation
+ *      2. True: If frag is already attached part of any
+ *              nbuf
+ * @minsize: Minimum size to allocate
+ * @func: Caller function name
+ * @line: Caller function line no.
+ *
+ * if number of frag exceed maximum frag array. A new nbuf is allocated
+ * with minimum headroom and frag it added to that nbuf.
+ * new nbuf is added as frag_list to the master nbuf.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+qdf_nbuf_add_frag_debug(qdf_device_t osdev, qdf_frag_t buf,
+			qdf_nbuf_t nbuf, int offset,
+			int frag_len, unsigned int truesize,
+			bool take_frag_ref, unsigned int minsize,
+			const char *func, uint32_t line);
+
 #ifdef MEMORY_DEBUG
 /**
  * qdf_nbuf_acquire_track_lock - acquire the nbuf spinlock at the

+ 39 - 0
qdf/linux/src/i_qdf_nbuf.h

@@ -1985,6 +1985,38 @@ __qdf_nbuf_copy_expand(struct sk_buff *buf, int headroom, int tailroom)
 	return skb_copy_expand(buf, headroom, tailroom, GFP_ATOMIC);
 }
 
+/**
+ * __qdf_nbuf_has_fraglist() - check buf has fraglist
+ * @buf: Network buf instance
+ *
+ * Return: True, if buf has frag_list else return False
+ */
+static inline bool
+__qdf_nbuf_has_fraglist(struct sk_buff *buf)
+{
+	return skb_has_frag_list(buf);
+}
+
+/**
+ * __qdf_nbuf_get_last_frag_list_nbuf() - Get last frag_list nbuf
+ * @buf: Network buf instance
+ *
+ * Return: Network buf instance
+ */
+static inline struct sk_buff *
+__qdf_nbuf_get_last_frag_list_nbuf(struct sk_buff *buf)
+{
+	struct sk_buff *list;
+
+	if (!__qdf_nbuf_has_fraglist(buf))
+		return NULL;
+
+	for (list = skb_shinfo(buf)->frag_list; list->next; list = list->next)
+		;
+
+	return list;
+}
+
 /**
  * __qdf_nbuf_get_ref_fraglist() - get reference to fragments
  * @buf: Network buf instance
@@ -2542,6 +2574,13 @@ void __qdf_nbuf_add_rx_frag(__qdf_frag_t buf, __qdf_nbuf_t nbuf,
 			    int offset, int frag_len,
 			    unsigned int truesize, bool take_frag_ref);
 
+/**
+ * __qdf_nbuf_ref_frag() - get frag reference
+ *
+ * Return: void
+ */
+void __qdf_nbuf_ref_frag(qdf_frag_t buf);
+
 /**
  * __qdf_nbuf_set_mark() - Set nbuf mark
  * @buf: Pointer to nbuf

+ 143 - 0
qdf/linux/src/qdf_nbuf.c

@@ -5181,6 +5181,24 @@ void __qdf_nbuf_add_rx_frag(__qdf_frag_t buf, __qdf_nbuf_t nbuf,
 
 qdf_export_symbol(__qdf_nbuf_add_rx_frag);
 
+void __qdf_nbuf_ref_frag(__qdf_frag_t buf)
+{
+	struct page *page;
+	skb_frag_t frag = {0};
+
+	page = virt_to_head_page(buf);
+	__skb_frag_set_page(&frag, page);
+
+	/*
+	 * since __skb_frag_ref() just use page to increase ref
+	 * we just decode page alone
+	 */
+	qdf_frag_count_inc(QDF_NBUF_FRAG_DEBUG_COUNT_ONE);
+	__skb_frag_ref(&frag);
+}
+
+qdf_export_symbol(__qdf_nbuf_ref_frag);
+
 #ifdef NBUF_FRAG_MEMORY_DEBUG
 
 QDF_STATUS qdf_nbuf_move_frag_page_offset_debug(qdf_nbuf_t nbuf, uint8_t idx,
@@ -5240,6 +5258,25 @@ void qdf_nbuf_add_rx_frag_debug(qdf_frag_t buf, qdf_nbuf_t nbuf,
 
 qdf_export_symbol(qdf_nbuf_add_rx_frag_debug);
 
+/**
+ * qdf_nbuf_ref_frag_debug() - get frag reference
+ * @buf: Frag pointer needs to be taken reference.
+ *
+ * return: void
+ */
+void qdf_nbuf_ref_frag_debug(qdf_frag_t buf, const char *func, uint32_t line)
+{
+	__qdf_nbuf_ref_frag(buf);
+
+	if (qdf_likely(is_initial_mem_debug_disabled))
+		return;
+
+	/* Update frag refcount in frag debug tracking table */
+	qdf_frag_debug_refcount_inc(buf, func, line);
+}
+
+qdf_export_symbol(qdf_nbuf_ref_frag_debug);
+
 void qdf_net_buf_debug_acquire_frag(qdf_nbuf_t buf, const char *func,
 				    uint32_t line)
 {
@@ -5346,6 +5383,112 @@ void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf, const char *func,
 qdf_export_symbol(qdf_net_buf_debug_release_frag);
 #endif /* NBUF_FRAG_MEMORY_DEBUG */
 
+/**
+ * qdf_get_nbuf_valid_frag() - Get nbuf to store frag
+ * @nbuf: qdf_nbuf_t master nbuf
+ *
+ * Return: qdf_nbuf_t
+ */
+static inline qdf_nbuf_t qdf_get_nbuf_valid_frag(qdf_nbuf_t nbuf)
+{
+	qdf_nbuf_t last_nbuf;
+	uint32_t num_frags;
+
+	if (qdf_unlikely(!nbuf))
+		return NULL;
+
+	num_frags = qdf_nbuf_get_nr_frags(nbuf);
+
+	/* Check nbuf has enough memory to store frag memory */
+	if (num_frags <= QDF_NBUF_MAX_FRAGS)
+		return nbuf;
+
+	if (num_frags > QDF_NBUF_MAX_FRAGS && !__qdf_nbuf_has_fraglist(nbuf))
+		return NULL;
+
+	last_nbuf = __qdf_nbuf_get_last_frag_list_nbuf(nbuf);
+	if (qdf_unlikely(!last_nbuf))
+		return NULL;
+
+	num_frags = qdf_nbuf_get_nr_frags(last_nbuf);
+	if (num_frags < QDF_NBUF_MAX_FRAGS)
+		return last_nbuf;
+
+	return NULL;
+}
+
+/**
+ * qdf_nbuf_add_frag_debug() - Add frag to nbuf
+ * @osdev: Device handle
+ * @buf: Frag pointer needs to be added in nbuf frag
+ * @nbuf: qdf_nbuf_t where frag will be added
+ * @offset: Offset in frag to be added to nbuf_frags
+ * @frag_len: Frag length
+ * @truesize: truesize
+ * @take_frag_ref: Whether to take ref for frag or not
+ *      This bool must be set as per below comdition:
+ *      1. False: If this frag is being added in any nbuf
+ *              for the first time after allocation
+ *      2. True: If frag is already attached part of any
+ *              nbuf
+ * @minsize: Minimum size to allocate
+ * @func: Caller function name
+ * @line: Caller function line no.
+ *
+ * if number of frag exceed maximum frag array. A new nbuf is allocated
+ * with minimum headroom and frag it added to that nbuf.
+ * new nbuf is added as frag_list to the master nbuf.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+qdf_nbuf_add_frag_debug(qdf_device_t osdev, qdf_frag_t buf,
+			qdf_nbuf_t nbuf, int offset,
+			int frag_len, unsigned int truesize,
+			bool take_frag_ref, unsigned int minsize,
+			const char *func, uint32_t line)
+{
+	qdf_nbuf_t cur_nbuf;
+	qdf_nbuf_t this_nbuf;
+
+	cur_nbuf = nbuf;
+	this_nbuf = nbuf;
+
+	if (qdf_unlikely(!frag_len || !buf)) {
+		qdf_nofl_err("%s : %d frag[ buf[%pK] len[%d]] not valid\n",
+			     func, line,
+			     buf, frag_len);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	this_nbuf = qdf_get_nbuf_valid_frag(this_nbuf);
+
+	if (this_nbuf) {
+		cur_nbuf = this_nbuf;
+	} else {
+		/* allocate a dummy mpdu buffer of 64 bytes headroom */
+		this_nbuf = qdf_nbuf_alloc(osdev, minsize, minsize, 4, false);
+		if (qdf_unlikely(!this_nbuf)) {
+			qdf_nofl_err("%s : %d no memory to allocate\n",
+				     func, line);
+			return QDF_STATUS_E_NOMEM;
+		}
+	}
+
+	qdf_nbuf_add_rx_frag(buf, this_nbuf, offset, frag_len, truesize,
+			     take_frag_ref);
+
+	if (this_nbuf != cur_nbuf) {
+		/* add new skb to frag list */
+		qdf_nbuf_append_ext_list(nbuf, this_nbuf,
+					 qdf_nbuf_len(this_nbuf));
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+qdf_export_symbol(qdf_nbuf_add_frag_debug);
+
 #ifdef MEMORY_DEBUG
 void qdf_nbuf_acquire_track_lock(uint32_t index,
 				 unsigned long irq_flag)