net: rkwifi: fix using wext protocol anomaly
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / hnd_pktpool.c
index 242f4322117a2efd86d7759c87cf323241f60696..f3555e40ce91497ed8130299747da9f72717f683 100755 (executable)
@@ -1,16 +1,51 @@
 /*
  * HND generic packet pool operation primitives
  *
- * $Copyright Open Broadcom Corporation$
+ * Copyright (C) 1999-2016, Broadcom Corporation
+ * 
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: $
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hnd_pktpool.c 591285 2015-10-07 11:56:29Z $
  */
 
 #include <typedefs.h>
 #include <osl.h>
+#include <osl_ext.h>
 #include <bcmutils.h>
 #include <hnd_pktpool.h>
 
+/* mutex macros for thread safe */
+#ifdef HND_PKTPOOL_THREAD_SAFE
+#define HND_PKTPOOL_MUTEX_CREATE(name, mutex)  osl_ext_mutex_create(name, mutex)
+#define HND_PKTPOOL_MUTEX_DELETE(mutex)                osl_ext_mutex_delete(mutex)
+#define HND_PKTPOOL_MUTEX_ACQUIRE(mutex, msec) osl_ext_mutex_acquire(mutex, msec)
+#define HND_PKTPOOL_MUTEX_RELEASE(mutex)       osl_ext_mutex_release(mutex)
+#else
+#define HND_PKTPOOL_MUTEX_CREATE(name, mutex)  OSL_EXT_SUCCESS
+#define HND_PKTPOOL_MUTEX_DELETE(mutex)                OSL_EXT_SUCCESS
+#define HND_PKTPOOL_MUTEX_ACQUIRE(mutex, msec) OSL_EXT_SUCCESS
+#define HND_PKTPOOL_MUTEX_RELEASE(mutex)       OSL_EXT_SUCCESS
+#endif
+
 /* Registry size is one larger than max pools, as slot #0 is reserved */
 #define PKTPOOLREG_RSVD_ID                             (0U)
 #define PKTPOOLREG_RSVD_PTR                            (POOLPTR(0xdeaddead))
 #define PKTPOOL_REGISTRY_FOREACH(id)   \
                for ((id) = 1U; (id) <= pktpools_max; (id)++)
 
+enum pktpool_empty_cb_state {
+       EMPTYCB_ENABLED = 0,    /* Enable callback when new packets are added to pool */
+       EMPTYCB_DISABLED,       /* Disable callback when new packets are added to pool */
+       EMPTYCB_SKIPPED         /* Packet was added to pool when callback was disabled */
+};
+
 uint32 pktpools_max = 0U; /* maximum number of pools that may be initialized */
 pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; /* Pktpool registry */
 
@@ -42,7 +83,18 @@ pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; /* Pktpool registry */
 static int pktpool_register(pktpool_t * poolptr);
 static int pktpool_deregister(pktpool_t * poolptr);
 
+/** add declaration */
+static int pktpool_avail_notify(pktpool_t *pktp);
+
 /** accessor functions required when ROMming this file, forced into RAM */
+
+
+pktpool_t *
+BCMRAMFN(get_pktpools_registry)(int id)
+{
+       return pktpools_registry[id];
+}
+
 static void
 BCMRAMFN(pktpool_registry_set)(int id, pktpool_t *pp)
 {
@@ -185,6 +237,10 @@ pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx, uint8
        pktp->plen = (uint16)plen;
        pktp->type = type;
 
+       if (HND_PKTPOOL_MUTEX_CREATE("pktpool", &pktp->mutex) != OSL_EXT_SUCCESS) {
+               return BCME_ERROR;
+       }
+
        pktp->maxlen = PKTPOOL_LEN_MAX;
        pktplen = LIMIT_TO_MAX(pktplen, pktp->maxlen);
 
@@ -269,6 +325,9 @@ pktpool_deinit(osl_t *osh, pktpool_t *pktp)
        pktpool_deregister(pktp); /* release previously acquired unique pool id */
        POOLSETID(pktp, PKTPOOL_INVALID_ID);
 
+       if (HND_PKTPOOL_MUTEX_DELETE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        pktp->inited = FALSE;
 
        /* Are there still pending pkts? */
@@ -284,6 +343,10 @@ pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal)
        int err = 0;
        int len, psize, maxlen;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        ASSERT(pktp->plen != 0);
 
        maxlen = pktp->maxlen;
@@ -304,13 +367,22 @@ pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal)
                }
        }
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
+       if (pktp->cbcnt) {
+               if (pktp->empty == FALSE)
+                       pktpool_avail_notify(pktp);
+       }
+
        return err;
 }
 
 static void *
 pktpool_deq(pktpool_t *pktp)
 {
-       void *p;
+       void *p = NULL;
 
        if (pktp->avail == 0)
                return NULL;
@@ -358,6 +430,8 @@ pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg)
 
        ASSERT(cb != NULL);
 
