Merge branch 'develop-3.10' of ssh://10.10.10.29/rk/kernel into develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / hnd_pktpool.c
1 /*
2  * HND generic packet pool operation primitives
3  *
4  * $Copyright Open Broadcom Corporation$
5  *
6  * $Id: $
7  */
8
9 #include <typedefs.h>
10 #include <osl.h>
11 #include <bcmutils.h>
12 #include <hnd_pktpool.h>
13
14 /* Registry size is one larger than max pools, as slot #0 is reserved */
15 #define PKTPOOLREG_RSVD_ID                              (0U)
16 #define PKTPOOLREG_RSVD_PTR                             (POOLPTR(0xdeaddead))
17 #define PKTPOOLREG_FREE_PTR                             (POOLPTR(NULL))
18
19 #define PKTPOOL_REGISTRY_SET(id, pp)    (pktpool_registry_set((id), (pp)))
20 #define PKTPOOL_REGISTRY_CMP(id, pp)    (pktpool_registry_cmp((id), (pp)))
21
22 /* Tag a registry entry as free for use */
23 #define PKTPOOL_REGISTRY_CLR(id)                \
24                 PKTPOOL_REGISTRY_SET((id), PKTPOOLREG_FREE_PTR)
25 #define PKTPOOL_REGISTRY_ISCLR(id)              \
26                 (PKTPOOL_REGISTRY_CMP((id), PKTPOOLREG_FREE_PTR))
27
28 /* Tag registry entry 0 as reserved */
29 #define PKTPOOL_REGISTRY_RSV()                  \
30                 PKTPOOL_REGISTRY_SET(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR)
31 #define PKTPOOL_REGISTRY_ISRSVD()               \
32                 (PKTPOOL_REGISTRY_CMP(PKTPOOLREG_RSVD_ID, PKTPOOLREG_RSVD_PTR))
33
34 /* Walk all un-reserved entries in registry */
35 #define PKTPOOL_REGISTRY_FOREACH(id)    \
36                 for ((id) = 1U; (id) <= pktpools_max; (id)++)
37
38 uint32 pktpools_max = 0U; /* maximum number of pools that may be initialized */
39 pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1]; /* Pktpool registry */
40
41 /* Register/Deregister a pktpool with registry during pktpool_init/deinit */
42 static int pktpool_register(pktpool_t * poolptr);
43 static int pktpool_deregister(pktpool_t * poolptr);
44
45 /** accessor functions required when ROMming this file, forced into RAM */
46 static void
47 BCMRAMFN(pktpool_registry_set)(int id, pktpool_t *pp)
48 {
49         pktpools_registry[id] = pp;
50 }
51
52 static bool
53 BCMRAMFN(pktpool_registry_cmp)(int id, pktpool_t *pp)
54 {
55         return pktpools_registry[id] == pp;
56 }
57
58 int /* Construct a pool registry to serve a maximum of total_pools */
59 pktpool_attach(osl_t *osh, uint32 total_pools)
60 {
61         uint32 poolid;
62
63         if (pktpools_max != 0U) {
64                 return BCME_ERROR;
65         }
66
67         ASSERT(total_pools <= PKTPOOL_MAXIMUM_ID);
68
69         /* Initialize registry: reserve slot#0 and tag others as free */
70         PKTPOOL_REGISTRY_RSV();         /* reserve slot#0 */
71
72         PKTPOOL_REGISTRY_FOREACH(poolid) {      /* tag all unreserved entries as free */
73                 PKTPOOL_REGISTRY_CLR(poolid);
74         }
75
76         pktpools_max = total_pools;
77
78         return (int)pktpools_max;
79 }
80
81 int /* Destruct the pool registry. Ascertain all pools were first de-inited */
82 pktpool_dettach(osl_t *osh)
83 {
84         uint32 poolid;
85
86         if (pktpools_max == 0U) {
87                 return BCME_OK;
88         }
89
90         /* Ascertain that no pools are still registered */
91         ASSERT(PKTPOOL_REGISTRY_ISRSVD()); /* assert reserved slot */
92
93         PKTPOOL_REGISTRY_FOREACH(poolid) {      /* ascertain all others are free */
94                 ASSERT(PKTPOOL_REGISTRY_ISCLR(poolid));
95         }
96
97         pktpools_max = 0U; /* restore boot state */
98
99         return BCME_OK;
100 }
101
102 static int      /* Register a pool in a free slot; return the registry slot index */
103 pktpool_register(pktpool_t * poolptr)
104 {
105         uint32 poolid;
106
107         if (pktpools_max == 0U) {
108                 return PKTPOOL_INVALID_ID; /* registry has not yet been constructed */
109         }
110
111         ASSERT(pktpools_max != 0U);
112
113         /* find an empty slot in pktpools_registry */
114         PKTPOOL_REGISTRY_FOREACH(poolid) {
115                 if (PKTPOOL_REGISTRY_ISCLR(poolid)) {
116                         PKTPOOL_REGISTRY_SET(poolid, POOLPTR(poolptr)); /* register pool */
117                         return (int)poolid; /* return pool ID */
118                 }
119         } /* FOREACH */
120
121         return PKTPOOL_INVALID_ID;      /* error: registry is full */
122 }
123
124 static int      /* Deregister a pktpool, given the pool pointer; tag slot as free */
125 pktpool_deregister(pktpool_t * poolptr)
126 {
127         uint32 poolid;
128
129         ASSERT(POOLPTR(poolptr) != POOLPTR(NULL));
130
131         poolid = POOLID(poolptr);
132         ASSERT(poolid <= pktpools_max);
133
134         /* Asertain that a previously registered poolptr is being de-registered */
135         if (PKTPOOL_REGISTRY_CMP(poolid, POOLPTR(poolptr))) {
136                 PKTPOOL_REGISTRY_CLR(poolid); /* mark as free */
137         } else {
138                 ASSERT(0);
139                 return BCME_ERROR; /* mismatch in registry */
140         }
141
142         return BCME_OK;
143 }
144
145
146 /*
147  * pktpool_init:
148  * User provides a pktpool_t sturcture and specifies the number of packets to
149  * be pre-filled into the pool (pplen). The size of all packets in a pool must
150  * be the same and is specified by plen.
151  * pktpool_init first attempts to register the pool and fetch a unique poolid.
152  * If registration fails, it is considered an BCME_ERR, caused by either the
153  * registry was not pre-created (pktpool_attach) or the registry is full.
154  * If registration succeeds, then the requested number of packets will be filled
155  * into the pool as part of initialization. In the event that there is no
156  * available memory to service the request, then BCME_NOMEM will be returned
157  * along with the count of how many packets were successfully allocated.
158  * In dongle builds, prior to memory reclaimation, one should limit the number
159  * of packets to be allocated during pktpool_init and fill the pool up after
160  * reclaim stage.
161  */
162 int
163 pktpool_init(osl_t *osh, pktpool_t *pktp, int *pplen, int plen, bool istx, uint8 type)
164 {
165         int i, err = BCME_OK;
166         int pktplen;
167         uint8 pktp_id;
168
169         ASSERT(pktp != NULL);
170         ASSERT(osh != NULL);
171         ASSERT(pplen != NULL);
172
173         pktplen = *pplen;
174
175         bzero(pktp, sizeof(pktpool_t));
176
177         /* assign a unique pktpool id */
178         if ((pktp_id = (uint8) pktpool_register(pktp)) == PKTPOOL_INVALID_ID) {
179                 return BCME_ERROR;
180         }
181         POOLSETID(pktp, pktp_id);
182
183         pktp->inited = TRUE;
184         pktp->istx = istx ? TRUE : FALSE;
185         pktp->plen = (uint16)plen;
186         pktp->type = type;
187
188         pktp->maxlen = PKTPOOL_LEN_MAX;
189         pktplen = LIMIT_TO_MAX(pktplen, pktp->maxlen);
190
191         for (i = 0; i < pktplen; i++) {
192                 void *p;
193                 p = PKTGET(osh, plen, TRUE);
194
195                 if (p == NULL) {
196                         /* Not able to allocate all requested pkts
197                          * so just return what was actually allocated
198                          * We can add to the pool later
199                          */
200                         if (pktp->freelist == NULL) /* pktpool free list is empty */
201                                 err = BCME_NOMEM;
202
203                         goto exit;
204                 }
205
206                 PKTSETPOOL(osh, p, TRUE, pktp); /* Tag packet with pool ID */
207
208                 PKTSETFREELIST(p, pktp->freelist); /* insert p at head of free list */
209                 pktp->freelist = p;
210
211                 pktp->avail++;
212
213 #ifdef BCMDBG_POOL
214                 pktp->dbg_q[pktp->dbg_qlen++].p = p;
215 #endif
216         }
217
218 exit:
219         pktp->len = pktp->avail;
220
221         *pplen = pktp->len;
222         return err;
223 }
224
225 /*
226  * pktpool_deinit:
227  * Prior to freeing a pktpool, all packets must be first freed into the pktpool.
228  * Upon pktpool_deinit, all packets in the free pool will be freed to the heap.
229  * An assert is in place to ensure that there are no packets still lingering
230  * around. Packets freed to a pool after the deinit will cause a memory
231  * corruption as the pktpool_t structure no longer exists.
232  */
233 int
234 pktpool_deinit(osl_t *osh, pktpool_t *pktp)
235 {
236         uint16 freed = 0;
237
238         ASSERT(osh != NULL);
239         ASSERT(pktp != NULL);
240
241 #ifdef BCMDBG_POOL
242         {
243                 int i;
244                 for (i = 0; i <= pktp->len; i++) {
245                         pktp->dbg_q[i].p = NULL;
246                 }
247         }
248 #endif
249
250         while (pktp->freelist != NULL) {
251                 void * p = pktp->freelist;
252
253                 pktp->freelist = PKTFREELIST(p); /* unlink head packet from free list */
254                 PKTSETFREELIST(p, NULL);
255
256                 PKTSETPOOL(osh, p, FALSE, NULL); /* clear pool ID tag in pkt */
257
258                 PKTFREE(osh, p, pktp->istx); /* free the packet */
259
260                 freed++;
261                 ASSERT(freed <= pktp->len);
262         }
263
264         pktp->avail -= freed;
265         ASSERT(pktp->avail == 0);
266
267         pktp->len -= freed;
268
269         pktpool_deregister(pktp); /* release previously acquired unique pool id */
270         POOLSETID(pktp, PKTPOOL_INVALID_ID);
271
272         pktp->inited = FALSE;
273
274         /* Are there still pending pkts? */
275         ASSERT(pktp->len == 0);
276
277         return 0;
278 }
279
280 int
281 pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal)
282 {
283         void *p;
284         int err = 0;
285         int len, psize, maxlen;
286
287         ASSERT(pktp->plen != 0);
288
289         maxlen = pktp->maxlen;
290         psize = minimal ? (maxlen >> 2) : maxlen;
291         for (len = (int)pktp->len; len < psize; len++) {
292
293                 p = PKTGET(osh, pktp->len, TRUE);
294
295                 if (p == NULL) {
296                         err = BCME_NOMEM;
297                         break;
298                 }
299
300                 if (pktpool_add(pktp, p) != BCME_OK) {
301                         PKTFREE(osh, p, FALSE);
302                         err = BCME_ERROR;
303                         break;
304                 }
305         }
306
307         return err;
308 }
309
310 static void *
311 pktpool_deq(pktpool_t *pktp)
312 {
313         void *p;
314
315         if (pktp->avail == 0)
316                 return NULL;
317
318         ASSERT(pktp->freelist != NULL);
319
320         p = pktp->freelist;  /* dequeue packet from head of pktpool free list */
321         pktp->freelist = PKTFREELIST(p); /* free list points to next packet */
322         PKTSETFREELIST(p, NULL);
323
324         pktp->avail--;
325
326         return p;
327 }
328
329 static void
330 pktpool_enq(pktpool_t *pktp, void *p)
331 {
332         ASSERT(p != NULL);
333
334         PKTSETFREELIST(p, pktp->freelist); /* insert at head of pktpool free list */
335         pktp->freelist = p; /* free list points to newly inserted packet */
336
337         pktp->avail++;
338         ASSERT(pktp->avail <= pktp->len);
339 }
340
341 /* utility for registering host addr fill function called from pciedev */
342 int
343 /* BCMATTACHFN */
344 (pktpool_hostaddr_fill_register)(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg)
345 {
346
347         ASSERT(cb != NULL);
348
349         ASSERT(pktp->cbext.cb == NULL);
350         pktp->cbext.cb = cb;
351         pktp->cbext.arg = arg;
352         return 0;
353 }
354
355 int
356 pktpool_rxcplid_fill_register(pktpool_t *pktp, pktpool_cb_extn_t cb, void *arg)
357 {
358
359         ASSERT(cb != NULL);
360
361         ASSERT(pktp->rxcplidfn.cb == NULL);
362         pktp->rxcplidfn.cb = cb;
363         pktp->rxcplidfn.arg = arg;
364         return 0;
365 }
366 /* Callback functions for split rx modes */
367 /* when evr host posts rxbuffer, invike dma_rxfill from pciedev layer */
368 void
369 pktpool_invoke_dmarxfill(pktpool_t *pktp)
370 {
371         ASSERT(pktp->dmarxfill.cb);
372         ASSERT(pktp->dmarxfill.arg);
373
374         if (pktp->dmarxfill.cb)
375                 pktp->dmarxfill.cb(pktp, pktp->dmarxfill.arg);
376 }
377 int
378 pkpool_haddr_avail_register_cb(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
379 {
380
381         ASSERT(cb != NULL);
382
383         pktp->dmarxfill.cb = cb;
384         pktp->dmarxfill.arg = arg;
385
386         return 0;
387 }
388 /* No BCMATTACHFN as it is used in xdc_enable_ep which is not an attach function */
389 int
390 pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
391 {
392         int i;
393
394         ASSERT(cb != NULL);
395
396         i = pktp->cbcnt;
397         if (i == PKTPOOL_CB_MAX)
398                 return BCME_ERROR;
399
400         ASSERT(pktp->cbs[i].cb == NULL);
401         pktp->cbs[i].cb = cb;
402         pktp->cbs[i].arg = arg;
403         pktp->cbcnt++;
404
405         return 0;
406 }
407
408 int
409 pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
410 {
411         int i;
412
413         ASSERT(cb != NULL);
414
415         i = pktp->ecbcnt;
416         if (i == PKTPOOL_CB_MAX)
417                 return BCME_ERROR;
418
419         ASSERT(pktp->ecbs[i].cb == NULL);
420         pktp->ecbs[i].cb = cb;
421         pktp->ecbs[i].arg = arg;
422         pktp->ecbcnt++;
423
424         return 0;
425 }
426
427 static int
428 pktpool_empty_notify(pktpool_t *pktp)
429 {
430         int i;
431
432         pktp->empty = TRUE;
433         for (i = 0; i < pktp->ecbcnt; i++) {
434                 ASSERT(pktp->ecbs[i].cb != NULL);
435                 pktp->ecbs[i].cb(pktp, pktp->ecbs[i].arg);
436         }
437         pktp->empty = FALSE;
438
439         return 0;
440 }
441
442 #ifdef BCMDBG_POOL
443 int
444 pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg)
445 {
446         int i;
447
448         ASSERT(cb);
449
450         i = pktp->dbg_cbcnt;
451         if (i == PKTPOOL_CB_MAX)
452                 return BCME_ERROR;
453
454         ASSERT(pktp->dbg_cbs[i].cb == NULL);
455         pktp->dbg_cbs[i].cb = cb;
456         pktp->dbg_cbs[i].arg = arg;
457         pktp->dbg_cbcnt++;
458
459         return 0;
460 }
461
462 int pktpool_dbg_notify(pktpool_t *pktp);
463
464 int
465 pktpool_dbg_notify(pktpool_t *pktp)
466 {
467         int i;
468
469         for (i = 0; i < pktp->dbg_cbcnt; i++) {
470                 ASSERT(pktp->dbg_cbs[i].cb);
471                 pktp->dbg_cbs[i].cb(pktp, pktp->dbg_cbs[i].arg);
472         }
473
474         return 0;
475 }
476
477 int
478 pktpool_dbg_dump(pktpool_t *pktp)
479 {
480         int i;
481
482         printf("pool len=%d maxlen=%d\n",  pktp->dbg_qlen, pktp->maxlen);
483         for (i = 0; i < pktp->dbg_qlen; i++) {
484                 ASSERT(pktp->dbg_q[i].p);
485                 printf("%d, p: 0x%x dur:%lu us state:%d\n", i,
486                         pktp->dbg_q[i].p, pktp->dbg_q[i].dur/100, PKTPOOLSTATE(pktp->dbg_q[i].p));
487         }
488
489         return 0;
490 }
491
492 int
493 pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats)
494 {
495         int i;
496         int state;
497
498         bzero(stats, sizeof(pktpool_stats_t));
499         for (i = 0; i < pktp->dbg_qlen; i++) {
500                 ASSERT(pktp->dbg_q[i].p != NULL);
501
502                 state = PKTPOOLSTATE(pktp->dbg_q[i].p);
503                 switch (state) {
504                         case POOL_TXENQ:
505                                 stats->enq++; break;
506                         case POOL_TXDH:
507                                 stats->txdh++; break;
508                         case POOL_TXD11:
509                                 stats->txd11++; break;
510                         case POOL_RXDH:
511                                 stats->rxdh++; break;
512                         case POOL_RXD11:
513                                 stats->rxd11++; break;
514                         case POOL_RXFILL:
515                                 stats->rxfill++; break;
516                         case POOL_IDLE:
517                                 stats->idle++; break;
518                 }
519         }
520
521         return 0;
522 }
523
524 int
525 pktpool_start_trigger(pktpool_t *pktp, void *p)
526 {
527         uint32 cycles, i;
528
529         if (!PKTPOOL(OSH_NULL, p))
530                 return 0;
531
532         OSL_GETCYCLES(cycles);
533
534         for (i = 0; i < pktp->dbg_qlen; i++) {
535                 ASSERT(pktp->dbg_q[i].p != NULL);
536
537                 if (pktp->dbg_q[i].p == p) {
538                         pktp->dbg_q[i].cycles = cycles;
539                         break;
540                 }
541         }
542
543         return 0;
544 }
545
546 int pktpool_stop_trigger(pktpool_t *pktp, void *p);
547 int
548 pktpool_stop_trigger(pktpool_t *pktp, void *p)
549 {
550         uint32 cycles, i;
551
552         if (!PKTPOOL(OSH_NULL, p))
553                 return 0;
554
555         OSL_GETCYCLES(cycles);
556
557         for (i = 0; i < pktp->dbg_qlen; i++) {
558                 ASSERT(pktp->dbg_q[i].p != NULL);
559
560                 if (pktp->dbg_q[i].p == p) {
561                         if (pktp->dbg_q[i].cycles == 0)
562                                 break;
563
564                         if (cycles >= pktp->dbg_q[i].cycles)
565                                 pktp->dbg_q[i].dur = cycles - pktp->dbg_q[i].cycles;
566                         else
567                                 pktp->dbg_q[i].dur =
568                                         (((uint32)-1) - pktp->dbg_q[i].cycles) + cycles + 1;
569
570                         pktp->dbg_q[i].cycles = 0;
571                         break;
572                 }
573         }
574
575         return 0;
576 }
577 #endif /* BCMDBG_POOL */
578
579 int
580 pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp)
581 {
582         ASSERT(pktp);
583         pktp->availcb_excl = NULL;
584         return 0;
585 }
586
587 int
588 pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb)
589 {
590         int i;
591
592         ASSERT(pktp);
593         ASSERT(pktp->availcb_excl == NULL);
594         for (i = 0; i < pktp->cbcnt; i++) {
595                 if (cb == pktp->cbs[i].cb) {
596                         pktp->availcb_excl = &pktp->cbs[i];
597                         break;
598                 }
599         }
600
601         if (pktp->availcb_excl == NULL)
602                 return BCME_ERROR;
603         else
604                 return 0;
605 }
606
607 static int
608 pktpool_avail_notify(pktpool_t *pktp)
609 {
610         int i, k, idx;
611         int avail;
612
613         ASSERT(pktp);
614         if (pktp->availcb_excl != NULL) {
615                 pktp->availcb_excl->cb(pktp, pktp->availcb_excl->arg);
616                 return 0;
617         }
618
619         k = pktp->cbcnt - 1;
620         for (i = 0; i < pktp->cbcnt; i++) {
621                 avail = pktp->avail;
622
623                 if (avail) {
624                         if (pktp->cbtoggle)
625                                 idx = i;
626                         else
627                                 idx = k--;
628
629                         ASSERT(pktp->cbs[idx].cb != NULL);
630                         pktp->cbs[idx].cb(pktp, pktp->cbs[idx].arg);
631                 }
632         }
633
634         /* Alternate between filling from head or tail
635          */
636         pktp->cbtoggle ^= 1;
637
638         return 0;
639 }
640
641 void *
642 pktpool_get(pktpool_t *pktp)
643 {
644         void *p;
645
646         p = pktpool_deq(pktp);
647
648         if (p == NULL) {
649                 /* Notify and try to reclaim tx pkts */
650                 if (pktp->ecbcnt)
651                         pktpool_empty_notify(pktp);
652
653                 p = pktpool_deq(pktp);
654                 if (p == NULL)
655                         return NULL;
656         }
657
658         return p;
659 }
660
661 void
662 pktpool_free(pktpool_t *pktp, void *p)
663 {
664         ASSERT(p != NULL);
665 #ifdef BCMDBG_POOL
666         /* pktpool_stop_trigger(pktp, p); */
667 #endif
668
669         pktpool_enq(pktp, p);
670
671         if (pktp->emptycb_disable)
672                 return;
673
674         if (pktp->cbcnt) {
675                 if (pktp->empty == FALSE)
676                         pktpool_avail_notify(pktp);
677         }
678 }
679
680 int
681 pktpool_add(pktpool_t *pktp, void *p)
682 {
683         ASSERT(p != NULL);
684
685         if (pktp->len == pktp->maxlen)
686                 return BCME_RANGE;
687
688         /* pkts in pool have same length */
689         ASSERT(pktp->plen == PKTLEN(OSH_NULL, p));
690         PKTSETPOOL(OSH_NULL, p, TRUE, pktp);
691
692         pktp->len++;
693         pktpool_enq(pktp, p);
694
695 #ifdef BCMDBG_POOL
696         pktp->dbg_q[pktp->dbg_qlen++].p = p;
697 #endif
698
699         return 0;
700 }
701
702 /* Force pktpool_setmaxlen () into RAM as it uses a constant
703  * (PKTPOOL_LEN_MAX) that may be changed post tapeout for ROM-based chips.
704  */
705 int
706 BCMRAMFN(pktpool_setmaxlen)(pktpool_t *pktp, uint16 maxlen)
707 {
708         if (maxlen > PKTPOOL_LEN_MAX)
709                 maxlen = PKTPOOL_LEN_MAX;
710
711         /* if pool is already beyond maxlen, then just cap it
712          * since we currently do not reduce the pool len
713          * already allocated
714          */
715         pktp->maxlen = (pktp->len > maxlen) ? pktp->len : maxlen;
716
717         return pktp->maxlen;
718 }
719
720 void
721 pktpool_emptycb_disable(pktpool_t *pktp, bool disable)
722 {
723         ASSERT(pktp);
724
725         pktp->emptycb_disable = disable;
726 }
727
728 bool
729 pktpool_emptycb_disabled(pktpool_t *pktp)
730 {
731         ASSERT(pktp);
732         return pktp->emptycb_disable;
733 }