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>
2020-09-30 19:38:25 +03:00
# include <linux/hmm.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 ;
2020-09-30 19:38:25 +03:00
size_t ndmas , npfns ;
2019-08-19 14:17:06 +03:00
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 ;
2020-09-30 19:38:25 +03:00
ndmas = ( end - start ) > > umem_odp - > page_shift ;
if ( ! ndmas )
2019-08-19 14:17:02 +03:00
return - EINVAL ;
2020-09-30 19:38:25 +03:00
npfns = ( end - start ) > > PAGE_SHIFT ;
umem_odp - > pfn_list = kvcalloc (
npfns , sizeof ( * umem_odp - > pfn_list ) , GFP_KERNEL ) ;
if ( ! umem_odp - > pfn_list )
2019-08-19 14:17:02 +03:00
return - ENOMEM ;
2019-08-19 14:17:07 +03:00
umem_odp - > dma_list = kvcalloc (
2020-09-30 19:38:25 +03:00
ndmas , sizeof ( * umem_odp - > dma_list ) , GFP_KERNEL ) ;
2019-08-19 14:17:02 +03:00
if ( ! umem_odp - > dma_list ) {
ret = - ENOMEM ;
2020-09-30 19:38:25 +03:00
goto out_pfn_list ;
2019-08-19 14:17:02 +03:00
}
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 ) ;
2020-09-30 19:38:25 +03:00
out_pfn_list :
kvfree ( umem_odp - > pfn_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
2020-06-21 02:07:38 +00:00
* @ ops : MMU interval ops , currently only @ invalidate
2019-08-19 14:17:03 +03:00
*/
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
2020-06-21 02:07:38 +00:00
* @ ops : MMU interval ops , currently only @ invalidate
2019-08-19 14:17:04 +03:00
*
* 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 ) ;
2020-09-30 19:38:25 +03:00
kvfree ( umem_odp - > pfn_list ) ;
2019-08-19 14:17:01 +03:00
}
2020-03-04 14:16:07 -04:00
put_pid ( umem_odp - > tgid ) ;
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 .
2020-09-30 19:38:25 +03:00
* @ dma_index : index in the umem to add the dma to .
2014-12-11 17:04:17 +02:00
* @ 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
*
2020-09-30 19:38:25 +03:00
* The function returns - EFAULT if the DMA mapping operation fails .
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 ,
2020-09-30 19:38:25 +03:00
unsigned int dma_index ,
2014-12-11 17:04:17 +02:00
struct page * page ,
2020-09-30 19:38:25 +03:00
u64 access_mask )
2014-12-11 17:04:17 +02:00
{
2019-08-06 20:15:44 -03:00
struct ib_device * dev = umem_odp - > umem . ibdev ;
2020-09-30 19:38:25 +03:00
dma_addr_t * dma_addr = & umem_odp - > dma_list [ dma_index ] ;
2014-12-11 17:04:17 +02:00
2020-09-30 19:38:25 +03:00
if ( * dma_addr ) {
2019-10-09 13:09:35 -03:00
/*
2020-09-30 19:38:25 +03:00
* If the page is already dma mapped it means it went through
* a non - invalidating trasition , like read - only to writable .
* Resync the flags .
2019-10-09 13:09:35 -03:00
*/
2020-09-30 19:38:25 +03:00
* dma_addr = ( * dma_addr & ODP_DMA_ADDR_MASK ) | access_mask ;
return 0 ;
2014-12-11 17:04:17 +02:00
}
2020-09-30 19:38:25 +03:00
* dma_addr = ib_dma_map_page ( dev , page , 0 , 1 < < umem_odp - > page_shift ,
DMA_BIDIRECTIONAL ) ;
if ( ib_dma_mapping_error ( dev , * dma_addr ) ) {
* dma_addr = 0 ;
return - EFAULT ;
}
umem_odp - > npages + + ;
* dma_addr | = access_mask ;
return 0 ;
2014-12-11 17:04:17 +02:00
}
/**
2020-09-30 19:38:25 +03:00
* ib_umem_odp_map_dma_and_lock - DMA map userspace memory in an ODP MR and lock it .
2014-12-11 17:04:17 +02:00
*
2020-09-30 19:38:25 +03:00
* Maps the range passed in the argument to DMA addresses .
* The DMA addresses of the mapped pages is updated in umem_odp - > dma_list .
* Upon success the ODP MR will be locked to let caller complete its device
* page table update .
2014-12-11 17:04:17 +02:00
*
* Returns the number of pages mapped in success , negative error code
* for failure .
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 .
2020-09-30 19:38:26 +03:00
* @ fault : is faulting required for the given range
2014-12-11 17:04:17 +02:00
*/
2020-09-30 19:38:25 +03:00
int ib_umem_odp_map_dma_and_lock ( struct ib_umem_odp * umem_odp , u64 user_virt ,
2020-09-30 19:38:26 +03:00
u64 bcnt , u64 access_mask , bool fault )
2020-09-30 19:38:25 +03:00
__acquires ( & umem_odp - > umem_mutex )
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 ;
2020-09-30 19:38:25 +03:00
int pfn_index , dma_index , ret = 0 , start_idx ;
unsigned int page_shift , hmm_order , pfn_start_idx ;
unsigned long num_pfns , current_seq ;
struct hmm_range range = { } ;
unsigned long timeout ;
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 ;
2019-05-20 09:05:25 +03:00
page_shift = umem_odp - > page_shift ;
2014-12-11 17:04:17 +02:00
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 ;
}
2020-09-30 19:38:25 +03:00
range . notifier = & umem_odp - > notifier ;
range . start = ALIGN_DOWN ( user_virt , 1UL < < page_shift ) ;
range . end = ALIGN ( user_virt + bcnt , 1UL < < page_shift ) ;
pfn_start_idx = ( range . start - ib_umem_start ( umem_odp ) ) > > PAGE_SHIFT ;
num_pfns = ( range . end - range . start ) > > PAGE_SHIFT ;
2020-09-30 19:38:26 +03:00
if ( fault ) {
range . default_flags = HMM_PFN_REQ_FAULT ;
2020-09-30 19:38:25 +03:00
2020-09-30 19:38:26 +03:00
if ( access_mask & ODP_WRITE_ALLOWED_BIT )
range . default_flags | = HMM_PFN_REQ_WRITE ;
}
2020-09-30 19:38:25 +03:00
range . hmm_pfns = & ( umem_odp - > pfn_list [ pfn_start_idx ] ) ;
timeout = jiffies + msecs_to_jiffies ( HMM_RANGE_DEFAULT_TIMEOUT ) ;
retry :
current_seq = range . notifier_seq =
mmu_interval_read_begin ( & umem_odp - > notifier ) ;
mmap_read_lock ( owning_mm ) ;
ret = hmm_range_fault ( & range ) ;
mmap_read_unlock ( owning_mm ) ;
if ( unlikely ( ret ) ) {
if ( ret = = - EBUSY & & ! time_after ( jiffies , timeout ) )
goto retry ;
goto out_put_mm ;
}
2016-10-13 01:20:17 +01:00
2020-09-30 19:38:25 +03:00
start_idx = ( range . start - ib_umem_start ( umem_odp ) ) > > page_shift ;
dma_index = start_idx ;
2014-12-11 17:04:17 +02:00
2020-09-30 19:38:25 +03:00
mutex_lock ( & umem_odp - > umem_mutex ) ;
if ( mmu_interval_read_retry ( & umem_odp - > notifier , current_seq ) ) {
mutex_unlock ( & umem_odp - > umem_mutex ) ;
goto retry ;
}
2014-12-11 17:04:17 +02:00
2020-09-30 19:38:25 +03:00
for ( pfn_index = 0 ; pfn_index < num_pfns ;
pfn_index + = 1 < < ( page_shift - PAGE_SHIFT ) , dma_index + + ) {
2020-09-30 19:38:26 +03:00
if ( fault ) {
/*
* Since we asked for hmm_range_fault ( ) to populate
* pages it shouldn ' t return an error entry on success .
*/
WARN_ON ( range . hmm_pfns [ pfn_index ] & HMM_PFN_ERROR ) ;
WARN_ON ( ! ( range . hmm_pfns [ pfn_index ] & HMM_PFN_VALID ) ) ;
} else {
if ( ! ( range . hmm_pfns [ pfn_index ] & HMM_PFN_VALID ) ) {
WARN_ON ( umem_odp - > dma_list [ dma_index ] ) ;
continue ;
}
access_mask = ODP_READ_ALLOWED_BIT ;
if ( range . hmm_pfns [ pfn_index ] & HMM_PFN_WRITE )
access_mask | = ODP_WRITE_ALLOWED_BIT ;
}
2020-09-30 19:38:25 +03:00
hmm_order = hmm_pfn_to_map_order ( range . hmm_pfns [ pfn_index ] ) ;
/* If a hugepage was detected and ODP wasn't set for, the umem
* page_shift will be used , the opposite case is an error .
2014-12-11 17:04:17 +02:00
*/
2020-09-30 19:38:25 +03:00
if ( hmm_order + PAGE_SHIFT < page_shift ) {
ret = - EINVAL ;
ibdev_dbg ( umem_odp - > umem . ibdev ,
" %s: un-expected hmm_order %d, page_shift %d \n " ,
__func__ , hmm_order , page_shift ) ;
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
2020-09-30 19:38:25 +03:00
ret = ib_umem_odp_map_dma_single_page (
umem_odp , dma_index , hmm_pfn_to_page ( range . hmm_pfns [ pfn_index ] ) ,
access_mask ) ;
2014-12-11 17:04:17 +02:00
if ( ret < 0 ) {
2020-09-30 19:38:25 +03:00
ibdev_dbg ( umem_odp - > umem . ibdev ,
" ib_umem_odp_map_dma_single_page failed with error %d \n " , ret ) ;
2014-12-11 17:04:17 +02:00
break ;
}
}
2020-09-30 19:38:25 +03:00
/* upon sucesss lock should stay on hold for the callee */
if ( ! ret )
ret = dma_index - start_idx ;
else
mutex_unlock ( & umem_odp - > umem_mutex ) ;
2014-12-11 17:04:17 +02:00
2020-09-30 19:38:25 +03:00
out_put_mm :
2014-12-11 17:04:17 +02:00
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
return ret ;
}
2020-09-30 19:38:25 +03:00
EXPORT_SYMBOL ( ib_umem_odp_map_dma_and_lock ) ;
2014-12-11 17:04:17 +02:00
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 )
{
2020-09-30 19:38:25 +03:00
dma_addr_t dma_addr ;
dma_addr_t dma ;
2014-12-11 17:04:17 +02:00
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 ) ) ;
for ( addr = virt ; addr < bound ; addr + = BIT ( umem_odp - > page_shift ) ) {
idx = ( addr - ib_umem_start ( umem_odp ) ) > > umem_odp - > page_shift ;
2020-09-30 19:38:25 +03:00
dma = umem_odp - > dma_list [ idx ] ;
2014-12-11 17:04:17 +02:00
2020-09-30 19:38:25 +03:00
/* The access flags guaranteed a valid DMA address in case was NULL */
if ( dma ) {
unsigned long pfn_idx = ( addr - ib_umem_start ( umem_odp ) ) > > PAGE_SHIFT ;
struct page * page = hmm_pfn_to_page ( umem_odp - > pfn_list [ pfn_idx ] ) ;
2014-12-11 17:04:17 +02:00
2020-09-30 19:38:25 +03:00
dma_addr = dma & ODP_DMA_ADDR_MASK ;
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 - > 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 ) ;