+       if (pktp == NULL)
+               return BCME_ERROR;
        ASSERT(pktp->rxcplidfn.cb == NULL);
        pktp->rxcplidfn.cb = cb;
        pktp->rxcplidfn.arg = arg;
@@ -389,39 +463,63 @@ pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
 int
 pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
 {
+       int err = 0;
        int i;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        ASSERT(cb != NULL);
 
        i = pktp->cbcnt;
-       if (i == PKTPOOL_CB_MAX)
-               return BCME_ERROR;
+       if (i == PKTPOOL_CB_MAX_AVL) {
+               err = BCME_ERROR;
+               goto done;
+       }
 
        ASSERT(pktp->cbs[i].cb == NULL);
        pktp->cbs[i].cb = cb;
        pktp->cbs[i].arg = arg;
        pktp->cbcnt++;
 
-       return 0;
+done:
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
+       return err;
 }
 
 int
 pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
 {
+       int err = 0;
        int i;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        ASSERT(cb != NULL);
 
        i = pktp->ecbcnt;
-       if (i == PKTPOOL_CB_MAX)
-               return BCME_ERROR;
+       if (i == PKTPOOL_CB_MAX) {
+               err = BCME_ERROR;
+               goto done;
+       }
 
        ASSERT(pktp->ecbs[i].cb == NULL);
        pktp->ecbs[i].cb = cb;
        pktp->ecbs[i].arg = arg;
        pktp->ecbcnt++;
 
-       return 0;
+done:
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
+       return err;
 }
 
 static int
@@ -443,20 +541,32 @@ pktpool_empty_notify(pktpool_t *pktp)
 int
 pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
 {
+       int err = 0;
        int i;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        ASSERT(cb);
 
        i = pktp->dbg_cbcnt;
-       if (i == PKTPOOL_CB_MAX)
-               return BCME_ERROR;
+       if (i == PKTPOOL_CB_MAX) {
+               err = BCME_ERROR;
+               goto done;
+       }
 
        ASSERT(pktp->dbg_cbs[i].cb == NULL);
        pktp->dbg_cbs[i].cb = cb;
        pktp->dbg_cbs[i].arg = arg;
        pktp->dbg_cbcnt++;
 
-       return 0;
+done:
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
+       return err;
 }
 
 int pktpool_dbg_notify(pktpool_t *pktp);
@@ -466,11 +576,19 @@ pktpool_dbg_notify(pktpool_t *pktp)
 {
        int i;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        for (i = 0; i < pktp->dbg_cbcnt; i++) {
                ASSERT(pktp->dbg_cbs[i].cb);
                pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg);
        }
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        return 0;
 }
 
@@ -479,6 +597,10 @@ pktpool_dbg_dump(pktpool_t *pktp)
 {
        int i;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        printf("pool len=%d maxlen=%d\n",  pktp->dbg_qlen, pktp->maxlen);
        for (i = 0; i < pktp->dbg_qlen; i++) {
                ASSERT(pktp->dbg_q[i].p);
@@ -486,6 +608,10 @@ pktpool_dbg_dump(pktpool_t *pktp)
                        pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p));
        }
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        return 0;
 }
 
