Merge branch 'for-arm' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal...
[firefly-linux-kernel-4.4.55.git] / drivers / infiniband / hw / cxgb4 / resource.c
index 407ff39241509ffeb73af496fc0421dd60801f4d..cdef4d7fb6d823405a5ed6e0f67a8481a5db870c 100644 (file)
  * SOFTWARE.
  */
 /* Crude resource management */
-#include <linux/kernel.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/kfifo.h>
 #include <linux/spinlock.h>
-#include <linux/errno.h>
 #include <linux/genalloc.h>
 #include <linux/ratelimit.h>
 #include "iw_cxgb4.h"
 
-#define RANDOM_SIZE 16
-
-static int __c4iw_init_resource_fifo(struct kfifo *fifo,
-                                  spinlock_t *fifo_lock,
-                                  u32 nr, u32 skip_low,
-                                  u32 skip_high,
-                                  int random)
-{
-       u32 i, j, entry = 0, idx;
-       u32 random_bytes;
-       u32 rarray[16];
-       spin_lock_init(fifo_lock);
-
-       if (kfifo_alloc(fifo, nr * sizeof(u32), GFP_KERNEL))
-               return -ENOMEM;
-
-       for (i = 0; i < skip_low + skip_high; i++)
-               kfifo_in(fifo, (unsigned char *) &entry, sizeof(u32));
-       if (random) {
-               j = 0;
-               random_bytes = random32();
-               for (i = 0; i < RANDOM_SIZE; i++)
-                       rarray[i] = i + skip_low;
-               for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
-                       if (j >= RANDOM_SIZE) {
-                               j = 0;
-                               random_bytes = random32();
-                       }
-                       idx = (random_bytes >> (j * 2)) & 0xF;
-                       kfifo_in(fifo,
-                               (unsigned char *) &rarray[idx],
-                               sizeof(u32));
-                       rarray[idx] = i;
-                       j++;
-               }
-               for (i = 0; i < RANDOM_SIZE; i++)
-                       kfifo_in(fifo,
-                               (unsigned char *) &rarray[i],
-                               sizeof(u32));
-       } else
-               for (i = skip_low; i < nr - skip_high; i++)
-                       kfifo_in(fifo, (unsigned char *) &i, sizeof(u32));
-
-       for (i = 0; i < skip_low + skip_high; i++)
-               if (kfifo_out_locked(fifo, (unsigned char *) &entry,
-                                    sizeof(u32), fifo_lock))
-                       break;
-       return 0;
-}
-
-static int c4iw_init_resource_fifo(struct kfifo *fifo, spinlock_t * fifo_lock,
-                                  u32 nr, u32 skip_low, u32 skip_high)
-{
-       return __c4iw_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
-                                         skip_high, 0);
-}
-
-static int c4iw_init_resource_fifo_random(struct kfifo *fifo,
-                                  spinlock_t *fifo_lock,
-                                  u32 nr, u32 skip_low, u32 skip_high)
-{
-       return __c4iw_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
-                                         skip_high, 1);
-}
-
-static int c4iw_init_qid_fifo(struct c4iw_rdev *rdev)
+static int c4iw_init_qid_table(struct c4iw_rdev *rdev)
 {
        u32 i;
 
-       spin_lock_init(&rdev->resource.qid_fifo_lock);
-
-       if (kfifo_alloc(&rdev->resource.qid_fifo, rdev->lldi.vr->qp.size *
-                       sizeof(u32), GFP_KERNEL))
+       if (c4iw_id_table_alloc(&rdev->resource.qid_table,
+                               rdev->lldi.vr->qp.start,
+                               rdev->lldi.vr->qp.size,
+                               rdev->lldi.vr->qp.size, 0))
                return -ENOMEM;
 
        for (i = rdev->lldi.vr->qp.start;
-            i < rdev->lldi.vr->qp.start + rdev->lldi.vr->qp.size; i++)
+               i < rdev->lldi.vr->qp.start + rdev->lldi.vr->qp.size; i++)
                if (!(i & rdev->qpmask))
