1 /******************************************************************************
3 * Copyright (c) 2014 - 2019 Samsung Electronics Co., Ltd. All rights reserved
5 *****************************************************************************/
11 * mbulk(bulk memory) API
13 * This header file describes APIs of the bulk memory management.
14 * The diagram below is an example of a mbulk buffer with one
15 * segment (i.e. not a chained mbulk).
19 * | |<--------- dat_bufsz ---------->|
20 * +--------------------------------------------------+
21 * | mbulk| signal | bulk buffer |
22 * +-------------------------+---------------+--------+
23 * | | | valid data | |
24 * | | |<--------+---->| |
25 * | | | mbulk_tlen(m) | |
26 * | |<----->| | |<------>|
27 * | mbulk_headroom(m)| | mbulk_tailroom(m)
31 * mbulk_get_sig(m) mbulk_dat(m) |
35 * In general, all clients are supposed to use only mbulk_xxx() APIs (but not
36 * mbulk_seg_xxx() APIs), as they can handle S/G chained mbulk as well.
37 * But as of now, specially in Condor, S/G chained mbulk is not supported,
38 * which means the most of mbulk_xxx() would be wrappers of mbulk_seg_xxx().
40 * An in-lined signal buffer can be allocated along with a mbulk buffer.
41 * There is no direct life-cycle relationship between the signal and the
42 * associated mbulk in this case, which means that the signal buffer should be
43 * de-allocated independently of the mbulk buffer.
48 * bulk buffer descriptor
55 #define MBULK_POOL_ID_DATA (0)
56 #define MBULK_POOL_ID_CTRL (1)
57 #define MBULK_POOL_ID_MAX (2)
60 * mbulk buffer classification
62 * Note that PACKED attribute is added to enum definition so that
63 * compiler assigns the smallest integral type (u8).
66 MBULK_CLASS_CONTROL
= 0,
67 MBULK_CLASS_HOSTIO
= 1,
68 MBULK_CLASS_DEBUG
= 2,
70 MBULK_CLASS_FROM_HOST_DAT
= 3,
71 MBULK_CLASS_FROM_HOST_CTL
= 4,
72 MBULK_CLASS_FROM_RADIO
= 5,
74 MBULK_CLASS_OTHERS
= 7,
75 MBULK_CLASS_FROM_RADIO_FORWARDED
= 8,
80 * The private definition of mbulk structure is included here
81 * so that its members can be directly accessed, and the access
82 * codes can be in-lined by the compiler.
83 * But client codes are not supposed to directly refer to mbulk
84 * members, nor use mbulk_seg_xxx() functions. Only modules handling
85 * mbulk scatter/gather chain would directly use mulk_seg_xxx() APIs.
87 #include "mbulk_def.h"
90 * Get the bulk data reference counter
92 * After a bulk buffer with non-zero data buffer size is created,
93 * the reference counter is set to one. Each time it is duplicated,
94 * its reference counter would be increased.
96 * Note that the reference counter is initialized to zero if a signal
97 * is created from mbulk pool but with zero data buffer size, as there
100 static inline int mbulk_refcnt(const struct mbulk
*m
)
102 return MBULK_SEG_REFCNT(m
);
106 * Get the bulk data buffer size
109 static inline int mbulk_buffer_size(const struct mbulk
*m
)
111 return MBULK_SEG_DAT_BUFSIZE(m
);
115 * Check if mbulk has an in-lined signal buffer
118 static inline bool mbulk_has_signal(const struct mbulk
*m
)
120 return MBULK_SEG_HAS_SIGNAL(m
);
124 * Set mbulk to be read-only
126 static inline void mbulk_set_readonly(struct mbulk
*m
)
128 MBULK_SEG_SET_READONLY(m
);
134 static inline bool mbulk_is_readonly(const struct mbulk
*m
)
136 return MBULK_SEG_IS_READONLY(m
);
140 * check if mbulk is a scatter/gather chained buffer
143 static inline bool mbulk_is_sg(const struct mbulk
*m
)
145 return MBULK_SEG_IS_CHAIN_HEAD(m
);
149 * check if mbulk is a part of scatter/gather chained buffer
152 static inline bool mbulk_is_chained(const struct mbulk
*m
)
154 return MBULK_SEG_IS_CHAINED(m
);
158 * Allocate a bulk buffer with an in-lined signal buffer
160 * Only one mbulk segment is used for allocation starting from the
161 * mbulk pool with the smallest segment size. If no segment fitting
162 * the requested size, then return NULL without trying to create
166 struct mbulk
*mbulk_with_signal_alloc(enum mbulk_class clas
, size_t sig_bufsz
,
169 * Allocate a bulk buffer with an in-lined signal buffer
171 * A mbulk segment is allocated from the given the pool, if its size
172 * meeting the requested size.
175 struct mbulk
*mbulk_with_signal_alloc_by_pool(u8 pool_id
, u16 colour
,
176 enum mbulk_class clas
, size_t sig_bufsz
, size_t dat_bufsz
);
179 * Get the number of free mbulk slots in a pool
181 * Returns the number of mbulk slots available in a given pool.
183 int mbulk_pool_get_free_count(u8 pool_id
);
186 * Get a signal buffer address
188 * Given a mbulk buffer, returns a signal buffer address.
191 * @return in-lined signal buffer
193 static inline void *mbulk_get_seg(const struct mbulk
*m
)
195 return (void *)MBULK_SEG_B(m
);
199 * Get a signal buffer address
201 * Given a mbulk buffer, returns a signal buffer address if any in-lined
205 static inline void *mbulk_get_signal(const struct mbulk
*m
)
209 ret
= mbulk_has_signal(m
);
211 return ret
? mbulk_get_seg(m
) : NULL
;
215 * Allocate a bulk buffer
217 * Only one mbulk segment is used for allocation starting from the
218 * mbulk pool with the smallest segment size. If no segment fitting
219 * the requested size, then return NULL without trying to create
223 static inline struct mbulk
*mbulk_alloc(enum mbulk_class clas
, size_t dat_bufsz
)
225 return mbulk_with_signal_alloc(clas
, 0, dat_bufsz
);
231 * After checking the bulk reference counter, this function return the buffer
232 * to the mbulk pool if it is zero. Note that this doesn't free the in-lined
235 static inline void mbulk_free(struct mbulk
*m
)
241 * get bulk buffer address for read or write access
243 * The address is the buffer address after the headroom in the mbulk segment.
244 * Note that this function can only be used to access the data in the same
245 * segment, including a segment in the mbulk chain (for example, to access
246 * the 802.11 header of A-MSDU).
249 static inline void *mbulk_dat_rw(const struct mbulk
*m
)
251 WARN_ON(MBULK_SEG_IS_READONLY(m
));
252 return MBULK_SEG_DAT(m
);
256 * get bulk buffer address for read-only
258 * The address is the buffer address after the headroom in the mbulk segment.
259 * Note that this function can only be used to access the data in the same
260 * segment, including a segment in the mbulk chain (for example, to access
261 * the 802.11 header of A-MSDU).
264 static inline const void *mbulk_dat_r(const struct mbulk
*m
)
266 return (const void *)MBULK_SEG_DAT(m
);
270 * get bulk buffer address at the offset for read or write access
273 static inline void *mbulk_dat_at_rw(const struct mbulk
*m
, size_t off
)
275 WARN_ON(MBULK_SEG_IS_READONLY(m
));
276 return MBULK_SEG_DAT_AT(m
, off
);
280 * get bulk buffer address at the offset for read access
283 static inline /*const*/ void *mbulk_dat_at_r(const struct mbulk
*m
, size_t off
)
285 return (/*const */ void *)MBULK_SEG_DAT_AT(m
, off
);
289 * get valid data length
292 static inline size_t mbulk_tlen(const struct mbulk
*m
)
294 return MBULK_SEG_LEN(m
);
301 static inline size_t mbulk_headroom(const struct mbulk
*m
)
303 return MBULK_SEG_HEADROOM(m
);
306 static inline size_t mbulk_tailroom(const struct mbulk
*m
)
308 return MBULK_SEG_TAILROOM(m
);
314 * Note this API should be called right after mbulk is created or the valid
315 * data length is zero.
318 static inline bool mbulk_reserve_head(struct mbulk
*m
, size_t headroom
)
320 return mbulk_seg_reserve_head(m
, headroom
);
324 * adjust the valid data range
326 * headroom would be placed after the signal buffer (or mbuf descriptor if
327 * no in-lined signal), and the valid data length is set to \len.
330 static inline bool mbulk_adjust_range(struct mbulk
*m
, size_t headroom
, size_t len
)
332 return mbulk_seg_adjust_range(m
, headroom
, len
);
336 * extend the data range at the head
338 * The headroom would be reduced, and the data range is extended.
339 * To prepend data in the head, the headroom should have been reserved before.
342 static inline bool mbulk_prepend_head(struct mbulk
*m
, size_t more
)
344 return mbulk_seg_prepend_head(m
, more
);
348 * extend the data at the tail
350 * Data range is expanded towards the tail.
353 static inline bool mbulk_append_tail(struct mbulk
*m
, size_t more
)
355 return mbulk_seg_append_tail(m
, more
);
359 * trim data at the head
361 * The headroom would be increased, and the valid data range is reduced
365 static inline bool mbulk_trim_head(struct mbulk
*m
, size_t less
)
367 return mbulk_seg_trim_head(m
, less
);
371 * trim data at the tail
373 * The data length would be reduced.
376 static inline bool mbulk_trim_tail(struct mbulk
*m
, size_t less
)
378 return mbulk_seg_trim_tail(m
, less
);
384 * There is no data copy. but the referece counter of the orignal mbulk is
388 static inline struct mbulk
*mbulk_duplicate(struct mbulk
*m
)
390 return mbulk_seg_duplicate(m
);
396 * New mbulk buffer is created, and contents are copied. The signal is copied
397 * only when \copy_sig is TRUE.
400 static inline struct mbulk
*mbulk_clone(const struct mbulk
*m
, enum mbulk_class clas
,
403 return mbulk_seg_clone(m
, clas
, copy_sig
);
407 * allocate a signal buffer from mbulk pool
410 void *msignal_alloc(size_t sig_sz
);
413 * free a signal buffer created from mbulk pool
416 void msignal_free(void *sig
);
419 * get mbulk descriptor given a signal buffer address
422 struct mbulk
*msignal_to_mbulk(void *sig
);
425 * get next chained mbulk in a scatter/gathered list
427 static inline scsc_mifram_ref
mbulk_chain_next(struct mbulk
*m
)
429 return MBULK_SEG_CHAIN_NEXT(m
);
432 #ifdef MBULK_SUPPORT_SG_CHAIN
434 * Scatter/Gather Chained Mbulk APIs
435 * =================================
439 * allocate a chained mbulk buffer from a specific mbulk pool
442 struct mbulk
*mbulk_chain_with_signal_alloc_by_pool(u8 pool_id
,
443 enum mbulk_class clas
, size_t sig_bufsz
, size_t dat_bufsz
);
446 * free a chained mbulk
448 void mbulk_chain_free(struct mbulk
*sg
);
451 * get a tail mbulk in the chain
454 struct mbulk
*mbulk_chain_tail(struct mbulk
*m
);
457 * total buffer size in a chanied mbulk
460 size_t mbulk_chain_bufsz(struct mbulk
*m
);
463 * total data length in a chanied mbulk
466 size_t mbulk_chain_tlen(struct mbulk
*m
);
469 * get a number of mbulk segments in a chained mbulk
471 static inline int mbulk_chain_num(const struct mbulk
*m
)
473 if (mbulk_is_sg(m
)) {
485 /* NOT IMPLEMENTED YET. */
486 void *mbulk_chain_access(struct mbulk
*m
, size_t off
, char *local_buf
, size_t local_bufsz
);
487 void *mbulk_chain_writeback(struct mbulk
*m
, size_t off
, char *local_buf
, size_t local_bufsz
);
488 void *mbulk_chain_copy_from(struct mbulk
*m
, size_t off
, char *buf
, int len
);
489 void *mbulk_chain_copy_to(struct mbulk
*m
, size_t off
, char *buf
, int len
);
490 #endif /*MBULK_SUPPORT_SG_CHAIN*/
495 /*extern void init_mbulk(void);*/
496 void init_mbulk(void *mem
, size_t pool_size
);
499 * add a memory zone to a mbulk pool list
502 #ifdef CONFIG_SCSC_WLAN_DEBUG
503 int mbulk_pool_add(u8 pool_id
, char *base
, char *end
, size_t seg_size
, u8 guard
, int minor
);
505 int mbulk_pool_add(u8 pool_id
, char *base
, char *end
, size_t buf_size
, u8 guard
);
508 * check sanity of a mbulk pool
510 void mbulk_pool_check_sanity(u8 pool_id
);
513 * configure the handler which returning the buffer to the host
515 void mbulk_set_handler_return_host_mbulk(void (*free_host_buf
)(struct mbulk
*m
));
518 * free a mbulk in the virtual host
520 void mbulk_free_virt_host(struct mbulk
*m
);
521 void mbulk_pool_dump(u8 pool_id
, int max_cnt
);
523 #endif /*__MBULK_H__*/