Commit 87b81670 authored by Roland Dreier's avatar Roland Dreier Committed by Roland Dreier

[PATCH] IB/mthca: Factor out common queue alloc code

Clean up the allocation of memory for queues by factoring out the
common code into mthca_buf_alloc() and mthca_buf_free().  Now CQs and
QPs share the same queue allocation code, which we'll also use for SRQs.
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent f520ba5a
......@@ -177,3 +177,119 @@ void mthca_array_cleanup(struct mthca_array *array, int nent)
kfree(array->page_list);
}
/*
* Handling for queue buffers -- we allocate a bunch of memory and
* register it in a memory region at HCA virtual address 0. If the
* requested size is > max_direct, we split the allocation into
* multiple pages, so we don't require too much contiguous memory.
*/
int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct,
union mthca_buf *buf, int *is_direct, struct mthca_pd *pd,
int hca_write, struct mthca_mr *mr)
{
int err = -ENOMEM;
int npages, shift;
u64 *dma_list = NULL;
dma_addr_t t;
int i;
if (size <= max_direct) {
*is_direct = 1;
npages = 1;
shift = get_order(size) + PAGE_SHIFT;
buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev,
size, &t, GFP_KERNEL);
if (!buf->direct.buf)
return -ENOMEM;
pci_unmap_addr_set(&buf->direct, mapping, t);
memset(buf->direct.buf, 0, size);
while (t & ((1 << shift) - 1)) {
--shift;
npages *= 2;
}
dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
if (!dma_list)
goto err_free;
for (i = 0; i < npages; ++i)
dma_list[i] = t + i * (1 << shift);
} else {
*is_direct = 0;
npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
shift = PAGE_SHIFT;
dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
if (!dma_list)
return -ENOMEM;
buf->page_list = kmalloc(npages * sizeof *buf->page_list,
GFP_KERNEL);
if (!buf->page_list)
goto err_out;
for (i = 0; i < npages; ++i)
buf->page_list[i].buf = NULL;
for (i = 0; i < npages; ++i) {
buf->page_list[i].buf =
dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
&t, GFP_KERNEL);
if (!buf->page_list[i].buf)
goto err_free;
dma_list[i] = t;
pci_unmap_addr_set(&buf->page_list[i], mapping, t);
memset(buf->page_list[i].buf, 0, PAGE_SIZE);
}
}
err = mthca_mr_alloc_phys(dev, pd->pd_num,
dma_list, shift, npages,
0, size,
MTHCA_MPT_FLAG_LOCAL_READ |
(hca_write ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0),
mr);
if (err)
goto err_free;
kfree(dma_list);
return 0;
err_free:
mthca_buf_free(dev, size, buf, *is_direct, NULL);
err_out:
kfree(dma_list);
return err;
}
void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf,
int is_direct, struct mthca_mr *mr)
{
int i;
if (mr)
mthca_free_mr(dev, mr);
if (is_direct)
dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf,
pci_unmap_addr(&buf->direct, mapping));
else {
for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
buf->page_list[i].buf,
pci_unmap_addr(&buf->page_list[i],
mapping));
kfree(buf->page_list);
}
}
......@@ -639,113 +639,8 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
{
int i;
int size;
if (cq->is_direct)
dma_free_coherent(&dev->pdev->dev,
(cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
cq->queue.direct.buf,
pci_unmap_addr(&cq->queue.direct,
mapping));
else {
size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
if (cq->queue.page_list[i].buf)
dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
cq->queue.page_list[i].buf,
pci_unmap_addr(&cq->queue.page_list[i],
mapping));
kfree(cq->queue.page_list);
}
}
static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
struct mthca_cq *cq)
{
int err = -ENOMEM;
int npages, shift;
u64 *dma_list = NULL;
dma_addr_t t;
int i;
if (size <= MTHCA_MAX_DIRECT_CQ_SIZE) {
cq->is_direct = 1;
npages = 1;
shift = get_order(size) + PAGE_SHIFT;
cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
size, &t, GFP_KERNEL);
if (!cq->queue.direct.buf)
return -ENOMEM;
pci_unmap_addr_set(&cq->queue.direct, mapping, t);
memset(cq->queue.direct.buf, 0, size);
while (t & ((1 << shift) - 1)) {
--shift;
npages *= 2;
}
dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
if (!dma_list)
goto err_free;
for (i = 0; i < npages; ++i)
dma_list[i] = t + i * (1 << shift);
} else {
cq->is_direct = 0;
npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
shift = PAGE_SHIFT;
dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
if (!dma_list)
return -ENOMEM;
cq->queue.page_list = kmalloc(npages * sizeof *cq->queue.page_list,
GFP_KERNEL);
if (!cq->queue.page_list)
goto err_out;
for (i = 0; i < npages; ++i)
cq->queue.page_list[i].buf = NULL;
for (i = 0; i < npages; ++i) {
cq->queue.page_list[i].buf =
dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
&t, GFP_KERNEL);
if (!cq->queue.page_list[i].buf)
goto err_free;
dma_list[i] = t;
pci_unmap_addr_set(&cq->queue.page_list[i], mapping, t);
memset(cq->queue.page_list[i].buf, 0, PAGE_SIZE);
}
}
err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
dma_list, shift, npages,
0, size,
MTHCA_MPT_FLAG_LOCAL_WRITE |
MTHCA_MPT_FLAG_LOCAL_READ,
&cq->mr);
if (err)
goto err_free;
kfree(dma_list);
return 0;
err_free:
mthca_free_cq_buf(dev, cq);
err_out:
kfree(dma_list);
return err;
mthca_buf_free(dev, (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
&cq->queue, cq->is_direct, &cq->mr);
}
int mthca_init_cq(struct mthca_dev *dev, int nent,
......@@ -797,7 +692,9 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq_context = mailbox->buf;
if (cq->is_kernel) {
err = mthca_alloc_cq_buf(dev, size, cq);
err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_CQ_SIZE,
&cq->queue, &cq->is_direct,
&dev->driver_pd, 1, &cq->mr);
if (err)
goto err_out_mailbox;
......@@ -858,10 +755,8 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
return 0;
err_out_free_mr:
if (cq->is_kernel) {
mthca_free_mr(dev, &cq->mr);
if (cq->is_kernel)
mthca_free_cq_buf(dev, cq);
}
err_out_mailbox:
mthca_free_mailbox(dev, mailbox);
......@@ -929,7 +824,6 @@ void mthca_free_cq(struct mthca_dev *dev,
wait_event(cq->wait, !atomic_read(&cq->refcount));
if (cq->is_kernel) {
mthca_free_mr(dev, &cq->mr);
mthca_free_cq_buf(dev, cq);
if (mthca_is_memfree(dev)) {
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
......
......@@ -361,6 +361,11 @@ int mthca_array_set(struct mthca_array *array, int index, void *value);
void mthca_array_clear(struct mthca_array *array, int index);
int mthca_array_init(struct mthca_array *array, int nent);
void mthca_array_cleanup(struct mthca_array *array, int nent);
int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct,
union mthca_buf *buf, int *is_direct, struct mthca_pd *pd,
int hca_write, struct mthca_mr *mr);
void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf,
int is_direct, struct mthca_mr *mr);
int mthca_init_uar_table(struct mthca_dev *dev);
int mthca_init_pd_table(struct mthca_dev *dev);
......
......@@ -51,6 +51,11 @@ struct mthca_buf_list {
DECLARE_PCI_UNMAP_ADDR(mapping)
};
union mthca_buf {
struct mthca_buf_list direct;
struct mthca_buf_list *page_list;
};
struct mthca_uar {
unsigned long pfn;
int index;
......@@ -187,10 +192,7 @@ struct mthca_cq {
__be32 *arm_db;
int arm_sn;
union {
struct mthca_buf_list direct;
struct mthca_buf_list *page_list;
} queue;
union mthca_buf queue;
struct mthca_mr mr;
wait_queue_head_t wait;
};
......@@ -228,10 +230,7 @@ struct mthca_qp {
int send_wqe_offset;
u64 *wrid;
union {
struct mthca_buf_list direct;
struct mthca_buf_list *page_list;
} queue;
union mthca_buf queue;
wait_queue_head_t wait;
};
......
......@@ -926,10 +926,6 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
struct mthca_qp *qp)
{
int size;
int i;
int npages, shift;
dma_addr_t t;
u64 *dma_list = NULL;
int err = -ENOMEM;
size = sizeof (struct mthca_next_seg) +
......@@ -979,116 +975,24 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
if (!qp->wrid)
goto err_out;
if (size <= MTHCA_MAX_DIRECT_QP_SIZE) {
qp->is_direct = 1;
npages = 1;
shift = get_order(size) + PAGE_SHIFT;
if (0)
mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
size, shift);
qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
&t, GFP_KERNEL);
if (!qp->queue.direct.buf)
goto err_out;
pci_unmap_addr_set(&qp->queue.direct, mapping, t);
memset(qp->queue.direct.buf, 0, size);
while (t & ((1 << shift) - 1)) {
--shift;
npages *= 2;
}
dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
if (!dma_list)
goto err_out_free;
for (i = 0; i < npages; ++i)
dma_list[i] = t + i * (1 << shift);
} else {
qp->is_direct = 0;
npages = size / PAGE_SIZE;
shift = PAGE_SHIFT;
if (0)
mthca_dbg(dev, "Creating indirect QP with %d pages\n", npages);
dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
if (!dma_list)
goto err_out;
qp->queue.page_list = kmalloc(npages *
sizeof *qp->queue.page_list,
GFP_KERNEL);
if (!qp->queue.page_list)
goto err_out;
for (i = 0; i < npages; ++i) {
qp->queue.page_list[i].buf =
dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
&t, GFP_KERNEL);
if (!qp->queue.page_list[i].buf)
goto err_out_free;
memset(qp->queue.page_list[i].buf, 0, PAGE_SIZE);
pci_unmap_addr_set(&qp->queue.page_list[i], mapping, t);
dma_list[i] = t;
}
}
err = mthca_mr_alloc_phys(dev, pd->pd_num, dma_list, shift,
npages, 0, size,
MTHCA_MPT_FLAG_LOCAL_READ,
&qp->mr);
err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_QP_SIZE,
&qp->queue, &qp->is_direct, pd, 0, &qp->mr);
if (err)
goto err_out_free;
goto err_out;
kfree(dma_list);
return 0;
err_out_free:
if (qp->is_direct) {
dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
pci_unmap_addr(&qp->queue.direct, mapping));
} else
for (i = 0; i < npages; ++i) {
if (qp->queue.page_list[i].buf)
dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
qp->queue.page_list[i].buf,
pci_unmap_addr(&qp->queue.page_list[i],
mapping));
}
err_out:
err_out:
kfree(qp->wrid);
kfree(dma_list);
return err;
}
static void mthca_free_wqe_buf(struct mthca_dev *dev,
struct mthca_qp *qp)
{
int i;
int size = PAGE_ALIGN(qp->send_wqe_offset +
(qp->sq.max << qp->sq.wqe_shift));
if (qp->is_direct) {
dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
pci_unmap_addr(&qp->queue.direct, mapping));
} else {
for (i = 0; i < size / PAGE_SIZE; ++i) {
dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
qp->queue.page_list[i].buf,
pci_unmap_addr(&qp->queue.page_list[i],
mapping));
}
}
mthca_buf_free(dev, PAGE_ALIGN(qp->send_wqe_offset +
(qp->sq.max << qp->sq.wqe_shift)),
&qp->queue, qp->is_direct, &qp->mr);
kfree(qp->wrid);
}
......@@ -1433,7 +1337,6 @@ void mthca_free_qp(struct mthca_dev *dev,
if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
mthca_free_mr(dev, &qp->mr);
mthca_free_memfree(dev, qp);
mthca_free_wqe_buf(dev, qp);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment