Skip to content

Commit 38a65e7

Browse files
RajuRangojugregkh
authored andcommitted
RDMA/cxgb4: release hw resources on device removal
commit 26bff1b upstream. The c4iw_rdev_close() logic was not releasing all the hw resources (PBL and RQT memory) during the device removal event (driver unload / system reboot). This can cause panic in gen_pool_destroy(). The module remove function will wait for all the hw resources to be released during the device removal event. Fixes c12a67f(iw_cxgb4: free EQ queue memory on last deref) Signed-off-by: Raju Rangoju <rajur@chelsio.com> Reviewed-by: Steve Wise <swise@opengridcomputing.com> Cc: stable@vger.kernel.org Signed-off-by: Doug Ledford <dledford@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent bd9ca96 commit 38a65e7

3 files changed

Lines changed: 36 additions & 3 deletions

File tree

drivers/infiniband/hw/cxgb4/device.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,11 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
884884

885885
rdev->status_page->db_off = 0;
886886

887+
init_completion(&rdev->rqt_compl);
888+
init_completion(&rdev->pbl_compl);
889+
kref_init(&rdev->rqt_kref);
890+
kref_init(&rdev->pbl_kref);
891+
887892
return 0;
888893
err_free_status_page_and_wr_log:
889894
if (c4iw_wr_log && rdev->wr_log)
@@ -902,13 +907,15 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
902907

903908
static void c4iw_rdev_close(struct c4iw_rdev *rdev)
904909
{
905-
destroy_workqueue(rdev->free_workq);
906910
kfree(rdev->wr_log);
907911
c4iw_release_dev_ucontext(rdev, &rdev->uctx);
908912
free_page((unsigned long)rdev->status_page);
909913
c4iw_pblpool_destroy(rdev);
910914
c4iw_rqtpool_destroy(rdev);
915+
wait_for_completion(&rdev->pbl_compl);
916+
wait_for_completion(&rdev->rqt_compl);
911917
c4iw_ocqp_pool_destroy(rdev);
918+
destroy_workqueue(rdev->free_workq);
912919
c4iw_destroy_resource(&rdev->resource);
913920
}
914921

drivers/infiniband/hw/cxgb4/iw_cxgb4.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ struct c4iw_rdev {
185185
struct wr_log_entry *wr_log;
186186
int wr_log_size;
187187
struct workqueue_struct *free_workq;
188+
struct completion rqt_compl;
189+
struct completion pbl_compl;
190+
struct kref rqt_kref;
191+
struct kref pbl_kref;
188192
};
189193

190194
static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)

drivers/infiniband/hw/cxgb4/resource.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,19 +260,30 @@ u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
260260
rdev->stats.pbl.cur += roundup(size, 1 << MIN_PBL_SHIFT);
261261
if (rdev->stats.pbl.cur > rdev->stats.pbl.max)
262262
rdev->stats.pbl.max = rdev->stats.pbl.cur;
263+
kref_get(&rdev->pbl_kref);
263264
} else
264265
rdev->stats.pbl.fail++;
265266
mutex_unlock(&rdev->stats.lock);
266267
return (u32)addr;
267268
}
268269

270+
static void destroy_pblpool(struct kref *kref)
271+
{
272+
struct c4iw_rdev *rdev;
273+
274+
rdev = container_of(kref, struct c4iw_rdev, pbl_kref);
275+
gen_pool_destroy(rdev->pbl_pool);
276+
complete(&rdev->pbl_compl);
277+
}
278+
269279
void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
270280
{
271281
pr_debug("%s addr 0x%x size %d\n", __func__, addr, size);
272282
mutex_lock(&rdev->stats.lock);
273283
rdev->stats.pbl.cur -= roundup(size, 1 << MIN_PBL_SHIFT);
274284
mutex_unlock(&rdev->stats.lock);
275285
gen_pool_free(rdev->pbl_pool, (unsigned long)addr, size);
286+
kref_put(&rdev->pbl_kref, destroy_pblpool);
276287
}
277288

278289
int c4iw_pblpool_create(struct c4iw_rdev *rdev)
@@ -310,7 +321,7 @@ int c4iw_pblpool_create(struct c4iw_rdev *rdev)
310321

311322
void c4iw_pblpool_destroy(struct c4iw_rdev *rdev)
312323
{
313-
gen_pool_destroy(rdev->pbl_pool);
324+
kref_put(&rdev->pbl_kref, destroy_pblpool);
314325
}
315326

316327
/*
@@ -331,19 +342,30 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
331342
rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT);
332343
if (rdev->stats.rqt.cur > rdev->stats.rqt.max)
333344
rdev->stats.rqt.max = rdev->stats.rqt.cur;
345+
kref_get(&rdev->rqt_kref);
334346
} else
335347
rdev->stats.rqt.fail++;
336348
mutex_unlock(&rdev->stats.lock);
337349
return (u32)addr;
338350
}
339351

352+
static void destroy_rqtpool(struct kref *kref)
353+
{
354+
struct c4iw_rdev *rdev;
355+
356+
rdev = container_of(kref, struct c4iw_rdev, rqt_kref);
357+
gen_pool_destroy(rdev->rqt_pool);
358+
complete(&rdev->rqt_compl);
359+
}
360+
340361
void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
341362
{
342363
pr_debug("%s addr 0x%x size %d\n", __func__, addr, size << 6);
343364
mutex_lock(&rdev->stats.lock);
344365
rdev->stats.rqt.cur -= roundup(size << 6, 1 << MIN_RQT_SHIFT);
345366
mutex_unlock(&rdev->stats.lock);
346367
gen_pool_free(rdev->rqt_pool, (unsigned long)addr, size << 6);
368+
kref_put(&rdev->rqt_kref, destroy_rqtpool);
347369
}
348370

349371
int c4iw_rqtpool_create(struct c4iw_rdev *rdev)
@@ -380,7 +402,7 @@ int c4iw_rqtpool_create(struct c4iw_rdev *rdev)
380402

381403
void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev)
382404
{
383-
gen_pool_destroy(rdev->rqt_pool);
405+
kref_put(&rdev->rqt_kref, destroy_rqtpool);
384406
}
385407

386408
/*

0 commit comments

Comments
 (0)