@@ -495,6 +621,10 @@ pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats)
        int i;
        int state;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        bzero(stats, sizeof(pktpool_stats_t));
        for (i = 0; i < pktp->dbg_qlen; i++) {
                ASSERT(pktp->dbg_q[i].p != NULL);
@@ -518,6 +648,10 @@ pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats)
                }
        }
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        return 0;
 }
 
@@ -526,8 +660,12 @@ pktpool_start_trigger(pktpool_t *pktp, void *p)
 {
        uint32 cycles, i;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        if (!PKTPOOL(OSH_NULL, p))
-               return 0;
+               goto done;
 
        OSL_GETCYCLES(cycles);
 
@@ -540,6 +678,11 @@ pktpool_start_trigger(pktpool_t *pktp, void *p)
                }
        }
 
+done:
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        return 0;
 }
 
@@ -549,8 +692,12 @@ pktpool_stop_trigger(pktpool_t *pktp, void *p)
 {
        uint32 cycles, i;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        if (!PKTPOOL(OSH_NULL, p))
-               return 0;
+               goto done;
 
        OSL_GETCYCLES(cycles);
 
@@ -572,6 +719,11 @@ pktpool_stop_trigger(pktpool_t *pktp, void *p)
                }
        }
 
+done:
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        return 0;
 }
 #endif /* BCMDBG_POOL */
@@ -580,7 +732,17 @@ int
 pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp)
 {
        ASSERT(pktp);
+
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        pktp->availcb_excl = NULL;
+
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        return 0;
 }
 
@@ -588,8 +750,14 @@ int
 pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb)
 {
        int i;
+       int err;
 
        ASSERT(pktp);
+
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        ASSERT(pktp->availcb_excl == NULL);
        for (i = 0; i < pktp->cbcnt; i++) {
                if (cb == pktp->cbs[i].cb) {
@@ -599,9 +767,15 @@ pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb)
        }
 
        if (pktp->availcb_excl == NULL)
-               return BCME_ERROR;
+               err = BCME_ERROR;
        else
-               return 0;
+               err = 0;
+
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
+       return err;
 }
 
 static int
@@ -643,6 +817,11 @@ pktpool_get(pktpool_t *pktp)
 {
        void *p;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return NULL;
+
+
        p = pktpool_deq(pktp);
 
        if (p == NULL) {
@@ -652,15 +831,25 @@ pktpool_get(pktpool_t *pktp)
 
                p = pktpool_deq(pktp);
                if (p == NULL)
-                       return NULL;
+                       goto done;
        }
 
+
+done:
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return NULL;
+
        return p;
 }
 
 void
 pktpool_free(pktpool_t *pktp, void *p)
 {
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return;
+
        ASSERT(p != NULL);
 #ifdef BCMDBG_POOL
        /* pktpool_stop_trigger(pktp, p); */
@@ -668,22 +857,51 @@ pktpool_free(pktpool_t *pktp, void *p)
 
        pktpool_enq(pktp, p);
 
-       if (pktp->emptycb_disable)
-               return;
-
+       /**
+        * Feed critical DMA with freshly freed packets, to avoid DMA starvation.
+        * If any avail callback functions are registered, send a notification
+        * that a new packet is available in the pool.
+        */
        if (pktp->cbcnt) {
-               if (pktp->empty == FALSE)
-                       pktpool_avail_notify(pktp);
+               /* To more efficiently use the cpu cycles, callbacks can be temporarily disabled.
+                * This allows to feed on burst basis as opposed to inefficient per-packet basis.
+                */
+               if (pktp->emptycb_disable == EMPTYCB_ENABLED) {
+                       /**
+                        * If the call originated from pktpool_empty_notify, the just freed packet
+                        * is needed in pktpool_get.
+                        * Therefore don't call pktpool_avail_notify.
+                        */
+                       if (pktp->empty == FALSE)
+                               pktpool_avail_notify(pktp);
+               } else {
+                       /**
+                        * The callback is temporarily disabled, log that a packet has been freed.
+                        */
+                       pktp->emptycb_disable = EMPTYCB_SKIPPED;
+               }
        }
+
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return;
 }
 
 int
 pktpool_add(pktpool_t *pktp, void *p)
 {
+       int err = 0;
+
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        ASSERT(p != NULL);
 
-       if (pktp->len == pktp->maxlen)
-               return BCME_RANGE;
+       if (pktp->len == pktp->maxlen) {
+               err = BCME_RANGE;
+               goto done;
+       }
 
        /* pkts in pool have same length */
        ASSERT(pktp->plen == PKTLEN(OSH_NULL, p));
@@ -696,7 +914,12 @@ pktpool_add(pktpool_t *pktp, void *p)
        pktp->dbg_q[pktp->dbg_qlen++].p = p;
 #endif
 
-       return 0;
+done:
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
+       return err;
 }
 
 /* Force pktpool_setmaxlen () into RAM as it uses a constant
@@ -705,6 +928,10 @@ pktpool_add(pktpool_t *pktp, void *p)
 int
 BCMRAMFN(pktpool_setmaxlen)(pktpool_t *pktp, uint16 maxlen)
 {
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_ACQUIRE(&pktp->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        if (maxlen > PKTPOOL_LEN_MAX)
                maxlen = PKTPOOL_LEN_MAX;
 
@@ -714,6 +941,10 @@ BCMRAMFN(pktpool_setmaxlen)(pktpool_t *pktp, uint16 maxlen)
         */
        pktp->maxlen = (pktp->len > maxlen) ? pktp->len : maxlen;
 
