aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2012-06-27 11:08:19 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-28 00:20:08 -0400
commita2028b2376a858cb68a7fcc129f6508f59b45381 (patch)
tree133b51113a4f2c9c9c741a1d21fd693477e7ddda /drivers
parentc10237e077cef50e925f052e49f3b4fead9d71f9 (diff)
cnic: Fix occasional NULL pointer dereference during reboot.
We register with bnx2x before we allocate ctx_tbl structure, so it is possible for bnx2x to call cnic_ctl before the structure is allocated. This can sometimes cause NULL pointer dereference of cp->ctx_tbl. We fix this by adding simple checking for valid state before proceeding. The cnic_ctl call is RCU protected so we don't have to deal with race conditions. Because of the additional checking, we need to finish the shutdown before clearing the CNIC_UP flag. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 0e9be2ba924e..31b05ad325d0 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -291,6 +291,9 @@ static int cnic_get_l5_cid(struct cnic_local *cp, u32 cid, u32 *l5_cid)
291{ 291{
292 u32 i; 292 u32 i;
293 293
294 if (!cp->ctx_tbl)
295 return -EINVAL;
296
294 for (i = 0; i < cp->max_cid_space; i++) { 297 for (i = 0; i < cp->max_cid_space; i++) {
295 if (cp->ctx_tbl[i].cid == cid) { 298 if (cp->ctx_tbl[i].cid == cid) {
296 *l5_cid = i; 299 *l5_cid = i;
@@ -3220,6 +3223,9 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
3220 u32 l5_cid; 3223 u32 l5_cid;
3221 struct cnic_local *cp = dev->cnic_priv; 3224 struct cnic_local *cp = dev->cnic_priv;
3222 3225
3226 if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
3227 break;
3228
3223 if (cnic_get_l5_cid(cp, cid, &l5_cid) == 0) { 3229 if (cnic_get_l5_cid(cp, cid, &l5_cid) == 0) {
3224 struct cnic_context *ctx = &cp->ctx_tbl[l5_cid]; 3230 struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
3225 3231
@@ -4253,8 +4259,6 @@ static int cnic_cm_shutdown(struct cnic_dev *dev)
4253 struct cnic_local *cp = dev->cnic_priv; 4259 struct cnic_local *cp = dev->cnic_priv;
4254 int i; 4260 int i;
4255 4261
4256 cp->stop_cm(dev);
4257
4258 if (!cp->csk_tbl) 4262 if (!cp->csk_tbl)
4259 return 0; 4263 return 0;
4260 4264
@@ -5290,6 +5294,7 @@ static void cnic_stop_hw(struct cnic_dev *dev)
5290 i++; 5294 i++;
5291 } 5295 }
5292 cnic_shutdown_rings(dev); 5296 cnic_shutdown_rings(dev);
5297 cp->stop_cm(dev);
5293 clear_bit(CNIC_F_CNIC_UP, &dev->flags); 5298 clear_bit(CNIC_F_CNIC_UP, &dev->flags);
5294 RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL); 5299 RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL);
5295 synchronize_rcu(); 5300 synchronize_rcu();