mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-25 21:54:06 +08:00
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: Mike Marciniszyn <mike.marciniszyn@intel.com> Signed-off-by: Mitko Haralanov <mitko.haralanov@intel.com> Signed-off-by: Jubin John <jubin.john@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
parent
e1bf0d5ecd
commit
0840aea98c
@ -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 @@
|
|||||||
*
|
*
|
||||||
* 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 {
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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(¤t->mm->mmap_sem);
|
||||||
struct user_sdma_iovec, list);
|
current->mm->pinned_vm -= unpinned;
|
||||||
list_del_init(&ioptr->list);
|
up_write(¤t->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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
* 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 {
|
|||||||
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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user