2015-09-29 18:15:55 -07:00
/*
* Intel MIC Platform Software Stack ( MPSS )
*
* Copyright ( c ) 2015 Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License , version 2 , as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* Intel SCIF driver .
*
*/
# include "scif_main.h"
/*
* struct scif_vma_info - Information about a remote memory mapping
* created via scif_mmap ( . . )
* @ vma : VM area struct
* @ list : link to list of active vmas
*/
struct scif_vma_info {
struct vm_area_struct * vma ;
struct list_head list ;
} ;
void scif_recv_munmap ( struct scif_dev * scifdev , struct scifmsg * msg )
{
struct scif_rma_req req ;
struct scif_window * window = NULL ;
struct scif_window * recv_window =
( struct scif_window * ) msg - > payload [ 0 ] ;
struct scif_endpt * ep ;
ep = ( struct scif_endpt * ) recv_window - > ep ;
req . out_window = & window ;
req . offset = recv_window - > offset ;
req . prot = recv_window - > prot ;
req . nr_bytes = recv_window - > nr_pages < < PAGE_SHIFT ;
req . type = SCIF_WINDOW_FULL ;
req . head = & ep - > rma_info . reg_list ;
msg - > payload [ 0 ] = ep - > remote_ep ;
mutex_lock ( & ep - > rma_info . rma_lock ) ;
/* Does a valid window exist? */
if ( scif_query_window ( & req ) ) {
dev_err ( & scifdev - > sdev - > dev ,
" %s %d -ENXIO \n " , __func__ , __LINE__ ) ;
msg - > uop = SCIF_UNREGISTER_ACK ;
goto error ;
}
scif_put_window ( window , window - > nr_pages ) ;
if ( ! window - > ref_count ) {
atomic_inc ( & ep - > rma_info . tw_refcount ) ;
ep - > rma_info . async_list_del = 1 ;
list_del_init ( & window - > list ) ;
scif_free_window_offset ( ep , window , window - > offset ) ;
}
error :
mutex_unlock ( & ep - > rma_info . rma_lock ) ;
if ( window & & ! window - > ref_count )
scif_queue_for_cleanup ( window , & scif_info . rma ) ;
}
/*
* Remove valid remote memory mappings created via scif_mmap ( . . ) from the
* process address space since the remote node is lost
*/
static void __scif_zap_mmaps ( struct scif_endpt * ep )
{
struct list_head * item ;
struct scif_vma_info * info ;
struct vm_area_struct * vma ;
unsigned long size ;
spin_lock ( & ep - > lock ) ;
list_for_each ( item , & ep - > rma_info . vma_list ) {
info = list_entry ( item , struct scif_vma_info , list ) ;
vma = info - > vma ;
size = vma - > vm_end - vma - > vm_start ;
zap_vma_ptes ( vma , vma - > vm_start , size ) ;
dev_dbg ( scif_info . mdev . this_device ,
" %s ep %p zap vma %p size 0x%lx \n " ,
__func__ , ep , info - > vma , size ) ;
}
spin_unlock ( & ep - > lock ) ;
}
/*
* Traverse the list of endpoints for a particular remote node and
* zap valid remote memory mappings since the remote node is lost
*/
static void _scif_zap_mmaps ( int node , struct list_head * head )
{
struct scif_endpt * ep ;
struct list_head * item ;
mutex_lock ( & scif_info . connlock ) ;
list_for_each ( item , head ) {
ep = list_entry ( item , struct scif_endpt , list ) ;
if ( ep - > remote_dev - > node = = node )
__scif_zap_mmaps ( ep ) ;
}
mutex_unlock ( & scif_info . connlock ) ;
}
/*
* Wrapper for removing remote memory mappings for a particular node . This API
* is called by peer nodes as part of handling a lost node .
*/
void scif_zap_mmaps ( int node )
{
_scif_zap_mmaps ( node , & scif_info . connected ) ;
_scif_zap_mmaps ( node , & scif_info . disconnected ) ;
}
/*
* This API is only called while handling a lost node :
* a ) Remote node is dead .
* b ) Remote memory mappings have been zapped
* So we can traverse the remote_reg_list without any locks . Since
* the window has not yet been unregistered we can drop the ref count
* and queue it to the cleanup thread .
*/
static void __scif_cleanup_rma_for_zombies ( struct scif_endpt * ep )
{
struct list_head * pos , * tmp ;
struct scif_window * window ;
list_for_each_safe ( pos , tmp , & ep - > rma_info . remote_reg_list ) {
window = list_entry ( pos , struct scif_window , list ) ;
if ( window - > ref_count )
scif_put_window ( window , window - > nr_pages ) ;
else
dev_err ( scif_info . mdev . this_device ,
" %s %d unexpected \n " ,
__func__ , __LINE__ ) ;
if ( ! window - > ref_count ) {
atomic_inc ( & ep - > rma_info . tw_refcount ) ;
list_del_init ( & window - > list ) ;
scif_queue_for_cleanup ( window , & scif_info . rma ) ;
}
}
}
/* Cleanup remote registration lists for zombie endpoints */
void scif_cleanup_rma_for_zombies ( int node )
{
struct scif_endpt * ep ;
struct list_head * item ;
mutex_lock ( & scif_info . eplock ) ;
list_for_each ( item , & scif_info . zombie ) {
ep = list_entry ( item , struct scif_endpt , list ) ;
if ( ep - > remote_dev & & ep - > remote_dev - > node = = node )
__scif_cleanup_rma_for_zombies ( ep ) ;
}
mutex_unlock ( & scif_info . eplock ) ;
flush_work ( & scif_info . misc_work ) ;
}
/* Insert the VMA into the per endpoint VMA list */
static int scif_insert_vma ( struct scif_endpt * ep , struct vm_area_struct * vma )
{
struct scif_vma_info * info ;
int err = 0 ;
info = kzalloc ( sizeof ( * info ) , GFP_KERNEL ) ;
if ( ! info ) {
err = - ENOMEM ;
goto done ;
}
info - > vma = vma ;
spin_lock ( & ep - > lock ) ;
list_add_tail ( & info - > list , & ep - > rma_info . vma_list ) ;
spin_unlock ( & ep - > lock ) ;
done :
return err ;
}
/* Delete the VMA from the per endpoint VMA list */
static void scif_delete_vma ( struct scif_endpt * ep , struct vm_area_struct * vma )
{
struct list_head * item ;
struct scif_vma_info * info ;
spin_lock ( & ep - > lock ) ;
list_for_each ( item , & ep - > rma_info . vma_list ) {
info = list_entry ( item , struct scif_vma_info , list ) ;
if ( info - > vma = = vma ) {
list_del ( & info - > list ) ;
kfree ( info ) ;
break ;
}
}
spin_unlock ( & ep - > lock ) ;
}
static phys_addr_t scif_get_phys ( phys_addr_t phys , struct scif_endpt * ep )
{
struct scif_dev * scifdev = ( struct scif_dev * ) ep - > remote_dev ;
struct scif_hw_dev * sdev = scifdev - > sdev ;
phys_addr_t out_phys , apt_base = 0 ;
/*
* If the DMA address is card relative then we need to add the
* aperture base for mmap to work correctly
*/
if ( ! scifdev_self ( scifdev ) & & sdev - > aper & & sdev - > card_rel_da )
apt_base = sdev - > aper - > pa ;
out_phys = apt_base + phys ;
return out_phys ;
}
int scif_get_pages ( scif_epd_t epd , off_t offset , size_t len ,
struct scif_range * * pages )
{
struct scif_endpt * ep = ( struct scif_endpt * ) epd ;
struct scif_rma_req req ;
struct scif_window * window = NULL ;
int nr_pages , err , i ;
dev_dbg ( scif_info . mdev . this_device ,
" SCIFAPI get_pinned_pages: ep %p offset 0x%lx len 0x%lx \n " ,
ep , offset , len ) ;
err = scif_verify_epd ( ep ) ;
if ( err )
return err ;
if ( ! len | | ( offset < 0 ) | |
( offset + len < offset ) | |
( ALIGN ( offset , PAGE_SIZE ) ! = offset ) | |
( ALIGN ( len , PAGE_SIZE ) ! = len ) )
return - EINVAL ;
nr_pages = len > > PAGE_SHIFT ;
req . out_window = & window ;
req . offset = offset ;
req . prot = 0 ;
req . nr_bytes = len ;
req . type = SCIF_WINDOW_SINGLE ;
req . head = & ep - > rma_info . remote_reg_list ;
mutex_lock ( & ep - > rma_info . rma_lock ) ;
/* Does a valid window exist? */
err = scif_query_window ( & req ) ;
if ( err ) {
dev_err ( & ep - > remote_dev - > sdev - > dev ,
" %s %d err %d \n " , __func__ , __LINE__ , err ) ;
goto error ;
}
/* Allocate scif_range */
* pages = kzalloc ( sizeof ( * * pages ) , GFP_KERNEL ) ;
if ( ! * pages ) {
err = - ENOMEM ;
goto error ;
}
/* Allocate phys addr array */
( * pages ) - > phys_addr = scif_zalloc ( nr_pages * sizeof ( dma_addr_t ) ) ;
if ( ! ( ( * pages ) - > phys_addr ) ) {
err = - ENOMEM ;
goto error ;
}
if ( scif_is_mgmt_node ( ) & & ! scifdev_self ( ep - > remote_dev ) ) {
/* Allocate virtual address array */
( ( * pages ) - > va = scif_zalloc ( nr_pages * sizeof ( void * ) ) ) ;
if ( ! ( * pages ) - > va ) {
err = - ENOMEM ;
goto error ;
}
}
/* Populate the values */
( * pages ) - > cookie = window ;
( * pages ) - > nr_pages = nr_pages ;
( * pages ) - > prot_flags = window - > prot ;
for ( i = 0 ; i < nr_pages ; i + + ) {
( * pages ) - > phys_addr [ i ] =
__scif_off_to_dma_addr ( window , offset +
( i * PAGE_SIZE ) ) ;
( * pages ) - > phys_addr [ i ] = scif_get_phys ( ( * pages ) - > phys_addr [ i ] ,
ep ) ;
if ( scif_is_mgmt_node ( ) & & ! scifdev_self ( ep - > remote_dev ) )
( * pages ) - > va [ i ] =
ep - > remote_dev - > sdev - > aper - > va +
( * pages ) - > phys_addr [ i ] -
ep - > remote_dev - > sdev - > aper - > pa ;
}
scif_get_window ( window , nr_pages ) ;
error :
mutex_unlock ( & ep - > rma_info . rma_lock ) ;
if ( err ) {
if ( * pages ) {
scif_free ( ( * pages ) - > phys_addr ,
nr_pages * sizeof ( dma_addr_t ) ) ;
scif_free ( ( * pages ) - > va ,
nr_pages * sizeof ( void * ) ) ;
kfree ( * pages ) ;
* pages = NULL ;
}
dev_err ( & ep - > remote_dev - > sdev - > dev ,
" %s %d err %d \n " , __func__ , __LINE__ , err ) ;
}
return err ;
}
EXPORT_SYMBOL_GPL ( scif_get_pages ) ;
int scif_put_pages ( struct scif_range * pages )
{
struct scif_endpt * ep ;
struct scif_window * window ;
struct scifmsg msg ;
if ( ! pages | | ! pages - > cookie )
return - EINVAL ;
window = pages - > cookie ;
if ( ! window | | window - > magic ! = SCIFEP_MAGIC )
return - EINVAL ;
ep = ( struct scif_endpt * ) window - > ep ;
/*
* If the state is SCIFEP_CONNECTED or SCIFEP_DISCONNECTED then the
* callee should be allowed to release references to the pages ,
* else the endpoint was not connected in the first place ,
* hence the ENOTCONN .
*/
if ( ep - > state ! = SCIFEP_CONNECTED & & ep - > state ! = SCIFEP_DISCONNECTED )
return - ENOTCONN ;
mutex_lock ( & ep - > rma_info . rma_lock ) ;
scif_put_window ( window , pages - > nr_pages ) ;
/* Initiate window destruction if ref count is zero */
if ( ! window - > ref_count ) {
list_del ( & window - > list ) ;
mutex_unlock ( & ep - > rma_info . rma_lock ) ;
scif_drain_dma_intr ( ep - > remote_dev - > sdev ,
ep - > rma_info . dma_chan ) ;
/* Inform the peer about this window being destroyed. */
msg . uop = SCIF_MUNMAP ;
msg . src = ep - > port ;
msg . payload [ 0 ] = window - > peer_window ;
/* No error handling for notification messages */
scif_nodeqp_send ( ep - > remote_dev , & msg ) ;
/* Destroy this window from the peer's registered AS */
scif_destroy_remote_window ( window ) ;
} else {
mutex_unlock ( & ep - > rma_info . rma_lock ) ;
}
scif_free ( pages - > phys_addr , pages - > nr_pages * sizeof ( dma_addr_t ) ) ;
scif_free ( pages - > va , pages - > nr_pages * sizeof ( void * ) ) ;
kfree ( pages ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( scif_put_pages ) ;
/*
* scif_rma_list_mmap :
*
* Traverse the remote registration list starting from start_window :
* 1 ) Create VtoP mappings via remap_pfn_range ( . . )
* 2 ) Once step 1 ) and 2 ) complete successfully then traverse the range of
* windows again and bump the reference count .
* RMA lock must be held .
*/
static int scif_rma_list_mmap ( struct scif_window * start_window , s64 offset ,
int nr_pages , struct vm_area_struct * vma )
{
s64 end_offset , loop_offset = offset ;
struct scif_window * window = start_window ;
int loop_nr_pages , nr_pages_left = nr_pages ;
struct scif_endpt * ep = ( struct scif_endpt * ) start_window - > ep ;
struct list_head * head = & ep - > rma_info . remote_reg_list ;
int i , err = 0 ;
dma_addr_t phys_addr ;
struct scif_window_iter src_win_iter ;
size_t contig_bytes = 0 ;
might_sleep ( ) ;
list_for_each_entry_from ( window , head , list ) {
end_offset = window - > offset +
( window - > nr_pages < < PAGE_SHIFT ) ;
loop_nr_pages = min_t ( int ,
( end_offset - loop_offset ) > > PAGE_SHIFT ,
nr_pages_left ) ;
scif_init_window_iter ( window , & src_win_iter ) ;
for ( i = 0 ; i < loop_nr_pages ; i + + ) {
phys_addr = scif_off_to_dma_addr ( window , loop_offset ,
& contig_bytes ,
& src_win_iter ) ;
phys_addr = scif_get_phys ( phys_addr , ep ) ;
err = remap_pfn_range ( vma ,
vma - > vm_start +
loop_offset - offset ,
phys_addr > > PAGE_SHIFT ,
PAGE_SIZE ,
vma - > vm_page_prot ) ;
if ( err )
goto error ;
loop_offset + = PAGE_SIZE ;
}
nr_pages_left - = loop_nr_pages ;
if ( ! nr_pages_left )
break ;
}
/*
* No more failures expected . Bump up the ref count for all
* the windows . Another traversal from start_window required
* for handling errors encountered across windows during
* remap_pfn_range ( . . ) .
*/
loop_offset = offset ;
nr_pages_left = nr_pages ;
window = start_window ;
head = & ep - > rma_info . remote_reg_list ;
list_for_each_entry_from ( window , head , list ) {
end_offset = window - > offset +
( window - > nr_pages < < PAGE_SHIFT ) ;
loop_nr_pages = min_t ( int ,
( end_offset - loop_offset ) > > PAGE_SHIFT ,
nr_pages_left ) ;
scif_get_window ( window , loop_nr_pages ) ;
nr_pages_left - = loop_nr_pages ;
loop_offset + = ( loop_nr_pages < < PAGE_SHIFT ) ;
if ( ! nr_pages_left )
break ;
}
error :
if ( err )
dev_err ( scif_info . mdev . this_device ,
" %s %d err %d \n " , __func__ , __LINE__ , err ) ;
return err ;
}
/*
* scif_rma_list_munmap :
*
* Traverse the remote registration list starting from window :
* 1 ) Decrement ref count .
* 2 ) If the ref count drops to zero then send a SCIF_MUNMAP message to peer .
* RMA lock must be held .
*/
static void scif_rma_list_munmap ( struct scif_window * start_window ,
s64 offset , int nr_pages )
{
struct scifmsg msg ;
s64 loop_offset = offset , end_offset ;
int loop_nr_pages , nr_pages_left = nr_pages ;
struct scif_endpt * ep = ( struct scif_endpt * ) start_window - > ep ;
struct list_head * head = & ep - > rma_info . remote_reg_list ;
struct scif_window * window = start_window , * _window ;
msg . uop = SCIF_MUNMAP ;
msg . src = ep - > port ;
loop_offset = offset ;
nr_pages_left = nr_pages ;
list_for_each_entry_safe_from ( window , _window , head , list ) {
end_offset = window - > offset +
( window - > nr_pages < < PAGE_SHIFT ) ;
loop_nr_pages = min_t ( int ,
( end_offset - loop_offset ) > > PAGE_SHIFT ,
nr_pages_left ) ;
scif_put_window ( window , loop_nr_pages ) ;
if ( ! window - > ref_count ) {
struct scif_dev * rdev = ep - > remote_dev ;
scif_drain_dma_intr ( rdev - > sdev ,
ep - > rma_info . dma_chan ) ;
/* Inform the peer about this munmap */
msg . payload [ 0 ] = window - > peer_window ;
/* No error handling for Notification messages. */
scif_nodeqp_send ( ep - > remote_dev , & msg ) ;
list_del ( & window - > list ) ;
/* Destroy this window from the peer's registered AS */
scif_destroy_remote_window ( window ) ;
}
nr_pages_left - = loop_nr_pages ;
loop_offset + = ( loop_nr_pages < < PAGE_SHIFT ) ;
if ( ! nr_pages_left )
break ;
}
}
/*
* The private data field of each VMA used to mmap a remote window
* points to an instance of struct vma_pvt
*/
struct vma_pvt {
struct scif_endpt * ep ; /* End point for remote window */
s64 offset ; /* offset within remote window */
bool valid_offset ; /* offset is valid only if the original
* mmap request was for a single page
* else the offset within the vma is
* the correct offset
*/
struct kref ref ;
} ;
static void vma_pvt_release ( struct kref * ref )
{
struct vma_pvt * vmapvt = container_of ( ref , struct vma_pvt , ref ) ;
kfree ( vmapvt ) ;
}
/**
* scif_vma_open - VMA open driver callback
* @ vma : VMM memory area .
* The open method is called by the kernel to allow the subsystem implementing
* the VMA to initialize the area . This method is invoked any time a new
* reference to the VMA is made ( when a process forks , for example ) .
* The one exception happens when the VMA is first created by mmap ;
* in this case , the driver ' s mmap method is called instead .
* This function is also invoked when an existing VMA is split by the kernel
* due to a call to munmap on a subset of the VMA resulting in two VMAs .
* The kernel invokes this function only on one of the two VMAs .
*/
static void scif_vma_open ( struct vm_area_struct * vma )
{
struct vma_pvt * vmapvt = vma - > vm_private_data ;
dev_dbg ( scif_info . mdev . this_device ,
" SCIFAPI vma open: vma_start 0x%lx vma_end 0x%lx \n " ,
vma - > vm_start , vma - > vm_end ) ;
scif_insert_vma ( vmapvt - > ep , vma ) ;
kref_get ( & vmapvt - > ref ) ;
}
/**
* scif_munmap - VMA close driver callback .
* @ vma : VMM memory area .
* When an area is destroyed , the kernel calls its close operation .
* Note that there ' s no usage count associated with VMA ' s ; the area
* is opened and closed exactly once by each process that uses it .
*/
static void scif_munmap ( struct vm_area_struct * vma )
{
struct scif_endpt * ep ;
struct vma_pvt * vmapvt = vma - > vm_private_data ;
2016-05-21 18:41:38 +05:30
int nr_pages = vma_pages ( vma ) ;
2015-09-29 18:15:55 -07:00
s64 offset ;
struct scif_rma_req req ;
struct scif_window * window = NULL ;
int err ;
might_sleep ( ) ;
dev_dbg ( scif_info . mdev . this_device ,
" SCIFAPI munmap: vma_start 0x%lx vma_end 0x%lx \n " ,
vma - > vm_start , vma - > vm_end ) ;
ep = vmapvt - > ep ;
offset = vmapvt - > valid_offset ? vmapvt - > offset :
( vma - > vm_pgoff ) < < PAGE_SHIFT ;
dev_dbg ( scif_info . mdev . this_device ,
" SCIFAPI munmap: ep %p nr_pages 0x%x offset 0x%llx \n " ,
ep , nr_pages , offset ) ;
req . out_window = & window ;
req . offset = offset ;
req . nr_bytes = vma - > vm_end - vma - > vm_start ;
req . prot = vma - > vm_flags & ( VM_READ | VM_WRITE ) ;
req . type = SCIF_WINDOW_PARTIAL ;
req . head = & ep - > rma_info . remote_reg_list ;
mutex_lock ( & ep - > rma_info . rma_lock ) ;
err = scif_query_window ( & req ) ;
if ( err )
dev_err ( scif_info . mdev . this_device ,
" %s %d err %d \n " , __func__ , __LINE__ , err ) ;
else
scif_rma_list_munmap ( window , offset , nr_pages ) ;
mutex_unlock ( & ep - > rma_info . rma_lock ) ;
/*
* The kernel probably zeroes these out but we still want
* to clean up our own mess just in case .
*/
vma - > vm_ops = NULL ;
vma - > vm_private_data = NULL ;
kref_put ( & vmapvt - > ref , vma_pvt_release ) ;
scif_delete_vma ( ep , vma ) ;
}
static const struct vm_operations_struct scif_vm_ops = {
. open = scif_vma_open ,
. close = scif_munmap ,
} ;
/**
* scif_mmap - Map pages in virtual address space to a remote window .
* @ vma : VMM memory area .
* @ epd : endpoint descriptor
*
* Return : Upon successful completion , scif_mmap ( ) returns zero
* else an apt error is returned as documented in scif . h
*/
int scif_mmap ( struct vm_area_struct * vma , scif_epd_t epd )
{
struct scif_rma_req req ;
struct scif_window * window = NULL ;
struct scif_endpt * ep = ( struct scif_endpt * ) epd ;
s64 start_offset = vma - > vm_pgoff < < PAGE_SHIFT ;
2016-05-21 18:41:38 +05:30
int nr_pages = vma_pages ( vma ) ;
2015-09-29 18:15:55 -07:00
int err ;
struct vma_pvt * vmapvt ;
dev_dbg ( scif_info . mdev . this_device ,
" SCIFAPI mmap: ep %p start_offset 0x%llx nr_pages 0x%x \n " ,
ep , start_offset , nr_pages ) ;
err = scif_verify_epd ( ep ) ;
if ( err )
return err ;
might_sleep ( ) ;
err = scif_insert_vma ( ep , vma ) ;
if ( err )
return err ;
vmapvt = kzalloc ( sizeof ( * vmapvt ) , GFP_KERNEL ) ;
if ( ! vmapvt ) {
scif_delete_vma ( ep , vma ) ;
return - ENOMEM ;
}
vmapvt - > ep = ep ;
kref_init ( & vmapvt - > ref ) ;
req . out_window = & window ;
req . offset = start_offset ;
req . nr_bytes = vma - > vm_end - vma - > vm_start ;
req . prot = vma - > vm_flags & ( VM_READ | VM_WRITE ) ;
req . type = SCIF_WINDOW_PARTIAL ;
req . head = & ep - > rma_info . remote_reg_list ;
mutex_lock ( & ep - > rma_info . rma_lock ) ;
/* Does a valid window exist? */
err = scif_query_window ( & req ) ;
if ( err ) {
dev_err ( & ep - > remote_dev - > sdev - > dev ,
" %s %d err %d \n " , __func__ , __LINE__ , err ) ;
goto error_unlock ;
}
/* Default prot for loopback */
if ( ! scifdev_self ( ep - > remote_dev ) )
vma - > vm_page_prot = pgprot_writecombine ( vma - > vm_page_prot ) ;
/*
* VM_DONTCOPY - Do not copy this vma on fork
* VM_DONTEXPAND - Cannot expand with mremap ( )
* VM_RESERVED - Count as reserved_vm like IO
* VM_PFNMAP - Page - ranges managed without " struct page "
* VM_IO - Memory mapped I / O or similar
*
* We do not want to copy this VMA automatically on a fork ( ) ,
* expand this VMA due to mremap ( ) or swap out these pages since
* the VMA is actually backed by physical pages in the remote
* node ' s physical memory and not via a struct page .
*/
vma - > vm_flags | = VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP ;
if ( ! scifdev_self ( ep - > remote_dev ) )
vma - > vm_flags | = VM_IO | VM_PFNMAP ;
/* Map this range of windows */
err = scif_rma_list_mmap ( window , start_offset , nr_pages , vma ) ;
if ( err ) {
dev_err ( & ep - > remote_dev - > sdev - > dev ,
" %s %d err %d \n " , __func__ , __LINE__ , err ) ;
goto error_unlock ;
}
/* Set up the driver call back */
vma - > vm_ops = & scif_vm_ops ;
vma - > vm_private_data = vmapvt ;
error_unlock :
mutex_unlock ( & ep - > rma_info . rma_lock ) ;
if ( err ) {
kfree ( vmapvt ) ;
dev_err ( & ep - > remote_dev - > sdev - > dev ,
" %s %d err %d \n " , __func__ , __LINE__ , err ) ;
scif_delete_vma ( ep , vma ) ;
}
return err ;
}