2014-12-11 17:04:17 +02:00
/*
* Copyright ( c ) 2014 Mellanox Technologies . 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 .
*/
# include <linux/types.h>
# include <linux/sched.h>
2017-02-08 18:51:29 +01:00
# include <linux/sched/mm.h>
2017-02-05 15:30:50 +01:00
# include <linux/sched/task.h>
2014-12-11 17:04:17 +02:00
# include <linux/pid.h>
# include <linux/slab.h>
# include <linux/export.h>
# include <linux/vmalloc.h>
2017-04-05 09:23:57 +03:00
# include <linux/hugetlb.h>
2019-08-19 14:16:59 +03:00
# include <linux/interval_tree.h>
2019-03-04 11:46:45 -08:00
# include <linux/pagemap.h>
2014-12-11 17:04:17 +02:00
# include <rdma/ib_verbs.h>
# include <rdma/ib_umem.h>
# include <rdma/ib_umem_odp.h>
2019-08-19 14:17:03 +03:00
# include "uverbs.h"
2019-11-12 16:22:22 -04:00
static inline int ib_init_umem_odp ( struct ib_umem_odp * umem_odp ,
const struct mmu_interval_notifier_ops * ops )
2014-12-11 17:04:18 +02:00
{
2019-08-19 14:17:02 +03:00
int ret ;
umem_odp - > umem . is_odp = 1 ;
2019-11-12 16:22:22 -04:00
mutex_init ( & umem_odp - > umem_mutex ) ;
2019-08-19 14:17:02 +03:00
if ( ! umem_odp - > is_implicit_odp ) {
2019-08-19 14:17:06 +03:00
size_t page_size = 1UL < < umem_odp - > page_shift ;
2019-11-12 16:22:22 -04:00
unsigned long start ;
unsigned long end ;
2019-08-19 14:17:06 +03:00
size_t pages ;
2019-11-12 16:22:22 -04:00
start = ALIGN_DOWN ( umem_odp - > umem . address , page_size ) ;
2019-08-19 14:17:06 +03:00
if ( check_add_overflow ( umem_odp - > umem . address ,
2019-09-08 11:07:26 +03:00
( unsigned long ) umem_odp - > umem . length ,
2019-11-12 16:22:22 -04:00
& end ) )
2019-08-19 14:17:06 +03:00
return - EOVERFLOW ;
2019-11-12 16:22:22 -04:00
end = ALIGN ( end , page_size ) ;
if ( unlikely ( end < page_size ) )
2019-08-19 14:17:06 +03:00
return - EOVERFLOW ;
2019-11-12 16:22:22 -04:00
pages = ( end - start ) > > umem_odp - > page_shift ;
2019-08-19 14:17:02 +03:00
if ( ! pages )
return - EINVAL ;
2019-08-19 14:17:07 +03:00
umem_odp - > page_list = kvcalloc (
pages , sizeof ( * umem_odp - > page_list ) , GFP_KERNEL ) ;
2019-08-19 14:17:02 +03:00
if ( ! umem_odp - > page_list )
return - ENOMEM ;
2019-08-19 14:17:07 +03:00
umem_odp - > dma_list = kvcalloc (
pages , sizeof ( * umem_odp - > dma_list ) , GFP_KERNEL ) ;
2019-08-19 14:17:02 +03:00
if ( ! umem_odp - > dma_list ) {
ret = - ENOMEM ;
goto out_page_list ;
}
2019-11-12 16:22:22 -04:00
ret = mmu_interval_notifier_insert ( & umem_odp - > notifier ,
umem_odp - > umem . owning_mm ,
start , end - start , ops ) ;
if ( ret )
goto out_dma_list ;
2019-08-19 14:17:02 +03:00
}
return 0 ;
2019-08-06 20:15:43 -03:00
out_dma_list :
2019-08-19 14:17:07 +03:00
kvfree ( umem_odp - > dma_list ) ;
2019-08-19 14:17:02 +03:00
out_page_list :
2019-08-19 14:17:07 +03:00
kvfree ( umem_odp - > page_list ) ;
2019-08-19 14:17:02 +03:00
return ret ;
}
2019-08-19 14:17:03 +03:00
/**
* ib_umem_odp_alloc_implicit - Allocate a parent implicit ODP umem
*
* Implicit ODP umems do not have a VA range and do not have any page lists .
* They exist only to hold the per_mm reference to help the driver create
* children umems .
*
2020-01-15 14:43:31 +02:00
* @ device : IB device to create UMEM
2019-08-19 14:17:03 +03:00
* @ access : ib_reg_mr access flags
*/
2020-01-15 14:43:31 +02:00
struct ib_umem_odp * ib_umem_odp_alloc_implicit ( struct ib_device * device ,
2019-08-19 14:17:03 +03:00
int access )
{
struct ib_umem * umem ;
struct ib_umem_odp * umem_odp ;
int ret ;
if ( access & IB_ACCESS_HUGETLB )
return ERR_PTR ( - EINVAL ) ;
umem_odp = kzalloc ( sizeof ( * umem_odp ) , GFP_KERNEL ) ;
if ( ! umem_odp )
return ERR_PTR ( - ENOMEM ) ;
umem = & umem_odp - > umem ;
2020-01-15 14:43:31 +02:00
umem - > ibdev = device ;
2019-08-19 14:17:03 +03:00
umem - > writable = ib_access_writable ( access ) ;
umem - > owning_mm = current - > mm ;
umem_odp - > is_implicit_odp = 1 ;
umem_odp - > page_shift = PAGE_SHIFT ;
2019-11-12 16:22:22 -04:00
umem_odp - > tgid = get_task_pid ( current - > group_leader , PIDTYPE_PID ) ;
ret = ib_init_umem_odp ( umem_odp , NULL ) ;
2019-08-19 14:17:03 +03:00
if ( ret ) {
2019-11-12 16:22:22 -04:00
put_pid ( umem_odp - > tgid ) ;
2019-08-19 14:17:03 +03:00
kfree ( umem_odp ) ;
return ERR_PTR ( ret ) ;
}
return umem_odp ;
}
EXPORT_SYMBOL ( ib_umem_odp_alloc_implicit ) ;
/**
* ib_umem_odp_alloc_child - Allocate a child ODP umem under an implicit
* parent ODP umem
*
* @ root : The parent umem enclosing the child . This must be allocated using
* ib_alloc_implicit_odp_umem ( )
* @ addr : The starting userspace VA
* @ size : The length of the userspace VA
*/
2019-11-12 16:22:22 -04:00
struct ib_umem_odp *
ib_umem_odp_alloc_child ( struct ib_umem_odp * root , unsigned long addr ,
size_t size ,
const struct mmu_interval_notifier_ops * ops )
2018-09-16 20:48:08 +03:00
{
2019-08-19 14:17:02 +03:00
/*
* Caller must ensure that root cannot be freed during the call to
* ib_alloc_odp_umem .
*/
2017-01-18 16:58:07 +02:00
struct ib_umem_odp * odp_data ;
2018-09-16 20:48:05 +03:00
struct ib_umem * umem ;
2017-01-18 16:58:07 +02:00
int ret ;
2019-08-19 14:17:03 +03:00
if ( WARN_ON ( ! root - > is_implicit_odp ) )
return ERR_PTR ( - EINVAL ) ;
2018-09-16 20:48:05 +03:00
odp_data = kzalloc ( sizeof ( * odp_data ) , GFP_KERNEL ) ;
if ( ! odp_data )
2017-01-18 16:58:07 +02:00
return ERR_PTR ( - ENOMEM ) ;
2018-09-16 20:48:05 +03:00
umem = & odp_data - > umem ;
2019-08-06 20:15:44 -03:00
umem - > ibdev = root - > umem . ibdev ;
2017-04-05 09:23:50 +03:00
umem - > length = size ;
umem - > address = addr ;
2019-01-22 09:16:08 +02:00
umem - > writable = root - > umem . writable ;
2019-08-19 14:17:02 +03:00
umem - > owning_mm = root - > umem . owning_mm ;
odp_data - > page_shift = PAGE_SHIFT ;
2019-11-12 16:22:22 -04:00
odp_data - > notifier . ops = ops ;
2017-01-18 16:58:07 +02:00
2020-02-27 13:41:18 +02:00
/*
* A mmget must be held when registering a notifier , the owming_mm only
* has a mm_grab at this point .
*/
if ( ! mmget_not_zero ( umem - > owning_mm ) ) {
ret = - EFAULT ;
goto out_free ;
}
2019-11-12 16:22:22 -04:00
odp_data - > tgid = get_pid ( root - > tgid ) ;
ret = ib_init_umem_odp ( odp_data , ops ) ;
2020-02-27 13:41:18 +02:00
if ( ret )
goto out_tgid ;
mmput ( umem - > owning_mm ) ;
2018-09-16 20:48:04 +03:00
return odp_data ;
2020-02-27 13:41:18 +02:00
out_tgid :
put_pid ( odp_data - > tgid ) ;
mmput ( umem - > owning_mm ) ;
out_free :
kfree ( odp_data ) ;
return ERR_PTR ( ret ) ;
2017-01-18 16:58:07 +02:00
}
2019-08-19 14:17:03 +03:00
EXPORT_SYMBOL ( ib_umem_odp_alloc_child ) ;
2017-01-18 16:58:07 +02:00
2019-08-19 14:17:03 +03:00
/**
2019-08-19 14:17:04 +03:00
* ib_umem_odp_get - Create a umem_odp for a userspace va
2019-08-19 14:17:03 +03:00
*
2020-01-15 14:43:31 +02:00
* @ device : IB device struct to get UMEM
2019-08-19 14:17:04 +03:00
* @ addr : userspace virtual address to start at
* @ size : length of region to pin
* @ access : IB_ACCESS_xxx flags for memory being pinned
*
* The driver should use when the access flags indicate ODP memory . It avoids
* pinning , instead , stores the mm for future page fault handling in
* conjunction with MMU notifiers .
2019-08-19 14:17:03 +03:00
*/
2020-01-15 14:43:31 +02:00
struct ib_umem_odp * ib_umem_odp_get ( struct ib_device * device ,
unsigned long addr , size_t size , int access ,
2019-11-12 16:22:22 -04:00
const struct mmu_interval_notifier_ops * ops )
2014-12-11 17:04:17 +02:00
{
2019-08-19 14:17:04 +03:00
struct ib_umem_odp * umem_odp ;
struct mm_struct * mm ;
int ret ;
2019-11-12 16:22:22 -04:00
if ( WARN_ON_ONCE ( ! ( access & IB_ACCESS_ON_DEMAND ) ) )
2019-08-19 14:17:04 +03:00
return ERR_PTR ( - EINVAL ) ;
umem_odp = kzalloc ( sizeof ( struct ib_umem_odp ) , GFP_KERNEL ) ;
if ( ! umem_odp )
return ERR_PTR ( - ENOMEM ) ;
2020-01-15 14:43:31 +02:00
umem_odp - > umem . ibdev = device ;
2019-08-19 14:17:04 +03:00
umem_odp - > umem . length = size ;
umem_odp - > umem . address = addr ;
umem_odp - > umem . writable = ib_access_writable ( access ) ;
umem_odp - > umem . owning_mm = mm = current - > mm ;
2019-11-12 16:22:22 -04:00
umem_odp - > notifier . ops = ops ;
2014-12-11 17:04:17 +02:00
2019-05-20 09:05:25 +03:00
umem_odp - > page_shift = PAGE_SHIFT ;
2020-01-09 09:47:30 +01:00
# ifdef CONFIG_HUGETLB_PAGE
2019-12-22 14:46:49 +02:00
if ( access & IB_ACCESS_HUGETLB )
umem_odp - > page_shift = HPAGE_SHIFT ;
2020-01-09 09:47:30 +01:00
# endif
2017-04-05 09:23:57 +03:00
2019-11-12 16:22:22 -04:00
umem_odp - > tgid = get_task_pid ( current - > group_leader , PIDTYPE_PID ) ;
ret = ib_init_umem_odp ( umem_odp , ops ) ;
2019-08-19 14:17:04 +03:00
if ( ret )
2019-11-12 16:22:22 -04:00
goto err_put_pid ;
2019-08-19 14:17:04 +03:00
return umem_odp ;
2019-11-12 16:22:22 -04:00
err_put_pid :
put_pid ( umem_odp - > tgid ) ;
2019-08-19 14:17:04 +03:00
kfree ( umem_odp ) ;
return ERR_PTR ( ret ) ;
2014-12-11 17:04:17 +02:00
}
2019-08-19 14:17:04 +03:00
EXPORT_SYMBOL ( ib_umem_odp_get ) ;
2014-12-11 17:04:17 +02:00
2018-09-16 20:48:04 +03:00
void ib_umem_odp_release ( struct ib_umem_odp * umem_odp )
2014-12-11 17:04:17 +02:00
{
/*
* Ensure that no more pages are mapped in the umem .
*
* It is the driver ' s responsibility to ensure , before calling us ,
* that the hardware will not attempt to access the MR any more .
*/
2019-08-19 14:17:01 +03:00
if ( ! umem_odp - > is_implicit_odp ) {
2019-10-01 12:38:18 -03:00
mutex_lock ( & umem_odp - > umem_mutex ) ;
2019-08-19 14:17:01 +03:00
ib_umem_odp_unmap_dma_pages ( umem_odp , ib_umem_start ( umem_odp ) ,
ib_umem_end ( umem_odp ) ) ;
2019-10-01 12:38:18 -03:00
mutex_unlock ( & umem_odp - > umem_mutex ) ;
2019-11-12 16:22:22 -04:00
mmu_interval_notifier_remove ( & umem_odp - > notifier ) ;
2019-08-19 14:17:07 +03:00
kvfree ( umem_odp - > dma_list ) ;
kvfree ( umem_odp - > page_list ) ;
2019-11-12 16:22:22 -04:00
put_pid ( umem_odp - > tgid ) ;
2019-08-19 14:17:01 +03:00
}
2019-08-19 14:17:05 +03:00
kfree ( umem_odp ) ;
2014-12-11 17:04:17 +02:00
}
2019-08-19 14:17:05 +03:00
EXPORT_SYMBOL ( ib_umem_odp_release ) ;
2014-12-11 17:04:17 +02:00
/*
* Map for DMA and insert a single page into the on - demand paging page tables .
*
* @ umem : the umem to insert the page to .
* @ page_index : index in the umem to add the page to .
* @ page : the page struct to map and add .
* @ access_mask : access permissions needed for this page .
* @ current_seq : sequence number for synchronization with invalidations .
* the sequence number is taken from
2018-09-16 20:48:04 +03:00
* umem_odp - > notifiers_seq .
2014-12-11 17:04:17 +02:00
*
2014-12-11 17:04:18 +02:00
* The function returns - EFAULT if the DMA mapping operation fails . It returns
* - EAGAIN if a concurrent invalidation prevents us from updating the page .
2014-12-11 17:04:17 +02:00
*
2020-01-30 22:13:02 -08:00
* The page is released via put_page even if the operation failed . For on - demand
* pinning , the page is released whenever it isn ' t stored in the umem .
2014-12-11 17:04:17 +02:00
*/
static int ib_umem_odp_map_dma_single_page (
2018-09-16 20:48:04 +03:00
struct ib_umem_odp * umem_odp ,
2019-11-12 16:22:22 -04:00
unsigned int page_index ,
2014-12-11 17:04:17 +02:00
struct page * page ,
u64 access_mask ,
unsigned long current_seq )
{
2019-08-06 20:15:44 -03:00
struct ib_device * dev = umem_odp - > umem . ibdev ;
2014-12-11 17:04:17 +02:00
dma_addr_t dma_addr ;
int ret = 0 ;
2019-11-12 16:22:22 -04:00
if ( mmu_interval_check_retry ( & umem_odp - > notifier , current_seq ) ) {
2014-12-11 17:04:18 +02:00
ret = - EAGAIN ;
goto out ;
}
2018-09-16 20:48:04 +03:00
if ( ! ( umem_odp - > dma_list [ page_index ] ) ) {
2019-05-20 09:05:25 +03:00
dma_addr =
ib_dma_map_page ( dev , page , 0 , BIT ( umem_odp - > page_shift ) ,
DMA_BIDIRECTIONAL ) ;
2014-12-11 17:04:17 +02:00
if ( ib_dma_mapping_error ( dev , dma_addr ) ) {
ret = - EFAULT ;
goto out ;
}
2018-09-16 20:48:04 +03:00
umem_odp - > dma_list [ page_index ] = dma_addr | access_mask ;
umem_odp - > page_list [ page_index ] = page ;
2019-04-02 14:52:52 -05:00
umem_odp - > npages + + ;
2018-09-16 20:48:04 +03:00
} else if ( umem_odp - > page_list [ page_index ] = = page ) {
umem_odp - > dma_list [ page_index ] | = access_mask ;
2014-12-11 17:04:17 +02:00
} else {
2019-10-09 13:09:35 -03:00
/*
* This is a race here where we could have done :
*
* CPU0 CPU1
* get_user_pages ( )
* invalidate ( )
* page_fault ( )
* mutex_lock ( umem_mutex )
* page from GUP ! = page in ODP
*
* It should be prevented by the retry test above as reading
* the seq number should be reliable under the
* umem_mutex . Thus something is really not working right if
* things get here .
*/
WARN ( true ,
" Got different pages in IB device and from get_user_pages. IB device page: %p, gup page: %p \n " ,
umem_odp - > page_list [ page_index ] , page ) ;
ret = - EAGAIN ;
2014-12-11 17:04:17 +02:00
}
out :
2020-01-30 22:13:02 -08:00
put_page ( page ) ;
2014-12-11 17:04:17 +02:00
return ret ;
}
/**
* ib_umem_odp_map_dma_pages - Pin and DMA map userspace memory in an ODP MR .
*
* Pins the range of pages passed in the argument , and maps them to
* DMA addresses . The DMA addresses of the mapped pages is updated in
2018-09-16 20:48:04 +03:00
* umem_odp - > dma_list .
2014-12-11 17:04:17 +02:00
*
* Returns the number of pages mapped in success , negative error code
* for failure .
2014-12-11 17:04:18 +02:00
* An - EAGAIN error code is returned when a concurrent mmu notifier prevents
* the function from completing its task .
2017-01-18 16:58:08 +02:00
* An - ENOENT error code indicates that userspace process is being terminated
* and mm was already destroyed .
2018-09-16 20:48:04 +03:00
* @ umem_odp : the umem to map and pin
2014-12-11 17:04:17 +02:00
* @ user_virt : the address from which we need to map .
* @ bcnt : the minimal number of bytes to pin and map . The mapping might be
* bigger due to alignment , and may also be smaller in case of an error
* pinning or mapping a page . The actual pages mapped is returned in
* the return value .
* @ access_mask : bit mask of the requested access permissions for the given
* range .
* @ current_seq : the MMU notifiers sequance value for synchronization with
* invalidations . the sequance number is read from
2018-09-16 20:48:04 +03:00
* umem_odp - > notifiers_seq before calling this function
2014-12-11 17:04:17 +02:00
*/
2018-09-16 20:48:04 +03:00
int ib_umem_odp_map_dma_pages ( struct ib_umem_odp * umem_odp , u64 user_virt ,
u64 bcnt , u64 access_mask ,
unsigned long current_seq )
2014-12-11 17:04:17 +02:00
{
struct task_struct * owning_process = NULL ;
2018-09-16 20:48:08 +03:00
struct mm_struct * owning_mm = umem_odp - > umem . owning_mm ;
2014-12-11 17:04:17 +02:00
struct page * * local_page_list = NULL ;
2017-04-05 09:23:55 +03:00
u64 page_mask , off ;
2019-05-20 09:05:25 +03:00
int j , k , ret = 0 , start_idx , npages = 0 ;
unsigned int flags = 0 , page_shift ;
2017-04-05 09:23:55 +03:00
phys_addr_t p = 0 ;
2014-12-11 17:04:17 +02:00
if ( access_mask = = 0 )
return - EINVAL ;
2019-05-20 09:05:25 +03:00
if ( user_virt < ib_umem_start ( umem_odp ) | |
user_virt + bcnt > ib_umem_end ( umem_odp ) )
2014-12-11 17:04:17 +02:00
return - EFAULT ;
local_page_list = ( struct page * * ) __get_free_page ( GFP_KERNEL ) ;
if ( ! local_page_list )
return - ENOMEM ;
2019-05-20 09:05:25 +03:00
page_shift = umem_odp - > page_shift ;
2017-04-05 09:23:55 +03:00
page_mask = ~ ( BIT ( page_shift ) - 1 ) ;
off = user_virt & ( ~ page_mask ) ;
user_virt = user_virt & page_mask ;
2014-12-11 17:04:17 +02:00
bcnt + = off ; /* Charge for the first page offset as well. */
2018-09-16 20:48:08 +03:00
/*
* owning_process is allowed to be NULL , this means somehow the mm is
* existing beyond the lifetime of the originating process . . Presumably
* mmget_not_zero will fail in this case .
*/
2019-11-12 16:22:22 -04:00
owning_process = get_pid_task ( umem_odp - > tgid , PIDTYPE_PID ) ;
2019-02-17 16:08:24 +02:00
if ( ! owning_process | | ! mmget_not_zero ( owning_mm ) ) {
2014-12-11 17:04:17 +02:00
ret = - EINVAL ;
goto out_put_task ;
}
2016-10-13 01:20:17 +01:00
if ( access_mask & ODP_WRITE_ALLOWED_BIT )
flags | = FOLL_WRITE ;
2019-05-20 09:05:25 +03:00
start_idx = ( user_virt - ib_umem_start ( umem_odp ) ) > > page_shift ;
2014-12-11 17:04:17 +02:00
k = start_idx ;
while ( bcnt > 0 ) {
2017-04-05 09:23:55 +03:00
const size_t gup_num_pages = min_t ( size_t ,
2019-12-22 14:46:48 +02:00
ALIGN ( bcnt , PAGE_SIZE ) / PAGE_SIZE ,
2017-04-05 09:23:55 +03:00
PAGE_SIZE / sizeof ( struct page * ) ) ;
2014-12-11 17:04:17 +02:00
down_read ( & owning_mm - > mmap_sem ) ;
/*
* Note : this might result in redundent page getting . We can
* avoid this by checking dma_list to be 0 before calling
* get_user_pages . However , this make the code much more
* complex ( and doesn ' t gain us much performance in most use
* cases ) .
*/
2016-02-12 13:01:54 -08:00
npages = get_user_pages_remote ( owning_process , owning_mm ,
user_virt , gup_num_pages ,
2016-12-14 15:06:52 -08:00
flags , local_page_list , NULL , NULL ) ;
2014-12-11 17:04:17 +02:00
up_read ( & owning_mm - > mmap_sem ) ;
2018-11-08 21:10:17 +02:00
if ( npages < 0 ) {
if ( npages ! = - EAGAIN )
pr_warn ( " fail to get %zu user pages with error %d \n " , gup_num_pages , npages ) ;
else
pr_debug ( " fail to get %zu user pages with error %d \n " , gup_num_pages , npages ) ;
2014-12-11 17:04:17 +02:00
break ;
2018-11-08 21:10:17 +02:00
}
2014-12-11 17:04:17 +02:00
bcnt - = min_t ( size_t , npages < < PAGE_SHIFT , bcnt ) ;
2018-09-16 20:48:04 +03:00
mutex_lock ( & umem_odp - > umem_mutex ) ;
2017-04-05 09:23:55 +03:00
for ( j = 0 ; j < npages ; j + + , user_virt + = PAGE_SIZE ) {
if ( user_virt & ~ page_mask ) {
p + = PAGE_SIZE ;
if ( page_to_phys ( local_page_list [ j ] ) ! = p ) {
ret = - EFAULT ;
break ;
}
2020-01-30 22:13:02 -08:00
put_page ( local_page_list [ j ] ) ;
2017-04-05 09:23:55 +03:00
continue ;
}
2014-12-11 17:04:17 +02:00
ret = ib_umem_odp_map_dma_single_page (
2018-09-16 20:48:04 +03:00
umem_odp , k , local_page_list [ j ] ,
2017-04-05 09:23:55 +03:00
access_mask , current_seq ) ;
2018-11-08 21:10:17 +02:00
if ( ret < 0 ) {
if ( ret ! = - EAGAIN )
pr_warn ( " ib_umem_odp_map_dma_single_page failed with error %d \n " , ret ) ;
else
pr_debug ( " ib_umem_odp_map_dma_single_page failed with error %d \n " , ret ) ;
2014-12-11 17:04:17 +02:00
break ;
2018-11-08 21:10:17 +02:00
}
2017-04-05 09:23:55 +03:00
p = page_to_phys ( local_page_list [ j ] ) ;
2014-12-11 17:04:17 +02:00
k + + ;
}
2018-09-16 20:48:04 +03:00
mutex_unlock ( & umem_odp - > umem_mutex ) ;
2014-12-11 17:04:17 +02:00
if ( ret < 0 ) {
2019-03-04 11:46:45 -08:00
/*
2019-03-05 18:00:22 -08:00
* Release pages , remembering that the first page
* to hit an error was already released by
* ib_umem_odp_map_dma_single_page ( ) .
2019-03-04 11:46:45 -08:00
*/
2019-03-05 18:00:22 -08:00
if ( npages - ( j + 1 ) > 0 )
2020-01-30 22:13:02 -08:00
release_pages ( & local_page_list [ j + 1 ] ,
npages - ( j + 1 ) ) ;
2014-12-11 17:04:17 +02:00
break ;
}
}
if ( ret > = 0 ) {
if ( npages < 0 & & k = = start_idx )
ret = npages ;
else
ret = k - start_idx ;
}
mmput ( owning_mm ) ;
out_put_task :
2018-09-16 20:48:08 +03:00
if ( owning_process )
put_task_struct ( owning_process ) ;
2014-12-11 17:04:17 +02:00
free_page ( ( unsigned long ) local_page_list ) ;
return ret ;
}
EXPORT_SYMBOL ( ib_umem_odp_map_dma_pages ) ;
2018-09-16 20:48:04 +03:00
void ib_umem_odp_unmap_dma_pages ( struct ib_umem_odp * umem_odp , u64 virt ,
2014-12-11 17:04:17 +02:00
u64 bound )
{
int idx ;
u64 addr ;
2019-08-06 20:15:44 -03:00
struct ib_device * dev = umem_odp - > umem . ibdev ;
2014-12-11 17:04:17 +02:00
2019-10-01 12:38:18 -03:00
lockdep_assert_held ( & umem_odp - > umem_mutex ) ;
2019-05-20 09:05:25 +03:00
virt = max_t ( u64 , virt , ib_umem_start ( umem_odp ) ) ;
bound = min_t ( u64 , bound , ib_umem_end ( umem_odp ) ) ;
2014-12-11 17:04:18 +02:00
/* Note that during the run of this function, the
* notifiers_count of the MR is > 0 , preventing any racing
* faults from completion . We might be racing with other
* invalidations , so we must make sure we free each page only
* once . */
2019-05-20 09:05:25 +03:00
for ( addr = virt ; addr < bound ; addr + = BIT ( umem_odp - > page_shift ) ) {
idx = ( addr - ib_umem_start ( umem_odp ) ) > > umem_odp - > page_shift ;
2018-09-16 20:48:04 +03:00
if ( umem_odp - > page_list [ idx ] ) {
struct page * page = umem_odp - > page_list [ idx ] ;
dma_addr_t dma = umem_odp - > dma_list [ idx ] ;
2014-12-11 17:04:17 +02:00
dma_addr_t dma_addr = dma & ODP_DMA_ADDR_MASK ;
WARN_ON ( ! dma_addr ) ;
2019-06-13 21:46:45 -03:00
ib_dma_unmap_page ( dev , dma_addr ,
BIT ( umem_odp - > page_shift ) ,
2014-12-11 17:04:17 +02:00
DMA_BIDIRECTIONAL ) ;
2015-04-15 18:17:57 +03:00
if ( dma & ODP_WRITE_ALLOWED_BIT ) {
struct page * head_page = compound_head ( page ) ;
2014-12-11 17:04:18 +02:00
/*
* set_page_dirty prefers being called with
* the page lock . However , MMU notifiers are
* called sometimes with and sometimes without
* the lock . We rely on the umem_mutex instead
* to prevent other mmu notifiers from
* continuing and allowing the page mapping to
* be removed .
*/
set_page_dirty ( head_page ) ;
2015-04-15 18:17:57 +03:00
}
2018-09-16 20:48:04 +03:00
umem_odp - > page_list [ idx ] = NULL ;
umem_odp - > dma_list [ idx ] = 0 ;
2019-04-02 14:52:52 -05:00
umem_odp - > npages - - ;
2014-12-11 17:04:17 +02:00
}
}
}
EXPORT_SYMBOL ( ib_umem_odp_unmap_dma_pages ) ;