0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/spinlock.h>
0034 #include <linux/genalloc.h>
0035 #include <linux/ratelimit.h>
0036 #include "iw_cxgb4.h"
0037
0038 static int c4iw_init_qid_table(struct c4iw_rdev *rdev)
0039 {
0040 u32 i;
0041
0042 if (c4iw_id_table_alloc(&rdev->resource.qid_table,
0043 rdev->lldi.vr->qp.start,
0044 rdev->lldi.vr->qp.size,
0045 rdev->lldi.vr->qp.size, 0))
0046 return -ENOMEM;
0047
0048 for (i = rdev->lldi.vr->qp.start;
0049 i < rdev->lldi.vr->qp.start + rdev->lldi.vr->qp.size; i++)
0050 if (!(i & rdev->qpmask))
0051 c4iw_id_free(&rdev->resource.qid_table, i);
0052 return 0;
0053 }
0054
0055
0056 int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt,
0057 u32 nr_pdid, u32 nr_srqt)
0058 {
0059 int err = 0;
0060 err = c4iw_id_table_alloc(&rdev->resource.tpt_table, 0, nr_tpt, 1,
0061 C4IW_ID_TABLE_F_RANDOM);
0062 if (err)
0063 goto tpt_err;
0064 err = c4iw_init_qid_table(rdev);
0065 if (err)
0066 goto qid_err;
0067 err = c4iw_id_table_alloc(&rdev->resource.pdid_table, 0,
0068 nr_pdid, 1, 0);
0069 if (err)
0070 goto pdid_err;
0071 if (!nr_srqt)
0072 err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
0073 1, 1, 0);
0074 else
0075 err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
0076 nr_srqt, 0, 0);
0077 if (err)
0078 goto srq_err;
0079 return 0;
0080 srq_err:
0081 c4iw_id_table_free(&rdev->resource.pdid_table);
0082 pdid_err:
0083 c4iw_id_table_free(&rdev->resource.qid_table);
0084 qid_err:
0085 c4iw_id_table_free(&rdev->resource.tpt_table);
0086 tpt_err:
0087 return -ENOMEM;
0088 }
0089
0090
0091
0092
0093 u32 c4iw_get_resource(struct c4iw_id_table *id_table)
0094 {
0095 u32 entry;
0096 entry = c4iw_id_alloc(id_table);
0097 if (entry == (u32)(-1))
0098 return 0;
0099 return entry;
0100 }
0101
0102 void c4iw_put_resource(struct c4iw_id_table *id_table, u32 entry)
0103 {
0104 pr_debug("entry 0x%x\n", entry);
0105 c4iw_id_free(id_table, entry);
0106 }
0107
0108 u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
0109 {
0110 struct c4iw_qid_list *entry;
0111 u32 qid;
0112 int i;
0113
0114 mutex_lock(&uctx->lock);
0115 if (!list_empty(&uctx->cqids)) {
0116 entry = list_entry(uctx->cqids.next, struct c4iw_qid_list,
0117 entry);
0118 list_del(&entry->entry);
0119 qid = entry->qid;
0120 kfree(entry);
0121 } else {
0122 qid = c4iw_get_resource(&rdev->resource.qid_table);
0123 if (!qid)
0124 goto out;
0125 mutex_lock(&rdev->stats.lock);
0126 rdev->stats.qid.cur += rdev->qpmask + 1;
0127 mutex_unlock(&rdev->stats.lock);
0128 for (i = qid+1; i & rdev->qpmask; i++) {
0129 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0130 if (!entry)
0131 goto out;
0132 entry->qid = i;
0133 list_add_tail(&entry->entry, &uctx->cqids);
0134 }
0135
0136
0137
0138
0139
0140 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0141 if (!entry)
0142 goto out;
0143 entry->qid = qid;
0144 list_add_tail(&entry->entry, &uctx->qpids);
0145 for (i = qid+1; i & rdev->qpmask; i++) {
0146 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0147 if (!entry)
0148 goto out;
0149 entry->qid = i;
0150 list_add_tail(&entry->entry, &uctx->qpids);
0151 }
0152 }
0153 out:
0154 mutex_unlock(&uctx->lock);
0155 pr_debug("qid 0x%x\n", qid);
0156 mutex_lock(&rdev->stats.lock);
0157 if (rdev->stats.qid.cur > rdev->stats.qid.max)
0158 rdev->stats.qid.max = rdev->stats.qid.cur;
0159 mutex_unlock(&rdev->stats.lock);
0160 return qid;
0161 }
0162
0163 void c4iw_put_cqid(struct c4iw_rdev *rdev, u32 qid,
0164 struct c4iw_dev_ucontext *uctx)
0165 {
0166 struct c4iw_qid_list *entry;
0167
0168 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0169 if (!entry)
0170 return;
0171 pr_debug("qid 0x%x\n", qid);
0172 entry->qid = qid;
0173 mutex_lock(&uctx->lock);
0174 list_add_tail(&entry->entry, &uctx->cqids);
0175 mutex_unlock(&uctx->lock);
0176 }
0177
0178 u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
0179 {
0180 struct c4iw_qid_list *entry;
0181 u32 qid;
0182 int i;
0183
0184 mutex_lock(&uctx->lock);
0185 if (!list_empty(&uctx->qpids)) {
0186 entry = list_entry(uctx->qpids.next, struct c4iw_qid_list,
0187 entry);
0188 list_del(&entry->entry);
0189 qid = entry->qid;
0190 kfree(entry);
0191 } else {
0192 qid = c4iw_get_resource(&rdev->resource.qid_table);
0193 if (!qid) {
0194 mutex_lock(&rdev->stats.lock);
0195 rdev->stats.qid.fail++;
0196 mutex_unlock(&rdev->stats.lock);
0197 goto out;
0198 }
0199 mutex_lock(&rdev->stats.lock);
0200 rdev->stats.qid.cur += rdev->qpmask + 1;
0201 mutex_unlock(&rdev->stats.lock);
0202 for (i = qid+1; i & rdev->qpmask; i++) {
0203 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0204 if (!entry)
0205 goto out;
0206 entry->qid = i;
0207 list_add_tail(&entry->entry, &uctx->qpids);
0208 }
0209
0210
0211
0212
0213
0214 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0215 if (!entry)
0216 goto out;
0217 entry->qid = qid;
0218 list_add_tail(&entry->entry, &uctx->cqids);
0219 for (i = qid + 1; i & rdev->qpmask; i++) {
0220 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0221 if (!entry)
0222 goto out;
0223 entry->qid = i;
0224 list_add_tail(&entry->entry, &uctx->cqids);
0225 }
0226 }
0227 out:
0228 mutex_unlock(&uctx->lock);
0229 pr_debug("qid 0x%x\n", qid);
0230 mutex_lock(&rdev->stats.lock);
0231 if (rdev->stats.qid.cur > rdev->stats.qid.max)
0232 rdev->stats.qid.max = rdev->stats.qid.cur;
0233 mutex_unlock(&rdev->stats.lock);
0234 return qid;
0235 }
0236
0237 void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qid,
0238 struct c4iw_dev_ucontext *uctx)
0239 {
0240 struct c4iw_qid_list *entry;
0241
0242 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0243 if (!entry)
0244 return;
0245 pr_debug("qid 0x%x\n", qid);
0246 entry->qid = qid;
0247 mutex_lock(&uctx->lock);
0248 list_add_tail(&entry->entry, &uctx->qpids);
0249 mutex_unlock(&uctx->lock);
0250 }
0251
0252 void c4iw_destroy_resource(struct c4iw_resource *rscp)
0253 {
0254 c4iw_id_table_free(&rscp->tpt_table);
0255 c4iw_id_table_free(&rscp->qid_table);
0256 c4iw_id_table_free(&rscp->pdid_table);
0257 }
0258
0259
0260
0261
0262
0263 #define MIN_PBL_SHIFT 8
0264
0265 u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
0266 {
0267 unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
0268 pr_debug("addr 0x%x size %d\n", (u32)addr, size);
0269 mutex_lock(&rdev->stats.lock);
0270 if (addr) {
0271 rdev->stats.pbl.cur += roundup(size, 1 << MIN_PBL_SHIFT);
0272 if (rdev->stats.pbl.cur > rdev->stats.pbl.max)
0273 rdev->stats.pbl.max = rdev->stats.pbl.cur;
0274 kref_get(&rdev->pbl_kref);
0275 } else
0276 rdev->stats.pbl.fail++;
0277 mutex_unlock(&rdev->stats.lock);
0278 return (u32)addr;
0279 }
0280
0281 static void destroy_pblpool(struct kref *kref)
0282 {
0283 struct c4iw_rdev *rdev;
0284
0285 rdev = container_of(kref, struct c4iw_rdev, pbl_kref);
0286 gen_pool_destroy(rdev->pbl_pool);
0287 complete(&rdev->pbl_compl);
0288 }
0289
0290 void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
0291 {
0292 pr_debug("addr 0x%x size %d\n", addr, size);
0293 mutex_lock(&rdev->stats.lock);
0294 rdev->stats.pbl.cur -= roundup(size, 1 << MIN_PBL_SHIFT);
0295 mutex_unlock(&rdev->stats.lock);
0296 gen_pool_free(rdev->pbl_pool, (unsigned long)addr, size);
0297 kref_put(&rdev->pbl_kref, destroy_pblpool);
0298 }
0299
0300 int c4iw_pblpool_create(struct c4iw_rdev *rdev)
0301 {
0302 unsigned pbl_start, pbl_chunk, pbl_top;
0303
0304 rdev->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
0305 if (!rdev->pbl_pool)
0306 return -ENOMEM;
0307
0308 pbl_start = rdev->lldi.vr->pbl.start;
0309 pbl_chunk = rdev->lldi.vr->pbl.size;
0310 pbl_top = pbl_start + pbl_chunk;
0311
0312 while (pbl_start < pbl_top) {
0313 pbl_chunk = min(pbl_top - pbl_start + 1, pbl_chunk);
0314 if (gen_pool_add(rdev->pbl_pool, pbl_start, pbl_chunk, -1)) {
0315 pr_debug("failed to add PBL chunk (%x/%x)\n",
0316 pbl_start, pbl_chunk);
0317 if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
0318 pr_warn("Failed to add all PBL chunks (%x/%x)\n",
0319 pbl_start, pbl_top - pbl_start);
0320 return 0;
0321 }
0322 pbl_chunk >>= 1;
0323 } else {
0324 pr_debug("added PBL chunk (%x/%x)\n",
0325 pbl_start, pbl_chunk);
0326 pbl_start += pbl_chunk;
0327 }
0328 }
0329
0330 return 0;
0331 }
0332
0333 void c4iw_pblpool_destroy(struct c4iw_rdev *rdev)
0334 {
0335 kref_put(&rdev->pbl_kref, destroy_pblpool);
0336 }
0337
0338
0339
0340
0341
0342 #define MIN_RQT_SHIFT 10
0343
0344 u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
0345 {
0346 unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
0347 pr_debug("addr 0x%x size %d\n", (u32)addr, size << 6);
0348 if (!addr)
0349 pr_warn_ratelimited("%s: Out of RQT memory\n",
0350 pci_name(rdev->lldi.pdev));
0351 mutex_lock(&rdev->stats.lock);
0352 if (addr) {
0353 rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT);
0354 if (rdev->stats.rqt.cur > rdev->stats.rqt.max)
0355 rdev->stats.rqt.max = rdev->stats.rqt.cur;
0356 kref_get(&rdev->rqt_kref);
0357 } else
0358 rdev->stats.rqt.fail++;
0359 mutex_unlock(&rdev->stats.lock);
0360 return (u32)addr;
0361 }
0362
0363 static void destroy_rqtpool(struct kref *kref)
0364 {
0365 struct c4iw_rdev *rdev;
0366
0367 rdev = container_of(kref, struct c4iw_rdev, rqt_kref);
0368 gen_pool_destroy(rdev->rqt_pool);
0369 complete(&rdev->rqt_compl);
0370 }
0371
0372 void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
0373 {
0374 pr_debug("addr 0x%x size %d\n", addr, size << 6);
0375 mutex_lock(&rdev->stats.lock);
0376 rdev->stats.rqt.cur -= roundup(size << 6, 1 << MIN_RQT_SHIFT);
0377 mutex_unlock(&rdev->stats.lock);
0378 gen_pool_free(rdev->rqt_pool, (unsigned long)addr, size << 6);
0379 kref_put(&rdev->rqt_kref, destroy_rqtpool);
0380 }
0381
0382 int c4iw_rqtpool_create(struct c4iw_rdev *rdev)
0383 {
0384 unsigned rqt_start, rqt_chunk, rqt_top;
0385 int skip = 0;
0386
0387 rdev->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1);
0388 if (!rdev->rqt_pool)
0389 return -ENOMEM;
0390
0391
0392
0393
0394
0395 if (rdev->lldi.vr->srq.size)
0396 skip = T4_RQT_ENTRY_SIZE;
0397
0398 rqt_start = rdev->lldi.vr->rq.start + skip;
0399 rqt_chunk = rdev->lldi.vr->rq.size - skip;
0400 rqt_top = rqt_start + rqt_chunk;
0401
0402 while (rqt_start < rqt_top) {
0403 rqt_chunk = min(rqt_top - rqt_start + 1, rqt_chunk);
0404 if (gen_pool_add(rdev->rqt_pool, rqt_start, rqt_chunk, -1)) {
0405 pr_debug("failed to add RQT chunk (%x/%x)\n",
0406 rqt_start, rqt_chunk);
0407 if (rqt_chunk <= 1024 << MIN_RQT_SHIFT) {
0408 pr_warn("Failed to add all RQT chunks (%x/%x)\n",
0409 rqt_start, rqt_top - rqt_start);
0410 return 0;
0411 }
0412 rqt_chunk >>= 1;
0413 } else {
0414 pr_debug("added RQT chunk (%x/%x)\n",
0415 rqt_start, rqt_chunk);
0416 rqt_start += rqt_chunk;
0417 }
0418 }
0419 return 0;
0420 }
0421
0422 void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev)
0423 {
0424 kref_put(&rdev->rqt_kref, destroy_rqtpool);
0425 }
0426
0427 int c4iw_alloc_srq_idx(struct c4iw_rdev *rdev)
0428 {
0429 int idx;
0430
0431 idx = c4iw_id_alloc(&rdev->resource.srq_table);
0432 mutex_lock(&rdev->stats.lock);
0433 if (idx == -1) {
0434 rdev->stats.srqt.fail++;
0435 mutex_unlock(&rdev->stats.lock);
0436 return -ENOMEM;
0437 }
0438 rdev->stats.srqt.cur++;
0439 if (rdev->stats.srqt.cur > rdev->stats.srqt.max)
0440 rdev->stats.srqt.max = rdev->stats.srqt.cur;
0441 mutex_unlock(&rdev->stats.lock);
0442 return idx;
0443 }
0444
0445 void c4iw_free_srq_idx(struct c4iw_rdev *rdev, int idx)
0446 {
0447 c4iw_id_free(&rdev->resource.srq_table, idx);
0448 mutex_lock(&rdev->stats.lock);
0449 rdev->stats.srqt.cur--;
0450 mutex_unlock(&rdev->stats.lock);
0451 }
0452
0453
0454
0455
0456 #define MIN_OCQP_SHIFT 12
0457
0458 u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
0459 {
0460 unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
0461 pr_debug("addr 0x%x size %d\n", (u32)addr, size);
0462 if (addr) {
0463 mutex_lock(&rdev->stats.lock);
0464 rdev->stats.ocqp.cur += roundup(size, 1 << MIN_OCQP_SHIFT);
0465 if (rdev->stats.ocqp.cur > rdev->stats.ocqp.max)
0466 rdev->stats.ocqp.max = rdev->stats.ocqp.cur;
0467 mutex_unlock(&rdev->stats.lock);
0468 }
0469 return (u32)addr;
0470 }
0471
0472 void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
0473 {
0474 pr_debug("addr 0x%x size %d\n", addr, size);
0475 mutex_lock(&rdev->stats.lock);
0476 rdev->stats.ocqp.cur -= roundup(size, 1 << MIN_OCQP_SHIFT);
0477 mutex_unlock(&rdev->stats.lock);
0478 gen_pool_free(rdev->ocqp_pool, (unsigned long)addr, size);
0479 }
0480
0481 int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev)
0482 {
0483 unsigned start, chunk, top;
0484
0485 rdev->ocqp_pool = gen_pool_create(MIN_OCQP_SHIFT, -1);
0486 if (!rdev->ocqp_pool)
0487 return -ENOMEM;
0488
0489 start = rdev->lldi.vr->ocq.start;
0490 chunk = rdev->lldi.vr->ocq.size;
0491 top = start + chunk;
0492
0493 while (start < top) {
0494 chunk = min(top - start + 1, chunk);
0495 if (gen_pool_add(rdev->ocqp_pool, start, chunk, -1)) {
0496 pr_debug("failed to add OCQP chunk (%x/%x)\n",
0497 start, chunk);
0498 if (chunk <= 1024 << MIN_OCQP_SHIFT) {
0499 pr_warn("Failed to add all OCQP chunks (%x/%x)\n",
0500 start, top - start);
0501 return 0;
0502 }
0503 chunk >>= 1;
0504 } else {
0505 pr_debug("added OCQP chunk (%x/%x)\n",
0506 start, chunk);
0507 start += chunk;
0508 }
0509 }
0510 return 0;
0511 }
0512
0513 void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev)
0514 {
0515 gen_pool_destroy(rdev->ocqp_pool);
0516 }