Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

RDMA/iw_cxgb4: Low resource fixes for Memory registration

Pre-allocate buffers for deregistering memory region and memory window
during RDMA connection close, when system is running out of memory.

Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>

authored by

Hariprasad S and committed by
Doug Ledford
0f8ab0b6 4a740838

+76 -37
+2
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
··· 384 384 struct ib_mr ibmr; 385 385 struct ib_umem *umem; 386 386 struct c4iw_dev *rhp; 387 + struct sk_buff *dereg_skb; 387 388 u64 kva; 388 389 struct tpt_attributes attr; 389 390 u64 *mpl; ··· 401 400 struct c4iw_mw { 402 401 struct ib_mw ibmw; 403 402 struct c4iw_dev *rhp; 403 + struct sk_buff *dereg_skb; 404 404 u64 kva; 405 405 struct tpt_attributes attr; 406 406 };
+74 -37
drivers/infiniband/hw/cxgb4/mem.c
··· 59 59 } 60 60 61 61 static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr, 62 - u32 len, dma_addr_t data, int wait) 62 + u32 len, dma_addr_t data, 63 + int wait, struct sk_buff *skb) 63 64 { 64 - struct sk_buff *skb; 65 65 struct ulp_mem_io *req; 66 66 struct ulptx_sgl *sgl; 67 67 u8 wr_len; ··· 74 74 c4iw_init_wr_wait(&wr_wait); 75 75 wr_len = roundup(sizeof(*req) + sizeof(*sgl), 16); 76 76 77 - skb = alloc_skb(wr_len, GFP_KERNEL); 78 - if (!skb) 79 - return -ENOMEM; 77 + if (!skb) { 78 + skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL); 79 + if (!skb) 80 + return -ENOMEM; 81 + } 80 82 set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 81 83 82 84 req = (struct ulp_mem_io *)__skb_put(skb, wr_len); ··· 110 108 } 111 109 112 110 static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len, 113 - void *data) 111 + void *data, struct sk_buff *skb) 114 112 { 115 - struct sk_buff *skb; 116 113 struct ulp_mem_io *req; 117 114 struct ulptx_idata *sc; 118 115 u8 wr_len, *to_dp, *from_dp; ··· 135 134 wr_len = roundup(sizeof *req + sizeof *sc + 136 135 roundup(copy_len, T4_ULPTX_MIN_IO), 16); 137 136 138 - skb = alloc_skb(wr_len, GFP_KERNEL); 139 - if (!skb) 140 - return -ENOMEM; 137 + if (!skb) { 138 + skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL); 139 + if (!skb) 140 + return -ENOMEM; 141 + } 141 142 set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 142 143 143 144 req = (struct ulp_mem_io *)__skb_put(skb, wr_len); ··· 176 173 memset(to_dp + copy_len, 0, T4_ULPTX_MIN_IO - 177 174 (copy_len % T4_ULPTX_MIN_IO)); 178 175 ret = c4iw_ofld_send(rdev, skb); 176 + skb = NULL; 179 177 if (ret) 180 178 return ret; 181 179 len -= C4IW_MAX_INLINE_SIZE; ··· 186 182 return ret; 187 183 } 188 184 189 - static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data) 185 + static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, 186 + void *data, struct sk_buff *skb) 190 187 { 191 188 u32 remain = len; 192 189 u32 dmalen; ··· 210 205 dmalen = T4_ULPTX_MAX_DMA; 211 206 remain -= dmalen; 212 207 ret = _c4iw_write_mem_dma_aligned(rdev, addr, dmalen, daddr, 213 - !remain); 208 + !remain, skb); 214 209 if (ret) 215 210 goto out; 216 211 addr += dmalen >> 5; ··· 218 213 daddr += dmalen; 219 214 } 220 215 if (remain) 221 - ret = _c4iw_write_mem_inline(rdev, addr, remain, data); 216 + ret = _c4iw_write_mem_inline(rdev, addr, remain, data, skb); 222 217 out: 223 218 dma_unmap_single(&rdev->lldi.pdev->dev, save, len, DMA_TO_DEVICE); 224 219 return ret; ··· 229 224 * If data is NULL, clear len byte of memory to zero. 230 225 */ 231 226 static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len, 232 - void *data) 227 + void *data, struct sk_buff *skb) 233 228 { 234 229 if (is_t5(rdev->lldi.adapter_type) && use_dsgl) { 235 230 if (len > inline_threshold) { 236 - if (_c4iw_write_mem_dma(rdev, addr, len, data)) { 231 + if (_c4iw_write_mem_dma(rdev, addr, len, data, skb)) { 237 232 printk_ratelimited(KERN_WARNING 238 233 "%s: dma map" 239 234 " failure (non fatal)\n", 240 235 pci_name(rdev->lldi.pdev)); 241 236 return _c4iw_write_mem_inline(rdev, addr, len, 242 - data); 243 - } else 237 + data, skb); 238 + } else { 244 239 return 0; 240 + } 245 241 } else 246 - return _c4iw_write_mem_inline(rdev, addr, len, data); 242 + return _c4iw_write_mem_inline(rdev, addr, 243 + len, data, skb); 247 244 } else 248 - return _c4iw_write_mem_inline(rdev, addr, len, data); 245 + return _c4iw_write_mem_inline(rdev, addr, len, data, skb); 249 246 } 250 247 251 248 /* ··· 260 253 u32 *stag, u8 stag_state, u32 pdid, 261 254 enum fw_ri_stag_type type, enum fw_ri_mem_perms perm, 262 255 int bind_enabled, u32 zbva, u64 to, 263 - u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr) 256 + u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr, 257 + struct sk_buff *skb) 264 258 { 265 259 int err; 266 260 struct fw_ri_tpte tpt; ··· 315 307 } 316 308 err = write_adapter_mem(rdev, stag_idx + 317 309 (rdev->lldi.vr->stag.start >> 5), 318 - sizeof(tpt), &tpt); 310 + sizeof(tpt), &tpt, skb); 319 311 320 312 if (reset_tpt_entry) { 321 313 c4iw_put_resource(&rdev->resource.tpt_table, stag_idx); ··· 335 327 __func__, pbl_addr, rdev->lldi.vr->pbl.start, 336 328 pbl_size); 337 329 338 - err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl); 330 + err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl, NULL); 339 331 return err; 340 332 } 341 333 342 334 static int dereg_mem(struct c4iw_rdev *rdev, u32 stag, u32 pbl_size, 343 - u32 pbl_addr) 335 + u32 pbl_addr, struct sk_buff *skb) 344 336 { 345 337 return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0, 346 - pbl_size, pbl_addr); 338 + pbl_size, pbl_addr, skb); 347 339 } 348 340 349 341 static int allocate_window(struct c4iw_rdev *rdev, u32 * stag, u32 pdid) 350 342 { 351 343 *stag = T4_STAG_UNSET; 352 344 return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_MW, 0, 0, 0, 353 - 0UL, 0, 0, 0, 0); 345 + 0UL, 0, 0, 0, 0, NULL); 354 346 } 355 347 356 - static int deallocate_window(struct c4iw_rdev *rdev, u32 stag) 348 + static int deallocate_window(struct c4iw_rdev *rdev, u32 stag, 349 + struct sk_buff *skb) 357 350 { 358 351 return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0, 0, 359 - 0); 352 + 0, skb); 360 353 } 361 354 362 355 static int allocate_stag(struct c4iw_rdev *rdev, u32 *stag, u32 pdid, ··· 365 356 { 366 357 *stag = T4_STAG_UNSET; 367 358 return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_NSMR, 0, 0, 0, 368 - 0UL, 0, 0, pbl_size, pbl_addr); 359 + 0UL, 0, 0, pbl_size, pbl_addr, NULL); 369 360 } 370 361 371 362 static int finish_mem_reg(struct c4iw_mr *mhp, u32 stag) ··· 392 383 mhp->attr.mw_bind_enable, mhp->attr.zbva, 393 384 mhp->attr.va_fbo, mhp->attr.len ? 394 385 mhp->attr.len : -1, shift - 12, 395 - mhp->attr.pbl_size, mhp->attr.pbl_addr); 386 + mhp->attr.pbl_size, mhp->attr.pbl_addr, NULL); 396 387 if (ret) 397 388 return ret; 398 389 399 390 ret = finish_mem_reg(mhp, stag); 400 - if (ret) 391 + if (ret) { 401 392 dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, 402 - mhp->attr.pbl_addr); 393 + mhp->attr.pbl_addr, mhp->dereg_skb); 394 + mhp->dereg_skb = NULL; 395 + } 403 396 return ret; 404 397 } 405 398 ··· 434 423 if (!mhp) 435 424 return ERR_PTR(-ENOMEM); 436 425 426 + mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL); 427 + if (!mhp->dereg_skb) { 428 + ret = -ENOMEM; 429 + goto err0; 430 + } 431 + 437 432 mhp->rhp = rhp; 438 433 mhp->attr.pdid = php->pdid; 439 434 mhp->attr.perms = c4iw_ib_to_tpt_access(acc); ··· 452 435 453 436 ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid, 454 437 FW_RI_STAG_NSMR, mhp->attr.perms, 455 - mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0); 438 + mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0, 439 + NULL); 456 440 if (ret) 457 441 goto err1; 458 442 ··· 463 445 return &mhp->ibmr; 464 446 err2: 465 447 dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, 466 - mhp->attr.pbl_addr); 448 + mhp->attr.pbl_addr, mhp->dereg_skb); 467 449 err1: 450 + kfree_skb(mhp->dereg_skb); 451 + err0: 468 452 kfree(mhp); 469 453 return ERR_PTR(ret); 470 454 } ··· 501 481 if (!mhp) 502 482 return ERR_PTR(-ENOMEM); 503 483 484 + mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL); 485 + if (!mhp->dereg_skb) { 486 + kfree(mhp); 487 + return ERR_PTR(-ENOMEM); 488 + } 489 + 504 490 mhp->rhp = rhp; 505 491 506 492 mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); 507 493 if (IS_ERR(mhp->umem)) { 508 494 err = PTR_ERR(mhp->umem); 495 + kfree_skb(mhp->dereg_skb); 509 496 kfree(mhp); 510 497 return ERR_PTR(err); 511 498 } ··· 577 550 578 551 err: 579 552 ib_umem_release(mhp->umem); 553 + kfree_skb(mhp->dereg_skb); 580 554 kfree(mhp); 581 555 return ERR_PTR(err); 582 556 } ··· 600 572 mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); 601 573 if (!mhp) 602 574 return ERR_PTR(-ENOMEM); 575 + 576 + mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL); 577 + if (!mhp->dereg_skb) { 578 + kfree(mhp); 579 + return ERR_PTR(-ENOMEM); 580 + } 581 + 603 582 ret = allocate_window(&rhp->rdev, &stag, php->pdid); 604 583 if (ret) { 584 + kfree(mhp->dereg_skb); 605 585 kfree(mhp); 606 586 return ERR_PTR(ret); 607 587 } ··· 620 584 mmid = (stag) >> 8; 621 585 mhp->ibmw.rkey = stag; 622 586 if (insert_handle(rhp, &rhp->mmidr, mhp, mmid)) { 623 - deallocate_window(&rhp->rdev, mhp->attr.stag); 587 + deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb); 588 + kfree(mhp->dereg_skb); 624 589 kfree(mhp); 625 590 return ERR_PTR(-ENOMEM); 626 591 } ··· 639 602 rhp = mhp->rhp; 640 603 mmid = (mw->rkey) >> 8; 641 604 remove_handle(rhp, &rhp->mmidr, mmid); 642 - deallocate_window(&rhp->rdev, mhp->attr.stag); 605 + deallocate_window(&rhp->rdev, mhp->attr.stag, mhp->dereg_skb); 643 606 kfree(mhp); 644 607 PDBG("%s ib_mw %p mmid 0x%x ptr %p\n", __func__, mw, mmid, mhp); 645 608 return 0; ··· 703 666 return &(mhp->ibmr); 704 667 err3: 705 668 dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size, 706 - mhp->attr.pbl_addr); 669 + mhp->attr.pbl_addr, mhp->dereg_skb); 707 670 err2: 708 671 c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr, 709 672 mhp->attr.pbl_size << 3); ··· 754 717 dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev, 755 718 mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr); 756 719 dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size, 757 - mhp->attr.pbl_addr); 720 + mhp->attr.pbl_addr, mhp->dereg_skb); 758 721 if (mhp->attr.pbl_size) 759 722 c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr, 760 723 mhp->attr.pbl_size << 3);