diff options
author | Chien Tung <chien.tin.tung@intel.com> | 2009-12-09 18:21:54 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2009-12-09 18:21:54 -0500 |
commit | e293a26fe97c8598a96562c1c9376d9ae6cb96dd (patch) | |
tree | 5dab2c24d0e5df36ba022c8b83111b76e10dd52f /drivers/infiniband/hw | |
parent | 649fe4aeab8c9b90eb31c899791534add0c78e04 (diff) |
RDMA/nes: Correct fast memory registration implementation
Replace alloc_fmr, unmap_fmr, dealloc_fmr and map_phys_fmr with
alloc_fast_reg_mr, alloc_fast_reg_page_list, free_fast_reg_page_list.
Signed-off-by: Chien Tung <chien.tin.tung@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.c | 5 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.h | 27 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_user.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.c | 557 |
4 files changed, 299 insertions, 291 deletions
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 3512d6de3019..3d9bbff4f7ac 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c | |||
@@ -424,8 +424,9 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) { | |||
424 | 424 | ||
425 | nesadapter->base_pd = 1; | 425 | nesadapter->base_pd = 1; |
426 | 426 | ||
427 | nesadapter->device_cap_flags = | 427 | nesadapter->device_cap_flags = IB_DEVICE_LOCAL_DMA_LKEY | |
428 | IB_DEVICE_LOCAL_DMA_LKEY | IB_DEVICE_MEM_WINDOW; | 428 | IB_DEVICE_MEM_WINDOW | |
429 | IB_DEVICE_MEM_MGT_EXTENSIONS; | ||
429 | 430 | ||
430 | nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter) | 431 | nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter) |
431 | [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]); | 432 | [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]); |
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index f28a41ba9fa1..8a4c7383bc08 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h | |||
@@ -546,11 +546,23 @@ enum nes_iwarp_sq_fmr_wqe_word_idx { | |||
546 | NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX = 14, | 546 | NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX = 14, |
547 | }; | 547 | }; |
548 | 548 | ||
549 | enum nes_iwarp_sq_fmr_opcodes { | ||
550 | NES_IWARP_SQ_FMR_WQE_ZERO_BASED = (1<<6), | ||
551 | NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_4K = (0<<7), | ||
552 | NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_2M = (1<<7), | ||
553 | NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_READ = (1<<16), | ||
554 | NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_WRITE = (1<<17), | ||
555 | NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_READ = (1<<18), | ||
556 | NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_WRITE = (1<<19), | ||
557 | NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_WINDOW_BIND = (1<<20), | ||
558 | }; | ||
559 | |||
560 | #define NES_IWARP_SQ_FMR_WQE_MR_LENGTH_HIGH_MASK 0xFF; | ||
561 | |||
549 | enum nes_iwarp_sq_locinv_wqe_word_idx { | 562 | enum nes_iwarp_sq_locinv_wqe_word_idx { |
550 | NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX = 6, | 563 | NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX = 6, |
551 | }; | 564 | }; |
552 | 565 | ||
553 | |||
554 | enum nes_iwarp_rq_wqe_word_idx { | 566 | enum nes_iwarp_rq_wqe_word_idx { |
555 | NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX = 1, | 567 | NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX = 1, |
556 | NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX = 2, | 568 | NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX = 2, |
@@ -1153,6 +1165,19 @@ struct nes_pbl { | |||
1153 | /* TODO: need to add list for two level tables */ | 1165 | /* TODO: need to add list for two level tables */ |
1154 | }; | 1166 | }; |
1155 | 1167 | ||
1168 | #define NES_4K_PBL_CHUNK_SIZE 4096 | ||
1169 | |||
1170 | struct nes_fast_mr_wqe_pbl { | ||
1171 | u64 *kva; | ||
1172 | dma_addr_t paddr; | ||
1173 | }; | ||
1174 | |||
1175 | struct nes_ib_fast_reg_page_list { | ||
1176 | struct ib_fast_reg_page_list ibfrpl; | ||
1177 | struct nes_fast_mr_wqe_pbl nes_wqe_pbl; | ||
1178 | u64 pbl; | ||
1179 | }; | ||
1180 | |||
1156 | struct nes_listener { | 1181 | struct nes_listener { |
1157 | struct work_struct work; | 1182 | struct work_struct work; |
1158 | struct workqueue_struct *wq; | 1183 | struct workqueue_struct *wq; |
diff --git a/drivers/infiniband/hw/nes/nes_user.h b/drivers/infiniband/hw/nes/nes_user.h index cc90c14b49eb..ce62f3c0037c 100644 --- a/drivers/infiniband/hw/nes/nes_user.h +++ b/drivers/infiniband/hw/nes/nes_user.h | |||
@@ -86,6 +86,7 @@ enum iwnes_memreg_type { | |||
86 | IWNES_MEMREG_TYPE_CQ = 0x0002, | 86 | IWNES_MEMREG_TYPE_CQ = 0x0002, |
87 | IWNES_MEMREG_TYPE_MW = 0x0003, | 87 | IWNES_MEMREG_TYPE_MW = 0x0003, |
88 | IWNES_MEMREG_TYPE_FMR = 0x0004, | 88 | IWNES_MEMREG_TYPE_FMR = 0x0004, |
89 | IWNES_MEMREG_TYPE_FMEM = 0x0005, | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | struct nes_mem_reg_req { | 92 | struct nes_mem_reg_req { |
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 499dd78cb821..0a2b18bad6ee 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c | |||
@@ -275,342 +275,236 @@ static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw, | |||
275 | } | 275 | } |
276 | 276 | ||
277 | 277 | ||
278 | /** | 278 | /* |
279 | * nes_alloc_fmr | 279 | * nes_alloc_fast_mr |
280 | */ | 280 | */ |
281 | static struct ib_fmr *nes_alloc_fmr(struct ib_pd *ibpd, | 281 | static int alloc_fast_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd, |
282 | int ibmr_access_flags, | 282 | u32 stag, u32 page_count) |
283 | struct ib_fmr_attr *ibfmr_attr) | ||
284 | { | 283 | { |
285 | unsigned long flags; | ||
286 | struct nes_pd *nespd = to_nespd(ibpd); | ||
287 | struct nes_vnic *nesvnic = to_nesvnic(ibpd->device); | ||
288 | struct nes_device *nesdev = nesvnic->nesdev; | ||
289 | struct nes_adapter *nesadapter = nesdev->nesadapter; | ||
290 | struct nes_fmr *nesfmr; | ||
291 | struct nes_cqp_request *cqp_request; | ||
292 | struct nes_hw_cqp_wqe *cqp_wqe; | 284 | struct nes_hw_cqp_wqe *cqp_wqe; |
285 | struct nes_cqp_request *cqp_request; | ||
286 | unsigned long flags; | ||
293 | int ret; | 287 | int ret; |
294 | u32 stag; | 288 | struct nes_adapter *nesadapter = nesdev->nesadapter; |
295 | u32 stag_index = 0; | ||
296 | u32 next_stag_index = 0; | ||
297 | u32 driver_key = 0; | ||
298 | u32 opcode = 0; | 289 | u32 opcode = 0; |
299 | u8 stag_key = 0; | 290 | u16 major_code; |
300 | int i=0; | 291 | u64 region_length = page_count * PAGE_SIZE; |
301 | struct nes_vpbl vpbl; | ||
302 | |||
303 | get_random_bytes(&next_stag_index, sizeof(next_stag_index)); | ||
304 | stag_key = (u8)next_stag_index; | ||
305 | |||
306 | driver_key = 0; | ||
307 | |||
308 | next_stag_index >>= 8; | ||
309 | next_stag_index %= nesadapter->max_mr; | ||
310 | |||
311 | ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, | ||
312 | nesadapter->max_mr, &stag_index, &next_stag_index); | ||
313 | if (ret) { | ||
314 | goto failed_resource_alloc; | ||
315 | } | ||
316 | |||
317 | nesfmr = kzalloc(sizeof(*nesfmr), GFP_KERNEL); | ||
318 | if (!nesfmr) { | ||
319 | ret = -ENOMEM; | ||
320 | goto failed_fmr_alloc; | ||
321 | } | ||
322 | |||
323 | nesfmr->nesmr.mode = IWNES_MEMREG_TYPE_FMR; | ||
324 | if (ibfmr_attr->max_pages == 1) { | ||
325 | /* use zero length PBL */ | ||
326 | nesfmr->nesmr.pbl_4k = 0; | ||
327 | nesfmr->nesmr.pbls_used = 0; | ||
328 | } else if (ibfmr_attr->max_pages <= 32) { | ||
329 | /* use PBL 256 */ | ||
330 | nesfmr->nesmr.pbl_4k = 0; | ||
331 | nesfmr->nesmr.pbls_used = 1; | ||
332 | } else if (ibfmr_attr->max_pages <= 512) { | ||
333 | /* use 4K PBLs */ | ||
334 | nesfmr->nesmr.pbl_4k = 1; | ||
335 | nesfmr->nesmr.pbls_used = 1; | ||
336 | } else { | ||
337 | /* use two level 4K PBLs */ | ||
338 | /* add support for two level 256B PBLs */ | ||
339 | nesfmr->nesmr.pbl_4k = 1; | ||
340 | nesfmr->nesmr.pbls_used = 1 + (ibfmr_attr->max_pages >> 9) + | ||
341 | ((ibfmr_attr->max_pages & 511) ? 1 : 0); | ||
342 | } | ||
343 | /* Register the region with the adapter */ | ||
344 | spin_lock_irqsave(&nesadapter->pbl_lock, flags); | ||
345 | |||
346 | /* track PBL resources */ | ||
347 | if (nesfmr->nesmr.pbls_used != 0) { | ||
348 | if (nesfmr->nesmr.pbl_4k) { | ||
349 | if (nesfmr->nesmr.pbls_used > nesadapter->free_4kpbl) { | ||
350 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | ||
351 | ret = -ENOMEM; | ||
352 | goto failed_vpbl_avail; | ||
353 | } else { | ||
354 | nesadapter->free_4kpbl -= nesfmr->nesmr.pbls_used; | ||
355 | } | ||
356 | } else { | ||
357 | if (nesfmr->nesmr.pbls_used > nesadapter->free_256pbl) { | ||
358 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | ||
359 | ret = -ENOMEM; | ||
360 | goto failed_vpbl_avail; | ||
361 | } else { | ||
362 | nesadapter->free_256pbl -= nesfmr->nesmr.pbls_used; | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | /* one level pbl */ | ||
368 | if (nesfmr->nesmr.pbls_used == 0) { | ||
369 | nesfmr->root_vpbl.pbl_vbase = NULL; | ||
370 | nes_debug(NES_DBG_MR, "zero level pbl \n"); | ||
371 | } else if (nesfmr->nesmr.pbls_used == 1) { | ||
372 | /* can change it to kmalloc & dma_map_single */ | ||
373 | nesfmr->root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096, | ||
374 | &nesfmr->root_vpbl.pbl_pbase); | ||
375 | if (!nesfmr->root_vpbl.pbl_vbase) { | ||
376 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | ||
377 | ret = -ENOMEM; | ||
378 | goto failed_vpbl_alloc; | ||
379 | } | ||
380 | nesfmr->leaf_pbl_cnt = 0; | ||
381 | nes_debug(NES_DBG_MR, "one level pbl, root_vpbl.pbl_vbase=%p \n", | ||
382 | nesfmr->root_vpbl.pbl_vbase); | ||
383 | } | ||
384 | /* two level pbl */ | ||
385 | else { | ||
386 | nesfmr->root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 8192, | ||
387 | &nesfmr->root_vpbl.pbl_pbase); | ||
388 | if (!nesfmr->root_vpbl.pbl_vbase) { | ||
389 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | ||
390 | ret = -ENOMEM; | ||
391 | goto failed_vpbl_alloc; | ||
392 | } | ||
393 | |||
394 | nesfmr->leaf_pbl_cnt = nesfmr->nesmr.pbls_used-1; | ||
395 | nesfmr->root_vpbl.leaf_vpbl = kzalloc(sizeof(*nesfmr->root_vpbl.leaf_vpbl)*1024, GFP_ATOMIC); | ||
396 | if (!nesfmr->root_vpbl.leaf_vpbl) { | ||
397 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | ||
398 | ret = -ENOMEM; | ||
399 | goto failed_leaf_vpbl_alloc; | ||
400 | } | ||
401 | |||
402 | nes_debug(NES_DBG_MR, "two level pbl, root_vpbl.pbl_vbase=%p" | ||
403 | " leaf_pbl_cnt=%d root_vpbl.leaf_vpbl=%p\n", | ||
404 | nesfmr->root_vpbl.pbl_vbase, nesfmr->leaf_pbl_cnt, nesfmr->root_vpbl.leaf_vpbl); | ||
405 | |||
406 | for (i=0; i<nesfmr->leaf_pbl_cnt; i++) | ||
407 | nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase = NULL; | ||
408 | |||
409 | for (i=0; i<nesfmr->leaf_pbl_cnt; i++) { | ||
410 | vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096, | ||
411 | &vpbl.pbl_pbase); | ||
412 | |||
413 | if (!vpbl.pbl_vbase) { | ||
414 | ret = -ENOMEM; | ||
415 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | ||
416 | goto failed_leaf_vpbl_pages_alloc; | ||
417 | } | ||
418 | |||
419 | nesfmr->root_vpbl.pbl_vbase[i].pa_low = cpu_to_le32((u32)vpbl.pbl_pbase); | ||
420 | nesfmr->root_vpbl.pbl_vbase[i].pa_high = cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32))); | ||
421 | nesfmr->root_vpbl.leaf_vpbl[i] = vpbl; | ||
422 | |||
423 | nes_debug(NES_DBG_MR, "pbase_low=0x%x, pbase_high=0x%x, vpbl=%p\n", | ||
424 | nesfmr->root_vpbl.pbl_vbase[i].pa_low, | ||
425 | nesfmr->root_vpbl.pbl_vbase[i].pa_high, | ||
426 | &nesfmr->root_vpbl.leaf_vpbl[i]); | ||
427 | } | ||
428 | } | ||
429 | nesfmr->ib_qp = NULL; | ||
430 | nesfmr->access_rights =0; | ||
431 | 292 | ||
432 | stag = stag_index << 8; | ||
433 | stag |= driver_key; | ||
434 | stag += (u32)stag_key; | ||
435 | 293 | ||
436 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | ||
437 | cqp_request = nes_get_cqp_request(nesdev); | 294 | cqp_request = nes_get_cqp_request(nesdev); |
438 | if (cqp_request == NULL) { | 295 | if (cqp_request == NULL) { |
439 | nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n"); | 296 | nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n"); |
440 | ret = -ENOMEM; | 297 | return -ENOMEM; |
441 | goto failed_leaf_vpbl_pages_alloc; | ||
442 | } | 298 | } |
299 | nes_debug(NES_DBG_MR, "alloc_fast_reg_mr: page_count = %d, " | ||
300 | "region_length = %llu\n", | ||
301 | page_count, region_length); | ||
443 | cqp_request->waiting = 1; | 302 | cqp_request->waiting = 1; |
444 | cqp_wqe = &cqp_request->cqp_wqe; | 303 | cqp_wqe = &cqp_request->cqp_wqe; |
445 | 304 | ||
446 | nes_debug(NES_DBG_MR, "Registering STag 0x%08X, index = 0x%08X\n", | 305 | spin_lock_irqsave(&nesadapter->pbl_lock, flags); |
447 | stag, stag_index); | 306 | if (nesadapter->free_4kpbl > 0) { |
448 | 307 | nesadapter->free_4kpbl--; | |
449 | opcode = NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR; | 308 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); |
450 | 309 | } else { | |
451 | if (nesfmr->nesmr.pbl_4k == 1) | 310 | /* No 4kpbl's available: */ |
452 | opcode |= NES_CQP_STAG_PBL_BLK_SIZE; | 311 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); |
453 | 312 | nes_debug(NES_DBG_MR, "Out of Pbls\n"); | |
454 | if (ibmr_access_flags & IB_ACCESS_REMOTE_WRITE) { | 313 | nes_free_cqp_request(nesdev, cqp_request); |
455 | opcode |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE | | 314 | return -ENOMEM; |
456 | NES_CQP_STAG_RIGHTS_LOCAL_WRITE | NES_CQP_STAG_REM_ACC_EN; | ||
457 | nesfmr->access_rights |= | ||
458 | NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_RIGHTS_LOCAL_WRITE | | ||
459 | NES_CQP_STAG_REM_ACC_EN; | ||
460 | } | 315 | } |
461 | 316 | ||
462 | if (ibmr_access_flags & IB_ACCESS_REMOTE_READ) { | 317 | opcode = NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_MR | |
463 | opcode |= NES_CQP_STAG_RIGHTS_REMOTE_READ | | 318 | NES_CQP_STAG_PBL_BLK_SIZE | NES_CQP_STAG_VA_TO | |
464 | NES_CQP_STAG_RIGHTS_LOCAL_READ | NES_CQP_STAG_REM_ACC_EN; | 319 | NES_CQP_STAG_REM_ACC_EN; |
465 | nesfmr->access_rights |= | 320 | /* |
466 | NES_CQP_STAG_RIGHTS_REMOTE_READ | NES_CQP_STAG_RIGHTS_LOCAL_READ | | 321 | * The current OFED API does not support the zero based TO option. |
467 | NES_CQP_STAG_REM_ACC_EN; | 322 | * If added then need to changed the NES_CQP_STAG_VA* option. Also, |
468 | } | 323 | * the API does not support that ability to have the MR set for local |
324 | * access only when created and not allow the SQ op to override. Given | ||
325 | * this the remote enable must be set here. | ||
326 | */ | ||
469 | 327 | ||
470 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | 328 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); |
471 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode); | 329 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode); |
472 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX, (nespd->pd_id & 0x00007fff)); | 330 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX, 1); |
473 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag); | ||
474 | 331 | ||
475 | cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = | 332 | cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] = |
476 | cpu_to_le32((nesfmr->nesmr.pbls_used>1) ? | 333 | cpu_to_le32((u32)(region_length >> 8) & 0xff000000); |
477 | (nesfmr->nesmr.pbls_used-1) : nesfmr->nesmr.pbls_used); | 334 | cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] |= |
335 | cpu_to_le32(nespd->pd_id & 0x00007fff); | ||
336 | |||
337 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag); | ||
338 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_VA_LOW_IDX, 0); | ||
339 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_LOW_IDX, 0); | ||
340 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, 0); | ||
341 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_LEN_IDX, (page_count * 8)); | ||
342 | cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_STAG_PBL_BLK_SIZE); | ||
343 | barrier(); | ||
478 | 344 | ||
479 | atomic_set(&cqp_request->refcount, 2); | 345 | atomic_set(&cqp_request->refcount, 2); |
480 | nes_post_cqp_request(nesdev, cqp_request); | 346 | nes_post_cqp_request(nesdev, cqp_request); |
481 | 347 | ||
482 | /* Wait for CQP */ | 348 | /* Wait for CQP */ |
483 | ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0), | 349 | ret = wait_event_timeout(cqp_request->waitq, |
484 | NES_EVENT_TIMEOUT); | 350 | (0 != cqp_request->request_done), |
485 | nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u," | 351 | NES_EVENT_TIMEOUT); |
486 | " CQP Major:Minor codes = 0x%04X:0x%04X.\n", | 352 | |
487 | stag, ret, cqp_request->major_code, cqp_request->minor_code); | 353 | nes_debug(NES_DBG_MR, "Allocate STag 0x%08X completed, " |
488 | 354 | "wait_event_timeout ret = %u, CQP Major:Minor codes = " | |
489 | if ((!ret) || (cqp_request->major_code)) { | 355 | "0x%04X:0x%04X.\n", stag, ret, cqp_request->major_code, |
490 | nes_put_cqp_request(nesdev, cqp_request); | 356 | cqp_request->minor_code); |
491 | ret = (!ret) ? -ETIME : -EIO; | 357 | major_code = cqp_request->major_code; |
492 | goto failed_leaf_vpbl_pages_alloc; | ||
493 | } | ||
494 | nes_put_cqp_request(nesdev, cqp_request); | 358 | nes_put_cqp_request(nesdev, cqp_request); |
495 | nesfmr->nesmr.ibfmr.lkey = stag; | ||
496 | nesfmr->nesmr.ibfmr.rkey = stag; | ||
497 | nesfmr->attr = *ibfmr_attr; | ||
498 | |||
499 | return &nesfmr->nesmr.ibfmr; | ||
500 | |||
501 | failed_leaf_vpbl_pages_alloc: | ||
502 | /* unroll all allocated pages */ | ||
503 | for (i=0; i<nesfmr->leaf_pbl_cnt; i++) { | ||
504 | if (nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase) { | ||
505 | pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase, | ||
506 | nesfmr->root_vpbl.leaf_vpbl[i].pbl_pbase); | ||
507 | } | ||
508 | } | ||
509 | if (nesfmr->root_vpbl.leaf_vpbl) | ||
510 | kfree(nesfmr->root_vpbl.leaf_vpbl); | ||
511 | |||
512 | failed_leaf_vpbl_alloc: | ||
513 | if (nesfmr->leaf_pbl_cnt == 0) { | ||
514 | if (nesfmr->root_vpbl.pbl_vbase) | ||
515 | pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.pbl_vbase, | ||
516 | nesfmr->root_vpbl.pbl_pbase); | ||
517 | } else | ||
518 | pci_free_consistent(nesdev->pcidev, 8192, nesfmr->root_vpbl.pbl_vbase, | ||
519 | nesfmr->root_vpbl.pbl_pbase); | ||
520 | 359 | ||
521 | failed_vpbl_alloc: | 360 | if (!ret || major_code) { |
522 | if (nesfmr->nesmr.pbls_used != 0) { | ||
523 | spin_lock_irqsave(&nesadapter->pbl_lock, flags); | 361 | spin_lock_irqsave(&nesadapter->pbl_lock, flags); |
524 | if (nesfmr->nesmr.pbl_4k) | 362 | nesadapter->free_4kpbl++; |
525 | nesadapter->free_4kpbl += nesfmr->nesmr.pbls_used; | ||
526 | else | ||
527 | nesadapter->free_256pbl += nesfmr->nesmr.pbls_used; | ||
528 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | 363 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); |
529 | } | 364 | } |
530 | 365 | ||
531 | failed_vpbl_avail: | 366 | if (!ret) |
532 | kfree(nesfmr); | 367 | return -ETIME; |
533 | 368 | else if (major_code) | |
534 | failed_fmr_alloc: | 369 | return -EIO; |
535 | nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index); | 370 | return 0; |
536 | |||
537 | failed_resource_alloc: | ||
538 | return ERR_PTR(ret); | ||
539 | } | 371 | } |
540 | 372 | ||
541 | 373 | /* | |
542 | /** | 374 | * nes_alloc_fast_reg_mr |
543 | * nes_dealloc_fmr | ||
544 | */ | 375 | */ |
545 | static int nes_dealloc_fmr(struct ib_fmr *ibfmr) | 376 | struct ib_mr *nes_alloc_fast_reg_mr(struct ib_pd *ibpd, int max_page_list_len) |
546 | { | 377 | { |
547 | unsigned long flags; | 378 | struct nes_pd *nespd = to_nespd(ibpd); |
548 | struct nes_mr *nesmr = to_nesmr_from_ibfmr(ibfmr); | 379 | struct nes_vnic *nesvnic = to_nesvnic(ibpd->device); |
549 | struct nes_fmr *nesfmr = to_nesfmr(nesmr); | ||
550 | struct nes_vnic *nesvnic = to_nesvnic(ibfmr->device); | ||
551 | struct nes_device *nesdev = nesvnic->nesdev; | 380 | struct nes_device *nesdev = nesvnic->nesdev; |
552 | struct nes_adapter *nesadapter = nesdev->nesadapter; | 381 | struct nes_adapter *nesadapter = nesdev->nesadapter; |
553 | int i = 0; | ||
554 | int rc; | ||
555 | 382 | ||
556 | /* free the resources */ | 383 | u32 next_stag_index; |
557 | if (nesfmr->leaf_pbl_cnt == 0) { | 384 | u8 stag_key = 0; |
558 | /* single PBL case */ | 385 | u32 driver_key = 0; |
559 | if (nesfmr->root_vpbl.pbl_vbase) | 386 | int err = 0; |
560 | pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.pbl_vbase, | 387 | u32 stag_index = 0; |
561 | nesfmr->root_vpbl.pbl_pbase); | 388 | struct nes_mr *nesmr; |
562 | } else { | 389 | u32 stag; |
563 | for (i = 0; i < nesfmr->leaf_pbl_cnt; i++) { | 390 | int ret; |
564 | pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase, | 391 | struct ib_mr *ibmr; |
565 | nesfmr->root_vpbl.leaf_vpbl[i].pbl_pbase); | 392 | /* |
566 | } | 393 | * Note: Set to always use a fixed length single page entry PBL. This is to allow |
567 | kfree(nesfmr->root_vpbl.leaf_vpbl); | 394 | * for the fast_reg_mr operation to always know the size of the PBL. |
568 | pci_free_consistent(nesdev->pcidev, 8192, nesfmr->root_vpbl.pbl_vbase, | 395 | */ |
569 | nesfmr->root_vpbl.pbl_pbase); | 396 | if (max_page_list_len > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) |
570 | } | 397 | return ERR_PTR(-E2BIG); |
571 | nesmr->ibmw.device = ibfmr->device; | ||
572 | nesmr->ibmw.pd = ibfmr->pd; | ||
573 | nesmr->ibmw.rkey = ibfmr->rkey; | ||
574 | nesmr->ibmw.uobject = NULL; | ||
575 | 398 | ||
576 | rc = nes_dealloc_mw(&nesmr->ibmw); | 399 | get_random_bytes(&next_stag_index, sizeof(next_stag_index)); |
400 | stag_key = (u8)next_stag_index; | ||
401 | next_stag_index >>= 8; | ||
402 | next_stag_index %= nesadapter->max_mr; | ||
577 | 403 | ||
578 | if ((rc == 0) && (nesfmr->nesmr.pbls_used != 0)) { | 404 | err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, |
579 | spin_lock_irqsave(&nesadapter->pbl_lock, flags); | 405 | nesadapter->max_mr, &stag_index, |
580 | if (nesfmr->nesmr.pbl_4k) { | 406 | &next_stag_index); |
581 | nesadapter->free_4kpbl += nesfmr->nesmr.pbls_used; | 407 | if (err) |
582 | WARN_ON(nesadapter->free_4kpbl > nesadapter->max_4kpbl); | 408 | return ERR_PTR(err); |
583 | } else { | 409 | |
584 | nesadapter->free_256pbl += nesfmr->nesmr.pbls_used; | 410 | nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL); |
585 | WARN_ON(nesadapter->free_256pbl > nesadapter->max_256pbl); | 411 | if (!nesmr) { |
586 | } | 412 | nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index); |
587 | spin_unlock_irqrestore(&nesadapter->pbl_lock, flags); | 413 | return ERR_PTR(-ENOMEM); |
588 | } | 414 | } |
589 | 415 | ||
590 | return rc; | 416 | stag = stag_index << 8; |
591 | } | 417 | stag |= driver_key; |
418 | stag += (u32)stag_key; | ||
592 | 419 | ||
420 | nes_debug(NES_DBG_MR, "Allocating STag 0x%08X index = 0x%08X\n", | ||
421 | stag, stag_index); | ||
593 | 422 | ||
594 | /** | 423 | ret = alloc_fast_reg_mr(nesdev, nespd, stag, max_page_list_len); |
595 | * nes_map_phys_fmr | 424 | |
425 | if (ret == 0) { | ||
426 | nesmr->ibmr.rkey = stag; | ||
427 | nesmr->ibmr.lkey = stag; | ||
428 | nesmr->mode = IWNES_MEMREG_TYPE_FMEM; | ||
429 | ibmr = &nesmr->ibmr; | ||
430 | } else { | ||
431 | kfree(nesmr); | ||
432 | nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index); | ||
433 | ibmr = ERR_PTR(-ENOMEM); | ||
434 | } | ||
435 | return ibmr; | ||
436 | } | ||
437 | |||
438 | /* | ||
439 | * nes_alloc_fast_reg_page_list | ||
596 | */ | 440 | */ |
597 | static int nes_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, | 441 | static struct ib_fast_reg_page_list *nes_alloc_fast_reg_page_list( |
598 | int list_len, u64 iova) | 442 | struct ib_device *ibdev, |
443 | int page_list_len) | ||
599 | { | 444 | { |
600 | return 0; | 445 | struct nes_vnic *nesvnic = to_nesvnic(ibdev); |
601 | } | 446 | struct nes_device *nesdev = nesvnic->nesdev; |
447 | struct ib_fast_reg_page_list *pifrpl; | ||
448 | struct nes_ib_fast_reg_page_list *pnesfrpl; | ||
602 | 449 | ||
450 | if (page_list_len > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) | ||
451 | return ERR_PTR(-E2BIG); | ||
452 | /* | ||
453 | * Allocate the ib_fast_reg_page_list structure, the | ||
454 | * nes_fast_bpl structure, and the PLB table. | ||
455 | */ | ||
456 | pnesfrpl = kmalloc(sizeof(struct nes_ib_fast_reg_page_list) + | ||
457 | page_list_len * sizeof(u64), GFP_KERNEL); | ||
458 | |||
459 | if (!pnesfrpl) | ||
460 | return ERR_PTR(-ENOMEM); | ||
603 | 461 | ||
604 | /** | 462 | pifrpl = &pnesfrpl->ibfrpl; |
605 | * nes_unmap_frm | 463 | pifrpl->page_list = &pnesfrpl->pbl; |
464 | pifrpl->max_page_list_len = page_list_len; | ||
465 | /* | ||
466 | * Allocate the WQE PBL | ||
467 | */ | ||
468 | pnesfrpl->nes_wqe_pbl.kva = pci_alloc_consistent(nesdev->pcidev, | ||
469 | page_list_len * sizeof(u64), | ||
470 | &pnesfrpl->nes_wqe_pbl.paddr); | ||
471 | |||
472 | if (!pnesfrpl->nes_wqe_pbl.kva) { | ||
473 | kfree(pnesfrpl); | ||
474 | return ERR_PTR(-ENOMEM); | ||
475 | } | ||
476 | nes_debug(NES_DBG_MR, "nes_alloc_fast_reg_pbl: nes_frpl = %p, " | ||
477 | "ibfrpl = %p, ibfrpl.page_list = %p, pbl.kva = %p, " | ||
478 | "pbl.paddr= %p\n", pnesfrpl, &pnesfrpl->ibfrpl, | ||
479 | pnesfrpl->ibfrpl.page_list, pnesfrpl->nes_wqe_pbl.kva, | ||
480 | (void *)pnesfrpl->nes_wqe_pbl.paddr); | ||
481 | |||
482 | return pifrpl; | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * nes_free_fast_reg_page_list | ||
606 | */ | 487 | */ |
607 | static int nes_unmap_fmr(struct list_head *ibfmr_list) | 488 | static void nes_free_fast_reg_page_list(struct ib_fast_reg_page_list *pifrpl) |
608 | { | 489 | { |
609 | return 0; | 490 | struct nes_vnic *nesvnic = to_nesvnic(pifrpl->device); |
491 | struct nes_device *nesdev = nesvnic->nesdev; | ||
492 | struct nes_ib_fast_reg_page_list *pnesfrpl; | ||
493 | |||
494 | pnesfrpl = container_of(pifrpl, struct nes_ib_fast_reg_page_list, ibfrpl); | ||
495 | /* | ||
496 | * Free the WQE PBL. | ||
497 | */ | ||
498 | pci_free_consistent(nesdev->pcidev, | ||
499 | pifrpl->max_page_list_len * sizeof(u64), | ||
500 | pnesfrpl->nes_wqe_pbl.kva, | ||
501 | pnesfrpl->nes_wqe_pbl.paddr); | ||
502 | /* | ||
503 | * Free the PBL structure | ||
504 | */ | ||
505 | kfree(pnesfrpl); | ||
610 | } | 506 | } |
611 | 507 | ||
612 | |||
613 | |||
614 | /** | 508 | /** |
615 | * nes_query_device | 509 | * nes_query_device |
616 | */ | 510 | */ |
@@ -3514,6 +3408,91 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr, | |||
3514 | NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX, | 3408 | NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX, |
3515 | ib_wr->ex.invalidate_rkey); | 3409 | ib_wr->ex.invalidate_rkey); |
3516 | break; | 3410 | break; |
3411 | case IB_WR_FAST_REG_MR: | ||
3412 | { | ||
3413 | int i; | ||
3414 | int flags = ib_wr->wr.fast_reg.access_flags; | ||
3415 | struct nes_ib_fast_reg_page_list *pnesfrpl = | ||
3416 | container_of(ib_wr->wr.fast_reg.page_list, | ||
3417 | struct nes_ib_fast_reg_page_list, | ||
3418 | ibfrpl); | ||
3419 | u64 *src_page_list = pnesfrpl->ibfrpl.page_list; | ||
3420 | u64 *dst_page_list = pnesfrpl->nes_wqe_pbl.kva; | ||
3421 | |||
3422 | if (ib_wr->wr.fast_reg.page_list_len > | ||
3423 | (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) { | ||
3424 | nes_debug(NES_DBG_IW_TX, "SQ_FMR: bad page_list_len\n"); | ||
3425 | err = -EINVAL; | ||
3426 | break; | ||
3427 | } | ||
3428 | wqe_misc = NES_IWARP_SQ_OP_FAST_REG; | ||
3429 | set_wqe_64bit_value(wqe->wqe_words, | ||
3430 | NES_IWARP_SQ_FMR_WQE_VA_FBO_LOW_IDX, | ||
3431 | ib_wr->wr.fast_reg.iova_start); | ||
3432 | set_wqe_32bit_value(wqe->wqe_words, | ||
3433 | NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX, | ||
3434 | ib_wr->wr.fast_reg.length); | ||
3435 | set_wqe_32bit_value(wqe->wqe_words, | ||
3436 | NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX, | ||
3437 | ib_wr->wr.fast_reg.rkey); | ||
3438 | /* Set page size: */ | ||
3439 | if (ib_wr->wr.fast_reg.page_shift == 12) { | ||
3440 | wqe_misc |= NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_4K; | ||
3441 | } else if (ib_wr->wr.fast_reg.page_shift == 21) { | ||
3442 | wqe_misc |= NES_IWARP_SQ_FMR_WQE_PAGE_SIZE_2M; | ||
3443 | } else { | ||
3444 | nes_debug(NES_DBG_IW_TX, "Invalid page shift," | ||
3445 | " ib_wr=%u, max=1\n", ib_wr->num_sge); | ||
3446 | err = -EINVAL; | ||
3447 | break; | ||
3448 | } | ||
3449 | /* Set access_flags */ | ||
3450 | wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_READ; | ||
3451 | if (flags & IB_ACCESS_LOCAL_WRITE) | ||
3452 | wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_LOCAL_WRITE; | ||
3453 | |||
3454 | if (flags & IB_ACCESS_REMOTE_WRITE) | ||
3455 | wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_WRITE; | ||
3456 | |||
3457 | if (flags & IB_ACCESS_REMOTE_READ) | ||
3458 | wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_REMOTE_READ; | ||
3459 | |||
3460 | if (flags & IB_ACCESS_MW_BIND) | ||
3461 | wqe_misc |= NES_IWARP_SQ_FMR_WQE_RIGHTS_ENABLE_WINDOW_BIND; | ||
3462 | |||
3463 | /* Fill in PBL info: */ | ||
3464 | if (ib_wr->wr.fast_reg.page_list_len > | ||
3465 | pnesfrpl->ibfrpl.max_page_list_len) { | ||
3466 | nes_debug(NES_DBG_IW_TX, "Invalid page list length," | ||
3467 | " ib_wr=%p, value=%u, max=%u\n", | ||
3468 | ib_wr, ib_wr->wr.fast_reg.page_list_len, | ||
3469 | pnesfrpl->ibfrpl.max_page_list_len); | ||
3470 | err = -EINVAL; | ||
3471 | break; | ||
3472 | } | ||
3473 | |||
3474 | set_wqe_64bit_value(wqe->wqe_words, | ||
3475 | NES_IWARP_SQ_FMR_WQE_PBL_ADDR_LOW_IDX, | ||
3476 | pnesfrpl->nes_wqe_pbl.paddr); | ||
3477 | |||
3478 | set_wqe_32bit_value(wqe->wqe_words, | ||
3479 | NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX, | ||
3480 | ib_wr->wr.fast_reg.page_list_len * 8); | ||
3481 | |||
3482 | for (i = 0; i < ib_wr->wr.fast_reg.page_list_len; i++) | ||
3483 | dst_page_list[i] = cpu_to_le64(src_page_list[i]); | ||
3484 | |||
3485 | nes_debug(NES_DBG_IW_TX, "SQ_FMR: iova_start: %p, " | ||
3486 | "length: %d, rkey: %0x, pgl_paddr: %p, " | ||
3487 | "page_list_len: %u, wqe_misc: %x\n", | ||
3488 | (void *)ib_wr->wr.fast_reg.iova_start, | ||
3489 | ib_wr->wr.fast_reg.length, | ||
3490 | ib_wr->wr.fast_reg.rkey, | ||
3491 | (void *)pnesfrpl->nes_wqe_pbl.paddr, | ||
3492 | ib_wr->wr.fast_reg.page_list_len, | ||
3493 | wqe_misc); | ||
3494 | break; | ||
3495 | } | ||
3517 | default: | 3496 | default: |
3518 | /* error */ | 3497 | /* error */ |
3519 | err = -EINVAL; | 3498 | err = -EINVAL; |
@@ -3752,6 +3731,9 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) | |||
3752 | case NES_IWARP_SQ_OP_LOCINV: | 3731 | case NES_IWARP_SQ_OP_LOCINV: |
3753 | entry->opcode = IB_WR_LOCAL_INV; | 3732 | entry->opcode = IB_WR_LOCAL_INV; |
3754 | break; | 3733 | break; |
3734 | case NES_IWARP_SQ_OP_FAST_REG: | ||
3735 | entry->opcode = IB_WC_FAST_REG_MR; | ||
3736 | break; | ||
3755 | } | 3737 | } |
3756 | 3738 | ||
3757 | nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1); | 3739 | nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1); |
@@ -3922,10 +3904,9 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev) | |||
3922 | nesibdev->ibdev.dealloc_mw = nes_dealloc_mw; | 3904 | nesibdev->ibdev.dealloc_mw = nes_dealloc_mw; |
3923 | nesibdev->ibdev.bind_mw = nes_bind_mw; | 3905 | nesibdev->ibdev.bind_mw = nes_bind_mw; |
3924 | 3906 | ||
3925 | nesibdev->ibdev.alloc_fmr = nes_alloc_fmr; | 3907 | nesibdev->ibdev.alloc_fast_reg_mr = nes_alloc_fast_reg_mr; |
3926 | nesibdev->ibdev.unmap_fmr = nes_unmap_fmr; | 3908 | nesibdev->ibdev.alloc_fast_reg_page_list = nes_alloc_fast_reg_page_list; |
3927 | nesibdev->ibdev.dealloc_fmr = nes_dealloc_fmr; | 3909 | nesibdev->ibdev.free_fast_reg_page_list = nes_free_fast_reg_page_list; |
3928 | nesibdev->ibdev.map_phys_fmr = nes_map_phys_fmr; | ||
3929 | 3910 | ||
3930 | nesibdev->ibdev.attach_mcast = nes_multicast_attach; | 3911 | nesibdev->ibdev.attach_mcast = nes_multicast_attach; |
3931 | nesibdev->ibdev.detach_mcast = nes_multicast_detach; | 3912 | nesibdev->ibdev.detach_mcast = nes_multicast_detach; |