-                       kfifo_in(&rdev->resource.qid_fifo,
-                                   (unsigned char *) &i, sizeof(u32));
+                       c4iw_id_free(&rdev->resource.qid_table, i);
        return 0;
 }
 
@@ -127,44 +56,42 @@ static int c4iw_init_qid_fifo(struct c4iw_rdev *rdev)
 int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid)
 {
        int err = 0;
-       err = c4iw_init_resource_fifo_random(&rdev->resource.tpt_fifo,
-                                            &rdev->resource.tpt_fifo_lock,
-                                            nr_tpt, 1, 0);
+       err = c4iw_id_table_alloc(&rdev->resource.tpt_table, 0, nr_tpt, 1,
+                                       C4IW_ID_TABLE_F_RANDOM);
        if (err)
                goto tpt_err;
-       err = c4iw_init_qid_fifo(rdev);
+       err = c4iw_init_qid_table(rdev);
        if (err)
                goto qid_err;
-       err = c4iw_init_resource_fifo(&rdev->resource.pdid_fifo,
-                                     &rdev->resource.pdid_fifo_lock,
-                                     nr_pdid, 1, 0);
+       err = c4iw_id_table_alloc(&rdev->resource.pdid_table, 0,
+                                       nr_pdid, 1, 0);
        if (err)
                goto pdid_err;
        return 0;
-pdid_err:
-       kfifo_free(&rdev->resource.qid_fifo);
-qid_err:
-       kfifo_free(&rdev->resource.tpt_fifo);
-tpt_err:
+ pdid_err:
+       c4iw_id_table_free(&rdev->resource.qid_table);
+ qid_err:
+       c4iw_id_table_free(&rdev->resource.tpt_table);
+ tpt_err:
        return -ENOMEM;
 }
 
 /*
  * returns 0 if no resource available
  */
-u32 c4iw_get_resource(struct kfifo *fifo, spinlock_t *lock)
+u32 c4iw_get_resource(struct c4iw_id_table *id_table)
 {
        u32 entry;
-       if (kfifo_out_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock))
-               return entry;
-       else
+       entry = c4iw_id_alloc(id_table);
+       if (entry == (u32)(-1))
                return 0;
+       return entry;
 }
 
-void c4iw_put_resource(struct kfifo *fifo, u32 entry, spinlock_t *lock)
+void c4iw_put_resource(struct c4iw_id_table *id_table, u32 entry)
 {
        PDBG("%s entry 0x%x\n", __func__, entry);
-       kfifo_in_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock);
+       c4iw_id_free(id_table, entry);
 }
 
 u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
