diff options
Diffstat (limited to 'drivers/net/cnic.c')
| -rw-r--r-- | drivers/net/cnic.c | 143 |
1 files changed, 104 insertions, 39 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 4869d77cbe91..74c342959b7b 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c | |||
| @@ -138,6 +138,16 @@ static struct cnic_dev *cnic_from_netdev(struct net_device *netdev) | |||
| 138 | return NULL; | 138 | return NULL; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | static inline void ulp_get(struct cnic_ulp_ops *ulp_ops) | ||
| 142 | { | ||
| 143 | atomic_inc(&ulp_ops->ref_count); | ||
| 144 | } | ||
| 145 | |||
| 146 | static inline void ulp_put(struct cnic_ulp_ops *ulp_ops) | ||
| 147 | { | ||
| 148 | atomic_dec(&ulp_ops->ref_count); | ||
| 149 | } | ||
| 150 | |||
| 141 | static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val) | 151 | static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val) |
| 142 | { | 152 | { |
| 143 | struct cnic_local *cp = dev->cnic_priv; | 153 | struct cnic_local *cp = dev->cnic_priv; |
| @@ -358,6 +368,7 @@ int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops) | |||
| 358 | } | 368 | } |
| 359 | read_unlock(&cnic_dev_lock); | 369 | read_unlock(&cnic_dev_lock); |
| 360 | 370 | ||
| 371 | atomic_set(&ulp_ops->ref_count, 0); | ||
| 361 | rcu_assign_pointer(cnic_ulp_tbl[ulp_type], ulp_ops); | 372 | rcu_assign_pointer(cnic_ulp_tbl[ulp_type], ulp_ops); |
| 362 | mutex_unlock(&cnic_lock); | 373 | mutex_unlock(&cnic_lock); |
| 363 | 374 | ||
| @@ -379,6 +390,8 @@ int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops) | |||
| 379 | int cnic_unregister_driver(int ulp_type) | 390 | int cnic_unregister_driver(int ulp_type) |
| 380 | { | 391 | { |
| 381 | struct cnic_dev *dev; | 392 | struct cnic_dev *dev; |
| 393 | struct cnic_ulp_ops *ulp_ops; | ||
| 394 | int i = 0; | ||
| 382 | 395 | ||
| 383 | if (ulp_type >= MAX_CNIC_ULP_TYPE) { | 396 | if (ulp_type >= MAX_CNIC_ULP_TYPE) { |
| 384 | printk(KERN_ERR PFX "cnic_unregister_driver: Bad type %d\n", | 397 | printk(KERN_ERR PFX "cnic_unregister_driver: Bad type %d\n", |
| @@ -386,7 +399,8 @@ int cnic_unregister_driver(int ulp_type) | |||
| 386 | return -EINVAL; | 399 | return -EINVAL; |
| 387 | } | 400 | } |
| 388 | mutex_lock(&cnic_lock); | 401 | mutex_lock(&cnic_lock); |
| 389 | if (!cnic_ulp_tbl[ulp_type]) { | 402 | ulp_ops = cnic_ulp_tbl[ulp_type]; |
| 403 | if (!ulp_ops) { | ||
| 390 | printk(KERN_ERR PFX "cnic_unregister_driver: Type %d has not " | 404 | printk(KERN_ERR PFX "cnic_unregister_driver: Type %d has not " |
| 391 | "been registered\n", ulp_type); | 405 | "been registered\n", ulp_type); |
| 392 | goto out_unlock; | 406 | goto out_unlock; |
| @@ -411,6 +425,14 @@ int cnic_unregister_driver(int ulp_type) | |||
| 411 | 425 | ||
| 412 | mutex_unlock(&cnic_lock); | 426 | mutex_unlock(&cnic_lock); |
| 413 | synchronize_rcu(); | 427 | synchronize_rcu(); |
| 428 | while ((atomic_read(&ulp_ops->ref_count) != 0) && (i < 20)) { | ||
| 429 | msleep(100); | ||
| 430 | i++; | ||
| 431 | } | ||
| 432 | |||
| 433 | if (atomic_read(&ulp_ops->ref_count) != 0) | ||
| 434 | printk(KERN_WARNING PFX "%s: Failed waiting for ref count to go" | ||
| 435 | " to zero.\n", dev->netdev->name); | ||
| 414 | return 0; | 436 | return 0; |
| 415 | 437 | ||
| 416 | out_unlock: | 438 | out_unlock: |
| @@ -466,6 +488,7 @@ EXPORT_SYMBOL(cnic_register_driver); | |||
| 466 | static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type) | 488 | static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type) |
| 467 | { | 489 | { |
| 468 | struct cnic_local *cp = dev->cnic_priv; | 490 | struct cnic_local *cp = dev->cnic_priv; |
| 491 | int i = 0; | ||
| 469 | 492 | ||
| 470 | if (ulp_type >= MAX_CNIC_ULP_TYPE) { | 493 | if (ulp_type >= MAX_CNIC_ULP_TYPE) { |
| 471 | printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n", | 494 | printk(KERN_ERR PFX "cnic_unregister_device: Bad type %d\n", |
| @@ -486,6 +509,15 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type) | |||
| 486 | 509 | ||
| 487 | synchronize_rcu(); | 510 | synchronize_rcu(); |
| 488 | 511 | ||
| 512 | while (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type]) && | ||
| 513 | i < 20) { | ||
| 514 | msleep(100); | ||
| 515 | i++; | ||
| 516 | } | ||
| 517 | if (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type])) | ||
| 518 | printk(KERN_WARNING PFX "%s: Failed waiting for ULP up call" | ||
| 519 | " to complete.\n", dev->netdev->name); | ||
| 520 | |||
| 489 | return 0; | 521 | return 0; |
| 490 | } | 522 | } |
| 491 | EXPORT_SYMBOL(cnic_unregister_driver); | 523 | EXPORT_SYMBOL(cnic_unregister_driver); |
| @@ -1076,18 +1108,23 @@ static void cnic_ulp_stop(struct cnic_dev *dev) | |||
| 1076 | if (cp->cnic_uinfo) | 1108 | if (cp->cnic_uinfo) |
| 1077 | cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); | 1109 | cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); |
| 1078 | 1110 | ||
| 1079 | rcu_read_lock(); | ||
| 1080 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { | 1111 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { |
| 1081 | struct cnic_ulp_ops *ulp_ops; | 1112 | struct cnic_ulp_ops *ulp_ops; |
| 1082 | 1113 | ||
| 1083 | ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); | 1114 | mutex_lock(&cnic_lock); |
| 1084 | if (!ulp_ops) | 1115 | ulp_ops = cp->ulp_ops[if_type]; |
| 1116 | if (!ulp_ops) { | ||
| 1117 | mutex_unlock(&cnic_lock); | ||
| 1085 | continue; | 1118 | continue; |
| 1119 | } | ||
| 1120 | set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
| 1121 | mutex_unlock(&cnic_lock); | ||
| 1086 | 1122 | ||
| 1087 | if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) | 1123 | if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) |
| 1088 | ulp_ops->cnic_stop(cp->ulp_handle[if_type]); | 1124 | ulp_ops->cnic_stop(cp->ulp_handle[if_type]); |
| 1125 | |||
| 1126 | clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
| 1089 | } | 1127 | } |
| 1090 | rcu_read_unlock(); | ||
| 1091 | } | 1128 | } |
| 1092 | 1129 | ||
| 1093 | static void cnic_ulp_start(struct cnic_dev *dev) | 1130 | static void cnic_ulp_start(struct cnic_dev *dev) |
| @@ -1095,18 +1132,23 @@ static void cnic_ulp_start(struct cnic_dev *dev) | |||
| 1095 | struct cnic_local *cp = dev->cnic_priv; | 1132 | struct cnic_local *cp = dev->cnic_priv; |
| 1096 | int if_type; | 1133 | int if_type; |
| 1097 | 1134 | ||
| 1098 | rcu_read_lock(); | ||
| 1099 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { | 1135 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { |
| 1100 | struct cnic_ulp_ops *ulp_ops; | 1136 | struct cnic_ulp_ops *ulp_ops; |
| 1101 | 1137 | ||
| 1102 | ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); | 1138 | mutex_lock(&cnic_lock); |
| 1103 | if (!ulp_ops || !ulp_ops->cnic_start) | 1139 | ulp_ops = cp->ulp_ops[if_type]; |
| 1140 | if (!ulp_ops || !ulp_ops->cnic_start) { | ||
| 1141 | mutex_unlock(&cnic_lock); | ||
| 1104 | continue; | 1142 | continue; |
| 1143 | } | ||
| 1144 | set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
| 1145 | mutex_unlock(&cnic_lock); | ||
| 1105 | 1146 | ||
| 1106 | if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type])) | 1147 | if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type])) |
| 1107 | ulp_ops->cnic_start(cp->ulp_handle[if_type]); | 1148 | ulp_ops->cnic_start(cp->ulp_handle[if_type]); |
| 1149 | |||
| 1150 | clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
| 1108 | } | 1151 | } |
| 1109 | rcu_read_unlock(); | ||
| 1110 | } | 1152 | } |
| 1111 | 1153 | ||
| 1112 | static int cnic_ctl(void *data, struct cnic_ctl_info *info) | 1154 | static int cnic_ctl(void *data, struct cnic_ctl_info *info) |
| @@ -1116,22 +1158,18 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info) | |||
| 1116 | switch (info->cmd) { | 1158 | switch (info->cmd) { |
| 1117 | case CNIC_CTL_STOP_CMD: | 1159 | case CNIC_CTL_STOP_CMD: |
| 1118 | cnic_hold(dev); | 1160 | cnic_hold(dev); |
| 1119 | mutex_lock(&cnic_lock); | ||
| 1120 | 1161 | ||
| 1121 | cnic_ulp_stop(dev); | 1162 | cnic_ulp_stop(dev); |
| 1122 | cnic_stop_hw(dev); | 1163 | cnic_stop_hw(dev); |
| 1123 | 1164 | ||
| 1124 | mutex_unlock(&cnic_lock); | ||
| 1125 | cnic_put(dev); | 1165 | cnic_put(dev); |
| 1126 | break; | 1166 | break; |
| 1127 | case CNIC_CTL_START_CMD: | 1167 | case CNIC_CTL_START_CMD: |
| 1128 | cnic_hold(dev); | 1168 | cnic_hold(dev); |
| 1129 | mutex_lock(&cnic_lock); | ||
| 1130 | 1169 | ||
| 1131 | if (!cnic_start_hw(dev)) | 1170 | if (!cnic_start_hw(dev)) |
| 1132 | cnic_ulp_start(dev); | 1171 | cnic_ulp_start(dev); |
| 1133 | 1172 | ||
| 1134 | mutex_unlock(&cnic_lock); | ||
| 1135 | cnic_put(dev); | 1173 | cnic_put(dev); |
| 1136 | break; | 1174 | break; |
| 1137 | default: | 1175 | default: |
| @@ -1145,19 +1183,23 @@ static void cnic_ulp_init(struct cnic_dev *dev) | |||
| 1145 | int i; | 1183 | int i; |
| 1146 | struct cnic_local *cp = dev->cnic_priv; | 1184 | struct cnic_local *cp = dev->cnic_priv; |
| 1147 | 1185 | ||
| 1148 | rcu_read_lock(); | ||
| 1149 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { | 1186 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { |
| 1150 | struct cnic_ulp_ops *ulp_ops; | 1187 | struct cnic_ulp_ops *ulp_ops; |
| 1151 | 1188 | ||
| 1152 | ulp_ops = rcu_dereference(cnic_ulp_tbl[i]); | 1189 | mutex_lock(&cnic_lock); |
| 1153 | if (!ulp_ops || !ulp_ops->cnic_init) | 1190 | ulp_ops = cnic_ulp_tbl[i]; |
| 1191 | if (!ulp_ops || !ulp_ops->cnic_init) { | ||
| 1192 | mutex_unlock(&cnic_lock); | ||
| 1154 | continue; | 1193 | continue; |
| 1194 | } | ||
| 1195 | ulp_get(ulp_ops); | ||
| 1196 | mutex_unlock(&cnic_lock); | ||
| 1155 | 1197 | ||
| 1156 | if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i])) | 1198 | if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i])) |
| 1157 | ulp_ops->cnic_init(dev); | 1199 | ulp_ops->cnic_init(dev); |
| 1158 | 1200 | ||
| 1201 | ulp_put(ulp_ops); | ||
| 1159 | } | 1202 | } |
| 1160 | rcu_read_unlock(); | ||
| 1161 | } | 1203 | } |
| 1162 | 1204 | ||
| 1163 | static void cnic_ulp_exit(struct cnic_dev *dev) | 1205 | static void cnic_ulp_exit(struct cnic_dev *dev) |
| @@ -1165,19 +1207,23 @@ static void cnic_ulp_exit(struct cnic_dev *dev) | |||
| 1165 | int i; | 1207 | int i; |
| 1166 | struct cnic_local *cp = dev->cnic_priv; | 1208 | struct cnic_local *cp = dev->cnic_priv; |
| 1167 | 1209 | ||
| 1168 | rcu_read_lock(); | ||
| 1169 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { | 1210 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { |
| 1170 | struct cnic_ulp_ops *ulp_ops; | 1211 | struct cnic_ulp_ops *ulp_ops; |
| 1171 | 1212 | ||
| 1172 | ulp_ops = rcu_dereference(cnic_ulp_tbl[i]); | 1213 | mutex_lock(&cnic_lock); |
| 1173 | if (!ulp_ops || !ulp_ops->cnic_exit) | 1214 | ulp_ops = cnic_ulp_tbl[i]; |
| 1215 | if (!ulp_ops || !ulp_ops->cnic_exit) { | ||
| 1216 | mutex_unlock(&cnic_lock); | ||
| 1174 | continue; | 1217 | continue; |
| 1218 | } | ||
| 1219 | ulp_get(ulp_ops); | ||
| 1220 | mutex_unlock(&cnic_lock); | ||
| 1175 | 1221 | ||
| 1176 | if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i])) | 1222 | if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i])) |
| 1177 | ulp_ops->cnic_exit(dev); | 1223 | ulp_ops->cnic_exit(dev); |
| 1178 | 1224 | ||
| 1225 | ulp_put(ulp_ops); | ||
| 1179 | } | 1226 | } |
| 1180 | rcu_read_unlock(); | ||
| 1181 | } | 1227 | } |
| 1182 | 1228 | ||
| 1183 | static int cnic_cm_offload_pg(struct cnic_sock *csk) | 1229 | static int cnic_cm_offload_pg(struct cnic_sock *csk) |
| @@ -2393,21 +2439,45 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev) | |||
| 2393 | return 0; | 2439 | return 0; |
| 2394 | } | 2440 | } |
| 2395 | 2441 | ||
| 2396 | static int cnic_start_hw(struct cnic_dev *dev) | 2442 | static int cnic_register_netdev(struct cnic_dev *dev) |
| 2397 | { | 2443 | { |
| 2398 | struct cnic_local *cp = dev->cnic_priv; | 2444 | struct cnic_local *cp = dev->cnic_priv; |
| 2399 | struct cnic_eth_dev *ethdev = cp->ethdev; | 2445 | struct cnic_eth_dev *ethdev = cp->ethdev; |
| 2400 | int err; | 2446 | int err; |
| 2401 | 2447 | ||
| 2402 | if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) | 2448 | if (!ethdev) |
| 2403 | return -EALREADY; | 2449 | return -ENODEV; |
| 2450 | |||
| 2451 | if (ethdev->drv_state & CNIC_DRV_STATE_REGD) | ||
| 2452 | return 0; | ||
| 2404 | 2453 | ||
| 2405 | err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev); | 2454 | err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev); |
| 2406 | if (err) { | 2455 | if (err) |
| 2407 | printk(KERN_ERR PFX "%s: register_cnic failed\n", | 2456 | printk(KERN_ERR PFX "%s: register_cnic failed\n", |
| 2408 | dev->netdev->name); | 2457 | dev->netdev->name); |
| 2409 | goto err2; | 2458 | |
| 2410 | } | 2459 | return err; |
| 2460 | } | ||
| 2461 | |||
| 2462 | static void cnic_unregister_netdev(struct cnic_dev *dev) | ||
| 2463 | { | ||
| 2464 | struct cnic_local *cp = dev->cnic_priv; | ||
| 2465 | struct cnic_eth_dev *ethdev = cp->ethdev; | ||
| 2466 | |||
| 2467 | if (!ethdev) | ||
| 2468 | return; | ||
| 2469 | |||
| 2470 | ethdev->drv_unregister_cnic(dev->netdev); | ||
| 2471 | } | ||
| 2472 | |||
| 2473 | static int cnic_start_hw(struct cnic_dev *dev) | ||
| 2474 | { | ||
| 2475 | struct cnic_local *cp = dev->cnic_priv; | ||
| 2476 | struct cnic_eth_dev *ethdev = cp->ethdev; | ||
| 2477 | int err; | ||
| 2478 | |||
| 2479 | if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) | ||
| 2480 | return -EALREADY; | ||
| 2411 | 2481 | ||
| 2412 | dev->regview = ethdev->io_base; | 2482 | dev->regview = ethdev->io_base; |
| 2413 | cp->chip_id = ethdev->chip_id; | 2483 | cp->chip_id = ethdev->chip_id; |
| @@ -2438,18 +2508,13 @@ static int cnic_start_hw(struct cnic_dev *dev) | |||
| 2438 | return 0; | 2508 | return 0; |
| 2439 | 2509 | ||
| 2440 | err1: | 2510 | err1: |
| 2441 | ethdev->drv_unregister_cnic(dev->netdev); | ||
| 2442 | cp->free_resc(dev); | 2511 | cp->free_resc(dev); |
| 2443 | pci_dev_put(dev->pcidev); | 2512 | pci_dev_put(dev->pcidev); |
| 2444 | err2: | ||
| 2445 | return err; | 2513 | return err; |
| 2446 | } | 2514 | } |
| 2447 | 2515 | ||
| 2448 | static void cnic_stop_bnx2_hw(struct cnic_dev *dev) | 2516 | static void cnic_stop_bnx2_hw(struct cnic_dev *dev) |
| 2449 | { | 2517 | { |
| 2450 | struct cnic_local *cp = dev->cnic_priv; | ||
| 2451 | struct cnic_eth_dev *ethdev = cp->ethdev; | ||
| 2452 | |||
| 2453 | cnic_disable_bnx2_int_sync(dev); | 2518 | cnic_disable_bnx2_int_sync(dev); |
| 2454 | 2519 | ||
| 2455 | cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0); | 2520 | cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0); |
| @@ -2461,8 +2526,6 @@ static void cnic_stop_bnx2_hw(struct cnic_dev *dev) | |||
| 2461 | cnic_setup_5709_context(dev, 0); | 2526 | cnic_setup_5709_context(dev, 0); |
| 2462 | cnic_free_irq(dev); | 2527 | cnic_free_irq(dev); |
| 2463 | 2528 | ||
| 2464 | ethdev->drv_unregister_cnic(dev->netdev); | ||
| 2465 | |||
| 2466 | cnic_free_resc(dev); | 2529 | cnic_free_resc(dev); |
| 2467 | } | 2530 | } |
| 2468 | 2531 | ||
| @@ -2543,7 +2606,7 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev) | |||
| 2543 | probe = symbol_get(bnx2_cnic_probe); | 2606 | probe = symbol_get(bnx2_cnic_probe); |
| 2544 | if (probe) { | 2607 | if (probe) { |
| 2545 | ethdev = (*probe)(dev); | 2608 | ethdev = (*probe)(dev); |
| 2546 | symbol_put_addr(probe); | 2609 | symbol_put(bnx2_cnic_probe); |
| 2547 | } | 2610 | } |
| 2548 | if (!ethdev) | 2611 | if (!ethdev) |
| 2549 | return NULL; | 2612 | return NULL; |
| @@ -2646,10 +2709,12 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event, | |||
| 2646 | else if (event == NETDEV_UNREGISTER) | 2709 | else if (event == NETDEV_UNREGISTER) |
| 2647 | cnic_ulp_exit(dev); | 2710 | cnic_ulp_exit(dev); |
| 2648 | else if (event == NETDEV_UP) { | 2711 | else if (event == NETDEV_UP) { |
| 2649 | mutex_lock(&cnic_lock); | 2712 | if (cnic_register_netdev(dev) != 0) { |
| 2713 | cnic_put(dev); | ||
| 2714 | goto done; | ||
| 2715 | } | ||
| 2650 | if (!cnic_start_hw(dev)) | 2716 | if (!cnic_start_hw(dev)) |
| 2651 | cnic_ulp_start(dev); | 2717 | cnic_ulp_start(dev); |
| 2652 | mutex_unlock(&cnic_lock); | ||
| 2653 | } | 2718 | } |
| 2654 | 2719 | ||
| 2655 | rcu_read_lock(); | 2720 | rcu_read_lock(); |
| @@ -2668,10 +2733,9 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event, | |||
| 2668 | rcu_read_unlock(); | 2733 | rcu_read_unlock(); |
| 2669 | 2734 | ||
| 2670 | if (event == NETDEV_GOING_DOWN) { | 2735 | if (event == NETDEV_GOING_DOWN) { |
| 2671 | mutex_lock(&cnic_lock); | ||
| 2672 | cnic_ulp_stop(dev); | 2736 | cnic_ulp_stop(dev); |
| 2673 | cnic_stop_hw(dev); | 2737 | cnic_stop_hw(dev); |
| 2674 | mutex_unlock(&cnic_lock); | 2738 | cnic_unregister_netdev(dev); |
| 2675 | } else if (event == NETDEV_UNREGISTER) { | 2739 | } else if (event == NETDEV_UNREGISTER) { |
| 2676 | write_lock(&cnic_dev_lock); | 2740 | write_lock(&cnic_dev_lock); |
| 2677 | list_del_init(&dev->list); | 2741 | list_del_init(&dev->list); |
| @@ -2703,6 +2767,7 @@ static void cnic_release(void) | |||
| 2703 | } | 2767 | } |
| 2704 | 2768 | ||
| 2705 | cnic_ulp_exit(dev); | 2769 | cnic_ulp_exit(dev); |
| 2770 | cnic_unregister_netdev(dev); | ||
| 2706 | list_del_init(&dev->list); | 2771 | list_del_init(&dev->list); |
| 2707 | cnic_free_dev(dev); | 2772 | cnic_free_dev(dev); |
| 2708 | } | 2773 | } |
