mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-28 07:04:00 +08:00
RDMA/bnxt_re: Avoid system hang during device un-reg
BNXT_RE_FLAG_TASK_IN_PROG doesn't handle multiple work requests posted together. Track schedule of multiple workqueue items by maintaining a per device counter and proceed with IB dereg only if this counter is zero. flush_workqueue is no longer required from NETDEV_UNREGISTER path. Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
parent
dcdaba0806
commit
7374fbd9e1
@ -120,7 +120,6 @@ struct bnxt_re_dev {
|
|||||||
#define BNXT_RE_FLAG_HAVE_L2_REF 3
|
#define BNXT_RE_FLAG_HAVE_L2_REF 3
|
||||||
#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4
|
#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4
|
||||||
#define BNXT_RE_FLAG_QOS_WORK_REG 5
|
#define BNXT_RE_FLAG_QOS_WORK_REG 5
|
||||||
#define BNXT_RE_FLAG_TASK_IN_PROG 6
|
|
||||||
#define BNXT_RE_FLAG_ISSUE_ROCE_STATS 29
|
#define BNXT_RE_FLAG_ISSUE_ROCE_STATS 29
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
unsigned int version, major, minor;
|
unsigned int version, major, minor;
|
||||||
@ -158,6 +157,7 @@ struct bnxt_re_dev {
|
|||||||
atomic_t srq_count;
|
atomic_t srq_count;
|
||||||
atomic_t mr_count;
|
atomic_t mr_count;
|
||||||
atomic_t mw_count;
|
atomic_t mw_count;
|
||||||
|
atomic_t sched_count;
|
||||||
/* Max of 2 lossless traffic class supported per port */
|
/* Max of 2 lossless traffic class supported per port */
|
||||||
u16 cosq[2];
|
u16 cosq[2];
|
||||||
|
|
||||||
|
@ -656,7 +656,6 @@ static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev)
|
|||||||
mutex_unlock(&bnxt_re_dev_lock);
|
mutex_unlock(&bnxt_re_dev_lock);
|
||||||
|
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
flush_workqueue(bnxt_re_wq);
|
|
||||||
|
|
||||||
ib_dealloc_device(&rdev->ibdev);
|
ib_dealloc_device(&rdev->ibdev);
|
||||||
/* rdev is gone */
|
/* rdev is gone */
|
||||||
@ -1441,7 +1440,7 @@ static void bnxt_re_task(struct work_struct *work)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
smp_mb__before_atomic();
|
smp_mb__before_atomic();
|
||||||
clear_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags);
|
atomic_dec(&rdev->sched_count);
|
||||||
kfree(re_work);
|
kfree(re_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1503,7 +1502,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
|
|||||||
/* netdev notifier will call NETDEV_UNREGISTER again later since
|
/* netdev notifier will call NETDEV_UNREGISTER again later since
|
||||||
* we are still holding the reference to the netdev
|
* we are still holding the reference to the netdev
|
||||||
*/
|
*/
|
||||||
if (test_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags))
|
if (atomic_read(&rdev->sched_count) > 0)
|
||||||
goto exit;
|
goto exit;
|
||||||
bnxt_re_ib_unreg(rdev, false);
|
bnxt_re_ib_unreg(rdev, false);
|
||||||
bnxt_re_remove_one(rdev);
|
bnxt_re_remove_one(rdev);
|
||||||
@ -1523,7 +1522,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
|
|||||||
re_work->vlan_dev = (real_dev == netdev ?
|
re_work->vlan_dev = (real_dev == netdev ?
|
||||||
NULL : netdev);
|
NULL : netdev);
|
||||||
INIT_WORK(&re_work->work, bnxt_re_task);
|
INIT_WORK(&re_work->work, bnxt_re_task);
|
||||||
set_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags);
|
atomic_inc(&rdev->sched_count);
|
||||||
queue_work(bnxt_re_wq, &re_work->work);
|
queue_work(bnxt_re_wq, &re_work->work);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user