@@ -181,10 +108,12 @@ u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
                qid = entry->qid;
                kfree(entry);
        } else {
-               qid = c4iw_get_resource(&rdev->resource.qid_fifo,
-                                       &rdev->resource.qid_fifo_lock);
+               qid = c4iw_get_resource(&rdev->resource.qid_table);
                if (!qid)
                        goto out;
+               mutex_lock(&rdev->stats.lock);
+               rdev->stats.qid.cur += rdev->qpmask + 1;
+               mutex_unlock(&rdev->stats.lock);
                for (i = qid+1; i & rdev->qpmask; i++) {
                        entry = kmalloc(sizeof *entry, GFP_KERNEL);
                        if (!entry)
@@ -213,6 +142,10 @@ u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
 out:
        mutex_unlock(&uctx->lock);
        PDBG("%s qid 0x%x\n", __func__, qid);
+       mutex_lock(&rdev->stats.lock);
+       if (rdev->stats.qid.cur > rdev->stats.qid.max)
+               rdev->stats.qid.max = rdev->stats.qid.cur;
+       mutex_unlock(&rdev->stats.lock);
        return qid;
 }
 
@@ -245,10 +178,12 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
                qid = entry->qid;
                kfree(entry);
        } else {
-               qid = c4iw_get_resource(&rdev->resource.qid_fifo,
-                                       &rdev->resource.qid_fifo_lock);
+               qid = c4iw_get_resource(&rdev->resource.qid_table);
                if (!qid)
                        goto out;
+               mutex_lock(&rdev->stats.lock);
+               rdev->stats.qid.cur += rdev->qpmask + 1;
+               mutex_unlock(&rdev->stats.lock);
                for (i = qid+1; i & rdev->qpmask; i++) {
                        entry = kmalloc(sizeof *entry, GFP_KERNEL);
                        if (!entry)
@@ -277,6 +212,10 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
 out:
        mutex_unlock(&uctx->lock);
        PDBG("%s qid 0x%x\n", __func__, qid);
+       mutex_lock(&rdev->stats.lock);
+       if (rdev->stats.qid.cur > rdev->stats.qid.max)
+               rdev->stats.qid.max = rdev->stats.qid.cur;
+       mutex_unlock(&rdev->stats.lock);
        return qid;
 }
 
@@ -297,9 +236,9 @@ void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qid,
 
 void c4iw_destroy_resource(struct c4iw_resource *rscp)
 {
-       kfifo_free(&rscp->tpt_fifo);
-       kfifo_free(&rscp->qid_fifo);
-       kfifo_free(&rscp->pdid_fifo);
+       c4iw_id_table_free(&rscp->tpt_table);
+       c4iw_id_table_free(&rscp->qid_table);
+       c4iw_id_table_free(&rscp->pdid_table);
 }
 
 /*
@@ -312,15 +251,23 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
 {
        unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
        PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
-       if (!addr)
-               printk_ratelimited(KERN_WARNING MOD "%s: Out of PBL memory\n",
-                      pci_name(rdev->lldi.pdev));
+       mutex_lock(&rdev->stats.lock);
+       if (addr) {
+               rdev->stats.pbl.cur += roundup(size, 1 << MIN_PBL_SHIFT);
+               if (rdev->stats.pbl.cur > rdev->stats.pbl.max)
+                       rdev->stats.pbl.max = rdev->stats.pbl.cur;
+       } else
+               rdev->stats.pbl.fail++;
+       mutex_unlock(&rdev->stats.lock);
        return (u32)addr;
 }
 
 void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
 {
        PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+       mutex_lock(&rdev->stats.lock);
+       rdev->stats.pbl.cur -= roundup(size, 1 << MIN_PBL_SHIFT);
+       mutex_unlock(&rdev->stats.lock);
        gen_pool_free(rdev->pbl_pool, (unsigned long)addr, size);
 }
 
@@ -377,12 +324,23 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
        if (!addr)
                printk_ratelimited(KERN_WARNING MOD "%s: Out of RQT memory\n",
                       pci_name(rdev->lldi.pdev));
+       mutex_lock(&rdev->stats.lock);
+       if (addr) {
+               rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT);
+               if (rdev->stats.rqt.cur > rdev->stats.rqt.max)
+                       rdev->stats.rqt.max = rdev->stats.rqt.cur;
+       } else
+               rdev->stats.rqt.fail++;
+       mutex_unlock(&rdev->stats.lock);
        return (u32)addr;
 }
 
 void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
 {
        PDBG("%s addr 0x%x size %d\n", __func__, addr, size << 6);
+       mutex_lock(&rdev->stats.lock);
+       rdev->stats.rqt.cur -= roundup(size << 6, 1 << MIN_RQT_SHIFT);
+       mutex_unlock(&rdev->stats.lock);
        gen_pool_free(rdev->rqt_pool, (unsigned long)addr, size << 6);
 }
 
@@ -433,12 +391,22 @@ u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
 {
        unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
        PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+       if (addr) {
+               mutex_lock(&rdev->stats.lock);
+               rdev->stats.ocqp.cur += roundup(size, 1 << MIN_OCQP_SHIFT);
+               if (rdev->stats.ocqp.cur > rdev->stats.ocqp.max)
+                       rdev->stats.ocqp.max = rdev->stats.ocqp.cur;
+               mutex_unlock(&rdev->stats.lock);
+       }
        return (u32)addr;
 }
 
 void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
 {
        PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+       mutex_lock(&rdev->stats.lock);
+       rdev->stats.ocqp.cur -= roundup(size, 1 << MIN_OCQP_SHIFT);
+       mutex_unlock(&rdev->stats.lock);
        gen_pool_free(rdev->ocqp_pool, (unsigned long)addr, size);
 }