+       /* protect shared resource */
+       if (HND_PKTPOOL_MUTEX_RELEASE(&pktp->mutex) != OSL_EXT_SUCCESS)
+               return BCME_ERROR;
+
        return pktp->maxlen;
 }
 
@@ -722,12 +953,179 @@ pktpool_emptycb_disable(pktpool_t *pktp, bool disable)
 {
        ASSERT(pktp);
 
-       pktp->emptycb_disable = disable;
+       /**
+        * To more efficiently use the cpu cycles, callbacks can be temporarily disabled.
+        * If callback is going to be re-enabled, check if any packet got
+        * freed and added back to the pool while callback was disabled.
+        * When this is the case do the callback now, provided that callback functions
+        * are registered and this call did not originate from pktpool_empty_notify.
+        */
+       if ((!disable) && (pktp->cbcnt) && (pktp->empty == FALSE) &&
+               (pktp->emptycb_disable == EMPTYCB_SKIPPED)) {
+                       pktpool_avail_notify(pktp);
+       }
+
+       /* Enable or temporarily disable callback when packet becomes available. */
+       pktp->emptycb_disable = disable ? EMPTYCB_DISABLED : EMPTYCB_ENABLED;
 }
 
 bool
 pktpool_emptycb_disabled(pktpool_t *pktp)
 {
        ASSERT(pktp);
-       return pktp->emptycb_disable;
+       return pktp->emptycb_disable != EMPTYCB_ENABLED;
+}
+
+#ifdef BCMPKTPOOL
+#include <hnd_lbuf.h>
+
+pktpool_t *pktpool_shared = NULL;
+
+#ifdef BCMFRAGPOOL
+pktpool_t *pktpool_shared_lfrag = NULL;
+#endif /* BCMFRAGPOOL */
+
+pktpool_t *pktpool_shared_rxlfrag = NULL;
+
+static osl_t *pktpool_osh = NULL;
+
+void
+hnd_pktpool_init(osl_t *osh)
+{
+       int n;
+
+       /* Construct a packet pool registry before initializing packet pools */
+       n = pktpool_attach(osh, PKTPOOL_MAXIMUM_ID);
+       if (n != PKTPOOL_MAXIMUM_ID) {
+               ASSERT(0);
+               return;
+       }
+
+       pktpool_shared = MALLOCZ(osh, sizeof(pktpool_t));
+       if (pktpool_shared == NULL) {
+               ASSERT(0);
+               goto error1;
+       }
+
+#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED)
+       pktpool_shared_lfrag = MALLOCZ(osh, sizeof(pktpool_t));
+       if (pktpool_shared_lfrag == NULL) {
+               ASSERT(0);
+               goto error2;
+       }
+#endif
+
+#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)
+       pktpool_shared_rxlfrag = MALLOCZ(osh, sizeof(pktpool_t));
+       if (pktpool_shared_rxlfrag == NULL) {
+               ASSERT(0);
+               goto error3;
+       }
+#endif
+
+
+       /*
+        * At this early stage, there's not enough memory to allocate all
+        * requested pkts in the shared pool.  Need to add to the pool
+        * after reclaim
+        *
+        * n = NRXBUFPOST + SDPCMD_RXBUFS;
+        *
+        * Initialization of packet pools may fail (BCME_ERROR), if the packet pool
+        * registry is not initialized or the registry is depleted.
+        *
+        * A BCME_NOMEM error only indicates that the requested number of packets
+        * were not filled into the pool.
+        */
+       n = 1;
+       if (pktpool_init(osh, pktpool_shared,
+                        &n, PKTBUFSZ, FALSE, lbuf_basic) == BCME_ERROR) {
+               ASSERT(0);
+               goto error4;
+       }
+       pktpool_setmaxlen(pktpool_shared, SHARED_POOL_LEN);
+
+#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED)
+       n = 1;
+       if (pktpool_init(osh, pktpool_shared_lfrag,
+                        &n, PKTFRAGSZ, TRUE, lbuf_frag) == BCME_ERROR) {
+               ASSERT(0);
+               goto error5;
+       }
+       pktpool_setmaxlen(pktpool_shared_lfrag, SHARED_FRAG_POOL_LEN);
+#endif
+#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)
+       n = 1;
+       if (pktpool_init(osh, pktpool_shared_rxlfrag,
+                        &n, PKTRXFRAGSZ, TRUE, lbuf_rxfrag) == BCME_ERROR) {
+               ASSERT(0);
+               goto error6;
+       }
+       pktpool_setmaxlen(pktpool_shared_rxlfrag, SHARED_RXFRAG_POOL_LEN);
+#endif
+
+       pktpool_osh = osh;
+
+       return;
+
+#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)
+error6:
+#endif
+
+#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED)
+       pktpool_deinit(osh, pktpool_shared_lfrag);
+error5:
+#endif
+
+#if (defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)) || \
+       (defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED))
+       pktpool_deinit(osh, pktpool_shared);
+#endif
+
+error4:
+#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)
+       hnd_free(pktpool_shared_rxlfrag);
+       pktpool_shared_rxlfrag = (pktpool_t *)NULL;
+error3:
+#endif /* BCMRXFRAGPOOL */
+
+#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED)
+       hnd_free(pktpool_shared_lfrag);
+       pktpool_shared_lfrag = (pktpool_t *)NULL;
+error2:
+#endif /* BCMFRAGPOOL */
+
+       hnd_free(pktpool_shared);
+       pktpool_shared = (pktpool_t *)NULL;
+
+error1:
+       pktpool_dettach(osh);
+}
+
+void
+hnd_pktpool_fill(pktpool_t *pktpool, bool minimal)
+{
+       pktpool_fill(pktpool_osh, pktpool, minimal);
+}
+
+/* refill pktpools after reclaim */
+void
+hnd_pktpool_refill(bool minimal)
+{
+       if (POOL_ENAB(pktpool_shared)) {
+               pktpool_fill(pktpool_osh, pktpool_shared, minimal);
+       }
+/* fragpool reclaim */
+#ifdef BCMFRAGPOOL
+       if (POOL_ENAB(pktpool_shared_lfrag)) {
+               pktpool_fill(pktpool_osh, pktpool_shared_lfrag, minimal);
+       }
+#endif /* BCMFRAGPOOL */
+/* rx fragpool reclaim */
+#ifdef BCMRXFRAGPOOL
+       if (POOL_ENAB(pktpool_shared_rxlfrag)) {
+               pktpool_fill(pktpool_osh, pktpool_shared_rxlfrag, minimal);
+       }
+#endif
 }
+#endif /* BCMPKTPOOL */