Commit 0840aea9 authored by Mitko Haralanov's avatar Mitko Haralanov Committed by Doug Ledford

staging/rdma/hfi1: Improve performance of user SDMA

To facilitate locked page counting, the user SDMA
routines would maintain a list of io vectors, which
were freed in the completion callback and then unpin
the associated pages during the next call into the
kernel.

Since the size of this list was unbounded, doing this
was bad for performance because the driver ended up
spending too much time freeing the io vectors.

This commit changes how the io vector freeing is done
by moving the actual page unpinning in the callback and
maintaining a count of unpinned pages. This count can
then be used during the next call into the kernel to
update the mm->pinned_vm variable (since that requires
process context and the ability to sleep.)
Reviewed-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: default avatarMitko Haralanov <mitko.haralanov@intel.com>
Signed-off-by: default avatarJubin John <jubin.john@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent e1bf0d5e
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* *
* BSD LICENSE * BSD LICENSE
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -236,8 +236,6 @@ struct user_sdma_request { ...@@ -236,8 +236,6 @@ struct user_sdma_request {
u64 seqcomp; u64 seqcomp;
u64 seqsubmitted; u64 seqsubmitted;
struct list_head txps; struct list_head txps;
spinlock_t txcmp_lock; /* protect txcmp list */
struct list_head txcmp;
unsigned long flags; unsigned long flags;
/* status of the last txreq completed */ /* status of the last txreq completed */
int status; int status;
...@@ -381,14 +379,12 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp) ...@@ -381,14 +379,12 @@ int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp)
goto pq_reqs_nomem; goto pq_reqs_nomem;
INIT_LIST_HEAD(&pq->list); INIT_LIST_HEAD(&pq->list);
INIT_LIST_HEAD(&pq->iovec_list);
pq->dd = dd; pq->dd = dd;
pq->ctxt = uctxt->ctxt; pq->ctxt = uctxt->ctxt;
pq->subctxt = fd->subctxt; pq->subctxt = fd->subctxt;
pq->n_max_reqs = hfi1_sdma_comp_ring_size; pq->n_max_reqs = hfi1_sdma_comp_ring_size;
pq->state = SDMA_PKT_Q_INACTIVE; pq->state = SDMA_PKT_Q_INACTIVE;
atomic_set(&pq->n_reqs, 0); atomic_set(&pq->n_reqs, 0);
spin_lock_init(&pq->iovec_lock);
init_waitqueue_head(&pq->wait); init_waitqueue_head(&pq->wait);
iowait_init(&pq->busy, 0, NULL, defer_packet_queue, iowait_init(&pq->busy, 0, NULL, defer_packet_queue,
...@@ -444,7 +440,6 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd) ...@@ -444,7 +440,6 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd)
{ {
struct hfi1_ctxtdata *uctxt = fd->uctxt; struct hfi1_ctxtdata *uctxt = fd->uctxt;
struct hfi1_user_sdma_pkt_q *pq; struct hfi1_user_sdma_pkt_q *pq;
struct user_sdma_iovec *iov;
unsigned long flags; unsigned long flags;
hfi1_cdbg(SDMA, "[%u:%u:%u] Freeing user SDMA queues", uctxt->dd->unit, hfi1_cdbg(SDMA, "[%u:%u:%u] Freeing user SDMA queues", uctxt->dd->unit,
...@@ -460,15 +455,6 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd) ...@@ -460,15 +455,6 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd)
wait_event_interruptible( wait_event_interruptible(
pq->wait, pq->wait,
(ACCESS_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE)); (ACCESS_ONCE(pq->state) == SDMA_PKT_Q_INACTIVE));
/* Unpin any left over buffers. */
while (!list_empty(&pq->iovec_list)) {
spin_lock_irqsave(&pq->iovec_lock, flags);
iov = list_first_entry(&pq->iovec_list,
struct user_sdma_iovec, list);
list_del_init(&iov->list);
spin_unlock_irqrestore(&pq->iovec_lock, flags);
unpin_vector_pages(iov);
}
kfree(pq->reqs); kfree(pq->reqs);
kmem_cache_destroy(pq->txreq_cache); kmem_cache_destroy(pq->txreq_cache);
kfree(pq); kfree(pq);
...@@ -492,11 +478,10 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec, ...@@ -492,11 +478,10 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
struct hfi1_user_sdma_pkt_q *pq = fd->pq; struct hfi1_user_sdma_pkt_q *pq = fd->pq;
struct hfi1_user_sdma_comp_q *cq = fd->cq; struct hfi1_user_sdma_comp_q *cq = fd->cq;
struct hfi1_devdata *dd = pq->dd; struct hfi1_devdata *dd = pq->dd;
unsigned long idx = 0, flags; unsigned long idx = 0, unpinned;
u8 pcount = initial_pkt_count; u8 pcount = initial_pkt_count;
struct sdma_req_info info; struct sdma_req_info info;
struct user_sdma_request *req; struct user_sdma_request *req;
struct user_sdma_iovec *ioptr;
u8 opcode, sc, vl; u8 opcode, sc, vl;
if (iovec[idx].iov_len < sizeof(info) + sizeof(req->hdr)) { if (iovec[idx].iov_len < sizeof(info) + sizeof(req->hdr)) {
...@@ -515,13 +500,11 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec, ...@@ -515,13 +500,11 @@ int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec,
} }
/* Process any completed vectors */ /* Process any completed vectors */
while (!list_empty(&pq->iovec_list)) { unpinned = xchg(&pq->unpinned, 0);
spin_lock_irqsave(&pq->iovec_lock, flags); if (unpinned) {
ioptr = list_first_entry(&pq->iovec_list, down_write(&current->mm->mmap_sem);
struct user_sdma_iovec, list); current->mm->pinned_vm -= unpinned;
list_del_init(&ioptr->list); up_write(&current->mm->mmap_sem);
spin_unlock_irqrestore(&pq->iovec_lock, flags);
unpin_vector_pages(ioptr);
} }
trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, fd->subctxt, trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, fd->subctxt,
...@@ -1075,10 +1058,6 @@ static int pin_vector_pages(struct user_sdma_request *req, ...@@ -1075,10 +1058,6 @@ static int pin_vector_pages(struct user_sdma_request *req,
unpin_vector_pages(iovec); unpin_vector_pages(iovec);
return -EFAULT; return -EFAULT;
} }
/*
* Get a reference to the process's mm so we can use it when
* unpinning the io vectors.
*/
return 0; return 0;
} }
...@@ -1368,7 +1347,7 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status, ...@@ -1368,7 +1347,7 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status,
struct hfi1_user_sdma_pkt_q *pq; struct hfi1_user_sdma_pkt_q *pq;
struct hfi1_user_sdma_comp_q *cq; struct hfi1_user_sdma_comp_q *cq;
u16 idx; u16 idx;
int i; int i, j;
if (!tx->req) if (!tx->req)
return; return;
...@@ -1379,15 +1358,19 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status, ...@@ -1379,15 +1358,19 @@ static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status,
/* /*
* If we have any io vectors associated with this txreq, * If we have any io vectors associated with this txreq,
* check whether they need to be 'freed'. We can't free them * check whether they need to be 'freed'.
* here because the unpin function needs to be able to sleep.
*/ */
for (i = tx->idx; i >= 0; i--) { for (i = tx->idx; i >= 0; i--) {
if (tx->iovecs[i].flags & TXREQ_FLAGS_IOVEC_LAST_PKT) { if (tx->iovecs[i].flags & TXREQ_FLAGS_IOVEC_LAST_PKT) {
spin_lock(&pq->iovec_lock); struct user_sdma_iovec *vec =
list_add_tail(&tx->iovecs[i].vec->list, tx->iovecs[i].vec;
&pq->iovec_list);
spin_unlock(&pq->iovec_lock); for (j = 0; j < vec->npages; j++)
put_page(vec->pages[j]);
xadd(&pq->unpinned, vec->npages);
kfree(vec->pages);
vec->pages = NULL;
vec->npages = 0;
} }
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* *
* BSD LICENSE * BSD LICENSE
* *
* Copyright(c) 2015 Intel Corporation. * Copyright(c) 2015, 2016 Intel Corporation.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -69,8 +69,7 @@ struct hfi1_user_sdma_pkt_q { ...@@ -69,8 +69,7 @@ struct hfi1_user_sdma_pkt_q {
struct iowait busy; struct iowait busy;
unsigned state; unsigned state;
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head iovec_list; unsigned long unpinned;
spinlock_t iovec_lock; /* protect iovec_list */
}; };
struct hfi1_user_sdma_comp_q { struct hfi1_user_sdma_comp_q {
......
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