OpenSS7
SS7 for the
Common Man

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified:

Home Overview Status News Documentation Resources About
   
 Overview
 Status
 News
 Documentation
 Resources
 About

   
Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/bufpool.h


File /code/strss7/drivers/bufpool.h



#ifndef __BUFPOOL_H__
#define __BUFPOOL_H__

/*
 *  -------------------------------------------------------------------------
 *
 *  Fast BUFPOOL buffer allocation/deallocation for ISRs.
 *
 *  -------------------------------------------------------------------------
 */

typedef struct ss7_bufpool {
	int initialized;
	mblk_t *head;
	atomic_t count;
	atomic_t reserve;
	spinlock_t lock;
} ss7_bufpool_t;

/*
 *  BUFPOOL ALLOCB
 *  -------------------------------------------------------------------------
 *  This is a fast allocation mechanism for FASTBUF sized buffers for the
 *  receive ISRs.  This increases FISU/LSSU compression performance.  If there
 *  are blocks in the pool we use one of those, otherwise we allocate as
 *  normal.
 */
/* assumes bufpool is locked */
STATIC INLINE mblk_t *__ss7_fast_allocb(struct ss7_bufpool *pool, size_t size, int prior)
{
	mblk_t *mp = NULL;
	if (size <= FASTBUF && prior == BPRI_HI) {
		if ((mp = pool->head)) {
			pool->head = mp->b_cont;
			atomic_dec(&pool->count);
			mp->b_cont = NULL;
			mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
			mp->b_datap->db_type = M_DATA;
		}
	}
	if (!mp)
		mp = allocb(size, prior);
	return (mp);
}

/* for use in the bottom half or tasklet */
STATIC INLINE mblk_t *ss7_fast_allocb(struct ss7_bufpool *pool, size_t size, int prior)
{
	mblk_t *mp = NULL;
	if (size <= FASTBUF && prior == BPRI_HI) {
		spin_lock(&pool->lock);
		if ((mp = pool->head)) {
			pool->head = mp->b_cont;
			spin_unlock(&pool->lock);
			atomic_dec(&pool->count);
			mp->b_cont = NULL;
			mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
			mp->b_datap->db_type = M_DATA;
		} else
			spin_unlock(&pool->lock);
	}
	if (!mp)
		mp = allocb(size, prior);
	return (mp);
}

/* for use outside the bottom half */
STATIC INLINE mblk_t *ss7_fast_allocb_bh(struct ss7_bufpool *pool, size_t size, int prior)
{
	mblk_t *mp = NULL;
	if (size <= FASTBUF && prior == BPRI_HI) {
		spin_lock_bh(&pool->lock);
		if ((mp = pool->head)) {
			pool->head = mp->b_cont;
			spin_unlock_bh(&pool->lock);
			atomic_dec(&pool->count);
			mp->b_cont = NULL;
			mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
			mp->b_datap->db_type = M_DATA;
		} else
			spin_unlock_bh(&pool->lock);
	}
	if (!mp)
		mp = allocb(size, prior);
	return (mp);
}

/*
 *  BUFPOOL FREEB
 *  -------------------------------------------------------------------------
 *  This is a fast deallocation mechanism for FASTBUF sized buffers for the
 *  receive ISRs.  This increases FISU/LSSU compression performance.  If there
 *  is only one reference to the message block, we just place the block in the
 *  pool.  If there is more than one reference, we free as normal.
 */
/* assumes bufpool is locked */
STATIC INLINE void __ss7_fast_freeb(struct ss7_bufpool *pool, mblk_t *mp)
{
	if (mp->b_datap->db_ref == 1 && mp->b_datap->db_size == FASTBUF &&
	    atomic_read(&pool->count) < atomic_read(&pool->reserve)) {
		mp->b_cont = xchg(&pool->head, mp);
		atomic_inc(&pool->count);
	} else {
		/* other references, use normal free mechanism */
		freeb(mp);
	}
}

/* for use inside the bottom half */
STATIC INLINE void ss7_fast_freeb(struct ss7_bufpool *pool, mblk_t *mp)
{
	if (mp->b_datap->db_ref == 1 && mp->b_datap->db_size == FASTBUF &&
	    atomic_read(&pool->count) < atomic_read(&pool->reserve)) {
		spin_lock(&pool->lock);
		mp->b_cont = xchg(&pool->head, mp);
		spin_unlock(&pool->lock);
		atomic_inc(&pool->count);
	} else {
		/* other references, use normal free mechanism */
		freeb(mp);
	}
}

