Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/hermon/hermon_mr.c
+++ new/usr/src/uts/common/io/ib/adapters/hermon/hermon_mr.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * hermon_mr.c
28 28 * Hermon Memory Region/Window Routines
29 29 *
30 30 * Implements all the routines necessary to provide the requisite memory
31 31 * registration verbs. These include operations like RegisterMemRegion(),
32 32 * DeregisterMemRegion(), ReregisterMemRegion, RegisterSharedMemRegion,
33 33 * etc., that affect Memory Regions. It also includes the verbs that
34 34 * affect Memory Windows, including AllocMemWindow(), FreeMemWindow(),
35 35 * and QueryMemWindow().
36 36 */
37 37
38 38 #include <sys/types.h>
39 39 #include <sys/conf.h>
40 40 #include <sys/ddi.h>
41 41 #include <sys/sunddi.h>
42 42 #include <sys/modctl.h>
43 43 #include <sys/esunddi.h>
44 44
45 45 #include <sys/ib/adapters/hermon/hermon.h>
46 46
47 47 extern uint32_t hermon_kernel_data_ro;
48 48 extern uint32_t hermon_user_data_ro;
49 49 extern int hermon_rdma_debug;
50 50
51 51 /*
52 52 * Used by hermon_mr_keycalc() below to fill in the "unconstrained" portion
53 53 * of Hermon memory keys (LKeys and RKeys)
54 54 */
55 55 static uint_t hermon_memkey_cnt = 0x00;
56 56 #define HERMON_MEMKEY_SHIFT 24
57 57
58 58 /* initial state of an MPT */
59 59 #define HERMON_MPT_SW_OWNERSHIP 0xF /* memory regions */
60 60 #define HERMON_MPT_FREE 0x3 /* allocate lkey */
61 61
62 62 static int hermon_mr_common_reg(hermon_state_t *state, hermon_pdhdl_t pd,
63 63 hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl, hermon_mr_options_t *op,
64 64 hermon_mpt_rsrc_type_t mpt_type);
65 65 static int hermon_mr_common_rereg(hermon_state_t *state, hermon_mrhdl_t mr,
66 66 hermon_pdhdl_t pd, hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl_new,
67 67 hermon_mr_options_t *op);
68 68 static int hermon_mr_rereg_xlat_helper(hermon_state_t *state, hermon_mrhdl_t mr,
69 69 hermon_bind_info_t *bind, hermon_mr_options_t *op, uint64_t *mtt_addr,
70 70 uint_t sleep, uint_t *dereg_level);
71 71 static uint64_t hermon_mr_nummtt_needed(hermon_state_t *state,
72 72 hermon_bind_info_t *bind, uint_t *mtt_pgsize);
73 73 static int hermon_mr_mem_bind(hermon_state_t *state, hermon_bind_info_t *bind,
74 74 ddi_dma_handle_t dmahdl, uint_t sleep, uint_t is_buffer);
75 75 static void hermon_mr_mem_unbind(hermon_state_t *state,
76 76 hermon_bind_info_t *bind);
77 77 static int hermon_mr_fast_mtt_write(hermon_state_t *state, hermon_rsrc_t *mtt,
78 78 hermon_bind_info_t *bind, uint32_t mtt_pgsize_bits);
79 79 static int hermon_mr_fast_mtt_write_fmr(hermon_state_t *state,
80 80 hermon_rsrc_t *mtt, ibt_pmr_attr_t *mem_pattr, uint32_t mtt_pgsize_bits);
81 81 static uint_t hermon_mtt_refcnt_inc(hermon_rsrc_t *rsrc);
82 82 static uint_t hermon_mtt_refcnt_dec(hermon_rsrc_t *rsrc);
83 83
84 84
85 85 /*
86 86 * The Hermon umem_lockmemory() callback ops. When userland memory is
87 87 * registered, these callback ops are specified. The hermon_umap_umemlock_cb()
88 88 * callback will be called whenever the memory for the corresponding
89 89 * ddi_umem_cookie_t is being freed.
90 90 */
91 91 static struct umem_callback_ops hermon_umem_cbops = {
92 92 UMEM_CALLBACK_VERSION,
93 93 hermon_umap_umemlock_cb,
94 94 };
95 95
96 96
97 97
98 98 /*
99 99 * hermon_mr_register()
100 100 * Context: Can be called from interrupt or base context.
101 101 */
102 102 int
103 103 hermon_mr_register(hermon_state_t *state, hermon_pdhdl_t pd,
104 104 ibt_mr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl, hermon_mr_options_t *op,
105 105 hermon_mpt_rsrc_type_t mpt_type)
106 106 {
107 107 hermon_bind_info_t bind;
108 108 int status;
109 109
110 110 /*
111 111 * Fill in the "bind" struct. This struct provides the majority
112 112 * of the information that will be used to distinguish between an
113 113 * "addr" binding (as is the case here) and a "buf" binding (see
114 114 * below). The "bind" struct is later passed to hermon_mr_mem_bind()
115 115 * which does most of the "heavy lifting" for the Hermon memory
116 116 * registration routines.
117 117 */
118 118 bind.bi_type = HERMON_BINDHDL_VADDR;
119 119 bind.bi_addr = mr_attr->mr_vaddr;
120 120 bind.bi_len = mr_attr->mr_len;
121 121 bind.bi_as = mr_attr->mr_as;
122 122 bind.bi_flags = mr_attr->mr_flags;
123 123 status = hermon_mr_common_reg(state, pd, &bind, mrhdl, op,
124 124 mpt_type);
125 125 return (status);
126 126 }
127 127
128 128
129 129 /*
130 130 * hermon_mr_register_buf()
131 131 * Context: Can be called from interrupt or base context.
132 132 */
133 133 int
134 134 hermon_mr_register_buf(hermon_state_t *state, hermon_pdhdl_t pd,
135 135 ibt_smr_attr_t *mr_attr, struct buf *buf, hermon_mrhdl_t *mrhdl,
136 136 hermon_mr_options_t *op, hermon_mpt_rsrc_type_t mpt_type)
137 137 {
138 138 hermon_bind_info_t bind;
139 139 int status;
140 140
141 141 /*
142 142 * Fill in the "bind" struct. This struct provides the majority
143 143 * of the information that will be used to distinguish between an
144 144 * "addr" binding (see above) and a "buf" binding (as is the case
145 145 * here). The "bind" struct is later passed to hermon_mr_mem_bind()
146 146 * which does most of the "heavy lifting" for the Hermon memory
147 147 * registration routines. Note: We have chosen to provide
148 148 * "b_un.b_addr" as the IB address (when the IBT_MR_PHYS_IOVA flag is
149 149 * not set). It is not critical what value we choose here as it need
150 150 * only be unique for the given RKey (which will happen by default),
151 151 * so the choice here is somewhat arbitrary.
152 152 */
153 153 bind.bi_type = HERMON_BINDHDL_BUF;
154 154 bind.bi_buf = buf;
155 155 if (mr_attr->mr_flags & IBT_MR_PHYS_IOVA) {
156 156 bind.bi_addr = mr_attr->mr_vaddr;
157 157 } else {
158 158 bind.bi_addr = (uint64_t)(uintptr_t)buf->b_un.b_addr;
159 159 }
160 160 bind.bi_as = NULL;
161 161 bind.bi_len = (uint64_t)buf->b_bcount;
162 162 bind.bi_flags = mr_attr->mr_flags;
163 163 status = hermon_mr_common_reg(state, pd, &bind, mrhdl, op, mpt_type);
164 164 return (status);
165 165 }
166 166
167 167
168 168 /*
169 169 * hermon_mr_register_shared()
170 170 * Context: Can be called from interrupt or base context.
171 171 */
172 172 int
173 173 hermon_mr_register_shared(hermon_state_t *state, hermon_mrhdl_t mrhdl,
174 174 hermon_pdhdl_t pd, ibt_smr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl_new)
175 175 {
176 176 hermon_rsrc_t *mpt, *mtt, *rsrc;
177 177 hermon_umap_db_entry_t *umapdb;
178 178 hermon_hw_dmpt_t mpt_entry;
179 179 hermon_mrhdl_t mr;
180 180 hermon_bind_info_t *bind;
181 181 ddi_umem_cookie_t umem_cookie;
182 182 size_t umem_len;
183 183 caddr_t umem_addr;
184 184 uint64_t mtt_addr, pgsize_msk;
185 185 uint_t sleep, mr_is_umem;
186 186 int status, umem_flags;
187 187
188 188 /*
189 189 * Check the sleep flag. Ensure that it is consistent with the
190 190 * current thread context (i.e. if we are currently in the interrupt
191 191 * context, then we shouldn't be attempting to sleep).
192 192 */
193 193 sleep = (mr_attr->mr_flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP :
194 194 HERMON_SLEEP;
195 195 if ((sleep == HERMON_SLEEP) &&
196 196 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
197 197 status = IBT_INVALID_PARAM;
198 198 goto mrshared_fail;
199 199 }
200 200
201 201 /* Increment the reference count on the protection domain (PD) */
202 202 hermon_pd_refcnt_inc(pd);
203 203
204 204 /*
205 205 * Allocate an MPT entry. This will be filled in with all the
206 206 * necessary parameters to define the shared memory region.
207 207 * Specifically, it will be made to reference the currently existing
208 208 * MTT entries and ownership of the MPT will be passed to the hardware
209 209 * in the last step below. If we fail here, we must undo the
210 210 * protection domain reference count.
211 211 */
212 212 status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
213 213 if (status != DDI_SUCCESS) {
214 214 status = IBT_INSUFF_RESOURCE;
215 215 goto mrshared_fail1;
216 216 }
217 217
218 218 /*
219 219 * Allocate the software structure for tracking the shared memory
↓ open down ↓ |
219 lines elided |
↑ open up ↑ |
220 220 * region (i.e. the Hermon Memory Region handle). If we fail here, we
221 221 * must undo the protection domain reference count and the previous
222 222 * resource allocation.
223 223 */
224 224 status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
225 225 if (status != DDI_SUCCESS) {
226 226 status = IBT_INSUFF_RESOURCE;
227 227 goto mrshared_fail2;
228 228 }
229 229 mr = (hermon_mrhdl_t)rsrc->hr_addr;
230 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
231 230
232 231 /*
233 232 * Setup and validate the memory region access flags. This means
234 233 * translating the IBTF's enable flags into the access flags that
235 234 * will be used in later operations.
236 235 */
237 236 mr->mr_accflag = 0;
238 237 if (mr_attr->mr_flags & IBT_MR_ENABLE_WINDOW_BIND)
239 238 mr->mr_accflag |= IBT_MR_WINDOW_BIND;
240 239 if (mr_attr->mr_flags & IBT_MR_ENABLE_LOCAL_WRITE)
241 240 mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
242 241 if (mr_attr->mr_flags & IBT_MR_ENABLE_REMOTE_READ)
243 242 mr->mr_accflag |= IBT_MR_REMOTE_READ;
244 243 if (mr_attr->mr_flags & IBT_MR_ENABLE_REMOTE_WRITE)
245 244 mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
246 245 if (mr_attr->mr_flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
247 246 mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
248 247
249 248 /*
250 249 * Calculate keys (Lkey, Rkey) from MPT index. Each key is formed
251 250 * from a certain number of "constrained" bits (the least significant
252 251 * bits) and some number of "unconstrained" bits. The constrained
253 252 * bits must be set to the index of the entry in the MPT table, but
254 253 * the unconstrained bits can be set to any value we wish. Note:
255 254 * if no remote access is required, then the RKey value is not filled
256 255 * in. Otherwise both Rkey and LKey are given the same value.
257 256 */
258 257 mr->mr_rkey = mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
259 258
260 259 /* Grab the MR lock for the current memory region */
261 260 mutex_enter(&mrhdl->mr_lock);
262 261
263 262 /*
264 263 * Check here to see if the memory region has already been partially
265 264 * deregistered as a result of a hermon_umap_umemlock_cb() callback.
266 265 * If so, this is an error, return failure.
267 266 */
268 267 if ((mrhdl->mr_is_umem) && (mrhdl->mr_umemcookie == NULL)) {
269 268 mutex_exit(&mrhdl->mr_lock);
270 269 status = IBT_MR_HDL_INVALID;
271 270 goto mrshared_fail3;
272 271 }
273 272
274 273 /*
275 274 * Determine if the original memory was from userland and, if so, pin
276 275 * the pages (again) with umem_lockmemory(). This will guarantee a
277 276 * separate callback for each of this shared region's MR handles.
278 277 * If this is userland memory, then allocate an entry in the
279 278 * "userland resources database". This will later be added to
280 279 * the database (after all further memory registration operations are
281 280 * successful). If we fail here, we must undo all the above setup.
282 281 */
283 282 mr_is_umem = mrhdl->mr_is_umem;
284 283 if (mr_is_umem) {
285 284 umem_len = ptob(btopr(mrhdl->mr_bindinfo.bi_len));
286 285 umem_addr = (caddr_t)((uintptr_t)mrhdl->mr_bindinfo.bi_addr &
287 286 ~PAGEOFFSET);
288 287 umem_flags = (DDI_UMEMLOCK_WRITE | DDI_UMEMLOCK_READ |
289 288 DDI_UMEMLOCK_LONGTERM);
290 289 status = umem_lockmemory(umem_addr, umem_len, umem_flags,
291 290 &umem_cookie, &hermon_umem_cbops, NULL);
292 291 if (status != 0) {
293 292 mutex_exit(&mrhdl->mr_lock);
294 293 status = IBT_INSUFF_RESOURCE;
295 294 goto mrshared_fail3;
296 295 }
297 296
298 297 umapdb = hermon_umap_db_alloc(state->hs_instance,
299 298 (uint64_t)(uintptr_t)umem_cookie, MLNX_UMAP_MRMEM_RSRC,
300 299 (uint64_t)(uintptr_t)rsrc);
301 300 if (umapdb == NULL) {
302 301 mutex_exit(&mrhdl->mr_lock);
303 302 status = IBT_INSUFF_RESOURCE;
304 303 goto mrshared_fail4;
305 304 }
306 305 }
307 306
308 307 /*
309 308 * Copy the MTT resource pointer (and additional parameters) from
310 309 * the original Hermon Memory Region handle. Note: this is normally
311 310 * where the hermon_mr_mem_bind() routine would be called, but because
312 311 * we already have bound and filled-in MTT entries it is simply a
↓ open down ↓ |
72 lines elided |
↑ open up ↑ |
313 312 * matter here of managing the MTT reference count and grabbing the
314 313 * address of the MTT table entries (for filling in the shared region's
315 314 * MPT entry).
316 315 */
317 316 mr->mr_mttrsrcp = mrhdl->mr_mttrsrcp;
318 317 mr->mr_logmttpgsz = mrhdl->mr_logmttpgsz;
319 318 mr->mr_bindinfo = mrhdl->mr_bindinfo;
320 319 mr->mr_mttrefcntp = mrhdl->mr_mttrefcntp;
321 320 mutex_exit(&mrhdl->mr_lock);
322 321 bind = &mr->mr_bindinfo;
323 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
324 322 mtt = mr->mr_mttrsrcp;
325 323
326 324 /*
327 325 * Increment the MTT reference count (to reflect the fact that
328 326 * the MTT is now shared)
329 327 */
330 328 (void) hermon_mtt_refcnt_inc(mr->mr_mttrefcntp);
331 329
332 330 /*
333 331 * Update the new "bind" virtual address. Do some extra work here
334 332 * to ensure proper alignment. That is, make sure that the page
335 333 * offset for the beginning of the old range is the same as the
336 334 * offset for this new mapping
337 335 */
338 336 pgsize_msk = (((uint64_t)1 << mr->mr_logmttpgsz) - 1);
339 337 bind->bi_addr = ((mr_attr->mr_vaddr & ~pgsize_msk) |
340 338 (mr->mr_bindinfo.bi_addr & pgsize_msk));
341 339
342 340 /*
343 341 * Fill in the MPT entry. This is the final step before passing
344 342 * ownership of the MPT entry to the Hermon hardware. We use all of
345 343 * the information collected/calculated above to fill in the
346 344 * requisite portions of the MPT.
347 345 */
348 346 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
349 347 mpt_entry.en_bind = (mr->mr_accflag & IBT_MR_WINDOW_BIND) ? 1 : 0;
350 348 mpt_entry.atomic = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
351 349 mpt_entry.rw = (mr->mr_accflag & IBT_MR_REMOTE_WRITE) ? 1 : 0;
352 350 mpt_entry.rr = (mr->mr_accflag & IBT_MR_REMOTE_READ) ? 1 : 0;
353 351 mpt_entry.lw = (mr->mr_accflag & IBT_MR_LOCAL_WRITE) ? 1 : 0;
354 352 mpt_entry.lr = 1;
355 353 mpt_entry.reg_win = HERMON_MPT_IS_REGION;
356 354 mpt_entry.entity_sz = mr->mr_logmttpgsz;
357 355 mpt_entry.mem_key = mr->mr_lkey;
358 356 mpt_entry.pd = pd->pd_pdnum;
359 357 mpt_entry.start_addr = bind->bi_addr;
360 358 mpt_entry.reg_win_len = bind->bi_len;
361 359 mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
362 360 mpt_entry.mtt_addr_h = mtt_addr >> 32;
363 361 mpt_entry.mtt_addr_l = mtt_addr >> 3;
364 362
365 363 /*
366 364 * Write the MPT entry to hardware. Lastly, we pass ownership of
367 365 * the entry to the hardware. Note: in general, this operation
368 366 * shouldn't fail. But if it does, we have to undo everything we've
369 367 * done above before returning error.
370 368 */
371 369 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
372 370 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
373 371 if (status != HERMON_CMD_SUCCESS) {
374 372 cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
375 373 status);
376 374 if (status == HERMON_CMD_INVALID_STATUS) {
377 375 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
378 376 }
379 377 status = ibc_get_ci_failure(0);
380 378 goto mrshared_fail5;
381 379 }
382 380
383 381 /*
384 382 * Fill in the rest of the Hermon Memory Region handle. Having
385 383 * successfully transferred ownership of the MPT, we can update the
386 384 * following fields for use in further operations on the MR.
387 385 */
388 386 mr->mr_mptrsrcp = mpt;
389 387 mr->mr_mttrsrcp = mtt;
390 388 mr->mr_mpt_type = HERMON_MPT_DMPT;
391 389 mr->mr_pdhdl = pd;
392 390 mr->mr_rsrcp = rsrc;
393 391 mr->mr_is_umem = mr_is_umem;
394 392 mr->mr_is_fmr = 0;
395 393 mr->mr_umemcookie = (mr_is_umem != 0) ? umem_cookie : NULL;
396 394 mr->mr_umem_cbfunc = NULL;
397 395 mr->mr_umem_cbarg1 = NULL;
398 396 mr->mr_umem_cbarg2 = NULL;
399 397 mr->mr_lkey = hermon_mr_key_swap(mr->mr_lkey);
400 398 mr->mr_rkey = hermon_mr_key_swap(mr->mr_rkey);
401 399
402 400 /*
403 401 * If this is userland memory, then we need to insert the previously
404 402 * allocated entry into the "userland resources database". This will
405 403 * allow for later coordination between the hermon_umap_umemlock_cb()
406 404 * callback and hermon_mr_deregister().
407 405 */
408 406 if (mr_is_umem) {
409 407 hermon_umap_db_add(umapdb);
410 408 }
411 409
412 410 *mrhdl_new = mr;
413 411
414 412 return (DDI_SUCCESS);
415 413
416 414 /*
417 415 * The following is cleanup for all possible failure cases in this routine
418 416 */
419 417 mrshared_fail5:
420 418 (void) hermon_mtt_refcnt_dec(mr->mr_mttrefcntp);
421 419 if (mr_is_umem) {
422 420 hermon_umap_db_free(umapdb);
423 421 }
424 422 mrshared_fail4:
425 423 if (mr_is_umem) {
426 424 ddi_umem_unlock(umem_cookie);
427 425 }
428 426 mrshared_fail3:
429 427 hermon_rsrc_free(state, &rsrc);
430 428 mrshared_fail2:
431 429 hermon_rsrc_free(state, &mpt);
432 430 mrshared_fail1:
433 431 hermon_pd_refcnt_dec(pd);
434 432 mrshared_fail:
435 433 return (status);
436 434 }
437 435
438 436 /*
439 437 * hermon_mr_alloc_fmr()
440 438 * Context: Can be called from interrupt or base context.
441 439 */
442 440 int
443 441 hermon_mr_alloc_fmr(hermon_state_t *state, hermon_pdhdl_t pd,
444 442 hermon_fmrhdl_t fmr_pool, hermon_mrhdl_t *mrhdl)
445 443 {
446 444 hermon_rsrc_t *mpt, *mtt, *rsrc;
447 445 hermon_hw_dmpt_t mpt_entry;
448 446 hermon_mrhdl_t mr;
449 447 hermon_bind_info_t bind;
450 448 uint64_t mtt_addr;
451 449 uint64_t nummtt;
452 450 uint_t sleep, mtt_pgsize_bits;
453 451 int status;
454 452 offset_t i;
455 453 hermon_icm_table_t *icm_table;
456 454 hermon_dma_info_t *dma_info;
457 455 uint32_t index1, index2, rindx;
458 456
459 457 /*
460 458 * Check the sleep flag. Ensure that it is consistent with the
461 459 * current thread context (i.e. if we are currently in the interrupt
462 460 * context, then we shouldn't be attempting to sleep).
463 461 */
464 462 sleep = (fmr_pool->fmr_flags & IBT_MR_SLEEP) ? HERMON_SLEEP :
465 463 HERMON_NOSLEEP;
466 464 if ((sleep == HERMON_SLEEP) &&
467 465 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
468 466 return (IBT_INVALID_PARAM);
469 467 }
470 468
471 469 /* Increment the reference count on the protection domain (PD) */
472 470 hermon_pd_refcnt_inc(pd);
473 471
474 472 /*
475 473 * Allocate an MPT entry. This will be filled in with all the
476 474 * necessary parameters to define the FMR. Specifically, it will be
477 475 * made to reference the currently existing MTT entries and ownership
478 476 * of the MPT will be passed to the hardware in the last step below.
479 477 * If we fail here, we must undo the protection domain reference count.
480 478 */
481 479
482 480 status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
483 481 if (status != DDI_SUCCESS) {
484 482 status = IBT_INSUFF_RESOURCE;
485 483 goto fmralloc_fail1;
486 484 }
487 485
488 486 /*
489 487 * Allocate the software structure for tracking the fmr memory
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
490 488 * region (i.e. the Hermon Memory Region handle). If we fail here, we
491 489 * must undo the protection domain reference count and the previous
492 490 * resource allocation.
493 491 */
494 492 status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
495 493 if (status != DDI_SUCCESS) {
496 494 status = IBT_INSUFF_RESOURCE;
497 495 goto fmralloc_fail2;
498 496 }
499 497 mr = (hermon_mrhdl_t)rsrc->hr_addr;
500 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
501 498
502 499 /*
503 500 * Setup and validate the memory region access flags. This means
504 501 * translating the IBTF's enable flags into the access flags that
505 502 * will be used in later operations.
506 503 */
507 504 mr->mr_accflag = 0;
508 505 if (fmr_pool->fmr_flags & IBT_MR_ENABLE_LOCAL_WRITE)
509 506 mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
510 507 if (fmr_pool->fmr_flags & IBT_MR_ENABLE_REMOTE_READ)
511 508 mr->mr_accflag |= IBT_MR_REMOTE_READ;
512 509 if (fmr_pool->fmr_flags & IBT_MR_ENABLE_REMOTE_WRITE)
513 510 mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
514 511 if (fmr_pool->fmr_flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
515 512 mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
516 513
517 514 /*
518 515 * Calculate keys (Lkey, Rkey) from MPT index. Each key is formed
519 516 * from a certain number of "constrained" bits (the least significant
520 517 * bits) and some number of "unconstrained" bits. The constrained
521 518 * bits must be set to the index of the entry in the MPT table, but
522 519 * the unconstrained bits can be set to any value we wish. Note:
523 520 * if no remote access is required, then the RKey value is not filled
524 521 * in. Otherwise both Rkey and LKey are given the same value.
525 522 */
526 523 mr->mr_fmr_key = 1; /* ready for the next reload */
527 524 mr->mr_rkey = mr->mr_lkey = mpt->hr_indx;
528 525
529 526 /*
530 527 * Determine number of pages spanned. This routine uses the
531 528 * information in the "bind" struct to determine the required
532 529 * number of MTT entries needed (and returns the suggested page size -
533 530 * as a "power-of-2" - for each MTT entry).
534 531 */
535 532 /* Assume address will be page aligned later */
536 533 bind.bi_addr = 0;
537 534 /* Calculate size based on given max pages */
538 535 bind.bi_len = fmr_pool->fmr_max_pages << PAGESHIFT;
539 536 nummtt = hermon_mr_nummtt_needed(state, &bind, &mtt_pgsize_bits);
540 537
541 538 /*
542 539 * Allocate the MTT entries. Use the calculations performed above to
543 540 * allocate the required number of MTT entries. If we fail here, we
544 541 * must not only undo all the previous resource allocation (and PD
545 542 * reference count), but we must also unbind the memory.
546 543 */
547 544 status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt, sleep, &mtt);
548 545 if (status != DDI_SUCCESS) {
549 546 IBTF_DPRINTF_L2("FMR", "FATAL: too few MTTs");
550 547 status = IBT_INSUFF_RESOURCE;
551 548 goto fmralloc_fail3;
552 549 }
553 550 mr->mr_logmttpgsz = mtt_pgsize_bits;
554 551
555 552 /*
556 553 * Fill in the MPT entry. This is the final step before passing
557 554 * ownership of the MPT entry to the Hermon hardware. We use all of
558 555 * the information collected/calculated above to fill in the
559 556 * requisite portions of the MPT.
560 557 */
561 558 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
562 559 mpt_entry.en_bind = 0;
563 560 mpt_entry.atomic = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
564 561 mpt_entry.rw = (mr->mr_accflag & IBT_MR_REMOTE_WRITE) ? 1 : 0;
565 562 mpt_entry.rr = (mr->mr_accflag & IBT_MR_REMOTE_READ) ? 1 : 0;
566 563 mpt_entry.lw = (mr->mr_accflag & IBT_MR_LOCAL_WRITE) ? 1 : 0;
567 564 mpt_entry.lr = 1;
568 565 mpt_entry.reg_win = HERMON_MPT_IS_REGION;
569 566 mpt_entry.pd = pd->pd_pdnum;
570 567
571 568 mpt_entry.entity_sz = mr->mr_logmttpgsz;
572 569 mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
573 570 mpt_entry.fast_reg_en = 1;
574 571 mpt_entry.mtt_size = (uint_t)nummtt;
575 572 mpt_entry.mtt_addr_h = mtt_addr >> 32;
576 573 mpt_entry.mtt_addr_l = mtt_addr >> 3;
577 574 mpt_entry.mem_key = mr->mr_lkey;
578 575
579 576 /*
580 577 * FMR sets these to 0 for now. Later during actual fmr registration
581 578 * these values are filled in.
582 579 */
583 580 mpt_entry.start_addr = 0;
584 581 mpt_entry.reg_win_len = 0;
585 582
586 583 /*
587 584 * Write the MPT entry to hardware. Lastly, we pass ownership of
588 585 * the entry to the hardware. Note: in general, this operation
589 586 * shouldn't fail. But if it does, we have to undo everything we've
590 587 * done above before returning error.
591 588 */
592 589 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
593 590 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
594 591 if (status != HERMON_CMD_SUCCESS) {
595 592 cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
596 593 status);
597 594 if (status == HERMON_CMD_INVALID_STATUS) {
598 595 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
599 596 }
600 597 status = ibc_get_ci_failure(0);
601 598 goto fmralloc_fail4;
602 599 }
603 600
604 601 /*
605 602 * Fill in the rest of the Hermon Memory Region handle. Having
606 603 * successfully transferred ownership of the MPT, we can update the
607 604 * following fields for use in further operations on the MR. Also, set
608 605 * that this is an FMR region.
609 606 */
610 607 mr->mr_mptrsrcp = mpt;
611 608 mr->mr_mttrsrcp = mtt;
612 609
613 610 mr->mr_mpt_type = HERMON_MPT_DMPT;
614 611 mr->mr_pdhdl = pd;
615 612 mr->mr_rsrcp = rsrc;
616 613 mr->mr_is_fmr = 1;
↓ open down ↓ |
106 lines elided |
↑ open up ↑ |
617 614 mr->mr_lkey = hermon_mr_key_swap(mr->mr_lkey);
618 615 mr->mr_rkey = hermon_mr_key_swap(mr->mr_rkey);
619 616 mr->mr_mttaddr = mtt_addr;
620 617 (void) memcpy(&mr->mr_bindinfo, &bind, sizeof (hermon_bind_info_t));
621 618
622 619 /* initialize hr_addr for use during register/deregister/invalidate */
623 620 icm_table = &state->hs_icm[HERMON_DMPT];
624 621 rindx = mpt->hr_indx;
625 622 hermon_index(index1, index2, rindx, icm_table, i);
626 623 dma_info = icm_table->icm_dma[index1] + index2;
627 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mpt))
628 624 mpt->hr_addr = (void *)((uintptr_t)(dma_info->vaddr + i * mpt->hr_len));
629 625
630 626 *mrhdl = mr;
631 627
632 628 return (DDI_SUCCESS);
633 629
634 630 /*
635 631 * The following is cleanup for all possible failure cases in this routine
636 632 */
637 633 fmralloc_fail4:
638 634 kmem_free(mtt, sizeof (hermon_rsrc_t) * nummtt);
639 635 fmralloc_fail3:
640 636 hermon_rsrc_free(state, &rsrc);
641 637 fmralloc_fail2:
642 638 hermon_rsrc_free(state, &mpt);
643 639 fmralloc_fail1:
644 640 hermon_pd_refcnt_dec(pd);
645 641 fmralloc_fail:
646 642 return (status);
647 643 }
648 644
649 645
650 646 /*
651 647 * hermon_mr_register_physical_fmr()
652 648 * Context: Can be called from interrupt or base context.
653 649 */
654 650 /*ARGSUSED*/
655 651 int
656 652 hermon_mr_register_physical_fmr(hermon_state_t *state,
657 653 ibt_pmr_attr_t *mem_pattr_p, hermon_mrhdl_t mr, ibt_pmr_desc_t *mem_desc_p)
658 654 {
659 655 hermon_rsrc_t *mpt;
660 656 uint64_t *mpt_table;
661 657 int status;
662 658 uint32_t key;
663 659
664 660 mutex_enter(&mr->mr_lock);
665 661 mpt = mr->mr_mptrsrcp;
666 662 mpt_table = (uint64_t *)mpt->hr_addr;
667 663
668 664 /* Write MPT status to SW bit */
669 665 *(uint8_t *)mpt_table = 0xF0;
670 666
671 667 membar_producer();
672 668
673 669 /*
674 670 * Write the mapped addresses into the MTT entries. FMR needs to do
675 671 * this a little differently, so we call the fmr specific fast mtt
676 672 * write here.
677 673 */
678 674 status = hermon_mr_fast_mtt_write_fmr(state, mr->mr_mttrsrcp,
679 675 mem_pattr_p, mr->mr_logmttpgsz);
680 676 if (status != DDI_SUCCESS) {
681 677 mutex_exit(&mr->mr_lock);
682 678 status = ibc_get_ci_failure(0);
683 679 goto fmr_reg_fail1;
684 680 }
685 681
686 682 /*
687 683 * Calculate keys (Lkey, Rkey) from MPT index. Each key is formed
688 684 * from a certain number of "constrained" bits (the least significant
689 685 * bits) and some number of "unconstrained" bits. The constrained
690 686 * bits must be set to the index of the entry in the MPT table, but
691 687 * the unconstrained bits can be set to any value we wish. Note:
692 688 * if no remote access is required, then the RKey value is not filled
693 689 * in. Otherwise both Rkey and LKey are given the same value.
694 690 */
695 691 key = mpt->hr_indx | (mr->mr_fmr_key++ << HERMON_MEMKEY_SHIFT);
696 692 mr->mr_lkey = mr->mr_rkey = hermon_mr_key_swap(key);
697 693
698 694 /* write mem key value */
699 695 *(uint32_t *)&mpt_table[1] = htonl(key);
700 696
701 697 /* write length value */
702 698 mpt_table[3] = htonll(mem_pattr_p->pmr_len);
703 699
704 700 /* write start addr value */
705 701 mpt_table[2] = htonll(mem_pattr_p->pmr_iova);
706 702
707 703 /* write lkey value */
708 704 *(uint32_t *)&mpt_table[4] = htonl(key);
709 705
710 706 membar_producer();
711 707
712 708 /* Write MPT status to HW bit */
713 709 *(uint8_t *)mpt_table = 0x00;
714 710
715 711 /* Fill in return parameters */
716 712 mem_desc_p->pmd_lkey = mr->mr_lkey;
717 713 mem_desc_p->pmd_rkey = mr->mr_rkey;
718 714 mem_desc_p->pmd_iova = mem_pattr_p->pmr_iova;
719 715 mem_desc_p->pmd_phys_buf_list_sz = mem_pattr_p->pmr_len;
720 716
721 717 /* Fill in MR bindinfo struct for later sync or query operations */
722 718 mr->mr_bindinfo.bi_addr = mem_pattr_p->pmr_iova;
723 719 mr->mr_bindinfo.bi_flags = mem_pattr_p->pmr_flags & IBT_MR_NONCOHERENT;
724 720
725 721 mutex_exit(&mr->mr_lock);
726 722
727 723 return (DDI_SUCCESS);
728 724
729 725 fmr_reg_fail1:
730 726 /*
731 727 * Note, we fail here, and purposely leave the memory ownership in
732 728 * software. The memory tables may be corrupt, so we leave the region
733 729 * unregistered.
734 730 */
735 731 return (status);
736 732 }
737 733
738 734
739 735 /*
740 736 * hermon_mr_deregister()
741 737 * Context: Can be called from interrupt or base context.
742 738 */
743 739 /* ARGSUSED */
744 740 int
745 741 hermon_mr_deregister(hermon_state_t *state, hermon_mrhdl_t *mrhdl, uint_t level,
746 742 uint_t sleep)
747 743 {
748 744 hermon_rsrc_t *mpt, *mtt, *rsrc, *mtt_refcnt;
749 745 hermon_umap_db_entry_t *umapdb;
750 746 hermon_pdhdl_t pd;
751 747 hermon_mrhdl_t mr;
752 748 hermon_bind_info_t *bind;
753 749 uint64_t value;
754 750 int status;
755 751 uint_t shared_mtt;
756 752
757 753 /*
758 754 * Check the sleep flag. Ensure that it is consistent with the
759 755 * current thread context (i.e. if we are currently in the interrupt
760 756 * context, then we shouldn't be attempting to sleep).
761 757 */
762 758 if ((sleep == HERMON_SLEEP) &&
763 759 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
764 760 status = IBT_INVALID_PARAM;
765 761 return (status);
766 762 }
767 763
768 764 /*
769 765 * Pull all the necessary information from the Hermon Memory Region
770 766 * handle. This is necessary here because the resource for the
771 767 * MR handle is going to be freed up as part of the this
772 768 * deregistration
773 769 */
774 770 mr = *mrhdl;
775 771 mutex_enter(&mr->mr_lock);
776 772 mpt = mr->mr_mptrsrcp;
777 773 mtt = mr->mr_mttrsrcp;
778 774 mtt_refcnt = mr->mr_mttrefcntp;
779 775 rsrc = mr->mr_rsrcp;
780 776 pd = mr->mr_pdhdl;
781 777 bind = &mr->mr_bindinfo;
782 778
783 779 /*
784 780 * Check here if the memory region is really an FMR. If so, this is a
785 781 * bad thing and we shouldn't be here. Return failure.
786 782 */
787 783 if (mr->mr_is_fmr) {
788 784 mutex_exit(&mr->mr_lock);
789 785 return (IBT_INVALID_PARAM);
790 786 }
791 787
792 788 /*
793 789 * Check here to see if the memory region has already been partially
794 790 * deregistered as a result of the hermon_umap_umemlock_cb() callback.
795 791 * If so, then jump to the end and free the remaining resources.
796 792 */
797 793 if ((mr->mr_is_umem) && (mr->mr_umemcookie == NULL)) {
798 794 goto mrdereg_finish_cleanup;
799 795 }
800 796 if (hermon_rdma_debug & 0x4)
801 797 IBTF_DPRINTF_L2("mr", "dereg: mr %p key %x",
802 798 mr, mr->mr_rkey);
803 799
804 800 /*
805 801 * We must drop the "mr_lock" here to ensure that both SLEEP and
806 802 * NOSLEEP calls into the firmware work as expected. Also, if two
807 803 * threads are attemping to access this MR (via de-register,
808 804 * re-register, or otherwise), then we allow the firmware to enforce
809 805 * the checking, that only one deregister is valid.
810 806 */
811 807 mutex_exit(&mr->mr_lock);
812 808
813 809 /*
814 810 * Reclaim MPT entry from hardware (if necessary). Since the
815 811 * hermon_mr_deregister() routine is used in the memory region
816 812 * reregistration process as well, it is possible that we will
817 813 * not always wish to reclaim ownership of the MPT. Check the
818 814 * "level" arg and, if necessary, attempt to reclaim it. If
819 815 * the ownership transfer fails for any reason, we check to see
820 816 * what command status was returned from the hardware. The only
821 817 * "expected" error status is the one that indicates an attempt to
822 818 * deregister a memory region that has memory windows bound to it
823 819 */
824 820 if (level >= HERMON_MR_DEREG_ALL) {
825 821 if (mr->mr_mpt_type >= HERMON_MPT_DMPT) {
826 822 status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT,
827 823 NULL, 0, mpt->hr_indx, sleep);
828 824 if (status != HERMON_CMD_SUCCESS) {
829 825 if (status == HERMON_CMD_REG_BOUND) {
830 826 return (IBT_MR_IN_USE);
831 827 } else {
832 828 cmn_err(CE_CONT, "Hermon: HW2SW_MPT "
833 829 "command failed: %08x\n", status);
834 830 if (status ==
835 831 HERMON_CMD_INVALID_STATUS) {
836 832 hermon_fm_ereport(state,
837 833 HCA_SYS_ERR,
838 834 DDI_SERVICE_LOST);
839 835 }
840 836 return (IBT_INVALID_PARAM);
841 837 }
842 838 }
843 839 }
844 840 }
845 841
846 842 /*
847 843 * Re-grab the mr_lock here. Since further access to the protected
848 844 * 'mr' structure is needed, and we would have returned previously for
849 845 * the multiple deregistration case, we can safely grab the lock here.
850 846 */
851 847 mutex_enter(&mr->mr_lock);
852 848
853 849 /*
854 850 * If the memory had come from userland, then we do a lookup in the
855 851 * "userland resources database". On success, we free the entry, call
856 852 * ddi_umem_unlock(), and continue the cleanup. On failure (which is
857 853 * an indication that the umem_lockmemory() callback has called
858 854 * hermon_mr_deregister()), we call ddi_umem_unlock() and invalidate
859 855 * the "mr_umemcookie" field in the MR handle (this will be used
860 856 * later to detect that only partial cleaup still remains to be done
861 857 * on the MR handle).
862 858 */
863 859 if (mr->mr_is_umem) {
864 860 status = hermon_umap_db_find(state->hs_instance,
865 861 (uint64_t)(uintptr_t)mr->mr_umemcookie,
866 862 MLNX_UMAP_MRMEM_RSRC, &value, HERMON_UMAP_DB_REMOVE,
867 863 &umapdb);
868 864 if (status == DDI_SUCCESS) {
869 865 hermon_umap_db_free(umapdb);
870 866 ddi_umem_unlock(mr->mr_umemcookie);
871 867 } else {
872 868 ddi_umem_unlock(mr->mr_umemcookie);
873 869 mr->mr_umemcookie = NULL;
874 870 }
875 871 }
876 872
877 873 /* mtt_refcnt is NULL in the case of hermon_dma_mr_register() */
878 874 if (mtt_refcnt != NULL) {
879 875 /*
880 876 * Decrement the MTT reference count. Since the MTT resource
881 877 * may be shared between multiple memory regions (as a result
882 878 * of a "RegisterSharedMR" verb) it is important that we not
883 879 * free up or unbind resources prematurely. If it's not shared
884 880 * (as indicated by the return status), then free the resource.
885 881 */
886 882 shared_mtt = hermon_mtt_refcnt_dec(mtt_refcnt);
887 883 if (!shared_mtt) {
888 884 hermon_rsrc_free(state, &mtt_refcnt);
889 885 }
890 886
891 887 /*
892 888 * Free up the MTT entries and unbind the memory. Here,
893 889 * as above, we attempt to free these resources only if
894 890 * it is appropriate to do so.
895 891 * Note, 'bind' is NULL in the alloc_lkey case.
896 892 */
897 893 if (!shared_mtt) {
898 894 if (level >= HERMON_MR_DEREG_NO_HW2SW_MPT) {
899 895 hermon_mr_mem_unbind(state, bind);
900 896 }
901 897 hermon_rsrc_free(state, &mtt);
902 898 }
903 899 }
904 900
905 901 /*
906 902 * If the MR handle has been invalidated, then drop the
907 903 * lock and return success. Note: This only happens because
908 904 * the umem_lockmemory() callback has been triggered. The
909 905 * cleanup here is partial, and further cleanup (in a
910 906 * subsequent hermon_mr_deregister() call) will be necessary.
911 907 */
912 908 if ((mr->mr_is_umem) && (mr->mr_umemcookie == NULL)) {
913 909 mutex_exit(&mr->mr_lock);
914 910 return (DDI_SUCCESS);
915 911 }
916 912
917 913 mrdereg_finish_cleanup:
918 914 mutex_exit(&mr->mr_lock);
919 915
920 916 /* Free the Hermon Memory Region handle */
921 917 hermon_rsrc_free(state, &rsrc);
922 918
923 919 /* Free up the MPT entry resource */
924 920 if (mpt != NULL)
925 921 hermon_rsrc_free(state, &mpt);
926 922
927 923 /* Decrement the reference count on the protection domain (PD) */
928 924 hermon_pd_refcnt_dec(pd);
929 925
930 926 /* Set the mrhdl pointer to NULL and return success */
931 927 *mrhdl = NULL;
932 928
933 929 return (DDI_SUCCESS);
934 930 }
935 931
936 932 /*
937 933 * hermon_mr_dealloc_fmr()
938 934 * Context: Can be called from interrupt or base context.
939 935 */
940 936 /* ARGSUSED */
941 937 int
942 938 hermon_mr_dealloc_fmr(hermon_state_t *state, hermon_mrhdl_t *mrhdl)
943 939 {
944 940 hermon_rsrc_t *mpt, *mtt, *rsrc;
945 941 hermon_pdhdl_t pd;
946 942 hermon_mrhdl_t mr;
947 943
948 944 /*
949 945 * Pull all the necessary information from the Hermon Memory Region
950 946 * handle. This is necessary here because the resource for the
951 947 * MR handle is going to be freed up as part of the this
952 948 * deregistration
953 949 */
954 950 mr = *mrhdl;
955 951 mutex_enter(&mr->mr_lock);
956 952 mpt = mr->mr_mptrsrcp;
957 953 mtt = mr->mr_mttrsrcp;
958 954 rsrc = mr->mr_rsrcp;
959 955 pd = mr->mr_pdhdl;
960 956 mutex_exit(&mr->mr_lock);
961 957
962 958 /* Free the MTT entries */
963 959 hermon_rsrc_free(state, &mtt);
964 960
965 961 /* Free the Hermon Memory Region handle */
966 962 hermon_rsrc_free(state, &rsrc);
967 963
968 964 /* Free up the MPT entry resource */
969 965 hermon_rsrc_free(state, &mpt);
970 966
971 967 /* Decrement the reference count on the protection domain (PD) */
972 968 hermon_pd_refcnt_dec(pd);
973 969
974 970 /* Set the mrhdl pointer to NULL and return success */
975 971 *mrhdl = NULL;
976 972
977 973 return (DDI_SUCCESS);
978 974 }
979 975
980 976
981 977 /*
982 978 * hermon_mr_query()
983 979 * Context: Can be called from interrupt or base context.
↓ open down ↓ |
346 lines elided |
↑ open up ↑ |
984 980 */
985 981 /* ARGSUSED */
986 982 int
987 983 hermon_mr_query(hermon_state_t *state, hermon_mrhdl_t mr,
988 984 ibt_mr_query_attr_t *attr)
989 985 {
990 986 int status;
991 987 hermon_hw_dmpt_t mpt_entry;
992 988 uint32_t lkey;
993 989
994 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*attr))
995 -
996 990 mutex_enter(&mr->mr_lock);
997 991
998 992 /*
999 993 * Check here to see if the memory region has already been partially
1000 994 * deregistered as a result of a hermon_umap_umemlock_cb() callback.
1001 995 * If so, this is an error, return failure.
1002 996 */
1003 997 if ((mr->mr_is_umem) && (mr->mr_umemcookie == NULL)) {
1004 998 mutex_exit(&mr->mr_lock);
1005 999 return (IBT_MR_HDL_INVALID);
1006 1000 }
1007 1001
1008 1002 status = hermon_cmn_query_cmd_post(state, QUERY_MPT, 0,
1009 1003 mr->mr_lkey >> 8, &mpt_entry, sizeof (hermon_hw_dmpt_t),
1010 1004 HERMON_NOSLEEP);
1011 1005 if (status != HERMON_CMD_SUCCESS) {
1012 1006 cmn_err(CE_CONT, "Hermon: QUERY_MPT failed: status %x", status);
1013 1007 mutex_exit(&mr->mr_lock);
1014 1008 return (ibc_get_ci_failure(0));
1015 1009 }
1016 1010
1017 1011 /* Update the mr sw struct from the hw struct. */
1018 1012 lkey = mpt_entry.mem_key;
1019 1013 mr->mr_lkey = mr->mr_rkey = (lkey >> 8) | (lkey << 24);
1020 1014 mr->mr_bindinfo.bi_addr = mpt_entry.start_addr;
1021 1015 mr->mr_bindinfo.bi_len = mpt_entry.reg_win_len;
1022 1016 mr->mr_accflag = (mr->mr_accflag & IBT_MR_RO_DISABLED) |
1023 1017 (mpt_entry.lw ? IBT_MR_LOCAL_WRITE : 0) |
1024 1018 (mpt_entry.rr ? IBT_MR_REMOTE_READ : 0) |
1025 1019 (mpt_entry.rw ? IBT_MR_REMOTE_WRITE : 0) |
1026 1020 (mpt_entry.atomic ? IBT_MR_REMOTE_ATOMIC : 0) |
1027 1021 (mpt_entry.en_bind ? IBT_MR_WINDOW_BIND : 0);
1028 1022 mr->mr_mttaddr = ((uint64_t)mpt_entry.mtt_addr_h << 32) |
1029 1023 (mpt_entry.mtt_addr_l << 3);
1030 1024 mr->mr_logmttpgsz = mpt_entry.entity_sz;
1031 1025
1032 1026 /* Fill in the queried attributes */
1033 1027 attr->mr_lkey_state =
1034 1028 (mpt_entry.status == HERMON_MPT_FREE) ? IBT_KEY_FREE :
1035 1029 (mpt_entry.status == HERMON_MPT_SW_OWNERSHIP) ? IBT_KEY_INVALID :
1036 1030 IBT_KEY_VALID;
1037 1031 attr->mr_phys_buf_list_sz = mpt_entry.mtt_size;
1038 1032 attr->mr_attr_flags = mr->mr_accflag;
1039 1033 attr->mr_pd = (ibt_pd_hdl_t)mr->mr_pdhdl;
1040 1034
1041 1035 /* Fill in the "local" attributes */
1042 1036 attr->mr_lkey = (ibt_lkey_t)mr->mr_lkey;
1043 1037 attr->mr_lbounds.pb_addr = (ib_vaddr_t)mr->mr_bindinfo.bi_addr;
1044 1038 attr->mr_lbounds.pb_len = (size_t)mr->mr_bindinfo.bi_len;
1045 1039
1046 1040 /*
1047 1041 * Fill in the "remote" attributes (if necessary). Note: the
1048 1042 * remote attributes are only valid if the memory region has one
1049 1043 * or more of the remote access flags set.
1050 1044 */
1051 1045 if ((mr->mr_accflag & IBT_MR_REMOTE_READ) ||
1052 1046 (mr->mr_accflag & IBT_MR_REMOTE_WRITE) ||
1053 1047 (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC)) {
1054 1048 attr->mr_rkey = (ibt_rkey_t)mr->mr_rkey;
1055 1049 attr->mr_rbounds.pb_addr = (ib_vaddr_t)mr->mr_bindinfo.bi_addr;
1056 1050 attr->mr_rbounds.pb_len = (size_t)mr->mr_bindinfo.bi_len;
1057 1051 }
1058 1052
1059 1053 /*
1060 1054 * If region is mapped for streaming (i.e. noncoherent), then set sync
1061 1055 * is required
1062 1056 */
1063 1057 attr->mr_sync_required = (mr->mr_bindinfo.bi_flags &
1064 1058 IBT_MR_NONCOHERENT) ? B_TRUE : B_FALSE;
1065 1059
1066 1060 mutex_exit(&mr->mr_lock);
1067 1061 return (DDI_SUCCESS);
1068 1062 }
1069 1063
1070 1064
1071 1065 /*
1072 1066 * hermon_mr_reregister()
1073 1067 * Context: Can be called from interrupt or base context.
1074 1068 */
1075 1069 int
1076 1070 hermon_mr_reregister(hermon_state_t *state, hermon_mrhdl_t mr,
1077 1071 hermon_pdhdl_t pd, ibt_mr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl_new,
1078 1072 hermon_mr_options_t *op)
1079 1073 {
1080 1074 hermon_bind_info_t bind;
1081 1075 int status;
1082 1076
1083 1077 /*
1084 1078 * Fill in the "bind" struct. This struct provides the majority
1085 1079 * of the information that will be used to distinguish between an
1086 1080 * "addr" binding (as is the case here) and a "buf" binding (see
1087 1081 * below). The "bind" struct is later passed to hermon_mr_mem_bind()
1088 1082 * which does most of the "heavy lifting" for the Hermon memory
1089 1083 * registration (and reregistration) routines.
1090 1084 */
1091 1085 bind.bi_type = HERMON_BINDHDL_VADDR;
1092 1086 bind.bi_addr = mr_attr->mr_vaddr;
1093 1087 bind.bi_len = mr_attr->mr_len;
1094 1088 bind.bi_as = mr_attr->mr_as;
1095 1089 bind.bi_flags = mr_attr->mr_flags;
1096 1090 status = hermon_mr_common_rereg(state, mr, pd, &bind, mrhdl_new, op);
1097 1091 return (status);
1098 1092 }
1099 1093
1100 1094
1101 1095 /*
1102 1096 * hermon_mr_reregister_buf()
1103 1097 * Context: Can be called from interrupt or base context.
1104 1098 */
1105 1099 int
1106 1100 hermon_mr_reregister_buf(hermon_state_t *state, hermon_mrhdl_t mr,
1107 1101 hermon_pdhdl_t pd, ibt_smr_attr_t *mr_attr, struct buf *buf,
1108 1102 hermon_mrhdl_t *mrhdl_new, hermon_mr_options_t *op)
1109 1103 {
1110 1104 hermon_bind_info_t bind;
1111 1105 int status;
1112 1106
1113 1107 /*
1114 1108 * Fill in the "bind" struct. This struct provides the majority
1115 1109 * of the information that will be used to distinguish between an
1116 1110 * "addr" binding (see above) and a "buf" binding (as is the case
1117 1111 * here). The "bind" struct is later passed to hermon_mr_mem_bind()
1118 1112 * which does most of the "heavy lifting" for the Hermon memory
1119 1113 * registration routines. Note: We have chosen to provide
1120 1114 * "b_un.b_addr" as the IB address (when the IBT_MR_PHYS_IOVA flag is
1121 1115 * not set). It is not critical what value we choose here as it need
1122 1116 * only be unique for the given RKey (which will happen by default),
1123 1117 * so the choice here is somewhat arbitrary.
1124 1118 */
1125 1119 bind.bi_type = HERMON_BINDHDL_BUF;
1126 1120 bind.bi_buf = buf;
1127 1121 if (mr_attr->mr_flags & IBT_MR_PHYS_IOVA) {
1128 1122 bind.bi_addr = mr_attr->mr_vaddr;
1129 1123 } else {
1130 1124 bind.bi_addr = (uint64_t)(uintptr_t)buf->b_un.b_addr;
1131 1125 }
1132 1126 bind.bi_len = (uint64_t)buf->b_bcount;
1133 1127 bind.bi_flags = mr_attr->mr_flags;
1134 1128 bind.bi_as = NULL;
1135 1129 status = hermon_mr_common_rereg(state, mr, pd, &bind, mrhdl_new, op);
1136 1130 return (status);
1137 1131 }
1138 1132
1139 1133
1140 1134 /*
1141 1135 * hermon_mr_sync()
1142 1136 * Context: Can be called from interrupt or base context.
1143 1137 */
1144 1138 /* ARGSUSED */
1145 1139 int
1146 1140 hermon_mr_sync(hermon_state_t *state, ibt_mr_sync_t *mr_segs, size_t num_segs)
1147 1141 {
1148 1142 hermon_mrhdl_t mrhdl;
1149 1143 uint64_t seg_vaddr, seg_len, seg_end;
1150 1144 uint64_t mr_start, mr_end;
1151 1145 uint_t type;
1152 1146 int status, i;
1153 1147
1154 1148 /* Process each of the ibt_mr_sync_t's */
1155 1149 for (i = 0; i < num_segs; i++) {
1156 1150 mrhdl = (hermon_mrhdl_t)mr_segs[i].ms_handle;
1157 1151
1158 1152 /* Check for valid memory region handle */
1159 1153 if (mrhdl == NULL) {
1160 1154 status = IBT_MR_HDL_INVALID;
1161 1155 goto mrsync_fail;
1162 1156 }
1163 1157
1164 1158 mutex_enter(&mrhdl->mr_lock);
1165 1159
1166 1160 /*
1167 1161 * Check here to see if the memory region has already been
1168 1162 * partially deregistered as a result of a
1169 1163 * hermon_umap_umemlock_cb() callback. If so, this is an
1170 1164 * error, return failure.
1171 1165 */
1172 1166 if ((mrhdl->mr_is_umem) && (mrhdl->mr_umemcookie == NULL)) {
1173 1167 mutex_exit(&mrhdl->mr_lock);
1174 1168 status = IBT_MR_HDL_INVALID;
1175 1169 goto mrsync_fail;
1176 1170 }
1177 1171
1178 1172 /* Check for valid bounds on sync request */
1179 1173 seg_vaddr = mr_segs[i].ms_vaddr;
1180 1174 seg_len = mr_segs[i].ms_len;
1181 1175 seg_end = seg_vaddr + seg_len - 1;
1182 1176 mr_start = mrhdl->mr_bindinfo.bi_addr;
1183 1177 mr_end = mr_start + mrhdl->mr_bindinfo.bi_len - 1;
1184 1178 if ((seg_vaddr < mr_start) || (seg_vaddr > mr_end)) {
1185 1179 mutex_exit(&mrhdl->mr_lock);
1186 1180 status = IBT_MR_VA_INVALID;
1187 1181 goto mrsync_fail;
1188 1182 }
1189 1183 if ((seg_end < mr_start) || (seg_end > mr_end)) {
1190 1184 mutex_exit(&mrhdl->mr_lock);
1191 1185 status = IBT_MR_LEN_INVALID;
1192 1186 goto mrsync_fail;
1193 1187 }
1194 1188
1195 1189 /* Determine what type (i.e. direction) for sync */
1196 1190 if (mr_segs[i].ms_flags & IBT_SYNC_READ) {
1197 1191 type = DDI_DMA_SYNC_FORDEV;
1198 1192 } else if (mr_segs[i].ms_flags & IBT_SYNC_WRITE) {
1199 1193 type = DDI_DMA_SYNC_FORCPU;
1200 1194 } else {
1201 1195 mutex_exit(&mrhdl->mr_lock);
1202 1196 status = IBT_INVALID_PARAM;
1203 1197 goto mrsync_fail;
1204 1198 }
1205 1199
1206 1200 (void) ddi_dma_sync(mrhdl->mr_bindinfo.bi_dmahdl,
1207 1201 (off_t)(seg_vaddr - mr_start), (size_t)seg_len, type);
1208 1202
1209 1203 mutex_exit(&mrhdl->mr_lock);
1210 1204 }
1211 1205
1212 1206 return (DDI_SUCCESS);
1213 1207
1214 1208 mrsync_fail:
1215 1209 return (status);
1216 1210 }
1217 1211
1218 1212
1219 1213 /*
1220 1214 * hermon_mw_alloc()
1221 1215 * Context: Can be called from interrupt or base context.
1222 1216 */
1223 1217 int
1224 1218 hermon_mw_alloc(hermon_state_t *state, hermon_pdhdl_t pd, ibt_mw_flags_t flags,
1225 1219 hermon_mwhdl_t *mwhdl)
1226 1220 {
1227 1221 hermon_rsrc_t *mpt, *rsrc;
1228 1222 hermon_hw_dmpt_t mpt_entry;
1229 1223 hermon_mwhdl_t mw;
1230 1224 uint_t sleep;
1231 1225 int status;
1232 1226
1233 1227 if (state != NULL) /* XXX - bogus test that is always TRUE */
1234 1228 return (IBT_INSUFF_RESOURCE);
1235 1229
1236 1230 /*
1237 1231 * Check the sleep flag. Ensure that it is consistent with the
1238 1232 * current thread context (i.e. if we are currently in the interrupt
1239 1233 * context, then we shouldn't be attempting to sleep).
1240 1234 */
1241 1235 sleep = (flags & IBT_MW_NOSLEEP) ? HERMON_NOSLEEP : HERMON_SLEEP;
1242 1236 if ((sleep == HERMON_SLEEP) &&
1243 1237 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
1244 1238 status = IBT_INVALID_PARAM;
1245 1239 goto mwalloc_fail;
1246 1240 }
1247 1241
1248 1242 /* Increment the reference count on the protection domain (PD) */
1249 1243 hermon_pd_refcnt_inc(pd);
1250 1244
1251 1245 /*
1252 1246 * Allocate an MPT entry (for use as a memory window). Since the
1253 1247 * Hermon hardware uses the MPT entry for memory regions and for
1254 1248 * memory windows, we will fill in this MPT with all the necessary
1255 1249 * parameters for the memory window. And then (just as we do for
1256 1250 * memory regions) ownership will be passed to the hardware in the
1257 1251 * final step below. If we fail here, we must undo the protection
1258 1252 * domain reference count.
1259 1253 */
1260 1254 status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
1261 1255 if (status != DDI_SUCCESS) {
1262 1256 status = IBT_INSUFF_RESOURCE;
1263 1257 goto mwalloc_fail1;
1264 1258 }
1265 1259
1266 1260 /*
1267 1261 * Allocate the software structure for tracking the memory window (i.e.
1268 1262 * the Hermon Memory Window handle). Note: This is actually the same
1269 1263 * software structure used for tracking memory regions, but since many
↓ open down ↓ |
264 lines elided |
↑ open up ↑ |
1270 1264 * of the same properties are needed, only a single structure is
1271 1265 * necessary. If we fail here, we must undo the protection domain
1272 1266 * reference count and the previous resource allocation.
1273 1267 */
1274 1268 status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
1275 1269 if (status != DDI_SUCCESS) {
1276 1270 status = IBT_INSUFF_RESOURCE;
1277 1271 goto mwalloc_fail2;
1278 1272 }
1279 1273 mw = (hermon_mwhdl_t)rsrc->hr_addr;
1280 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mw))
1281 1274
1282 1275 /*
1283 1276 * Calculate an "unbound" RKey from MPT index. In much the same way
1284 1277 * as we do for memory regions (above), this key is constructed from
1285 1278 * a "constrained" (which depends on the MPT index) and an
1286 1279 * "unconstrained" portion (which may be arbitrarily chosen).
1287 1280 */
1288 1281 mw->mr_rkey = hermon_mr_keycalc(mpt->hr_indx);
1289 1282
1290 1283 /*
1291 1284 * Fill in the MPT entry. This is the final step before passing
1292 1285 * ownership of the MPT entry to the Hermon hardware. We use all of
1293 1286 * the information collected/calculated above to fill in the
1294 1287 * requisite portions of the MPT. Note: fewer entries in the MPT
1295 1288 * entry are necessary to allocate a memory window.
1296 1289 */
1297 1290 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
1298 1291 mpt_entry.reg_win = HERMON_MPT_IS_WINDOW;
1299 1292 mpt_entry.mem_key = mw->mr_rkey;
1300 1293 mpt_entry.pd = pd->pd_pdnum;
1301 1294 mpt_entry.lr = 1;
1302 1295
1303 1296 /*
1304 1297 * Write the MPT entry to hardware. Lastly, we pass ownership of
1305 1298 * the entry to the hardware. Note: in general, this operation
1306 1299 * shouldn't fail. But if it does, we have to undo everything we've
1307 1300 * done above before returning error.
1308 1301 */
1309 1302 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
1310 1303 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
1311 1304 if (status != HERMON_CMD_SUCCESS) {
1312 1305 cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
1313 1306 status);
1314 1307 if (status == HERMON_CMD_INVALID_STATUS) {
1315 1308 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
1316 1309 }
1317 1310 status = ibc_get_ci_failure(0);
1318 1311 goto mwalloc_fail3;
1319 1312 }
1320 1313
1321 1314 /*
1322 1315 * Fill in the rest of the Hermon Memory Window handle. Having
1323 1316 * successfully transferred ownership of the MPT, we can update the
1324 1317 * following fields for use in further operations on the MW.
1325 1318 */
1326 1319 mw->mr_mptrsrcp = mpt;
1327 1320 mw->mr_pdhdl = pd;
1328 1321 mw->mr_rsrcp = rsrc;
1329 1322 mw->mr_rkey = hermon_mr_key_swap(mw->mr_rkey);
1330 1323 *mwhdl = mw;
1331 1324
1332 1325 return (DDI_SUCCESS);
1333 1326
1334 1327 mwalloc_fail3:
1335 1328 hermon_rsrc_free(state, &rsrc);
1336 1329 mwalloc_fail2:
1337 1330 hermon_rsrc_free(state, &mpt);
1338 1331 mwalloc_fail1:
1339 1332 hermon_pd_refcnt_dec(pd);
1340 1333 mwalloc_fail:
1341 1334 return (status);
1342 1335 }
1343 1336
1344 1337
1345 1338 /*
1346 1339 * hermon_mw_free()
1347 1340 * Context: Can be called from interrupt or base context.
1348 1341 */
1349 1342 int
1350 1343 hermon_mw_free(hermon_state_t *state, hermon_mwhdl_t *mwhdl, uint_t sleep)
1351 1344 {
1352 1345 hermon_rsrc_t *mpt, *rsrc;
1353 1346 hermon_mwhdl_t mw;
1354 1347 int status;
1355 1348 hermon_pdhdl_t pd;
1356 1349
1357 1350 /*
1358 1351 * Check the sleep flag. Ensure that it is consistent with the
1359 1352 * current thread context (i.e. if we are currently in the interrupt
1360 1353 * context, then we shouldn't be attempting to sleep).
1361 1354 */
1362 1355 if ((sleep == HERMON_SLEEP) &&
1363 1356 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
1364 1357 status = IBT_INVALID_PARAM;
1365 1358 return (status);
1366 1359 }
1367 1360
1368 1361 /*
↓ open down ↓ |
78 lines elided |
↑ open up ↑ |
1369 1362 * Pull all the necessary information from the Hermon Memory Window
1370 1363 * handle. This is necessary here because the resource for the
1371 1364 * MW handle is going to be freed up as part of the this operation.
1372 1365 */
1373 1366 mw = *mwhdl;
1374 1367 mutex_enter(&mw->mr_lock);
1375 1368 mpt = mw->mr_mptrsrcp;
1376 1369 rsrc = mw->mr_rsrcp;
1377 1370 pd = mw->mr_pdhdl;
1378 1371 mutex_exit(&mw->mr_lock);
1379 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mw))
1380 1372
1381 1373 /*
1382 1374 * Reclaim the MPT entry from hardware. Note: in general, it is
1383 1375 * unexpected for this operation to return an error.
1384 1376 */
1385 1377 status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT, NULL,
1386 1378 0, mpt->hr_indx, sleep);
1387 1379 if (status != HERMON_CMD_SUCCESS) {
1388 1380 cmn_err(CE_CONT, "Hermon: HW2SW_MPT command failed: %08x\n",
1389 1381 status);
1390 1382 if (status == HERMON_CMD_INVALID_STATUS) {
1391 1383 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
1392 1384 }
1393 1385 return (ibc_get_ci_failure(0));
1394 1386 }
1395 1387
1396 1388 /* Free the Hermon Memory Window handle */
1397 1389 hermon_rsrc_free(state, &rsrc);
1398 1390
1399 1391 /* Free up the MPT entry resource */
1400 1392 hermon_rsrc_free(state, &mpt);
1401 1393
1402 1394 /* Decrement the reference count on the protection domain (PD) */
1403 1395 hermon_pd_refcnt_dec(pd);
1404 1396
1405 1397 /* Set the mwhdl pointer to NULL and return success */
1406 1398 *mwhdl = NULL;
1407 1399
1408 1400 return (DDI_SUCCESS);
1409 1401 }
1410 1402
1411 1403
1412 1404 /*
1413 1405 * hermon_mr_keycalc()
1414 1406 * Context: Can be called from interrupt or base context.
1415 1407 * NOTE: Produces a key in the form of
1416 1408 * KKKKKKKK IIIIIIII IIIIIIII IIIIIIIII
1417 1409 * where K == the arbitrary bits and I == the index
1418 1410 */
1419 1411 uint32_t
1420 1412 hermon_mr_keycalc(uint32_t indx)
1421 1413 {
1422 1414 uint32_t tmp_key, tmp_indx;
1423 1415
1424 1416 /*
1425 1417 * Generate a simple key from counter. Note: We increment this
↓ open down ↓ |
36 lines elided |
↑ open up ↑ |
1426 1418 * static variable _intentionally_ without any kind of mutex around
1427 1419 * it. First, single-threading all operations through a single lock
1428 1420 * would be a bad idea (from a performance point-of-view). Second,
1429 1421 * the upper "unconstrained" bits don't really have to be unique
1430 1422 * because the lower bits are guaranteed to be (although we do make a
1431 1423 * best effort to ensure that they are). Third, the window for the
1432 1424 * race (where both threads read and update the counter at the same
1433 1425 * time) is incredibly small.
1434 1426 * And, lastly, we'd like to make this into a "random" key
1435 1427 */
1436 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hermon_memkey_cnt))
1437 1428 tmp_key = (hermon_memkey_cnt++) << HERMON_MEMKEY_SHIFT;
1438 1429 tmp_indx = indx & 0xffffff;
1439 1430 return (tmp_key | tmp_indx);
1440 1431 }
1441 1432
1442 1433
1443 1434 /*
1444 1435 * hermon_mr_key_swap()
1445 1436 * Context: Can be called from interrupt or base context.
1446 1437 * NOTE: Produces a key in the form of
1447 1438 * IIIIIIII IIIIIIII IIIIIIIII KKKKKKKK
1448 1439 * where K == the arbitrary bits and I == the index
1449 1440 */
1450 1441 uint32_t
1451 1442 hermon_mr_key_swap(uint32_t indx)
1452 1443 {
1453 1444 /*
1454 1445 * The memory key format to pass down to the hardware is
1455 1446 * (key[7:0],index[23:0]), which defines the index to the
1456 1447 * hardware resource. When the driver passes this as a memory
1457 1448 * key, (i.e. to retrieve a resource) the format is
1458 1449 * (index[23:0],key[7:0]).
1459 1450 */
1460 1451 return (((indx >> 24) & 0x000000ff) | ((indx << 8) & 0xffffff00));
1461 1452 }
1462 1453
1463 1454 /*
1464 1455 * hermon_mr_common_reg()
1465 1456 * Context: Can be called from interrupt or base context.
1466 1457 */
1467 1458 static int
1468 1459 hermon_mr_common_reg(hermon_state_t *state, hermon_pdhdl_t pd,
1469 1460 hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl, hermon_mr_options_t *op,
1470 1461 hermon_mpt_rsrc_type_t mpt_type)
1471 1462 {
1472 1463 hermon_rsrc_t *mpt, *mtt, *rsrc, *mtt_refcnt;
1473 1464 hermon_umap_db_entry_t *umapdb;
1474 1465 hermon_sw_refcnt_t *swrc_tmp;
1475 1466 hermon_hw_dmpt_t mpt_entry;
1476 1467 hermon_mrhdl_t mr;
1477 1468 ibt_mr_flags_t flags;
1478 1469 hermon_bind_info_t *bh;
1479 1470 ddi_dma_handle_t bind_dmahdl;
1480 1471 ddi_umem_cookie_t umem_cookie;
1481 1472 size_t umem_len;
1482 1473 caddr_t umem_addr;
1483 1474 uint64_t mtt_addr, max_sz;
1484 1475 uint_t sleep, mtt_pgsize_bits, bind_type, mr_is_umem;
1485 1476 int status, umem_flags, bind_override_addr;
1486 1477
1487 1478 /*
1488 1479 * Check the "options" flag. Currently this flag tells the driver
1489 1480 * whether or not the region should be bound normally (i.e. with
1490 1481 * entries written into the PCI IOMMU), whether it should be
1491 1482 * registered to bypass the IOMMU, and whether or not the resulting
1492 1483 * address should be "zero-based" (to aid the alignment restrictions
1493 1484 * for QPs).
1494 1485 */
1495 1486 if (op == NULL) {
1496 1487 bind_type = HERMON_BINDMEM_NORMAL;
1497 1488 bind_dmahdl = NULL;
1498 1489 bind_override_addr = 0;
1499 1490 } else {
1500 1491 bind_type = op->mro_bind_type;
1501 1492 bind_dmahdl = op->mro_bind_dmahdl;
1502 1493 bind_override_addr = op->mro_bind_override_addr;
1503 1494 }
1504 1495
1505 1496 /* check what kind of mpt to use */
1506 1497
1507 1498 /* Extract the flags field from the hermon_bind_info_t */
1508 1499 flags = bind->bi_flags;
1509 1500
1510 1501 /*
1511 1502 * Check for invalid length. Check is the length is zero or if the
1512 1503 * length is larger than the maximum configured value. Return error
1513 1504 * if it is.
1514 1505 */
1515 1506 max_sz = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_mrw_sz);
1516 1507 if ((bind->bi_len == 0) || (bind->bi_len > max_sz)) {
1517 1508 status = IBT_MR_LEN_INVALID;
1518 1509 goto mrcommon_fail;
1519 1510 }
1520 1511
1521 1512 /*
1522 1513 * Check the sleep flag. Ensure that it is consistent with the
1523 1514 * current thread context (i.e. if we are currently in the interrupt
1524 1515 * context, then we shouldn't be attempting to sleep).
1525 1516 */
1526 1517 sleep = (flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
1527 1518 if ((sleep == HERMON_SLEEP) &&
1528 1519 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
1529 1520 status = IBT_INVALID_PARAM;
1530 1521 goto mrcommon_fail;
1531 1522 }
1532 1523
1533 1524 /* Increment the reference count on the protection domain (PD) */
1534 1525 hermon_pd_refcnt_inc(pd);
1535 1526
1536 1527 /*
1537 1528 * Allocate an MPT entry. This will be filled in with all the
1538 1529 * necessary parameters to define the memory region. And then
1539 1530 * ownership will be passed to the hardware in the final step
1540 1531 * below. If we fail here, we must undo the protection domain
1541 1532 * reference count.
1542 1533 */
1543 1534 if (mpt_type == HERMON_MPT_DMPT) {
1544 1535 status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
1545 1536 if (status != DDI_SUCCESS) {
1546 1537 status = IBT_INSUFF_RESOURCE;
1547 1538 goto mrcommon_fail1;
1548 1539 }
1549 1540 } else {
1550 1541 mpt = NULL;
1551 1542 }
1552 1543
1553 1544 /*
1554 1545 * Allocate the software structure for tracking the memory region (i.e.
↓ open down ↓ |
108 lines elided |
↑ open up ↑ |
1555 1546 * the Hermon Memory Region handle). If we fail here, we must undo
1556 1547 * the protection domain reference count and the previous resource
1557 1548 * allocation.
1558 1549 */
1559 1550 status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
1560 1551 if (status != DDI_SUCCESS) {
1561 1552 status = IBT_INSUFF_RESOURCE;
1562 1553 goto mrcommon_fail2;
1563 1554 }
1564 1555 mr = (hermon_mrhdl_t)rsrc->hr_addr;
1565 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
1566 1556
1567 1557 /*
1568 1558 * Setup and validate the memory region access flags. This means
1569 1559 * translating the IBTF's enable flags into the access flags that
1570 1560 * will be used in later operations.
1571 1561 */
1572 1562 mr->mr_accflag = 0;
1573 1563 if (flags & IBT_MR_ENABLE_WINDOW_BIND)
1574 1564 mr->mr_accflag |= IBT_MR_WINDOW_BIND;
1575 1565 if (flags & IBT_MR_ENABLE_LOCAL_WRITE)
1576 1566 mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
1577 1567 if (flags & IBT_MR_ENABLE_REMOTE_READ)
1578 1568 mr->mr_accflag |= IBT_MR_REMOTE_READ;
1579 1569 if (flags & IBT_MR_ENABLE_REMOTE_WRITE)
1580 1570 mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
1581 1571 if (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
1582 1572 mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
1583 1573
1584 1574 /*
1585 1575 * Calculate keys (Lkey, Rkey) from MPT index. Each key is formed
1586 1576 * from a certain number of "constrained" bits (the least significant
1587 1577 * bits) and some number of "unconstrained" bits. The constrained
1588 1578 * bits must be set to the index of the entry in the MPT table, but
1589 1579 * the unconstrained bits can be set to any value we wish. Note:
1590 1580 * if no remote access is required, then the RKey value is not filled
1591 1581 * in. Otherwise both Rkey and LKey are given the same value.
1592 1582 */
1593 1583 if (mpt)
1594 1584 mr->mr_rkey = mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
1595 1585
1596 1586 /*
1597 1587 * Determine if the memory is from userland and pin the pages
1598 1588 * with umem_lockmemory() if necessary.
1599 1589 * Then, if this is userland memory, allocate an entry in the
1600 1590 * "userland resources database". This will later be added to
1601 1591 * the database (after all further memory registration operations are
1602 1592 * successful). If we fail here, we must undo the reference counts
1603 1593 * and the previous resource allocations.
1604 1594 */
1605 1595 mr_is_umem = (((bind->bi_as != NULL) && (bind->bi_as != &kas)) ? 1 : 0);
1606 1596 if (mr_is_umem) {
1607 1597 umem_len = ptob(btopr(bind->bi_len +
1608 1598 ((uintptr_t)bind->bi_addr & PAGEOFFSET)));
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
1609 1599 umem_addr = (caddr_t)((uintptr_t)bind->bi_addr & ~PAGEOFFSET);
1610 1600 umem_flags = (DDI_UMEMLOCK_WRITE | DDI_UMEMLOCK_READ |
1611 1601 DDI_UMEMLOCK_LONGTERM);
1612 1602 status = umem_lockmemory(umem_addr, umem_len, umem_flags,
1613 1603 &umem_cookie, &hermon_umem_cbops, NULL);
1614 1604 if (status != 0) {
1615 1605 status = IBT_INSUFF_RESOURCE;
1616 1606 goto mrcommon_fail3;
1617 1607 }
1618 1608
1619 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
1620 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind->bi_buf))
1621 -
1622 1609 bind->bi_buf = ddi_umem_iosetup(umem_cookie, 0, umem_len,
1623 1610 B_WRITE, 0, 0, NULL, DDI_UMEM_SLEEP);
1624 1611 if (bind->bi_buf == NULL) {
1625 1612 status = IBT_INSUFF_RESOURCE;
1626 1613 goto mrcommon_fail3;
1627 1614 }
1628 1615 bind->bi_type = HERMON_BINDHDL_UBUF;
1629 1616 bind->bi_buf->b_flags |= B_READ;
1630 1617
1631 - _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind->bi_buf))
1632 - _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind))
1633 -
1634 1618 umapdb = hermon_umap_db_alloc(state->hs_instance,
1635 1619 (uint64_t)(uintptr_t)umem_cookie, MLNX_UMAP_MRMEM_RSRC,
1636 1620 (uint64_t)(uintptr_t)rsrc);
1637 1621 if (umapdb == NULL) {
1638 1622 status = IBT_INSUFF_RESOURCE;
1639 1623 goto mrcommon_fail4;
1640 1624 }
1641 1625 }
1642 1626
1643 1627 /*
1644 1628 * Setup the bindinfo for the mtt bind call
1645 1629 */
1646 1630 bh = &mr->mr_bindinfo;
1647 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bh))
1648 1631 bcopy(bind, bh, sizeof (hermon_bind_info_t));
1649 1632 bh->bi_bypass = bind_type;
1650 1633 status = hermon_mr_mtt_bind(state, bh, bind_dmahdl, &mtt,
1651 1634 &mtt_pgsize_bits, mpt != NULL);
1652 1635 if (status != DDI_SUCCESS) {
1653 1636 /*
1654 1637 * When mtt_bind fails, freerbuf has already been done,
1655 1638 * so make sure not to call it again.
1656 1639 */
1657 1640 bind->bi_type = bh->bi_type;
1658 1641 goto mrcommon_fail5;
1659 1642 }
1660 1643 mr->mr_logmttpgsz = mtt_pgsize_bits;
1661 1644
1662 1645 /*
1663 1646 * Allocate MTT reference count (to track shared memory regions).
1664 1647 * This reference count resource may never be used on the given
1665 1648 * memory region, but if it is ever later registered as "shared"
1666 1649 * memory region then this resource will be necessary. If we fail
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
1667 1650 * here, we do pretty much the same as above to clean up.
1668 1651 */
1669 1652 status = hermon_rsrc_alloc(state, HERMON_REFCNT, 1, sleep,
1670 1653 &mtt_refcnt);
1671 1654 if (status != DDI_SUCCESS) {
1672 1655 status = IBT_INSUFF_RESOURCE;
1673 1656 goto mrcommon_fail6;
1674 1657 }
1675 1658 mr->mr_mttrefcntp = mtt_refcnt;
1676 1659 swrc_tmp = (hermon_sw_refcnt_t *)mtt_refcnt->hr_addr;
1677 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*swrc_tmp))
1678 1660 HERMON_MTT_REFCNT_INIT(swrc_tmp);
1679 1661
1680 1662 mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
1681 1663
1682 1664 /*
1683 1665 * Fill in the MPT entry. This is the final step before passing
1684 1666 * ownership of the MPT entry to the Hermon hardware. We use all of
1685 1667 * the information collected/calculated above to fill in the
1686 1668 * requisite portions of the MPT. Do this ONLY for DMPTs.
1687 1669 */
1688 1670 if (mpt == NULL)
1689 1671 goto no_passown;
1690 1672
1691 1673 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
1692 1674
1693 1675 mpt_entry.status = HERMON_MPT_SW_OWNERSHIP;
1694 1676 mpt_entry.en_bind = (mr->mr_accflag & IBT_MR_WINDOW_BIND) ? 1 : 0;
1695 1677 mpt_entry.atomic = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
1696 1678 mpt_entry.rw = (mr->mr_accflag & IBT_MR_REMOTE_WRITE) ? 1 : 0;
1697 1679 mpt_entry.rr = (mr->mr_accflag & IBT_MR_REMOTE_READ) ? 1 : 0;
1698 1680 mpt_entry.lw = (mr->mr_accflag & IBT_MR_LOCAL_WRITE) ? 1 : 0;
1699 1681 mpt_entry.lr = 1;
1700 1682 mpt_entry.phys_addr = 0;
1701 1683 mpt_entry.reg_win = HERMON_MPT_IS_REGION;
1702 1684
1703 1685 mpt_entry.entity_sz = mr->mr_logmttpgsz;
1704 1686 mpt_entry.mem_key = mr->mr_lkey;
1705 1687 mpt_entry.pd = pd->pd_pdnum;
1706 1688 mpt_entry.rem_acc_en = 0;
1707 1689 mpt_entry.fast_reg_en = 0;
1708 1690 mpt_entry.en_inval = 0;
1709 1691 mpt_entry.lkey = 0;
1710 1692 mpt_entry.win_cnt = 0;
1711 1693
1712 1694 if (bind_override_addr == 0) {
1713 1695 mpt_entry.start_addr = bh->bi_addr;
1714 1696 } else {
1715 1697 bh->bi_addr = bh->bi_addr & ((1 << mr->mr_logmttpgsz) - 1);
1716 1698 mpt_entry.start_addr = bh->bi_addr;
1717 1699 }
1718 1700 mpt_entry.reg_win_len = bh->bi_len;
1719 1701
1720 1702 mpt_entry.mtt_addr_h = mtt_addr >> 32; /* only 8 more bits */
1721 1703 mpt_entry.mtt_addr_l = mtt_addr >> 3; /* only 29 bits */
1722 1704
1723 1705 /*
1724 1706 * Write the MPT entry to hardware. Lastly, we pass ownership of
1725 1707 * the entry to the hardware if needed. Note: in general, this
1726 1708 * operation shouldn't fail. But if it does, we have to undo
1727 1709 * everything we've done above before returning error.
1728 1710 *
1729 1711 * For Hermon, this routine (which is common to the contexts) will only
1730 1712 * set the ownership if needed - the process of passing the context
1731 1713 * itself to HW will take care of setting up the MPT (based on type
1732 1714 * and index).
1733 1715 */
1734 1716
1735 1717 mpt_entry.bnd_qp = 0; /* dMPT for a qp, check for window */
1736 1718 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
1737 1719 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
1738 1720 if (status != HERMON_CMD_SUCCESS) {
1739 1721 cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
1740 1722 status);
1741 1723 if (status == HERMON_CMD_INVALID_STATUS) {
1742 1724 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
1743 1725 }
1744 1726 status = ibc_get_ci_failure(0);
1745 1727 goto mrcommon_fail7;
1746 1728 }
1747 1729 if (hermon_rdma_debug & 0x4)
1748 1730 IBTF_DPRINTF_L2("mr", " reg: mr %p key %x",
1749 1731 mr, hermon_mr_key_swap(mr->mr_rkey));
1750 1732 no_passown:
1751 1733
1752 1734 /*
1753 1735 * Fill in the rest of the Hermon Memory Region handle. Having
1754 1736 * successfully transferred ownership of the MPT, we can update the
1755 1737 * following fields for use in further operations on the MR.
1756 1738 */
1757 1739 mr->mr_mttaddr = mtt_addr;
1758 1740
1759 1741 mr->mr_log2_pgsz = (mr->mr_logmttpgsz - HERMON_PAGESHIFT);
1760 1742 mr->mr_mptrsrcp = mpt;
1761 1743 mr->mr_mttrsrcp = mtt;
1762 1744 mr->mr_pdhdl = pd;
1763 1745 mr->mr_rsrcp = rsrc;
1764 1746 mr->mr_is_umem = mr_is_umem;
1765 1747 mr->mr_is_fmr = 0;
1766 1748 mr->mr_umemcookie = (mr_is_umem != 0) ? umem_cookie : NULL;
1767 1749 mr->mr_umem_cbfunc = NULL;
1768 1750 mr->mr_umem_cbarg1 = NULL;
1769 1751 mr->mr_umem_cbarg2 = NULL;
1770 1752 mr->mr_lkey = hermon_mr_key_swap(mr->mr_lkey);
1771 1753 mr->mr_rkey = hermon_mr_key_swap(mr->mr_rkey);
1772 1754 mr->mr_mpt_type = mpt_type;
1773 1755
1774 1756 /*
1775 1757 * If this is userland memory, then we need to insert the previously
1776 1758 * allocated entry into the "userland resources database". This will
1777 1759 * allow for later coordination between the hermon_umap_umemlock_cb()
1778 1760 * callback and hermon_mr_deregister().
1779 1761 */
1780 1762 if (mr_is_umem) {
1781 1763 hermon_umap_db_add(umapdb);
1782 1764 }
1783 1765
1784 1766 *mrhdl = mr;
1785 1767
1786 1768 return (DDI_SUCCESS);
1787 1769
1788 1770 /*
1789 1771 * The following is cleanup for all possible failure cases in this routine
1790 1772 */
1791 1773 mrcommon_fail7:
1792 1774 hermon_rsrc_free(state, &mtt_refcnt);
1793 1775 mrcommon_fail6:
1794 1776 hermon_mr_mem_unbind(state, bh);
1795 1777 bind->bi_type = bh->bi_type;
1796 1778 mrcommon_fail5:
1797 1779 if (mr_is_umem) {
↓ open down ↓ |
110 lines elided |
↑ open up ↑ |
1798 1780 hermon_umap_db_free(umapdb);
1799 1781 }
1800 1782 mrcommon_fail4:
1801 1783 if (mr_is_umem) {
1802 1784 /*
1803 1785 * Free up the memory ddi_umem_iosetup() allocates
1804 1786 * internally.
1805 1787 */
1806 1788 if (bind->bi_type == HERMON_BINDHDL_UBUF) {
1807 1789 freerbuf(bind->bi_buf);
1808 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
1809 1790 bind->bi_type = HERMON_BINDHDL_NONE;
1810 - _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind))
1811 1791 }
1812 1792 ddi_umem_unlock(umem_cookie);
1813 1793 }
1814 1794 mrcommon_fail3:
1815 1795 hermon_rsrc_free(state, &rsrc);
1816 1796 mrcommon_fail2:
1817 1797 if (mpt != NULL)
1818 1798 hermon_rsrc_free(state, &mpt);
1819 1799 mrcommon_fail1:
1820 1800 hermon_pd_refcnt_dec(pd);
1821 1801 mrcommon_fail:
1822 1802 return (status);
1823 1803 }
1824 1804
1825 1805 /*
1826 1806 * hermon_dma_mr_register()
1827 1807 * Context: Can be called from base context.
1828 1808 */
1829 1809 int
1830 1810 hermon_dma_mr_register(hermon_state_t *state, hermon_pdhdl_t pd,
1831 1811 ibt_dmr_attr_t *mr_attr, hermon_mrhdl_t *mrhdl)
1832 1812 {
1833 1813 hermon_rsrc_t *mpt, *rsrc;
1834 1814 hermon_hw_dmpt_t mpt_entry;
1835 1815 hermon_mrhdl_t mr;
1836 1816 ibt_mr_flags_t flags;
1837 1817 uint_t sleep;
1838 1818 int status;
1839 1819
1840 1820 /* Extract the flags field */
1841 1821 flags = mr_attr->dmr_flags;
1842 1822
1843 1823 /*
1844 1824 * Check the sleep flag. Ensure that it is consistent with the
1845 1825 * current thread context (i.e. if we are currently in the interrupt
1846 1826 * context, then we shouldn't be attempting to sleep).
1847 1827 */
1848 1828 sleep = (flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
1849 1829 if ((sleep == HERMON_SLEEP) &&
1850 1830 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
1851 1831 status = IBT_INVALID_PARAM;
1852 1832 goto mrcommon_fail;
1853 1833 }
1854 1834
1855 1835 /* Increment the reference count on the protection domain (PD) */
1856 1836 hermon_pd_refcnt_inc(pd);
1857 1837
1858 1838 /*
1859 1839 * Allocate an MPT entry. This will be filled in with all the
1860 1840 * necessary parameters to define the memory region. And then
1861 1841 * ownership will be passed to the hardware in the final step
1862 1842 * below. If we fail here, we must undo the protection domain
1863 1843 * reference count.
1864 1844 */
1865 1845 status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
1866 1846 if (status != DDI_SUCCESS) {
1867 1847 status = IBT_INSUFF_RESOURCE;
1868 1848 goto mrcommon_fail1;
1869 1849 }
1870 1850
1871 1851 /*
1872 1852 * Allocate the software structure for tracking the memory region (i.e.
↓ open down ↓ |
52 lines elided |
↑ open up ↑ |
1873 1853 * the Hermon Memory Region handle). If we fail here, we must undo
1874 1854 * the protection domain reference count and the previous resource
1875 1855 * allocation.
1876 1856 */
1877 1857 status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
1878 1858 if (status != DDI_SUCCESS) {
1879 1859 status = IBT_INSUFF_RESOURCE;
1880 1860 goto mrcommon_fail2;
1881 1861 }
1882 1862 mr = (hermon_mrhdl_t)rsrc->hr_addr;
1883 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
1884 1863 bzero(mr, sizeof (*mr));
1885 1864
1886 1865 /*
1887 1866 * Setup and validate the memory region access flags. This means
1888 1867 * translating the IBTF's enable flags into the access flags that
1889 1868 * will be used in later operations.
1890 1869 */
1891 1870 mr->mr_accflag = 0;
1892 1871 if (flags & IBT_MR_ENABLE_WINDOW_BIND)
1893 1872 mr->mr_accflag |= IBT_MR_WINDOW_BIND;
1894 1873 if (flags & IBT_MR_ENABLE_LOCAL_WRITE)
1895 1874 mr->mr_accflag |= IBT_MR_LOCAL_WRITE;
1896 1875 if (flags & IBT_MR_ENABLE_REMOTE_READ)
1897 1876 mr->mr_accflag |= IBT_MR_REMOTE_READ;
1898 1877 if (flags & IBT_MR_ENABLE_REMOTE_WRITE)
1899 1878 mr->mr_accflag |= IBT_MR_REMOTE_WRITE;
1900 1879 if (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
1901 1880 mr->mr_accflag |= IBT_MR_REMOTE_ATOMIC;
1902 1881
1903 1882 /*
1904 1883 * Calculate keys (Lkey, Rkey) from MPT index. Each key is formed
1905 1884 * from a certain number of "constrained" bits (the least significant
1906 1885 * bits) and some number of "unconstrained" bits. The constrained
1907 1886 * bits must be set to the index of the entry in the MPT table, but
1908 1887 * the unconstrained bits can be set to any value we wish. Note:
1909 1888 * if no remote access is required, then the RKey value is not filled
1910 1889 * in. Otherwise both Rkey and LKey are given the same value.
1911 1890 */
1912 1891 if (mpt)
1913 1892 mr->mr_rkey = mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
1914 1893
1915 1894 /*
1916 1895 * Fill in the MPT entry. This is the final step before passing
1917 1896 * ownership of the MPT entry to the Hermon hardware. We use all of
1918 1897 * the information collected/calculated above to fill in the
1919 1898 * requisite portions of the MPT. Do this ONLY for DMPTs.
1920 1899 */
1921 1900 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
1922 1901
1923 1902 mpt_entry.status = HERMON_MPT_SW_OWNERSHIP;
1924 1903 mpt_entry.en_bind = (mr->mr_accflag & IBT_MR_WINDOW_BIND) ? 1 : 0;
1925 1904 mpt_entry.atomic = (mr->mr_accflag & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
1926 1905 mpt_entry.rw = (mr->mr_accflag & IBT_MR_REMOTE_WRITE) ? 1 : 0;
1927 1906 mpt_entry.rr = (mr->mr_accflag & IBT_MR_REMOTE_READ) ? 1 : 0;
1928 1907 mpt_entry.lw = (mr->mr_accflag & IBT_MR_LOCAL_WRITE) ? 1 : 0;
1929 1908 mpt_entry.lr = 1;
1930 1909 mpt_entry.phys_addr = 1; /* critical bit for this */
1931 1910 mpt_entry.reg_win = HERMON_MPT_IS_REGION;
1932 1911
1933 1912 mpt_entry.entity_sz = mr->mr_logmttpgsz;
1934 1913 mpt_entry.mem_key = mr->mr_lkey;
1935 1914 mpt_entry.pd = pd->pd_pdnum;
1936 1915 mpt_entry.rem_acc_en = 0;
1937 1916 mpt_entry.fast_reg_en = 0;
1938 1917 mpt_entry.en_inval = 0;
1939 1918 mpt_entry.lkey = 0;
1940 1919 mpt_entry.win_cnt = 0;
1941 1920
1942 1921 mpt_entry.start_addr = mr_attr->dmr_paddr;
1943 1922 mpt_entry.reg_win_len = mr_attr->dmr_len;
1944 1923 if (mr_attr->dmr_len == 0)
1945 1924 mpt_entry.len_b64 = 1; /* needed for 2^^64 length */
1946 1925
1947 1926 mpt_entry.mtt_addr_h = 0;
1948 1927 mpt_entry.mtt_addr_l = 0;
1949 1928
1950 1929 /*
1951 1930 * Write the MPT entry to hardware. Lastly, we pass ownership of
1952 1931 * the entry to the hardware if needed. Note: in general, this
1953 1932 * operation shouldn't fail. But if it does, we have to undo
1954 1933 * everything we've done above before returning error.
1955 1934 *
1956 1935 * For Hermon, this routine (which is common to the contexts) will only
1957 1936 * set the ownership if needed - the process of passing the context
1958 1937 * itself to HW will take care of setting up the MPT (based on type
1959 1938 * and index).
1960 1939 */
1961 1940
1962 1941 mpt_entry.bnd_qp = 0; /* dMPT for a qp, check for window */
1963 1942 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
1964 1943 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
1965 1944 if (status != HERMON_CMD_SUCCESS) {
1966 1945 cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
1967 1946 status);
1968 1947 if (status == HERMON_CMD_INVALID_STATUS) {
1969 1948 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
1970 1949 }
1971 1950 status = ibc_get_ci_failure(0);
1972 1951 goto mrcommon_fail7;
1973 1952 }
1974 1953
1975 1954 /*
1976 1955 * Fill in the rest of the Hermon Memory Region handle. Having
1977 1956 * successfully transferred ownership of the MPT, we can update the
1978 1957 * following fields for use in further operations on the MR.
1979 1958 */
1980 1959 mr->mr_mttaddr = 0;
1981 1960
1982 1961 mr->mr_log2_pgsz = 0;
1983 1962 mr->mr_mptrsrcp = mpt;
1984 1963 mr->mr_mttrsrcp = NULL;
1985 1964 mr->mr_pdhdl = pd;
1986 1965 mr->mr_rsrcp = rsrc;
1987 1966 mr->mr_is_umem = 0;
1988 1967 mr->mr_is_fmr = 0;
1989 1968 mr->mr_umemcookie = NULL;
1990 1969 mr->mr_umem_cbfunc = NULL;
1991 1970 mr->mr_umem_cbarg1 = NULL;
1992 1971 mr->mr_umem_cbarg2 = NULL;
1993 1972 mr->mr_lkey = hermon_mr_key_swap(mr->mr_lkey);
1994 1973 mr->mr_rkey = hermon_mr_key_swap(mr->mr_rkey);
1995 1974 mr->mr_mpt_type = HERMON_MPT_DMPT;
1996 1975
1997 1976 *mrhdl = mr;
1998 1977
1999 1978 return (DDI_SUCCESS);
2000 1979
2001 1980 /*
2002 1981 * The following is cleanup for all possible failure cases in this routine
2003 1982 */
2004 1983 mrcommon_fail7:
2005 1984 hermon_rsrc_free(state, &rsrc);
2006 1985 mrcommon_fail2:
2007 1986 hermon_rsrc_free(state, &mpt);
2008 1987 mrcommon_fail1:
2009 1988 hermon_pd_refcnt_dec(pd);
2010 1989 mrcommon_fail:
2011 1990 return (status);
2012 1991 }
2013 1992
2014 1993 /*
2015 1994 * hermon_mr_alloc_lkey()
2016 1995 * Context: Can be called from base context.
2017 1996 */
2018 1997 int
2019 1998 hermon_mr_alloc_lkey(hermon_state_t *state, hermon_pdhdl_t pd,
2020 1999 ibt_lkey_flags_t flags, uint_t nummtt, hermon_mrhdl_t *mrhdl)
2021 2000 {
2022 2001 hermon_rsrc_t *mpt, *mtt, *rsrc, *mtt_refcnt;
2023 2002 hermon_sw_refcnt_t *swrc_tmp;
2024 2003 hermon_hw_dmpt_t mpt_entry;
2025 2004 hermon_mrhdl_t mr;
2026 2005 uint64_t mtt_addr;
2027 2006 uint_t sleep;
2028 2007 int status;
2029 2008
2030 2009 /* Increment the reference count on the protection domain (PD) */
2031 2010 hermon_pd_refcnt_inc(pd);
2032 2011
2033 2012 sleep = (flags & IBT_KEY_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
2034 2013
2035 2014 /*
2036 2015 * Allocate an MPT entry. This will be filled in with "some" of the
2037 2016 * necessary parameters to define the memory region. And then
2038 2017 * ownership will be passed to the hardware in the final step
2039 2018 * below. If we fail here, we must undo the protection domain
2040 2019 * reference count.
2041 2020 *
2042 2021 * The MTTs will get filled in when the FRWR is processed.
2043 2022 */
2044 2023 status = hermon_rsrc_alloc(state, HERMON_DMPT, 1, sleep, &mpt);
2045 2024 if (status != DDI_SUCCESS) {
2046 2025 status = IBT_INSUFF_RESOURCE;
2047 2026 goto alloclkey_fail1;
2048 2027 }
2049 2028
2050 2029 /*
2051 2030 * Allocate the software structure for tracking the memory region (i.e.
↓ open down ↓ |
158 lines elided |
↑ open up ↑ |
2052 2031 * the Hermon Memory Region handle). If we fail here, we must undo
2053 2032 * the protection domain reference count and the previous resource
2054 2033 * allocation.
2055 2034 */
2056 2035 status = hermon_rsrc_alloc(state, HERMON_MRHDL, 1, sleep, &rsrc);
2057 2036 if (status != DDI_SUCCESS) {
2058 2037 status = IBT_INSUFF_RESOURCE;
2059 2038 goto alloclkey_fail2;
2060 2039 }
2061 2040 mr = (hermon_mrhdl_t)rsrc->hr_addr;
2062 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
2063 2041 bzero(mr, sizeof (*mr));
2064 2042 mr->mr_bindinfo.bi_type = HERMON_BINDHDL_LKEY;
2065 2043
2066 2044 mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
2067 2045
2068 2046 status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt, sleep, &mtt);
2069 2047 if (status != DDI_SUCCESS) {
2070 2048 status = IBT_INSUFF_RESOURCE;
2071 2049 goto alloclkey_fail3;
2072 2050 }
2073 2051 mr->mr_logmttpgsz = PAGESHIFT;
2074 2052
2075 2053 /*
2076 2054 * Allocate MTT reference count (to track shared memory regions).
2077 2055 * This reference count resource may never be used on the given
2078 2056 * memory region, but if it is ever later registered as "shared"
2079 2057 * memory region then this resource will be necessary. If we fail
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
2080 2058 * here, we do pretty much the same as above to clean up.
2081 2059 */
2082 2060 status = hermon_rsrc_alloc(state, HERMON_REFCNT, 1, sleep,
2083 2061 &mtt_refcnt);
2084 2062 if (status != DDI_SUCCESS) {
2085 2063 status = IBT_INSUFF_RESOURCE;
2086 2064 goto alloclkey_fail4;
2087 2065 }
2088 2066 mr->mr_mttrefcntp = mtt_refcnt;
2089 2067 swrc_tmp = (hermon_sw_refcnt_t *)mtt_refcnt->hr_addr;
2090 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*swrc_tmp))
2091 2068 HERMON_MTT_REFCNT_INIT(swrc_tmp);
2092 2069
2093 2070 mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
2094 2071
2095 2072 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
2096 2073 mpt_entry.status = HERMON_MPT_FREE;
2097 2074 mpt_entry.lw = 1;
2098 2075 mpt_entry.lr = 1;
2099 2076 mpt_entry.reg_win = HERMON_MPT_IS_REGION;
2100 2077 mpt_entry.entity_sz = mr->mr_logmttpgsz;
2101 2078 mpt_entry.mem_key = mr->mr_lkey;
2102 2079 mpt_entry.pd = pd->pd_pdnum;
2103 2080 mpt_entry.fast_reg_en = 1;
2104 2081 mpt_entry.rem_acc_en = 1;
2105 2082 mpt_entry.en_inval = 1;
2106 2083 if (flags & IBT_KEY_REMOTE) {
2107 2084 mpt_entry.ren_inval = 1;
2108 2085 }
2109 2086 mpt_entry.mtt_size = nummtt;
2110 2087 mpt_entry.mtt_addr_h = mtt_addr >> 32; /* only 8 more bits */
2111 2088 mpt_entry.mtt_addr_l = mtt_addr >> 3; /* only 29 bits */
2112 2089
2113 2090 /*
2114 2091 * Write the MPT entry to hardware. Lastly, we pass ownership of
2115 2092 * the entry to the hardware if needed. Note: in general, this
2116 2093 * operation shouldn't fail. But if it does, we have to undo
2117 2094 * everything we've done above before returning error.
2118 2095 *
2119 2096 * For Hermon, this routine (which is common to the contexts) will only
2120 2097 * set the ownership if needed - the process of passing the context
2121 2098 * itself to HW will take care of setting up the MPT (based on type
2122 2099 * and index).
2123 2100 */
2124 2101 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
2125 2102 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, sleep);
2126 2103 if (status != HERMON_CMD_SUCCESS) {
2127 2104 cmn_err(CE_CONT, "Hermon: alloc_lkey: SW2HW_MPT command "
2128 2105 "failed: %08x\n", status);
2129 2106 if (status == HERMON_CMD_INVALID_STATUS) {
2130 2107 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2131 2108 }
2132 2109 status = ibc_get_ci_failure(0);
2133 2110 goto alloclkey_fail5;
2134 2111 }
2135 2112
2136 2113 /*
2137 2114 * Fill in the rest of the Hermon Memory Region handle. Having
2138 2115 * successfully transferred ownership of the MPT, we can update the
2139 2116 * following fields for use in further operations on the MR.
2140 2117 */
2141 2118 mr->mr_accflag = IBT_MR_LOCAL_WRITE;
2142 2119 mr->mr_mttaddr = mtt_addr;
2143 2120 mr->mr_log2_pgsz = (mr->mr_logmttpgsz - HERMON_PAGESHIFT);
2144 2121 mr->mr_mptrsrcp = mpt;
2145 2122 mr->mr_mttrsrcp = mtt;
2146 2123 mr->mr_pdhdl = pd;
2147 2124 mr->mr_rsrcp = rsrc;
2148 2125 mr->mr_lkey = hermon_mr_key_swap(mr->mr_lkey);
2149 2126 mr->mr_rkey = mr->mr_lkey;
2150 2127 mr->mr_mpt_type = HERMON_MPT_DMPT;
2151 2128
2152 2129 *mrhdl = mr;
2153 2130 return (DDI_SUCCESS);
2154 2131
2155 2132 alloclkey_fail5:
2156 2133 hermon_rsrc_free(state, &mtt_refcnt);
2157 2134 alloclkey_fail4:
2158 2135 hermon_rsrc_free(state, &mtt);
2159 2136 alloclkey_fail3:
2160 2137 hermon_rsrc_free(state, &rsrc);
2161 2138 alloclkey_fail2:
2162 2139 hermon_rsrc_free(state, &mpt);
2163 2140 alloclkey_fail1:
2164 2141 hermon_pd_refcnt_dec(pd);
2165 2142 return (status);
2166 2143 }
2167 2144
2168 2145 /*
2169 2146 * hermon_mr_fexch_mpt_init()
2170 2147 * Context: Can be called from base context.
2171 2148 *
2172 2149 * This is the same as alloc_lkey, but not returning an mrhdl.
2173 2150 */
2174 2151 int
2175 2152 hermon_mr_fexch_mpt_init(hermon_state_t *state, hermon_pdhdl_t pd,
2176 2153 uint32_t mpt_indx, uint_t nummtt, uint64_t mtt_addr, uint_t sleep)
2177 2154 {
2178 2155 hermon_hw_dmpt_t mpt_entry;
2179 2156 int status;
2180 2157
2181 2158 /*
2182 2159 * The MTTs will get filled in when the FRWR is processed.
2183 2160 */
2184 2161
2185 2162 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
2186 2163 mpt_entry.status = HERMON_MPT_FREE;
2187 2164 mpt_entry.lw = 1;
2188 2165 mpt_entry.lr = 1;
2189 2166 mpt_entry.rw = 1;
2190 2167 mpt_entry.rr = 1;
2191 2168 mpt_entry.reg_win = HERMON_MPT_IS_REGION;
2192 2169 mpt_entry.entity_sz = PAGESHIFT;
2193 2170 mpt_entry.mem_key = mpt_indx;
2194 2171 mpt_entry.pd = pd->pd_pdnum;
2195 2172 mpt_entry.fast_reg_en = 1;
2196 2173 mpt_entry.rem_acc_en = 1;
2197 2174 mpt_entry.en_inval = 1;
2198 2175 mpt_entry.ren_inval = 1;
2199 2176 mpt_entry.mtt_size = nummtt;
2200 2177 mpt_entry.mtt_addr_h = mtt_addr >> 32; /* only 8 more bits */
2201 2178 mpt_entry.mtt_addr_l = mtt_addr >> 3; /* only 29 bits */
2202 2179
2203 2180 /*
2204 2181 * Write the MPT entry to hardware. Lastly, we pass ownership of
2205 2182 * the entry to the hardware if needed. Note: in general, this
2206 2183 * operation shouldn't fail. But if it does, we have to undo
2207 2184 * everything we've done above before returning error.
2208 2185 *
2209 2186 * For Hermon, this routine (which is common to the contexts) will only
2210 2187 * set the ownership if needed - the process of passing the context
2211 2188 * itself to HW will take care of setting up the MPT (based on type
2212 2189 * and index).
2213 2190 */
2214 2191 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
2215 2192 sizeof (hermon_hw_dmpt_t), mpt_indx, sleep);
2216 2193 if (status != HERMON_CMD_SUCCESS) {
2217 2194 cmn_err(CE_CONT, "Hermon: fexch_mpt_init: SW2HW_MPT command "
2218 2195 "failed: %08x\n", status);
2219 2196 if (status == HERMON_CMD_INVALID_STATUS) {
2220 2197 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2221 2198 }
2222 2199 status = ibc_get_ci_failure(0);
2223 2200 return (status);
2224 2201 }
2225 2202 /* Increment the reference count on the protection domain (PD) */
2226 2203 hermon_pd_refcnt_inc(pd);
2227 2204
2228 2205 return (DDI_SUCCESS);
2229 2206 }
2230 2207
2231 2208 /*
2232 2209 * hermon_mr_fexch_mpt_fini()
2233 2210 * Context: Can be called from base context.
2234 2211 *
2235 2212 * This is the same as deregister_mr, without an mrhdl.
2236 2213 */
2237 2214 int
2238 2215 hermon_mr_fexch_mpt_fini(hermon_state_t *state, hermon_pdhdl_t pd,
2239 2216 uint32_t mpt_indx, uint_t sleep)
2240 2217 {
2241 2218 int status;
2242 2219
2243 2220 status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT,
2244 2221 NULL, 0, mpt_indx, sleep);
2245 2222 if (status != DDI_SUCCESS) {
2246 2223 cmn_err(CE_CONT, "Hermon: fexch_mpt_fini: HW2SW_MPT command "
2247 2224 "failed: %08x\n", status);
2248 2225 if (status == HERMON_CMD_INVALID_STATUS) {
2249 2226 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2250 2227 }
2251 2228 status = ibc_get_ci_failure(0);
2252 2229 return (status);
2253 2230 }
2254 2231
2255 2232 /* Decrement the reference count on the protection domain (PD) */
2256 2233 hermon_pd_refcnt_dec(pd);
2257 2234
2258 2235 return (DDI_SUCCESS);
2259 2236 }
2260 2237
2261 2238 /*
2262 2239 * hermon_mr_mtt_bind()
2263 2240 * Context: Can be called from interrupt or base context.
2264 2241 */
2265 2242 int
2266 2243 hermon_mr_mtt_bind(hermon_state_t *state, hermon_bind_info_t *bind,
2267 2244 ddi_dma_handle_t bind_dmahdl, hermon_rsrc_t **mtt, uint_t *mtt_pgsize_bits,
2268 2245 uint_t is_buffer)
2269 2246 {
2270 2247 uint64_t nummtt;
2271 2248 uint_t sleep;
2272 2249 int status;
2273 2250
2274 2251 /*
2275 2252 * Check the sleep flag. Ensure that it is consistent with the
2276 2253 * current thread context (i.e. if we are currently in the interrupt
2277 2254 * context, then we shouldn't be attempting to sleep).
2278 2255 */
2279 2256 sleep = (bind->bi_flags & IBT_MR_NOSLEEP) ?
2280 2257 HERMON_NOSLEEP : HERMON_SLEEP;
2281 2258 if ((sleep == HERMON_SLEEP) &&
2282 2259 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
2283 2260 status = IBT_INVALID_PARAM;
2284 2261 goto mrmttbind_fail;
2285 2262 }
2286 2263
2287 2264 /*
2288 2265 * Bind the memory and determine the mapped addresses. This is
2289 2266 * the first of two routines that do all the "heavy lifting" for
2290 2267 * the Hermon memory registration routines. The hermon_mr_mem_bind()
2291 2268 * routine takes the "bind" struct with all its fields filled
2292 2269 * in and returns a list of DMA cookies (for the PCI mapped addresses
2293 2270 * corresponding to the specified address region) which are used by
2294 2271 * the hermon_mr_fast_mtt_write() routine below. If we fail here, we
2295 2272 * must undo all the previous resource allocation (and PD reference
2296 2273 * count).
2297 2274 */
2298 2275 status = hermon_mr_mem_bind(state, bind, bind_dmahdl, sleep, is_buffer);
2299 2276 if (status != DDI_SUCCESS) {
2300 2277 status = IBT_INSUFF_RESOURCE;
2301 2278 goto mrmttbind_fail;
2302 2279 }
2303 2280
2304 2281 /*
2305 2282 * Determine number of pages spanned. This routine uses the
2306 2283 * information in the "bind" struct to determine the required
2307 2284 * number of MTT entries needed (and returns the suggested page size -
2308 2285 * as a "power-of-2" - for each MTT entry).
2309 2286 */
2310 2287 nummtt = hermon_mr_nummtt_needed(state, bind, mtt_pgsize_bits);
2311 2288
2312 2289 /*
2313 2290 * Allocate the MTT entries. Use the calculations performed above to
2314 2291 * allocate the required number of MTT entries. If we fail here, we
2315 2292 * must not only undo all the previous resource allocation (and PD
2316 2293 * reference count), but we must also unbind the memory.
2317 2294 */
2318 2295 status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt, sleep, mtt);
2319 2296 if (status != DDI_SUCCESS) {
2320 2297 status = IBT_INSUFF_RESOURCE;
2321 2298 goto mrmttbind_fail2;
2322 2299 }
2323 2300
2324 2301 /*
2325 2302 * Write the mapped addresses into the MTT entries. This is part two
2326 2303 * of the "heavy lifting" routines that we talked about above. Note:
2327 2304 * we pass the suggested page size from the earlier operation here.
2328 2305 * And if we fail here, we again do pretty much the same huge clean up.
2329 2306 */
2330 2307 status = hermon_mr_fast_mtt_write(state, *mtt, bind, *mtt_pgsize_bits);
2331 2308 if (status != DDI_SUCCESS) {
2332 2309 /*
2333 2310 * hermon_mr_fast_mtt_write() returns DDI_FAILURE
2334 2311 * only if it detects a HW error during DMA.
2335 2312 */
2336 2313 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2337 2314 status = ibc_get_ci_failure(0);
2338 2315 goto mrmttbind_fail3;
2339 2316 }
2340 2317 return (DDI_SUCCESS);
2341 2318
2342 2319 /*
2343 2320 * The following is cleanup for all possible failure cases in this routine
2344 2321 */
2345 2322 mrmttbind_fail3:
2346 2323 hermon_rsrc_free(state, mtt);
2347 2324 mrmttbind_fail2:
2348 2325 hermon_mr_mem_unbind(state, bind);
2349 2326 mrmttbind_fail:
2350 2327 return (status);
2351 2328 }
2352 2329
2353 2330
2354 2331 /*
2355 2332 * hermon_mr_mtt_unbind()
2356 2333 * Context: Can be called from interrupt or base context.
2357 2334 */
2358 2335 int
2359 2336 hermon_mr_mtt_unbind(hermon_state_t *state, hermon_bind_info_t *bind,
2360 2337 hermon_rsrc_t *mtt)
2361 2338 {
2362 2339 /*
2363 2340 * Free up the MTT entries and unbind the memory. Here, as above, we
2364 2341 * attempt to free these resources only if it is appropriate to do so.
2365 2342 */
2366 2343 hermon_mr_mem_unbind(state, bind);
2367 2344 hermon_rsrc_free(state, &mtt);
2368 2345
2369 2346 return (DDI_SUCCESS);
2370 2347 }
2371 2348
2372 2349
2373 2350 /*
2374 2351 * hermon_mr_common_rereg()
2375 2352 * Context: Can be called from interrupt or base context.
2376 2353 */
2377 2354 static int
2378 2355 hermon_mr_common_rereg(hermon_state_t *state, hermon_mrhdl_t mr,
2379 2356 hermon_pdhdl_t pd, hermon_bind_info_t *bind, hermon_mrhdl_t *mrhdl_new,
2380 2357 hermon_mr_options_t *op)
↓ open down ↓ |
280 lines elided |
↑ open up ↑ |
2381 2358 {
2382 2359 hermon_rsrc_t *mpt;
2383 2360 ibt_mr_attr_flags_t acc_flags_to_use;
2384 2361 ibt_mr_flags_t flags;
2385 2362 hermon_pdhdl_t pd_to_use;
2386 2363 hermon_hw_dmpt_t mpt_entry;
2387 2364 uint64_t mtt_addr_to_use, vaddr_to_use, len_to_use;
2388 2365 uint_t sleep, dereg_level;
2389 2366 int status;
2390 2367
2391 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
2392 -
2393 2368 /*
2394 2369 * Check here to see if the memory region corresponds to a userland
2395 2370 * mapping. Reregistration of userland memory regions is not
2396 2371 * currently supported. Return failure.
2397 2372 */
2398 2373 if (mr->mr_is_umem) {
2399 2374 status = IBT_MR_HDL_INVALID;
2400 2375 goto mrrereg_fail;
2401 2376 }
2402 2377
2403 2378 mutex_enter(&mr->mr_lock);
2404 2379
2405 2380 /* Pull MPT resource pointer from the Hermon Memory Region handle */
2406 2381 mpt = mr->mr_mptrsrcp;
2407 2382
2408 2383 /* Extract the flags field from the hermon_bind_info_t */
2409 2384 flags = bind->bi_flags;
2410 2385
2411 2386 /*
2412 2387 * Check the sleep flag. Ensure that it is consistent with the
2413 2388 * current thread context (i.e. if we are currently in the interrupt
2414 2389 * context, then we shouldn't be attempting to sleep).
2415 2390 */
2416 2391 sleep = (flags & IBT_MR_NOSLEEP) ? HERMON_NOSLEEP: HERMON_SLEEP;
2417 2392 if ((sleep == HERMON_SLEEP) &&
2418 2393 (sleep != HERMON_SLEEPFLAG_FOR_CONTEXT())) {
2419 2394 mutex_exit(&mr->mr_lock);
2420 2395 status = IBT_INVALID_PARAM;
2421 2396 goto mrrereg_fail;
2422 2397 }
2423 2398
2424 2399 /*
2425 2400 * First step is to temporarily invalidate the MPT entry. This
2426 2401 * regains ownership from the hardware, and gives us the opportunity
2427 2402 * to modify the entry. Note: The HW2SW_MPT command returns the
2428 2403 * current MPT entry contents. These are saved away here because
2429 2404 * they will be reused in a later step below. If the region has
2430 2405 * bound memory windows that we fail returning an "in use" error code.
2431 2406 * Otherwise, this is an unexpected error and we deregister the
2432 2407 * memory region and return error.
2433 2408 *
2434 2409 * We use HERMON_CMD_NOSLEEP_SPIN here always because we must protect
2435 2410 * against holding the lock around this rereg call in all contexts.
2436 2411 */
2437 2412 status = hermon_cmn_ownership_cmd_post(state, HW2SW_MPT, &mpt_entry,
2438 2413 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, HERMON_CMD_NOSLEEP_SPIN);
2439 2414 if (status != HERMON_CMD_SUCCESS) {
2440 2415 mutex_exit(&mr->mr_lock);
2441 2416 if (status == HERMON_CMD_REG_BOUND) {
2442 2417 return (IBT_MR_IN_USE);
2443 2418 } else {
2444 2419 cmn_err(CE_CONT, "Hermon: HW2SW_MPT command failed: "
2445 2420 "%08x\n", status);
2446 2421 if (status == HERMON_CMD_INVALID_STATUS) {
2447 2422 hermon_fm_ereport(state, HCA_SYS_ERR,
2448 2423 HCA_ERR_SRV_LOST);
2449 2424 }
2450 2425 /*
2451 2426 * Call deregister and ensure that all current
2452 2427 * resources get freed up
2453 2428 */
2454 2429 if (hermon_mr_deregister(state, &mr,
2455 2430 HERMON_MR_DEREG_ALL, sleep) != DDI_SUCCESS) {
2456 2431 HERMON_WARNING(state, "failed to deregister "
2457 2432 "memory region");
2458 2433 }
2459 2434 return (ibc_get_ci_failure(0));
2460 2435 }
2461 2436 }
2462 2437
2463 2438 /*
2464 2439 * If we're changing the protection domain, then validate the new one
2465 2440 */
2466 2441 if (flags & IBT_MR_CHANGE_PD) {
2467 2442
2468 2443 /* Check for valid PD handle pointer */
2469 2444 if (pd == NULL) {
2470 2445 mutex_exit(&mr->mr_lock);
2471 2446 /*
2472 2447 * Call deregister and ensure that all current
2473 2448 * resources get properly freed up. Unnecessary
2474 2449 * here to attempt to regain software ownership
2475 2450 * of the MPT entry as that has already been
2476 2451 * done above.
2477 2452 */
2478 2453 if (hermon_mr_deregister(state, &mr,
2479 2454 HERMON_MR_DEREG_NO_HW2SW_MPT, sleep) !=
2480 2455 DDI_SUCCESS) {
2481 2456 HERMON_WARNING(state, "failed to deregister "
2482 2457 "memory region");
2483 2458 }
2484 2459 status = IBT_PD_HDL_INVALID;
2485 2460 goto mrrereg_fail;
2486 2461 }
2487 2462
2488 2463 /* Use the new PD handle in all operations below */
2489 2464 pd_to_use = pd;
2490 2465
2491 2466 } else {
2492 2467 /* Use the current PD handle in all operations below */
2493 2468 pd_to_use = mr->mr_pdhdl;
2494 2469 }
2495 2470
2496 2471 /*
2497 2472 * If we're changing access permissions, then validate the new ones
2498 2473 */
2499 2474 if (flags & IBT_MR_CHANGE_ACCESS) {
2500 2475 /*
2501 2476 * Validate the access flags. Both remote write and remote
2502 2477 * atomic require the local write flag to be set
2503 2478 */
2504 2479 if (((flags & IBT_MR_ENABLE_REMOTE_WRITE) ||
2505 2480 (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)) &&
2506 2481 !(flags & IBT_MR_ENABLE_LOCAL_WRITE)) {
2507 2482 mutex_exit(&mr->mr_lock);
2508 2483 /*
2509 2484 * Call deregister and ensure that all current
2510 2485 * resources get properly freed up. Unnecessary
2511 2486 * here to attempt to regain software ownership
2512 2487 * of the MPT entry as that has already been
2513 2488 * done above.
2514 2489 */
2515 2490 if (hermon_mr_deregister(state, &mr,
2516 2491 HERMON_MR_DEREG_NO_HW2SW_MPT, sleep) !=
2517 2492 DDI_SUCCESS) {
2518 2493 HERMON_WARNING(state, "failed to deregister "
2519 2494 "memory region");
2520 2495 }
2521 2496 status = IBT_MR_ACCESS_REQ_INVALID;
2522 2497 goto mrrereg_fail;
2523 2498 }
2524 2499
2525 2500 /*
2526 2501 * Setup and validate the memory region access flags. This
2527 2502 * means translating the IBTF's enable flags into the access
2528 2503 * flags that will be used in later operations.
2529 2504 */
2530 2505 acc_flags_to_use = 0;
2531 2506 if (flags & IBT_MR_ENABLE_WINDOW_BIND)
2532 2507 acc_flags_to_use |= IBT_MR_WINDOW_BIND;
2533 2508 if (flags & IBT_MR_ENABLE_LOCAL_WRITE)
2534 2509 acc_flags_to_use |= IBT_MR_LOCAL_WRITE;
2535 2510 if (flags & IBT_MR_ENABLE_REMOTE_READ)
2536 2511 acc_flags_to_use |= IBT_MR_REMOTE_READ;
2537 2512 if (flags & IBT_MR_ENABLE_REMOTE_WRITE)
2538 2513 acc_flags_to_use |= IBT_MR_REMOTE_WRITE;
2539 2514 if (flags & IBT_MR_ENABLE_REMOTE_ATOMIC)
2540 2515 acc_flags_to_use |= IBT_MR_REMOTE_ATOMIC;
2541 2516
2542 2517 } else {
2543 2518 acc_flags_to_use = mr->mr_accflag;
2544 2519 }
2545 2520
2546 2521 /*
2547 2522 * If we're modifying the translation, then figure out whether
2548 2523 * we can reuse the current MTT resources. This means calling
2549 2524 * hermon_mr_rereg_xlat_helper() which does most of the heavy lifting
2550 2525 * for the reregistration. If the current memory region contains
2551 2526 * sufficient MTT entries for the new regions, then it will be
2552 2527 * reused and filled in. Otherwise, new entries will be allocated,
2553 2528 * the old ones will be freed, and the new entries will be filled
2554 2529 * in. Note: If we're not modifying the translation, then we
2555 2530 * should already have all the information we need to update the MPT.
2556 2531 * Also note: If hermon_mr_rereg_xlat_helper() fails, it will return
2557 2532 * a "dereg_level" which is the level of cleanup that needs to be
2558 2533 * passed to hermon_mr_deregister() to finish the cleanup.
2559 2534 */
2560 2535 if (flags & IBT_MR_CHANGE_TRANSLATION) {
2561 2536 status = hermon_mr_rereg_xlat_helper(state, mr, bind, op,
2562 2537 &mtt_addr_to_use, sleep, &dereg_level);
2563 2538 if (status != DDI_SUCCESS) {
2564 2539 mutex_exit(&mr->mr_lock);
2565 2540 /*
2566 2541 * Call deregister and ensure that all resources get
2567 2542 * properly freed up.
2568 2543 */
2569 2544 if (hermon_mr_deregister(state, &mr, dereg_level,
2570 2545 sleep) != DDI_SUCCESS) {
2571 2546 HERMON_WARNING(state, "failed to deregister "
2572 2547 "memory region");
2573 2548 }
2574 2549 goto mrrereg_fail;
2575 2550 }
2576 2551 vaddr_to_use = mr->mr_bindinfo.bi_addr;
2577 2552 len_to_use = mr->mr_bindinfo.bi_len;
2578 2553 } else {
2579 2554 mtt_addr_to_use = mr->mr_mttaddr;
2580 2555 vaddr_to_use = mr->mr_bindinfo.bi_addr;
2581 2556 len_to_use = mr->mr_bindinfo.bi_len;
2582 2557 }
2583 2558
2584 2559 /*
2585 2560 * Calculate new keys (Lkey, Rkey) from MPT index. Just like they were
2586 2561 * when the region was first registered, each key is formed from
2587 2562 * "constrained" bits and "unconstrained" bits. Note: If no remote
2588 2563 * access is required, then the RKey value is not filled in. Otherwise
2589 2564 * both Rkey and LKey are given the same value.
2590 2565 */
2591 2566 mr->mr_lkey = hermon_mr_keycalc(mpt->hr_indx);
2592 2567 if ((acc_flags_to_use & IBT_MR_REMOTE_READ) ||
2593 2568 (acc_flags_to_use & IBT_MR_REMOTE_WRITE) ||
2594 2569 (acc_flags_to_use & IBT_MR_REMOTE_ATOMIC)) {
2595 2570 mr->mr_rkey = mr->mr_lkey;
2596 2571 } else
2597 2572 mr->mr_rkey = 0;
2598 2573
2599 2574 /*
2600 2575 * Fill in the MPT entry. This is the final step before passing
2601 2576 * ownership of the MPT entry to the Hermon hardware. We use all of
2602 2577 * the information collected/calculated above to fill in the
2603 2578 * requisite portions of the MPT.
2604 2579 */
2605 2580 bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
2606 2581
2607 2582 mpt_entry.status = HERMON_MPT_SW_OWNERSHIP;
2608 2583 mpt_entry.en_bind = (acc_flags_to_use & IBT_MR_WINDOW_BIND) ? 1 : 0;
2609 2584 mpt_entry.atomic = (acc_flags_to_use & IBT_MR_REMOTE_ATOMIC) ? 1 : 0;
2610 2585 mpt_entry.rw = (acc_flags_to_use & IBT_MR_REMOTE_WRITE) ? 1 : 0;
2611 2586 mpt_entry.rr = (acc_flags_to_use & IBT_MR_REMOTE_READ) ? 1 : 0;
2612 2587 mpt_entry.lw = (acc_flags_to_use & IBT_MR_LOCAL_WRITE) ? 1 : 0;
2613 2588 mpt_entry.lr = 1;
2614 2589 mpt_entry.phys_addr = 0;
2615 2590 mpt_entry.reg_win = HERMON_MPT_IS_REGION;
2616 2591
2617 2592 mpt_entry.entity_sz = mr->mr_logmttpgsz;
2618 2593 mpt_entry.mem_key = mr->mr_lkey;
2619 2594 mpt_entry.pd = pd_to_use->pd_pdnum;
2620 2595
2621 2596 mpt_entry.start_addr = vaddr_to_use;
2622 2597 mpt_entry.reg_win_len = len_to_use;
2623 2598 mpt_entry.mtt_addr_h = mtt_addr_to_use >> 32;
2624 2599 mpt_entry.mtt_addr_l = mtt_addr_to_use >> 3;
2625 2600
2626 2601 /*
2627 2602 * Write the updated MPT entry to hardware
2628 2603 *
2629 2604 * We use HERMON_CMD_NOSLEEP_SPIN here always because we must protect
2630 2605 * against holding the lock around this rereg call in all contexts.
2631 2606 */
2632 2607 status = hermon_cmn_ownership_cmd_post(state, SW2HW_MPT, &mpt_entry,
2633 2608 sizeof (hermon_hw_dmpt_t), mpt->hr_indx, HERMON_CMD_NOSLEEP_SPIN);
2634 2609 if (status != HERMON_CMD_SUCCESS) {
2635 2610 mutex_exit(&mr->mr_lock);
2636 2611 cmn_err(CE_CONT, "Hermon: SW2HW_MPT command failed: %08x\n",
2637 2612 status);
2638 2613 if (status == HERMON_CMD_INVALID_STATUS) {
2639 2614 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2640 2615 }
2641 2616 /*
2642 2617 * Call deregister and ensure that all current resources get
2643 2618 * properly freed up. Unnecessary here to attempt to regain
2644 2619 * software ownership of the MPT entry as that has already
2645 2620 * been done above.
2646 2621 */
2647 2622 if (hermon_mr_deregister(state, &mr,
2648 2623 HERMON_MR_DEREG_NO_HW2SW_MPT, sleep) != DDI_SUCCESS) {
2649 2624 HERMON_WARNING(state, "failed to deregister memory "
2650 2625 "region");
2651 2626 }
2652 2627 return (ibc_get_ci_failure(0));
2653 2628 }
2654 2629
2655 2630 /*
2656 2631 * If we're changing PD, then update their reference counts now.
2657 2632 * This means decrementing the reference count on the old PD and
2658 2633 * incrementing the reference count on the new PD.
2659 2634 */
2660 2635 if (flags & IBT_MR_CHANGE_PD) {
2661 2636 hermon_pd_refcnt_dec(mr->mr_pdhdl);
2662 2637 hermon_pd_refcnt_inc(pd);
2663 2638 }
2664 2639
2665 2640 /*
2666 2641 * Update the contents of the Hermon Memory Region handle to reflect
2667 2642 * what has been changed.
2668 2643 */
2669 2644 mr->mr_pdhdl = pd_to_use;
2670 2645 mr->mr_accflag = acc_flags_to_use;
2671 2646 mr->mr_is_umem = 0;
2672 2647 mr->mr_is_fmr = 0;
2673 2648 mr->mr_umemcookie = NULL;
2674 2649 mr->mr_lkey = hermon_mr_key_swap(mr->mr_lkey);
2675 2650 mr->mr_rkey = hermon_mr_key_swap(mr->mr_rkey);
2676 2651
2677 2652 /* New MR handle is same as the old */
2678 2653 *mrhdl_new = mr;
2679 2654 mutex_exit(&mr->mr_lock);
2680 2655
2681 2656 return (DDI_SUCCESS);
2682 2657
2683 2658 mrrereg_fail:
2684 2659 return (status);
2685 2660 }
2686 2661
2687 2662
2688 2663 /*
2689 2664 * hermon_mr_rereg_xlat_helper
2690 2665 * Context: Can be called from interrupt or base context.
2691 2666 * Note: This routine expects the "mr_lock" to be held when it
2692 2667 * is called. Upon returning failure, this routine passes information
2693 2668 * about what "dereg_level" should be passed to hermon_mr_deregister().
2694 2669 */
2695 2670 static int
2696 2671 hermon_mr_rereg_xlat_helper(hermon_state_t *state, hermon_mrhdl_t mr,
2697 2672 hermon_bind_info_t *bind, hermon_mr_options_t *op, uint64_t *mtt_addr,
2698 2673 uint_t sleep, uint_t *dereg_level)
2699 2674 {
2700 2675 hermon_rsrc_t *mtt, *mtt_refcnt;
2701 2676 hermon_sw_refcnt_t *swrc_old, *swrc_new;
2702 2677 ddi_dma_handle_t dmahdl;
2703 2678 uint64_t nummtt_needed, nummtt_in_currrsrc, max_sz;
2704 2679 uint_t mtt_pgsize_bits, bind_type, reuse_dmahdl;
2705 2680 int status;
2706 2681
2707 2682 ASSERT(MUTEX_HELD(&mr->mr_lock));
2708 2683
2709 2684 /*
2710 2685 * Check the "options" flag. Currently this flag tells the driver
2711 2686 * whether or not the region should be bound normally (i.e. with
2712 2687 * entries written into the PCI IOMMU) or whether it should be
2713 2688 * registered to bypass the IOMMU.
2714 2689 */
2715 2690 if (op == NULL) {
2716 2691 bind_type = HERMON_BINDMEM_NORMAL;
2717 2692 } else {
2718 2693 bind_type = op->mro_bind_type;
2719 2694 }
2720 2695
2721 2696 /*
2722 2697 * Check for invalid length. Check is the length is zero or if the
2723 2698 * length is larger than the maximum configured value. Return error
2724 2699 * if it is.
2725 2700 */
2726 2701 max_sz = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_mrw_sz);
2727 2702 if ((bind->bi_len == 0) || (bind->bi_len > max_sz)) {
2728 2703 /*
2729 2704 * Deregister will be called upon returning failure from this
2730 2705 * routine. This will ensure that all current resources get
2731 2706 * properly freed up. Unnecessary to attempt to regain
2732 2707 * software ownership of the MPT entry as that has already
2733 2708 * been done above (in hermon_mr_reregister())
2734 2709 */
2735 2710 *dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT;
2736 2711
2737 2712 status = IBT_MR_LEN_INVALID;
2738 2713 goto mrrereghelp_fail;
2739 2714 }
2740 2715
2741 2716 /*
2742 2717 * Determine the number of pages necessary for new region and the
2743 2718 * number of pages supported by the current MTT resources
2744 2719 */
2745 2720 nummtt_needed = hermon_mr_nummtt_needed(state, bind, &mtt_pgsize_bits);
2746 2721 nummtt_in_currrsrc = mr->mr_mttrsrcp->hr_len >> HERMON_MTT_SIZE_SHIFT;
2747 2722
2748 2723 /*
2749 2724 * Depending on whether we have enough pages or not, the next step is
2750 2725 * to fill in a set of MTT entries that reflect the new mapping. In
2751 2726 * the first case below, we already have enough entries. This means
2752 2727 * we need to unbind the memory from the previous mapping, bind the
2753 2728 * memory for the new mapping, write the new MTT entries, and update
2754 2729 * the mr to reflect the changes.
2755 2730 * In the second case below, we do not have enough entries in the
2756 2731 * current mapping. So, in this case, we need not only to unbind the
2757 2732 * current mapping, but we need to free up the MTT resources associated
2758 2733 * with that mapping. After we've successfully done that, we continue
2759 2734 * by binding the new memory, allocating new MTT entries, writing the
2760 2735 * new MTT entries, and updating the mr to reflect the changes.
2761 2736 */
2762 2737
2763 2738 /*
2764 2739 * If this region is being shared (i.e. MTT refcount != 1), then we
2765 2740 * can't reuse the current MTT resources regardless of their size.
2766 2741 * Instead we'll need to alloc new ones (below) just as if there
2767 2742 * hadn't been enough room in the current entries.
2768 2743 */
2769 2744 swrc_old = (hermon_sw_refcnt_t *)mr->mr_mttrefcntp->hr_addr;
2770 2745 if (HERMON_MTT_IS_NOT_SHARED(swrc_old) &&
2771 2746 (nummtt_needed <= nummtt_in_currrsrc)) {
2772 2747
2773 2748 /*
2774 2749 * Unbind the old mapping for this memory region, but retain
2775 2750 * the ddi_dma_handle_t (if possible) for reuse in the bind
2776 2751 * operation below. Note: If original memory region was
2777 2752 * bound for IOMMU bypass and the new region can not use
2778 2753 * bypass, then a new DMA handle will be necessary.
2779 2754 */
2780 2755 if (HERMON_MR_REUSE_DMAHDL(mr, bind->bi_flags)) {
2781 2756 mr->mr_bindinfo.bi_free_dmahdl = 0;
2782 2757 hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
2783 2758 dmahdl = mr->mr_bindinfo.bi_dmahdl;
2784 2759 reuse_dmahdl = 1;
2785 2760 } else {
2786 2761 hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
2787 2762 dmahdl = NULL;
2788 2763 reuse_dmahdl = 0;
2789 2764 }
2790 2765
2791 2766 /*
2792 2767 * Bind the new memory and determine the mapped addresses.
2793 2768 * As described, this routine and hermon_mr_fast_mtt_write()
2794 2769 * do the majority of the work for the memory registration
2795 2770 * operations. Note: When we successfully finish the binding,
2796 2771 * we will set the "bi_free_dmahdl" flag to indicate that
2797 2772 * even though we may have reused the ddi_dma_handle_t we do
2798 2773 * wish it to be freed up at some later time. Note also that
2799 2774 * if we fail, we may need to cleanup the ddi_dma_handle_t.
2800 2775 */
2801 2776 bind->bi_bypass = bind_type;
2802 2777 status = hermon_mr_mem_bind(state, bind, dmahdl, sleep, 1);
2803 2778 if (status != DDI_SUCCESS) {
2804 2779 if (reuse_dmahdl) {
2805 2780 ddi_dma_free_handle(&dmahdl);
2806 2781 }
2807 2782
2808 2783 /*
2809 2784 * Deregister will be called upon returning failure
2810 2785 * from this routine. This will ensure that all
2811 2786 * current resources get properly freed up.
2812 2787 * Unnecessary to attempt to regain software ownership
2813 2788 * of the MPT entry as that has already been done
2814 2789 * above (in hermon_mr_reregister()). Also unnecessary
2815 2790 * to attempt to unbind the memory.
2816 2791 */
2817 2792 *dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
2818 2793
2819 2794 status = IBT_INSUFF_RESOURCE;
2820 2795 goto mrrereghelp_fail;
2821 2796 }
2822 2797 if (reuse_dmahdl) {
2823 2798 bind->bi_free_dmahdl = 1;
2824 2799 }
2825 2800
2826 2801 /*
2827 2802 * Using the new mapping, but reusing the current MTT
2828 2803 * resources, write the updated entries to MTT
2829 2804 */
2830 2805 mtt = mr->mr_mttrsrcp;
2831 2806 status = hermon_mr_fast_mtt_write(state, mtt, bind,
2832 2807 mtt_pgsize_bits);
2833 2808 if (status != DDI_SUCCESS) {
2834 2809 /*
2835 2810 * Deregister will be called upon returning failure
2836 2811 * from this routine. This will ensure that all
2837 2812 * current resources get properly freed up.
2838 2813 * Unnecessary to attempt to regain software ownership
2839 2814 * of the MPT entry as that has already been done
2840 2815 * above (in hermon_mr_reregister()). Also unnecessary
2841 2816 * to attempt to unbind the memory.
2842 2817 *
2843 2818 * But we do need to unbind the newly bound memory
2844 2819 * before returning.
2845 2820 */
2846 2821 hermon_mr_mem_unbind(state, bind);
2847 2822 *dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
2848 2823
2849 2824 /*
2850 2825 * hermon_mr_fast_mtt_write() returns DDI_FAILURE
2851 2826 * only if it detects a HW error during DMA.
2852 2827 */
2853 2828 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
2854 2829 status = ibc_get_ci_failure(0);
2855 2830 goto mrrereghelp_fail;
2856 2831 }
2857 2832
2858 2833 /* Put the updated information into the Mem Region handle */
2859 2834 mr->mr_bindinfo = *bind;
2860 2835 mr->mr_logmttpgsz = mtt_pgsize_bits;
2861 2836
2862 2837 } else {
2863 2838 /*
2864 2839 * Check if the memory region MTT is shared by any other MRs.
2865 2840 * Since the resource may be shared between multiple memory
2866 2841 * regions (as a result of a "RegisterSharedMR()" verb) it is
2867 2842 * important that we not unbind any resources prematurely.
2868 2843 */
2869 2844 if (!HERMON_MTT_IS_SHARED(swrc_old)) {
2870 2845 /*
2871 2846 * Unbind the old mapping for this memory region, but
2872 2847 * retain the ddi_dma_handle_t for reuse in the bind
2873 2848 * operation below. Note: This can only be done here
2874 2849 * because the region being reregistered is not
2875 2850 * currently shared. Also if original memory region
2876 2851 * was bound for IOMMU bypass and the new region can
2877 2852 * not use bypass, then a new DMA handle will be
2878 2853 * necessary.
2879 2854 */
2880 2855 if (HERMON_MR_REUSE_DMAHDL(mr, bind->bi_flags)) {
2881 2856 mr->mr_bindinfo.bi_free_dmahdl = 0;
2882 2857 hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
2883 2858 dmahdl = mr->mr_bindinfo.bi_dmahdl;
2884 2859 reuse_dmahdl = 1;
2885 2860 } else {
2886 2861 hermon_mr_mem_unbind(state, &mr->mr_bindinfo);
2887 2862 dmahdl = NULL;
2888 2863 reuse_dmahdl = 0;
2889 2864 }
2890 2865 } else {
2891 2866 dmahdl = NULL;
2892 2867 reuse_dmahdl = 0;
2893 2868 }
2894 2869
2895 2870 /*
2896 2871 * Bind the new memory and determine the mapped addresses.
2897 2872 * As described, this routine and hermon_mr_fast_mtt_write()
2898 2873 * do the majority of the work for the memory registration
2899 2874 * operations. Note: When we successfully finish the binding,
2900 2875 * we will set the "bi_free_dmahdl" flag to indicate that
2901 2876 * even though we may have reused the ddi_dma_handle_t we do
2902 2877 * wish it to be freed up at some later time. Note also that
2903 2878 * if we fail, we may need to cleanup the ddi_dma_handle_t.
2904 2879 */
2905 2880 bind->bi_bypass = bind_type;
2906 2881 status = hermon_mr_mem_bind(state, bind, dmahdl, sleep, 1);
2907 2882 if (status != DDI_SUCCESS) {
2908 2883 if (reuse_dmahdl) {
2909 2884 ddi_dma_free_handle(&dmahdl);
2910 2885 }
2911 2886
2912 2887 /*
2913 2888 * Deregister will be called upon returning failure
2914 2889 * from this routine. This will ensure that all
2915 2890 * current resources get properly freed up.
2916 2891 * Unnecessary to attempt to regain software ownership
2917 2892 * of the MPT entry as that has already been done
2918 2893 * above (in hermon_mr_reregister()). Also unnecessary
2919 2894 * to attempt to unbind the memory.
2920 2895 */
2921 2896 *dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
2922 2897
2923 2898 status = IBT_INSUFF_RESOURCE;
2924 2899 goto mrrereghelp_fail;
2925 2900 }
2926 2901 if (reuse_dmahdl) {
2927 2902 bind->bi_free_dmahdl = 1;
2928 2903 }
2929 2904
2930 2905 /*
2931 2906 * Allocate the new MTT entries resource
2932 2907 */
2933 2908 status = hermon_rsrc_alloc(state, HERMON_MTT, nummtt_needed,
2934 2909 sleep, &mtt);
2935 2910 if (status != DDI_SUCCESS) {
2936 2911 /*
2937 2912 * Deregister will be called upon returning failure
2938 2913 * from this routine. This will ensure that all
2939 2914 * current resources get properly freed up.
2940 2915 * Unnecessary to attempt to regain software ownership
2941 2916 * of the MPT entry as that has already been done
2942 2917 * above (in hermon_mr_reregister()). Also unnecessary
2943 2918 * to attempt to unbind the memory.
2944 2919 *
2945 2920 * But we do need to unbind the newly bound memory
2946 2921 * before returning.
2947 2922 */
2948 2923 hermon_mr_mem_unbind(state, bind);
2949 2924 *dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
2950 2925
2951 2926 status = IBT_INSUFF_RESOURCE;
2952 2927 goto mrrereghelp_fail;
2953 2928 }
2954 2929
2955 2930 /*
2956 2931 * Allocate MTT reference count (to track shared memory
2957 2932 * regions). As mentioned elsewhere above, this reference
2958 2933 * count resource may never be used on the given memory region,
2959 2934 * but if it is ever later registered as a "shared" memory
2960 2935 * region then this resource will be necessary. Note: This
2961 2936 * is only necessary here if the existing memory region is
2962 2937 * already being shared (because otherwise we already have
2963 2938 * a useable reference count resource).
2964 2939 */
2965 2940 if (HERMON_MTT_IS_SHARED(swrc_old)) {
2966 2941 status = hermon_rsrc_alloc(state, HERMON_REFCNT, 1,
2967 2942 sleep, &mtt_refcnt);
2968 2943 if (status != DDI_SUCCESS) {
2969 2944 /*
2970 2945 * Deregister will be called upon returning
2971 2946 * failure from this routine. This will ensure
2972 2947 * that all current resources get properly
2973 2948 * freed up. Unnecessary to attempt to regain
2974 2949 * software ownership of the MPT entry as that
2975 2950 * has already been done above (in
2976 2951 * hermon_mr_reregister()). Also unnecessary
2977 2952 * to attempt to unbind the memory.
2978 2953 *
2979 2954 * But we need to unbind the newly bound
2980 2955 * memory and free up the newly allocated MTT
2981 2956 * entries before returning.
↓ open down ↓ |
579 lines elided |
↑ open up ↑ |
2982 2957 */
2983 2958 hermon_mr_mem_unbind(state, bind);
2984 2959 hermon_rsrc_free(state, &mtt);
2985 2960 *dereg_level =
2986 2961 HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
2987 2962
2988 2963 status = IBT_INSUFF_RESOURCE;
2989 2964 goto mrrereghelp_fail;
2990 2965 }
2991 2966 swrc_new = (hermon_sw_refcnt_t *)mtt_refcnt->hr_addr;
2992 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*swrc_new))
2993 2967 HERMON_MTT_REFCNT_INIT(swrc_new);
2994 2968 } else {
2995 2969 mtt_refcnt = mr->mr_mttrefcntp;
2996 2970 }
2997 2971
2998 2972 /*
2999 2973 * Using the new mapping and the new MTT resources, write the
3000 2974 * updated entries to MTT
3001 2975 */
3002 2976 status = hermon_mr_fast_mtt_write(state, mtt, bind,
3003 2977 mtt_pgsize_bits);
3004 2978 if (status != DDI_SUCCESS) {
3005 2979 /*
3006 2980 * Deregister will be called upon returning failure
3007 2981 * from this routine. This will ensure that all
3008 2982 * current resources get properly freed up.
3009 2983 * Unnecessary to attempt to regain software ownership
3010 2984 * of the MPT entry as that has already been done
3011 2985 * above (in hermon_mr_reregister()). Also unnecessary
3012 2986 * to attempt to unbind the memory.
3013 2987 *
3014 2988 * But we need to unbind the newly bound memory,
3015 2989 * free up the newly allocated MTT entries, and
3016 2990 * (possibly) free the new MTT reference count
3017 2991 * resource before returning.
3018 2992 */
3019 2993 if (HERMON_MTT_IS_SHARED(swrc_old)) {
3020 2994 hermon_rsrc_free(state, &mtt_refcnt);
3021 2995 }
3022 2996 hermon_mr_mem_unbind(state, bind);
3023 2997 hermon_rsrc_free(state, &mtt);
3024 2998 *dereg_level = HERMON_MR_DEREG_NO_HW2SW_MPT_OR_UNBIND;
3025 2999
3026 3000 status = IBT_INSUFF_RESOURCE;
3027 3001 goto mrrereghelp_fail;
3028 3002 }
3029 3003
3030 3004 /*
3031 3005 * Check if the memory region MTT is shared by any other MRs.
3032 3006 * Since the resource may be shared between multiple memory
3033 3007 * regions (as a result of a "RegisterSharedMR()" verb) it is
3034 3008 * important that we not free up any resources prematurely.
3035 3009 */
3036 3010 if (HERMON_MTT_IS_SHARED(swrc_old)) {
3037 3011 /* Decrement MTT reference count for "old" region */
3038 3012 (void) hermon_mtt_refcnt_dec(mr->mr_mttrefcntp);
3039 3013 } else {
3040 3014 /* Free up the old MTT entries resource */
3041 3015 hermon_rsrc_free(state, &mr->mr_mttrsrcp);
3042 3016 }
3043 3017
3044 3018 /* Put the updated information into the mrhdl */
3045 3019 mr->mr_bindinfo = *bind;
3046 3020 mr->mr_logmttpgsz = mtt_pgsize_bits;
3047 3021 mr->mr_mttrsrcp = mtt;
3048 3022 mr->mr_mttrefcntp = mtt_refcnt;
3049 3023 }
3050 3024
3051 3025 /*
3052 3026 * Calculate and return the updated MTT address (in the DDR address
3053 3027 * space). This will be used by the caller (hermon_mr_reregister) in
3054 3028 * the updated MPT entry
3055 3029 */
3056 3030 *mtt_addr = mtt->hr_indx << HERMON_MTT_SIZE_SHIFT;
3057 3031
3058 3032 return (DDI_SUCCESS);
3059 3033
3060 3034 mrrereghelp_fail:
3061 3035 return (status);
3062 3036 }
3063 3037
3064 3038
3065 3039 /*
3066 3040 * hermon_mr_nummtt_needed()
3067 3041 * Context: Can be called from interrupt or base context.
3068 3042 */
3069 3043 /* ARGSUSED */
3070 3044 static uint64_t
3071 3045 hermon_mr_nummtt_needed(hermon_state_t *state, hermon_bind_info_t *bind,
3072 3046 uint_t *mtt_pgsize_bits)
3073 3047 {
3074 3048 uint64_t pg_offset_mask;
3075 3049 uint64_t pg_offset, tmp_length;
3076 3050
3077 3051 /*
3078 3052 * For now we specify the page size as 8Kb (the default page size for
3079 3053 * the sun4u architecture), or 4Kb for x86. Figure out optimal page
3080 3054 * size by examining the dmacookies
3081 3055 */
3082 3056 *mtt_pgsize_bits = PAGESHIFT;
3083 3057
3084 3058 pg_offset_mask = ((uint64_t)1 << *mtt_pgsize_bits) - 1;
3085 3059 pg_offset = bind->bi_addr & pg_offset_mask;
3086 3060 tmp_length = pg_offset + (bind->bi_len - 1);
3087 3061 return ((tmp_length >> *mtt_pgsize_bits) + 1);
3088 3062 }
3089 3063
3090 3064
3091 3065 /*
3092 3066 * hermon_mr_mem_bind()
3093 3067 * Context: Can be called from interrupt or base context.
3094 3068 */
3095 3069 static int
3096 3070 hermon_mr_mem_bind(hermon_state_t *state, hermon_bind_info_t *bind,
3097 3071 ddi_dma_handle_t dmahdl, uint_t sleep, uint_t is_buffer)
↓ open down ↓ |
95 lines elided |
↑ open up ↑ |
3098 3072 {
3099 3073 ddi_dma_attr_t dma_attr;
3100 3074 int (*callback)(caddr_t);
3101 3075 int status;
3102 3076
3103 3077 /* bi_type must be set to a meaningful value to get a bind handle */
3104 3078 ASSERT(bind->bi_type == HERMON_BINDHDL_VADDR ||
3105 3079 bind->bi_type == HERMON_BINDHDL_BUF ||
3106 3080 bind->bi_type == HERMON_BINDHDL_UBUF);
3107 3081
3108 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
3109 -
3110 3082 /* Set the callback flag appropriately */
3111 3083 callback = (sleep == HERMON_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
3112 3084
3113 3085 /*
3114 3086 * Initialize many of the default DMA attributes. Then, if we're
3115 3087 * bypassing the IOMMU, set the DDI_DMA_FORCE_PHYSICAL flag.
3116 3088 */
3117 3089 if (dmahdl == NULL) {
3118 3090 hermon_dma_attr_init(state, &dma_attr);
3119 3091 #ifdef __sparc
3120 3092 if (bind->bi_bypass == HERMON_BINDMEM_BYPASS) {
3121 3093 dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL;
3122 3094 }
3123 3095 #endif
3124 3096
3125 3097 /* set RO if needed - tunable set and 'is_buffer' is non-0 */
3126 3098 if (is_buffer) {
3127 3099 if (! (bind->bi_flags & IBT_MR_DISABLE_RO)) {
3128 3100 if ((bind->bi_type != HERMON_BINDHDL_UBUF) &&
3129 3101 (hermon_kernel_data_ro ==
3130 3102 HERMON_RO_ENABLED)) {
3131 3103 dma_attr.dma_attr_flags |=
3132 3104 DDI_DMA_RELAXED_ORDERING;
3133 3105 }
3134 3106 if (((bind->bi_type == HERMON_BINDHDL_UBUF) &&
3135 3107 (hermon_user_data_ro ==
3136 3108 HERMON_RO_ENABLED))) {
3137 3109 dma_attr.dma_attr_flags |=
3138 3110 DDI_DMA_RELAXED_ORDERING;
3139 3111 }
3140 3112 }
3141 3113 }
3142 3114
3143 3115 /* Allocate a DMA handle for the binding */
3144 3116 status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr,
3145 3117 callback, NULL, &bind->bi_dmahdl);
3146 3118 if (status != DDI_SUCCESS) {
3147 3119 return (status);
3148 3120 }
3149 3121 bind->bi_free_dmahdl = 1;
3150 3122
3151 3123 } else {
3152 3124 bind->bi_dmahdl = dmahdl;
3153 3125 bind->bi_free_dmahdl = 0;
3154 3126 }
3155 3127
3156 3128
3157 3129 /*
3158 3130 * Bind the memory to get the PCI mapped addresses. The decision
3159 3131 * to call ddi_dma_addr_bind_handle() or ddi_dma_buf_bind_handle()
3160 3132 * is determined by the "bi_type" flag. Note: if the bind operation
3161 3133 * fails then we have to free up the DMA handle and return error.
3162 3134 */
3163 3135 if (bind->bi_type == HERMON_BINDHDL_VADDR) {
3164 3136 status = ddi_dma_addr_bind_handle(bind->bi_dmahdl, NULL,
3165 3137 (caddr_t)(uintptr_t)bind->bi_addr, bind->bi_len,
3166 3138 (DDI_DMA_RDWR | DDI_DMA_CONSISTENT), callback, NULL,
3167 3139 &bind->bi_dmacookie, &bind->bi_cookiecnt);
3168 3140
3169 3141 } else { /* HERMON_BINDHDL_BUF or HERMON_BINDHDL_UBUF */
3170 3142
3171 3143 status = ddi_dma_buf_bind_handle(bind->bi_dmahdl,
3172 3144 bind->bi_buf, (DDI_DMA_RDWR | DDI_DMA_CONSISTENT), callback,
3173 3145 NULL, &bind->bi_dmacookie, &bind->bi_cookiecnt);
3174 3146 }
3175 3147 if (status != DDI_DMA_MAPPED) {
3176 3148 if (bind->bi_free_dmahdl != 0) {
3177 3149 ddi_dma_free_handle(&bind->bi_dmahdl);
3178 3150 }
3179 3151 return (status);
3180 3152 }
3181 3153
3182 3154 return (DDI_SUCCESS);
3183 3155 }
3184 3156
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
3185 3157
3186 3158 /*
3187 3159 * hermon_mr_mem_unbind()
3188 3160 * Context: Can be called from interrupt or base context.
3189 3161 */
3190 3162 static void
3191 3163 hermon_mr_mem_unbind(hermon_state_t *state, hermon_bind_info_t *bind)
3192 3164 {
3193 3165 int status;
3194 3166
3195 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
3196 3167 /* there is nothing to unbind for alloc_lkey */
3197 3168 if (bind->bi_type == HERMON_BINDHDL_LKEY)
3198 3169 return;
3199 3170
3200 3171 /*
3201 3172 * In case of HERMON_BINDHDL_UBUF, the memory bi_buf points to
3202 3173 * is actually allocated by ddi_umem_iosetup() internally, then
3203 3174 * it's required to free it here. Reset bi_type to HERMON_BINDHDL_NONE
3204 3175 * not to free it again later.
3205 3176 */
3206 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*bind))
3207 3177 if (bind->bi_type == HERMON_BINDHDL_UBUF) {
3208 3178 freerbuf(bind->bi_buf);
3209 3179 bind->bi_type = HERMON_BINDHDL_NONE;
3210 3180 }
3211 - _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*bind))
3212 3181
3213 3182 /*
3214 3183 * Unbind the DMA memory for the region
3215 3184 *
3216 3185 * Note: The only way ddi_dma_unbind_handle() currently
3217 3186 * can return an error is if the handle passed in is invalid.
3218 3187 * Since this should never happen, we choose to return void
3219 3188 * from this function! If this does return an error, however,
3220 3189 * then we print a warning message to the console.
3221 3190 */
3222 3191 status = ddi_dma_unbind_handle(bind->bi_dmahdl);
3223 3192 if (status != DDI_SUCCESS) {
3224 3193 HERMON_WARNING(state, "failed to unbind DMA mapping");
3225 3194 return;
3226 3195 }
3227 3196
3228 3197 /* Free up the DMA handle */
3229 3198 if (bind->bi_free_dmahdl != 0) {
3230 3199 ddi_dma_free_handle(&bind->bi_dmahdl);
3231 3200 }
3232 3201 }
3233 3202
3234 3203
3235 3204 /*
3236 3205 * hermon_mr_fast_mtt_write()
3237 3206 * Context: Can be called from interrupt or base context.
3238 3207 */
3239 3208 static int
3240 3209 hermon_mr_fast_mtt_write(hermon_state_t *state, hermon_rsrc_t *mtt,
3241 3210 hermon_bind_info_t *bind, uint32_t mtt_pgsize_bits)
3242 3211 {
3243 3212 hermon_icm_table_t *icm_table;
3244 3213 hermon_dma_info_t *dma_info;
3245 3214 uint32_t index1, index2, rindx;
3246 3215 ddi_dma_cookie_t dmacookie;
3247 3216 uint_t cookie_cnt;
3248 3217 uint64_t *mtt_table;
3249 3218 uint64_t mtt_entry;
3250 3219 uint64_t addr, endaddr;
3251 3220 uint64_t pagesize;
3252 3221 offset_t i, start;
3253 3222 uint_t per_span;
3254 3223 int sync_needed;
3255 3224
3256 3225 /*
3257 3226 * XXX According to the PRM, we are to use the WRITE_MTT
3258 3227 * command to write out MTTs. Tavor does not do this,
3259 3228 * instead taking advantage of direct access to the MTTs,
3260 3229 * and knowledge that Mellanox FMR relies on our ability
3261 3230 * to write directly to the MTTs without any further
3262 3231 * notification to the firmware. Likewise, we will choose
3263 3232 * to not use the WRITE_MTT command, but to simply write
3264 3233 * out the MTTs.
3265 3234 */
3266 3235
3267 3236 /* Calculate page size from the suggested value passed in */
3268 3237 pagesize = ((uint64_t)1 << mtt_pgsize_bits);
3269 3238
3270 3239 /* Walk the "cookie list" and fill in the MTT table entries */
3271 3240 dmacookie = bind->bi_dmacookie;
3272 3241 cookie_cnt = bind->bi_cookiecnt;
3273 3242
3274 3243 icm_table = &state->hs_icm[HERMON_MTT];
3275 3244 rindx = mtt->hr_indx;
3276 3245 hermon_index(index1, index2, rindx, icm_table, i);
3277 3246 start = i;
3278 3247
3279 3248 per_span = icm_table->span;
3280 3249 dma_info = icm_table->icm_dma[index1] + index2;
3281 3250 mtt_table = (uint64_t *)(uintptr_t)dma_info->vaddr;
3282 3251
3283 3252 sync_needed = 0;
3284 3253 while (cookie_cnt-- > 0) {
3285 3254 addr = dmacookie.dmac_laddress;
3286 3255 endaddr = addr + (dmacookie.dmac_size - 1);
3287 3256 addr = addr & ~((uint64_t)pagesize - 1);
3288 3257
3289 3258 while (addr <= endaddr) {
3290 3259
3291 3260 /*
3292 3261 * Fill in the mapped addresses (calculated above) and
3293 3262 * set HERMON_MTT_ENTRY_PRESENT flag for each MTT entry.
3294 3263 */
3295 3264 mtt_entry = addr | HERMON_MTT_ENTRY_PRESENT;
3296 3265 mtt_table[i] = htonll(mtt_entry);
3297 3266 i++;
3298 3267 rindx++;
3299 3268
3300 3269 if (i == per_span) {
3301 3270
3302 3271 (void) ddi_dma_sync(dma_info->dma_hdl,
3303 3272 start * sizeof (hermon_hw_mtt_t),
3304 3273 (i - start) * sizeof (hermon_hw_mtt_t),
3305 3274 DDI_DMA_SYNC_FORDEV);
3306 3275
3307 3276 if ((addr + pagesize > endaddr) &&
3308 3277 (cookie_cnt == 0))
3309 3278 return (DDI_SUCCESS);
3310 3279
3311 3280 hermon_index(index1, index2, rindx, icm_table,
3312 3281 i);
3313 3282 start = i * sizeof (hermon_hw_mtt_t);
3314 3283 dma_info = icm_table->icm_dma[index1] + index2;
3315 3284 mtt_table =
↓ open down ↓ |
94 lines elided |
↑ open up ↑ |
3316 3285 (uint64_t *)(uintptr_t)dma_info->vaddr;
3317 3286
3318 3287 sync_needed = 0;
3319 3288 } else {
3320 3289 sync_needed = 1;
3321 3290 }
3322 3291
3323 3292 addr += pagesize;
3324 3293 if (addr == 0) {
3325 3294 static int do_once = 1;
3326 - _NOTE(SCHEME_PROTECTS_DATA("safe sharing",
3327 - do_once))
3328 3295 if (do_once) {
3329 3296 do_once = 0;
3330 3297 cmn_err(CE_NOTE, "probable error in "
3331 3298 "dma_cookie address from caller\n");
3332 3299 }
3333 3300 break;
3334 3301 }
3335 3302 }
3336 3303
3337 3304 /*
3338 3305 * When we've reached the end of the current DMA cookie,
3339 3306 * jump to the next cookie (if there are more)
3340 3307 */
3341 3308 if (cookie_cnt != 0) {
3342 3309 ddi_dma_nextcookie(bind->bi_dmahdl, &dmacookie);
3343 3310 }
3344 3311 }
3345 3312
3346 3313 /* done all the cookies, now sync the memory for the device */
3347 3314 if (sync_needed)
3348 3315 (void) ddi_dma_sync(dma_info->dma_hdl,
3349 3316 start * sizeof (hermon_hw_mtt_t),
3350 3317 (i - start) * sizeof (hermon_hw_mtt_t),
3351 3318 DDI_DMA_SYNC_FORDEV);
3352 3319
3353 3320 return (DDI_SUCCESS);
3354 3321 }
3355 3322
3356 3323 /*
3357 3324 * hermon_mr_fast_mtt_write_fmr()
3358 3325 * Context: Can be called from interrupt or base context.
3359 3326 */
3360 3327 /* ARGSUSED */
3361 3328 static int
3362 3329 hermon_mr_fast_mtt_write_fmr(hermon_state_t *state, hermon_rsrc_t *mtt,
3363 3330 ibt_pmr_attr_t *mem_pattr, uint32_t mtt_pgsize_bits)
3364 3331 {
3365 3332 hermon_icm_table_t *icm_table;
3366 3333 hermon_dma_info_t *dma_info;
3367 3334 uint32_t index1, index2, rindx;
3368 3335 uint64_t *mtt_table;
3369 3336 offset_t i, j;
3370 3337 uint_t per_span;
3371 3338
3372 3339 icm_table = &state->hs_icm[HERMON_MTT];
3373 3340 rindx = mtt->hr_indx;
3374 3341 hermon_index(index1, index2, rindx, icm_table, i);
3375 3342 per_span = icm_table->span;
3376 3343 dma_info = icm_table->icm_dma[index1] + index2;
3377 3344 mtt_table = (uint64_t *)(uintptr_t)dma_info->vaddr;
3378 3345
3379 3346 /*
3380 3347 * Fill in the MTT table entries
3381 3348 */
3382 3349 for (j = 0; j < mem_pattr->pmr_num_buf; j++) {
3383 3350 mtt_table[i] = mem_pattr->pmr_addr_list[j].p_laddr;
3384 3351 i++;
3385 3352 rindx++;
3386 3353 if (i == per_span) {
3387 3354 hermon_index(index1, index2, rindx, icm_table, i);
3388 3355 dma_info = icm_table->icm_dma[index1] + index2;
3389 3356 mtt_table = (uint64_t *)(uintptr_t)dma_info->vaddr;
3390 3357 }
3391 3358 }
3392 3359
3393 3360 return (DDI_SUCCESS);
3394 3361 }
3395 3362
3396 3363
3397 3364 /*
3398 3365 * hermon_mtt_refcnt_inc()
3399 3366 * Context: Can be called from interrupt or base context.
3400 3367 */
3401 3368 static uint_t
3402 3369 hermon_mtt_refcnt_inc(hermon_rsrc_t *rsrc)
3403 3370 {
3404 3371 hermon_sw_refcnt_t *rc;
3405 3372
3406 3373 rc = (hermon_sw_refcnt_t *)rsrc->hr_addr;
3407 3374 return (atomic_inc_uint_nv(&rc->swrc_refcnt));
3408 3375 }
3409 3376
3410 3377
3411 3378 /*
3412 3379 * hermon_mtt_refcnt_dec()
3413 3380 * Context: Can be called from interrupt or base context.
3414 3381 */
3415 3382 static uint_t
3416 3383 hermon_mtt_refcnt_dec(hermon_rsrc_t *rsrc)
3417 3384 {
3418 3385 hermon_sw_refcnt_t *rc;
3419 3386
3420 3387 rc = (hermon_sw_refcnt_t *)rsrc->hr_addr;
3421 3388 return (atomic_dec_uint_nv(&rc->swrc_refcnt));
3422 3389 }
↓ open down ↓ |
85 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX