/* * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE.
*/ /* Crude resource management */ #include <linux/spinlock.h> #include <linux/genalloc.h> #include <linux/ratelimit.h> #include"iw_cxgb4.h"
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++) if (!(i & rdev->qpmask))
c4iw_id_free(&rdev->resource.qid_table, i); return 0;
}
/* nr_* must be power of 2 */ int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt,
u32 nr_pdid, u32 nr_srqt)
{ int err = 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_table(rdev); if (err) goto qid_err;
err = c4iw_id_table_alloc(&rdev->resource.pdid_table, 0,
nr_pdid, 1, 0); if (err) goto pdid_err; if (!nr_srqt)
err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
1, 1, 0); else
err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
nr_srqt, 0, 0); if (err) goto srq_err; return 0;
srq_err:
c4iw_id_table_free(&rdev->resource.pdid_table);
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 c4iw_id_table *id_table)
{
u32 entry;
entry = c4iw_id_alloc(id_table); if (entry == (u32)(-1)) return 0; return entry;
}
mutex_lock(&uctx->lock); if (!list_empty(&uctx->cqids)) {
entry = list_entry(uctx->cqids.next, struct c4iw_qid_list,
entry);
list_del(&entry->entry);
qid = entry->qid;
kfree(entry);
} else {
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) goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->cqids);
}
/* * now put the same ids on the qp list since they all * map to the same db/gts page.
*/
entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto out;
entry->qid = qid;
list_add_tail(&entry->entry, &uctx->qpids); for (i = qid+1; i & rdev->qpmask; i++) {
entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->qpids);
}
}
out:
mutex_unlock(&uctx->lock);
pr_debug("qid 0x%x\n", 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;
}
mutex_lock(&uctx->lock); if (!list_empty(&uctx->qpids)) {
entry = list_entry(uctx->qpids.next, struct c4iw_qid_list,
entry);
list_del(&entry->entry);
qid = entry->qid;
kfree(entry);
} else {
qid = c4iw_get_resource(&rdev->resource.qid_table); if (!qid) {
mutex_lock(&rdev->stats.lock);
rdev->stats.qid.fail++;
mutex_unlock(&rdev->stats.lock); 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) goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->qpids);
}
/* * now put the same ids on the cq list since they all * map to the same db/gts page.
*/
entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto out;
entry->qid = qid;
list_add_tail(&entry->entry, &uctx->cqids); for (i = qid + 1; i & rdev->qpmask; i++) {
entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->cqids);
}
}
out:
mutex_unlock(&uctx->lock);
pr_debug("qid 0x%x\n", 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;
}
int c4iw_rqtpool_create(struct c4iw_rdev *rdev)
{ unsigned rqt_start, rqt_chunk, rqt_top; int skip = 0;
rdev->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1); if (!rdev->rqt_pool) return -ENOMEM;
/* * If SRQs are supported, then never use the first RQE from * the RQT region. This is because HW uses RQT index 0 as NULL.
*/ if (rdev->lldi.vr->srq.size)
skip = T4_RQT_ENTRY_SIZE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.