/* for use outside the bottom half */
STATIC INLINE void ss7_fast_freeb_bh(struct ss7_bufpool *pool, mblk_t *mp)
{
	if (mp->b_datap->db_ref == 1 && mp->b_datap->db_size == FASTBUF &&
	    atomic_read(&pool->count) < atomic_read(&pool->reserve)) {
		spin_lock_bh(&pool->lock);
		mp->b_cont = xchg(&pool->head, mp);
		spin_unlock_bh(&pool->lock);
		atomic_inc(&pool->count);
	} else {
		/* other references, use normal free mechanism */
		freeb(mp);
	}
}

/*
 *  BUFPOOL FREEMSG
 *  -------------------------------------------------------------------------
 *  This is a fast deallocation mechansim for FASTBUF sized buffers for the
 *  receive ISRs.  This increases FISU/LSSU compression performance.  If there
 *  is only one reference to the message block we just place the block in the
 *  pool.  If there is more than one reference, we free as normal.
 */
/* assumes bufpool is locked */
STATIC INLINE void __ss7_fast_freemsg(struct ss7_bufpool *pool, mblk_t *mp)
{
	mblk_t *bp, *bp_next = mp;
	while ((bp = bp_next)) {
		bp_next = bp->b_cont;
		__ss7_fast_freeb(pool, bp);
	}
}

/* for use inside the bottom half */
STATIC INLINE void ss7_fast_freemsg(struct ss7_bufpool *pool, mblk_t *mp)
{
	mblk_t *bp, *bp_next = mp;
	while ((bp = bp_next)) {
		bp_next = bp->b_cont;
		ss7_fast_freeb(pool, bp);
	}
}

/* for use outside the bottom half */
STATIC INLINE void ss7_fast_freemsg_bh(struct ss7_bufpool *pool, mblk_t *mp)
{
	mblk_t *bp, *bp_next = mp;
	while ((bp = bp_next)) {
		bp_next = bp->b_cont;
		ss7_fast_freeb_bh(pool, bp);
	}
}

/*
 *  BUFPOOL INIT and TERM
 *  -------------------------------------------------------------------------
 *  These initialization, allocation, deallocation and termination routines
 *  must be called outside of interrupts.
 */
/*
 *  BUFPOOL INIT
 *  -----------------------------------
 *  Initialized the buffer pool for operation.
 */
STATIC void ss7_bufpool_init(struct ss7_bufpool *pool)
{
	if (!pool->initialized) {
		pool->head = NULL;
		atomic_set(&pool->count, 0);
		atomic_set(&pool->reserve, 0);
		spin_lock_init(&pool->lock);
		pool->initialized = 1;
	} else
		swerr();
}

/*
 *  BUFPOOL RESERVE
 *  -----------------------------------
 *  Reserves n more FASTBUF sized blocks in the buffer pool and precharges
 *  those n blocks into the buffer pool.
 */
STATIC void ss7_bufpool_reserve(struct ss7_bufpool *pool, int n)
{
	mblk_t *mp;
	atomic_add(n, &pool->reserve);
	/* precharge the pool */
	while (n--) {
		if (!(mp = allocb(FASTBUF, BPRI_LO)))
			break;
		ss7_fast_freemsg_bh(pool, mp);
	}
}

/*
 *  BUFPOOL RELEASE
 *  -----------------------------------
 *  Releases reservation of n FASTBUF sized blocks.  We do not release them
 *  here, we wait for them to be used normally, or freed on termination.
 */
STATIC void ss7_bufpool_release(struct ss7_bufpool *pool, int n)
{
	atomic_sub(n, &pool->reserve);
}

/*
 *  BUFPOOL TERM
 *  -----------------------------------
 *  Terminate the buffer pool and free any blocks in the pool.
 */
STATIC void ss7_bufpool_term(struct ss7_bufpool *pool)
{
	int flags;
	spin_lock_irqsave(&pool->lock, flags);
	if (pool->initialized) {
		mblk_t *bp;
		while ((bp = pool->head)) {
			pool->head = bp->b_cont;
			freeb(bp);
		}
		atomic_set(&pool->count, 0);
		atomic_set(&pool->reserve, 0);
		pool->initialized = 0;
	}
	spin_unlock_irqrestore(&pool->lock, flags);
}

#endif				/* __BUFPOOL_H__ */


Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/drivers/bufpool.h

OpenSS7
SS7 for the
Common Man
Home Overview Status News Documentation Resources About

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified: