548 lines
13 KiB
C
Executable file
548 lines
13 KiB
C
Executable file
/******************************************************************************
|
|
*
|
|
* Copyright (c) 2014 - 2019 Samsung Electronics Co., Ltd. All rights reserved
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#ifndef __MBULK_H__
|
|
#define __MBULK_H__
|
|
|
|
/**
|
|
* mbulk(bulk memory) API
|
|
*
|
|
* This header file describes APIs of the bulk memory management.
|
|
* The diagram below is an example of a mbulk buffer with one
|
|
* segment (i.e. not a chained mbulk).
|
|
*
|
|
* sig_bufsz
|
|
* |<-------->|
|
|
* | |<--------- dat_bufsz ---------->|
|
|
* +--------------------------------------------------+
|
|
* | mbulk| signal | bulk buffer |
|
|
* +-------------------------+---------------+--------+
|
|
* | | | valid data | |
|
|
* | | |<--------+---->| |
|
|
* | | | mbulk_tlen(m) | |
|
|
* | |<----->| | |<------>|
|
|
* | mbulk_headroom(m)| | mbulk_tailroom(m)
|
|
* | | |
|
|
* | |-- off -->|
|
|
* v v |
|
|
* mbulk_get_sig(m) mbulk_dat(m) |
|
|
* v
|
|
* mbulk_dat_at(m,off)
|
|
*
|
|
* In general, all clients are supposed to use only mbulk_xxx() APIs (but not
|
|
* mbulk_seg_xxx() APIs), as they can handle S/G chained mbulk as well.
|
|
* But as of now, specially in Condor, S/G chained mbulk is not supported,
|
|
* which means the most of mbulk_xxx() would be wrappers of mbulk_seg_xxx().
|
|
*
|
|
* An in-lined signal buffer can be allocated along with a mbulk buffer.
|
|
* There is no direct life-cycle relationship between the signal and the
|
|
* associated mbulk in this case, which means that the signal buffer should be
|
|
* de-allocated independently of the mbulk buffer.
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* bulk buffer descriptor
|
|
*/
|
|
struct mbulk;
|
|
|
|
/**
|
|
* mbulk colour and it's accessors
|
|
*
|
|
* colour is defined as:
|
|
* u32 register bits:
|
|
* [7:0] - vif
|
|
* [15:8] - peer_index
|
|
* [23:16] - ac queue
|
|
* [31:24] - reserved
|
|
*/
|
|
typedef u32 mbulk_colour;
|
|
|
|
#ifndef CONFIG_SCSC_WLAN_TX_API
|
|
#define SLSI_MBULK_COLOUR_SET(colour, vif, peer_index, ac_q) (colour = (ac_q << 16) | (peer_index << 8) | (vif))
|
|
|
|
#define SLSI_MBULK_COLOUR_GET_VIF(colour) (colour & 0xFF)
|
|
#define SLSI_MBULK_COLOUR_GET_PEER_IDX(colour) ((colour >> 8) & 0xFF)
|
|
#define SLSI_MBULK_COLOUR_GET_AC(colour) ((colour >> 16) & 0xFF)
|
|
#endif
|
|
/**
|
|
* mbulk host pool ID
|
|
*/
|
|
#define MBULK_POOL_ID_DATA (0)
|
|
#define MBULK_POOL_ID_CTRL (1)
|
|
#define MBULK_POOL_ID_MAX (2)
|
|
|
|
/**
|
|
* mbulk buffer classification
|
|
*
|
|
* Note that PACKED attribute is added to enum definition so that
|
|
* compiler assigns the smallest integral type (u8).
|
|
*/
|
|
enum mbulk_class {
|
|
MBULK_CLASS_CONTROL = 0,
|
|
MBULK_CLASS_HOSTIO = 1,
|
|
MBULK_CLASS_DEBUG = 2,
|
|
MBULK_CLASS_DEBUG_CRIT = 3,
|
|
|
|
MBULK_CLASS_FROM_HOST_DAT = 4,
|
|
MBULK_CLASS_FROM_HOST_CTL = 5,
|
|
MBULK_CLASS_FROM_RADIO = 6,
|
|
MBULK_CLASS_DPLP = 7,
|
|
MBULK_CLASS_OTHERS = 8,
|
|
MBULK_CLASS_FROM_RADIO_FORWARDED = 9,
|
|
MBULK_CLASS_MAX
|
|
} __packed;
|
|
|
|
/**
|
|
* The private definition of mbulk structure is included here
|
|
* so that its members can be directly accessed, and the access
|
|
* codes can be in-lined by the compiler.
|
|
* But client codes are not supposed to directly refer to mbulk
|
|
* members, nor use mbulk_seg_xxx() functions. Only modules handling
|
|
* mbulk scatter/gather chain would directly use mulk_seg_xxx() APIs.
|
|
*/
|
|
#include "mbulk_def.h"
|
|
|
|
/**
|
|
* Get the bulk data reference counter
|
|
*
|
|
* After a bulk buffer with non-zero data buffer size is created,
|
|
* the reference counter is set to one. Each time it is duplicated,
|
|
* its reference counter would be increased.
|
|
*
|
|
* Note that the reference counter is initialized to zero if a signal
|
|
* is created from mbulk pool but with zero data buffer size, as there
|
|
* is no data buffer.
|
|
*/
|
|
static inline int mbulk_refcnt(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_REFCNT(m);
|
|
}
|
|
|
|
/**
|
|
* Get the bulk data buffer size
|
|
*
|
|
*/
|
|
static inline int mbulk_buffer_size(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_DAT_BUFSIZE(m);
|
|
}
|
|
|
|
/**
|
|
* Check if mbulk has an in-lined signal buffer
|
|
*
|
|
*/
|
|
static inline bool mbulk_has_signal(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_HAS_SIGNAL(m);
|
|
}
|
|
|
|
/**
|
|
* Set mbulk to be read-only
|
|
*/
|
|
static inline void mbulk_set_readonly(struct mbulk *m)
|
|
{
|
|
MBULK_SEG_SET_READONLY(m);
|
|
}
|
|
|
|
/**
|
|
* is mbulk read-only
|
|
*/
|
|
static inline bool mbulk_is_readonly(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_IS_READONLY(m);
|
|
}
|
|
|
|
/**
|
|
* check if mbulk is a scatter/gather chained buffer
|
|
*
|
|
*/
|
|
static inline bool mbulk_is_sg(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_IS_CHAIN_HEAD(m);
|
|
}
|
|
|
|
/**
|
|
* check if mbulk is a part of scatter/gather chained buffer
|
|
*
|
|
*/
|
|
static inline bool mbulk_is_chained(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_IS_CHAINED(m);
|
|
}
|
|
|
|
/**
|
|
* Allocate a bulk buffer with an in-lined signal buffer
|
|
*
|
|
* Only one mbulk segment is used for allocation starting from the
|
|
* mbulk pool with the smallest segment size. If no segment fitting
|
|
* the requested size, then return NULL without trying to create
|
|
* a chained buffer.
|
|
*
|
|
*/
|
|
struct mbulk *mbulk_with_signal_alloc(enum mbulk_class clas, size_t sig_bufsz,
|
|
size_t dat_bufsz);
|
|
/**
|
|
* Allocate a bulk buffer with an in-lined signal buffer
|
|
*
|
|
* A mbulk segment is allocated from the given the pool, if its size
|
|
* meeting the requested size.
|
|
*
|
|
*/
|
|
struct mbulk *mbulk_with_signal_alloc_by_pool(u8 pool_id, mbulk_colour colour,
|
|
enum mbulk_class clas, size_t sig_bufsz, size_t dat_bufsz);
|
|
|
|
/**
|
|
* Get the number of free mbulk slots in a pool
|
|
*
|
|
* Returns the number of mbulk slots available in a given pool.
|
|
*/
|
|
int mbulk_pool_get_free_count(u8 pool_id);
|
|
|
|
/**
|
|
* Get a signal buffer address
|
|
*
|
|
* Given a mbulk buffer, returns a signal buffer address.
|
|
*
|
|
* @param m mbulk
|
|
* @return in-lined signal buffer
|
|
*/
|
|
static inline void *mbulk_get_seg(const struct mbulk *m)
|
|
{
|
|
return (void *)MBULK_SEG_B(m);
|
|
}
|
|
|
|
/**
|
|
* Get a signal buffer address
|
|
*
|
|
* Given a mbulk buffer, returns a signal buffer address if any in-lined
|
|
* signal buffer.
|
|
*
|
|
*/
|
|
static inline void *mbulk_get_signal(const struct mbulk *m)
|
|
{
|
|
bool ret = false;
|
|
|
|
ret = mbulk_has_signal(m);
|
|
|
|
return ret ? mbulk_get_seg(m) : NULL;
|
|
}
|
|
|
|
/**
|
|
* Allocate a bulk buffer
|
|
*
|
|
* Only one mbulk segment is used for allocation starting from the
|
|
* mbulk pool with the smallest segment size. If no segment fitting
|
|
* the requested size, then return NULL without trying to create
|
|
* a chained buffer.
|
|
*
|
|
*/
|
|
static inline struct mbulk *mbulk_alloc(enum mbulk_class clas, size_t dat_bufsz)
|
|
{
|
|
return mbulk_with_signal_alloc(clas, 0, dat_bufsz);
|
|
}
|
|
|
|
/**
|
|
* free mbulk buffer
|
|
*
|
|
* After checking the bulk reference counter, this function return the buffer
|
|
* to the mbulk pool if it is zero. Note that this doesn't free the in-lined
|
|
* signal buffer.
|
|
*/
|
|
static inline void mbulk_free(struct mbulk *m)
|
|
{
|
|
mbulk_seg_free(m);
|
|
}
|
|
|
|
/**
|
|
* get bulk buffer address for read or write access
|
|
*
|
|
* The address is the buffer address after the headroom in the mbulk segment.
|
|
* Note that this function can only be used to access the data in the same
|
|
* segment, including a segment in the mbulk chain (for example, to access
|
|
* the 802.11 header of A-MSDU).
|
|
*
|
|
*/
|
|
static inline void *mbulk_dat_rw(const struct mbulk *m)
|
|
{
|
|
WARN_ON(MBULK_SEG_IS_READONLY(m));
|
|
return MBULK_SEG_DAT(m);
|
|
}
|
|
|
|
/**
|
|
* get bulk buffer address for read-only
|
|
*
|
|
* The address is the buffer address after the headroom in the mbulk segment.
|
|
* Note that this function can only be used to access the data in the same
|
|
* segment, including a segment in the mbulk chain (for example, to access
|
|
* the 802.11 header of A-MSDU).
|
|
*
|
|
*/
|
|
static inline const void *mbulk_dat_r(const struct mbulk *m)
|
|
{
|
|
return (const void *)MBULK_SEG_DAT(m);
|
|
}
|
|
|
|
/**
|
|
* get bulk buffer address at the offset for read or write access
|
|
*
|
|
*/
|
|
static inline void *mbulk_dat_at_rw(const struct mbulk *m, size_t off)
|
|
{
|
|
WARN_ON(MBULK_SEG_IS_READONLY(m));
|
|
return MBULK_SEG_DAT_AT(m, off);
|
|
}
|
|
|
|
/**
|
|
* get bulk buffer address at the offset for read access
|
|
*
|
|
*/
|
|
static inline /*const*/ void *mbulk_dat_at_r(const struct mbulk *m, size_t off)
|
|
{
|
|
return (/*const */ void *)MBULK_SEG_DAT_AT(m, off);
|
|
}
|
|
|
|
/**
|
|
* get valid data length
|
|
*
|
|
*/
|
|
static inline size_t mbulk_tlen(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_LEN(m);
|
|
}
|
|
|
|
/**
|
|
* get headroom
|
|
*
|
|
*/
|
|
static inline size_t mbulk_headroom(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_HEADROOM(m);
|
|
}
|
|
|
|
static inline size_t mbulk_tailroom(const struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_TAILROOM(m);
|
|
}
|
|
|
|
/**
|
|
* reserve headroom
|
|
*
|
|
* Note this API should be called right after mbulk is created or the valid
|
|
* data length is zero.
|
|
*
|
|
*/
|
|
static inline bool mbulk_reserve_head(struct mbulk *m, size_t headroom)
|
|
{
|
|
return mbulk_seg_reserve_head(m, headroom);
|
|
}
|
|
|
|
/**
|
|
* adjust the valid data range
|
|
*
|
|
* headroom would be placed after the signal buffer (or mbuf descriptor if
|
|
* no in-lined signal), and the valid data length is set to \len.
|
|
*
|
|
*/
|
|
static inline bool mbulk_adjust_range(struct mbulk *m, size_t headroom, size_t len)
|
|
{
|
|
return mbulk_seg_adjust_range(m, headroom, len);
|
|
}
|
|
|
|
/**
|
|
* extend the data range at the head
|
|
*
|
|
* The headroom would be reduced, and the data range is extended.
|
|
* To prepend data in the head, the headroom should have been reserved before.
|
|
*
|
|
*/
|
|
static inline bool mbulk_prepend_head(struct mbulk *m, size_t more)
|
|
{
|
|
return mbulk_seg_prepend_head(m, more);
|
|
}
|
|
|
|
/**
|
|
* extend the data at the tail
|
|
*
|
|
* Data range is expanded towards the tail.
|
|
*
|
|
*/
|
|
static inline bool mbulk_append_tail(struct mbulk *m, size_t more)
|
|
{
|
|
return mbulk_seg_append_tail(m, more);
|
|
}
|
|
|
|
/**
|
|
* trim data at the head
|
|
*
|
|
* The headroom would be increased, and the valid data range is reduced
|
|
* accordingly.
|
|
*
|
|
*/
|
|
static inline bool mbulk_trim_head(struct mbulk *m, size_t less)
|
|
{
|
|
return mbulk_seg_trim_head(m, less);
|
|
}
|
|
|
|
/**
|
|
* trim data at the tail
|
|
*
|
|
* The data length would be reduced.
|
|
*
|
|
*/
|
|
static inline bool mbulk_trim_tail(struct mbulk *m, size_t less)
|
|
{
|
|
return mbulk_seg_trim_tail(m, less);
|
|
}
|
|
|
|
/**
|
|
* duplicate a mbulk
|
|
*
|
|
* There is no data copy. but the referece counter of the orignal mbulk is
|
|
* increased by one.
|
|
*
|
|
*/
|
|
static inline struct mbulk *mbulk_duplicate(struct mbulk *m)
|
|
{
|
|
return mbulk_seg_duplicate(m);
|
|
}
|
|
|
|
/**
|
|
* clone a mbulk
|
|
*
|
|
* New mbulk buffer is created, and contents are copied. The signal is copied
|
|
* only when \copy_sig is TRUE.
|
|
*
|
|
*/
|
|
static inline struct mbulk *mbulk_clone(const struct mbulk *m, enum mbulk_class clas,
|
|
bool copy_sig)
|
|
{
|
|
return mbulk_seg_clone(m, clas, copy_sig);
|
|
}
|
|
|
|
/**
|
|
* allocate a signal buffer from mbulk pool
|
|
*
|
|
*/
|
|
void *msignal_alloc(size_t sig_sz);
|
|
|
|
/**
|
|
* free a signal buffer created from mbulk pool
|
|
*
|
|
*/
|
|
void msignal_free(void *sig);
|
|
|
|
/**
|
|
* get mbulk descriptor given a signal buffer address
|
|
*
|
|
*/
|
|
struct mbulk *msignal_to_mbulk(void *sig);
|
|
|
|
/**
|
|
* get next chained mbulk in a scatter/gathered list
|
|
*/
|
|
static inline scsc_mifram_ref mbulk_chain_next(struct mbulk *m)
|
|
{
|
|
return MBULK_SEG_CHAIN_NEXT(m);
|
|
}
|
|
|
|
#ifdef MBULK_SUPPORT_SG_CHAIN
|
|
/**
|
|
* Scatter/Gather Chained Mbulk APIs
|
|
* =================================
|
|
*/
|
|
|
|
/**
|
|
* allocate a chained mbulk buffer from a specific mbulk pool
|
|
*
|
|
*/
|
|
struct mbulk *mbulk_chain_with_signal_alloc_by_pool(u8 pool_id,
|
|
enum mbulk_class clas, size_t sig_bufsz, size_t dat_bufsz);
|
|
|
|
/**
|
|
* free a chained mbulk
|
|
*/
|
|
void mbulk_chain_free(struct mbulk *sg);
|
|
|
|
/**
|
|
* get a tail mbulk in the chain
|
|
*
|
|
*/
|
|
struct mbulk *mbulk_chain_tail(struct mbulk *m);
|
|
|
|
/**
|
|
* total buffer size in a chanied mbulk
|
|
*
|
|
*/
|
|
size_t mbulk_chain_bufsz(struct mbulk *m);
|
|
|
|
/**
|
|
* total data length in a chanied mbulk
|
|
*
|
|
*/
|
|
size_t mbulk_chain_tlen(struct mbulk *m);
|
|
|
|
/**
|
|
* get a number of mbulk segments in a chained mbulk
|
|
*/
|
|
static inline int mbulk_chain_num(const struct mbulk *m)
|
|
{
|
|
if (mbulk_is_sg(m)) {
|
|
int n = 0;
|
|
|
|
while (m != NULL) {
|
|
n++;
|
|
m = m->chain_next;
|
|
}
|
|
return n;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* NOT IMPLEMENTED YET. */
|
|
void *mbulk_chain_access(struct mbulk *m, size_t off, char *local_buf, size_t local_bufsz);
|
|
void *mbulk_chain_writeback(struct mbulk *m, size_t off, char *local_buf, size_t local_bufsz);
|
|
void *mbulk_chain_copy_from(struct mbulk *m, size_t off, char *buf, int len);
|
|
void *mbulk_chain_copy_to(struct mbulk *m, size_t off, char *buf, int len);
|
|
#endif /*MBULK_SUPPORT_SG_CHAIN*/
|
|
|
|
/**
|
|
* init mbulk library
|
|
*/
|
|
/*extern void init_mbulk(void);*/
|
|
void init_mbulk(void *mem, size_t pool_size);
|
|
|
|
/**
|
|
* add a memory zone to a mbulk pool list
|
|
*
|
|
*/
|
|
#ifdef CONFIG_SCSC_WLAN_DEBUG
|
|
int mbulk_pool_add(u8 pool_id, char *base, char *end, size_t seg_size, u8 guard, int minor);
|
|
#else
|
|
int mbulk_pool_add(u8 pool_id, char *base, char *end, size_t buf_size, u8 guard);
|
|
#endif
|
|
/* Remove pool */
|
|
void mbulk_pool_remove(u8 pool_id);
|
|
/**
|
|
* check sanity of a mbulk pool
|
|
*/
|
|
void mbulk_pool_check_sanity(u8 pool_id);
|
|
|
|
/**
|
|
* configure the handler which returning the buffer to the host
|
|
*/
|
|
void mbulk_set_handler_return_host_mbulk(void (*free_host_buf)(struct mbulk *m));
|
|
|
|
/**
|
|
* free a mbulk in the virtual host
|
|
*/
|
|
void mbulk_free_virt_host(struct mbulk *m);
|
|
void mbulk_pool_dump(u8 pool_id, int max_cnt);
|
|
/* Get pool colour */
|
|
mbulk_colour mbulk_get_colour(u8 pool_id, struct mbulk *m);
|
|
|
|
u16 mbulk_pool_seg_size(u8 pool_id);
|
|
#endif /*__MBULK_H__*/
|