2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
4 * This software is available to you under the OpenIB.org BSD license
\r
7 * Redistribution and use in source and binary forms, with or
\r
8 * without modification, are permitted provided that the following
\r
9 * conditions are met:
\r
11 * - Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\r
15 * - Redistributions in binary form must reproduce the above
\r
16 * copyright notice, this list of conditions and the following
\r
17 * disclaimer in the documentation and/or other materials
\r
18 * provided with the distribution.
\r
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
32 /* Registers a memory region */
\r
34 #include "ibspdll.h"
\r
37 __forceinline boolean_t
\r
39 IN struct memory_reg *p_reg,
\r
40 IN ib_access_t acl_mask,
\r
44 return( (p_reg->type.access_ctrl & acl_mask) == acl_mask &&
\r
45 start >= p_reg->type.vaddr &&
\r
46 ((uintn_t)start) + len <=
\r
47 ((uintn_t)(uint64_t)p_reg->type.vaddr) + p_reg->type.length );
\r
51 /* Find the first registered mr that matches the given region.
\r
52 * mem_list is either socket_info->buf_mem_list or socket_info->rdma_mem_list.
\r
54 struct memory_node *
\r
56 IN struct ibsp_socket_info *s,
\r
57 IN ib_access_t acl_mask,
\r
61 struct memory_node *p_node;
\r
62 cl_list_item_t *p_item;
\r
64 IBSP_ENTER( IBSP_DBG_MEM );
\r
66 cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex );
\r
68 for( p_item = cl_qlist_head( &s->mr_list );
\r
69 p_item != cl_qlist_end( &s->mr_list );
\r
70 p_item = cl_qlist_next( p_item ) )
\r
72 p_node = PARENT_STRUCT( p_item, struct memory_node, socket_item );
\r
74 if( __check_mr( p_node->p_reg, acl_mask, start, len ) )
\r
76 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
77 IBSP_EXIT( IBSP_DBG_MEM );
\r
82 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
84 IBSP_TRACE_EXIT( IBSP_DBG_MEM, ("mr not found\n") );
\r
89 /* Registers a memory region. The memory region might be cached.
\r
90 * mem_list is either socket_info->buf_mem_list or hca->rdma_mem_list.
\r
92 struct memory_node *
\r
94 IN struct ibsp_socket_info *s,
\r
95 IN ib_pd_handle_t pd,
\r
98 IN ib_access_t access_ctrl,
\r
101 struct memory_node *p_node;
\r
102 struct memory_reg *p_reg;
\r
103 cl_list_item_t *p_item;
\r
104 ib_api_status_t status;
\r
106 IBSP_ENTER( IBSP_DBG_MEM );
\r
108 CL_ASSERT( start != NULL );
\r
109 CL_ASSERT( len != 0 );
\r
110 CL_ASSERT( (access_ctrl & ~(IB_AC_RDMA_READ | IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE)) ==
\r
113 /* Optimistically allocate a tracking structure. */
\r
114 p_node = HeapAlloc( g_ibsp.heap, 0, sizeof(struct memory_node) );
\r
118 ("AllocateOverlappedBuf:HeapAlloc() failed: %d\n",
\r
120 *lpErrno = WSAENOBUFS;
\r
124 /* First, try to find a suitable MR */
\r
125 cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex );
\r
127 /* Find the first registered mr that matches the given region. */
\r
128 for( p_item = cl_qlist_head( &s->port->hca->rdma_mem_list.list );
\r
129 p_item != cl_qlist_end( &s->port->hca->rdma_mem_list.list );
\r
130 p_item = cl_qlist_next( p_item ) )
\r
132 p_reg = PARENT_STRUCT(p_item, struct memory_reg, item);
\r
134 if( __check_mr( p_reg, access_ctrl, start, len ) )
\r
136 p_node->p_reg = p_reg;
\r
138 cl_qlist_insert_tail( &p_reg->node_list, &p_node->mr_item );
\r
139 cl_qlist_insert_head(
\r
140 &s->mr_list, &p_node->socket_item );
\r
141 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
142 IBSP_EXIT( IBSP_DBG_MEM );
\r
147 /* No corresponding MR has been found. Create a new one. */
\r
148 p_reg = HeapAlloc( g_ibsp.heap, 0, sizeof(struct memory_reg) );
\r
153 ("AllocateOverlappedBuf:HeapAlloc() failed: %d\n",
\r
155 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
156 HeapFree( g_ibsp.heap, 0, p_node );
\r
157 *lpErrno = WSAENOBUFS;
\r
161 /* The node is not initialized yet. All the parameters given are
\r
162 * supposed to be valid so we don't check them. */
\r
163 cl_qlist_init( &p_reg->node_list );
\r
164 p_reg->type.vaddr = start;
\r
165 p_reg->type.length = len;
\r
166 p_reg->type.access_ctrl = access_ctrl;
\r
168 IBSP_TRACE2( IBSP_DBG_MEM, ("pinning memory node %p\n", p_node) );
\r
169 status = ib_reg_mem(
\r
170 pd, &p_reg->type, &p_reg->lkey, &p_reg->rkey, &p_reg->mr_handle );
\r
174 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
175 HeapFree( g_ibsp.heap, 0, p_reg );
\r
176 HeapFree( g_ibsp.heap, 0, p_node );
\r
179 ("ib_reg_mem returned %s\n", ib_get_err_str(status)) );
\r
181 *lpErrno = WSAEFAULT;
\r
185 STAT_INC( mr_num );
\r
187 p_node->p_reg = p_reg;
\r
190 /* Link to the list of nodes. */
\r
191 cl_qlist_insert_head( &s->port->hca->rdma_mem_list.list, &p_reg->item );
\r
192 cl_qlist_insert_head( &s->mr_list, &p_node->socket_item );
\r
193 cl_qlist_insert_tail( &p_reg->node_list, &p_node->mr_item );
\r
194 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
196 IBSP_EXIT( IBSP_DBG_MEM );
\r
203 static inline int __ibsp_dereg_mem_mr(
\r
204 IN struct memory_node *node )
\r
206 IBSP_ENTER( IBSP_DBG_MEM );
\r
208 // Underlying registration could be freed before the node.
\r
210 cl_qlist_remove_item( &node->p_reg->node_list, &node->mr_item );
\r
212 cl_qlist_remove_item( &node->s->mr_list, &node->socket_item );
\r
214 HeapFree( g_ibsp.heap, 0, node );
\r
216 IBSP_EXIT( IBSP_DBG_MEM );
\r
221 /* Deregisters a memory region */
\r
224 IN struct ibsp_socket_info *s,
\r
225 IN struct memory_node *node,
\r
226 OUT LPINT lpErrno )
\r
228 IBSP_ENTER( IBSP_DBG_MEM );
\r
230 cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex );
\r
231 *lpErrno = __ibsp_dereg_mem_mr( node );
\r
232 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
234 IBSP_EXIT( IBSP_DBG_MEM );
\r
235 return (*lpErrno? SOCKET_ERROR : 0);
\r
240 * Deregister the remaining memory regions on an HCA. This function should
\r
241 * only be called before destroying the PD. In normal case, the list should
\r
242 * be empty because the switch should have done it.
\r
246 IN struct mr_list *mem_list )
\r
248 cl_list_item_t *item;
\r
250 IBSP_ENTER( IBSP_DBG_MEM );
\r
252 cl_spinlock_acquire( &mem_list->mutex );
\r
253 IBSP_TRACE1( IBSP_DBG_MEM,
\r
254 ("%d registrations.\n", cl_qlist_count( &mem_list->list )) );
\r
256 for( item = cl_qlist_remove_head( &mem_list->list );
\r
257 item != cl_qlist_end( &mem_list->list );
\r
258 item = cl_qlist_remove_head( &mem_list->list ) )
\r
260 struct memory_reg *p_reg = PARENT_STRUCT(item, struct memory_reg, item);
\r
261 ib_api_status_t status;
\r
264 * Clear the pointer from the node to this registration. No need
\r
265 * to remove from the list as we're about to free the registration.
\r
267 for( item = cl_qlist_head( &p_reg->node_list );
\r
268 item != cl_qlist_end( &p_reg->node_list );
\r
269 item = cl_qlist_next( item ) )
\r
271 struct memory_node *p_node =
\r
272 PARENT_STRUCT( item, struct memory_node, mr_item );
\r
274 p_node->p_reg = NULL;
\r
277 IBSP_TRACE2( IBSP_DBG_MEM, ("unpinning ,memory reg %p\n", p_reg) );
\r
278 status = ib_dereg_mr( p_reg->mr_handle );
\r
282 ("ib_dereg_mem returned %s\n", ib_get_err_str( status )) );
\r
286 STAT_DEC( mr_num );
\r
289 HeapFree( g_ibsp.heap, 0, p_reg );
\r
292 cl_spinlock_release( &mem_list->mutex );
\r
294 IBSP_EXIT( IBSP_DBG_MEM );
\r
298 /* Deregister the remaining memory regions. This function should only
\r
299 * be called when destroying the socket. In normal case, the list should
\r
300 * be empty because the switch should have done it. */
\r
303 IN struct ibsp_socket_info *s )
\r
305 IBSP_ENTER( IBSP_DBG_MEM );
\r
309 CL_ASSERT( !cl_qlist_count( &s->mr_list ) );
\r
310 IBSP_EXIT( IBSP_DBG_MEM );
\r
314 cl_spinlock_acquire( &s->port->hca->rdma_mem_list.mutex );
\r
315 IBSP_TRACE1( IBSP_DBG_MEM,
\r
316 ("%d registrations.\n", cl_qlist_count( &s->mr_list )) );
\r
318 while( cl_qlist_count( &s->mr_list ) )
\r
320 __ibsp_dereg_mem_mr( PARENT_STRUCT( cl_qlist_head( &s->mr_list ),
\r
321 struct memory_node, socket_item) );
\r
324 cl_spinlock_release( &s->port->hca->rdma_mem_list.mutex );
\r
326 IBSP_EXIT( IBSP_DBG_MEM );
\r
331 * Loop through all the memory registrations on an HCA and release
\r
332 * all that fall within the specified range.
\r
335 ibsp_hca_flush_mr_cache(
\r
336 IN struct ibsp_hca *p_hca,
\r
337 IN LPVOID lpvAddress,
\r
340 struct memory_reg *p_reg;
\r
341 cl_list_item_t *p_item;
\r
342 ib_api_status_t status;
\r
344 IBSP_ENTER( IBSP_DBG_MEM );
\r
346 cl_spinlock_acquire( &p_hca->rdma_mem_list.mutex );
\r
347 p_item = cl_qlist_head( &p_hca->rdma_mem_list.list );
\r
348 while( p_item != cl_qlist_end( &p_hca->rdma_mem_list.list ) )
\r
350 p_reg = PARENT_STRUCT( p_item, struct memory_reg, item );
\r
352 /* Move to the next item now so we can remove the current. */
\r
353 p_item = cl_qlist_next( p_item );
\r
355 if( lpvAddress > p_reg->type.vaddr ||
\r
356 ((uintn_t)lpvAddress) + Size <
\r
357 ((uintn_t)(uint64_t)p_reg->type.vaddr) + p_reg->type.length )
\r
363 * Clear the pointer from all sockets' nodes to this registration.
\r
364 * No need to remove from the list as we're about to free the
\r
367 for( p_item = cl_qlist_head( &p_reg->node_list );
\r
368 p_item != cl_qlist_end( &p_reg->node_list );
\r
369 p_item = cl_qlist_next( p_item ) )
\r
371 struct memory_node *p_node =
\r
372 PARENT_STRUCT( p_item, struct memory_node, mr_item );
\r
374 p_node->p_reg = NULL;
\r
377 cl_qlist_remove_item( &p_hca->rdma_mem_list.list, &p_reg->item );
\r
379 status = ib_dereg_mr( p_reg->mr_handle );
\r
380 if( status != IB_SUCCESS )
\r
383 ("ib_dereg_mr returned %s\n", ib_get_err_str(status)) );
\r
386 HeapFree( g_ibsp.heap, 0, p_reg );
\r
388 cl_spinlock_release( &p_hca->rdma_mem_list.mutex );
\r
390 IBSP_EXIT( IBSP_DBG_MEM );
\r