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 f8a09236dc0a..d45eacb76702 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); |
@@ -1101,18 +1133,23 @@ static void cnic_ulp_stop(struct cnic_dev *dev) | |||
1101 | if (cp->cnic_uinfo) | 1133 | if (cp->cnic_uinfo) |
1102 | cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); | 1134 | cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL); |
1103 | 1135 | ||
1104 | rcu_read_lock(); | ||
1105 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { | 1136 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { |
1106 | struct cnic_ulp_ops *ulp_ops; | 1137 | struct cnic_ulp_ops *ulp_ops; |
1107 | 1138 | ||
1108 | ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); | 1139 | mutex_lock(&cnic_lock); |
1109 | if (!ulp_ops) | 1140 | ulp_ops = cp->ulp_ops[if_type]; |
1141 | if (!ulp_ops) { | ||
1142 | mutex_unlock(&cnic_lock); | ||
1110 | continue; | 1143 | continue; |
1144 | } | ||
1145 | set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
1146 | mutex_unlock(&cnic_lock); | ||
1111 | 1147 | ||
1112 | if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) | 1148 | if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type])) |
1113 | ulp_ops->cnic_stop(cp->ulp_handle[if_type]); | 1149 | ulp_ops->cnic_stop(cp->ulp_handle[if_type]); |
1150 | |||
1151 | clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
1114 | } | 1152 | } |
1115 | rcu_read_unlock(); | ||
1116 | } | 1153 | } |
1117 | 1154 | ||
1118 | static void cnic_ulp_start(struct cnic_dev *dev) | 1155 | static void cnic_ulp_start(struct cnic_dev *dev) |
@@ -1120,18 +1157,23 @@ static void cnic_ulp_start(struct cnic_dev *dev) | |||
1120 | struct cnic_local *cp = dev->cnic_priv; | 1157 | struct cnic_local *cp = dev->cnic_priv; |
1121 | int if_type; | 1158 | int if_type; |
1122 | 1159 | ||
1123 | rcu_read_lock(); | ||
1124 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { | 1160 | for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) { |
1125 | struct cnic_ulp_ops *ulp_ops; | 1161 | struct cnic_ulp_ops *ulp_ops; |
1126 | 1162 | ||
1127 | ulp_ops = rcu_dereference(cp->ulp_ops[if_type]); | 1163 | mutex_lock(&cnic_lock); |
1128 | if (!ulp_ops || !ulp_ops->cnic_start) | 1164 | ulp_ops = cp->ulp_ops[if_type]; |
1165 | if (!ulp_ops || !ulp_ops->cnic_start) { | ||
1166 | mutex_unlock(&cnic_lock); | ||
1129 | continue; | 1167 | continue; |
1168 | } | ||
1169 | set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
1170 | mutex_unlock(&cnic_lock); | ||
1130 | 1171 | ||
1131 | if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type])) | 1172 | if (!test_and_set_bit(ULP_F_START, &cp->ulp_flags[if_type])) |
1132 | ulp_ops->cnic_start(cp->ulp_handle[if_type]); | 1173 | ulp_ops->cnic_start(cp->ulp_handle[if_type]); |
1174 | |||
1175 | clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]); | ||
1133 | } | 1176 | } |
1134 | rcu_read_unlock(); | ||
1135 | } | 1177 | } |
1136 | 1178 | ||
1137 | static int cnic_ctl(void *data, struct cnic_ctl_info *info) | 1179 | static int cnic_ctl(void *data, struct cnic_ctl_info *info) |
@@ -1141,22 +1183,18 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info) | |||
1141 | switch (info->cmd) { | 1183 | switch (info->cmd) { |
1142 | case CNIC_CTL_STOP_CMD: | 1184 | case CNIC_CTL_STOP_CMD: |
1143 | cnic_hold(dev); | 1185 | cnic_hold(dev); |
1144 | mutex_lock(&cnic_lock); | ||
1145 | 1186 | ||
1146 | cnic_ulp_stop(dev); | 1187 | cnic_ulp_stop(dev); |
1147 | cnic_stop_hw(dev); | 1188 | cnic_stop_hw(dev); |
1148 | 1189 | ||
1149 | mutex_unlock(&cnic_lock); | ||
1150 | cnic_put(dev); | 1190 | cnic_put(dev); |
1151 | break; | 1191 | break; |
1152 | case CNIC_CTL_START_CMD: | 1192 | case CNIC_CTL_START_CMD: |
1153 | cnic_hold(dev); | 1193 | cnic_hold(dev); |
1154 | mutex_lock(&cnic_lock); | ||
1155 | 1194 | ||
1156 | if (!cnic_start_hw(dev)) | 1195 | if (!cnic_start_hw(dev)) |
1157 | cnic_ulp_start(dev); | 1196 | cnic_ulp_start(dev); |
1158 | 1197 | ||
1159 | mutex_unlock(&cnic_lock); | ||
1160 | cnic_put(dev); | 1198 | cnic_put(dev); |
1161 | break; | 1199 | break; |
1162 | default: | 1200 | default: |
@@ -1170,19 +1208,23 @@ static void cnic_ulp_init(struct cnic_dev *dev) | |||
1170 | int i; | 1208 | int i; |
1171 | struct cnic_local *cp = dev->cnic_priv; | 1209 | struct cnic_local *cp = dev->cnic_priv; |
1172 | 1210 | ||
1173 | rcu_read_lock(); | ||
1174 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { | 1211 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { |
1175 | struct cnic_ulp_ops *ulp_ops; | 1212 | struct cnic_ulp_ops *ulp_ops; |
1176 | 1213 | ||
1177 | ulp_ops = rcu_dereference(cnic_ulp_tbl[i]); | 1214 | mutex_lock(&cnic_lock); |
1178 | if (!ulp_ops || !ulp_ops->cnic_init) | 1215 | ulp_ops = cnic_ulp_tbl[i]; |
1216 | if (!ulp_ops || !ulp_ops->cnic_init) { | ||
1217 | mutex_unlock(&cnic_lock); | ||
1179 | continue; | 1218 | continue; |
1219 | } | ||
1220 | ulp_get(ulp_ops); | ||
1221 | mutex_unlock(&cnic_lock); | ||
1180 | 1222 | ||
1181 | if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i])) | 1223 | if (!test_and_set_bit(ULP_F_INIT, &cp->ulp_flags[i])) |
1182 | ulp_ops->cnic_init(dev); | 1224 | ulp_ops->cnic_init(dev); |
1183 | 1225 | ||
1226 | ulp_put(ulp_ops); | ||
1184 | } | 1227 | } |
1185 | rcu_read_unlock(); | ||
1186 | } | 1228 | } |
1187 | 1229 | ||
1188 | static void cnic_ulp_exit(struct cnic_dev *dev) | 1230 | static void cnic_ulp_exit(struct cnic_dev *dev) |
@@ -1190,19 +1232,23 @@ static void cnic_ulp_exit(struct cnic_dev *dev) | |||
1190 | int i; | 1232 | int i; |
1191 | struct cnic_local *cp = dev->cnic_priv; | 1233 | struct cnic_local *cp = dev->cnic_priv; |
1192 | 1234 | ||
1193 | rcu_read_lock(); | ||
1194 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { | 1235 | for (i = 0; i < MAX_CNIC_ULP_TYPE_EXT; i++) { |
1195 | struct cnic_ulp_ops *ulp_ops; | 1236 | struct cnic_ulp_ops *ulp_ops; |
1196 | 1237 | ||
1197 | ulp_ops = rcu_dereference(cnic_ulp_tbl[i]); | 1238 | mutex_lock(&cnic_lock); |
1198 | if (!ulp_ops || !ulp_ops->cnic_exit) | 1239 | ulp_ops = cnic_ulp_tbl[i]; |
1240 | if (!ulp_ops || !ulp_ops->cnic_exit) { | ||
1241 | mutex_unlock(&cnic_lock); | ||
1199 | continue; | 1242 | continue; |
1243 | } | ||
1244 | ulp_get(ulp_ops); | ||
1245 | mutex_unlock(&cnic_lock); | ||
1200 | 1246 | ||
1201 | if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i])) | 1247 | if (test_and_clear_bit(ULP_F_INIT, &cp->ulp_flags[i])) |
1202 | ulp_ops->cnic_exit(dev); | 1248 | ulp_ops->cnic_exit(dev); |
1203 | 1249 | ||
1250 | ulp_put(ulp_ops); | ||
1204 | } | 1251 | } |
1205 | rcu_read_unlock(); | ||
1206 | } | 1252 | } |
1207 | 1253 | ||
1208 | static int cnic_cm_offload_pg(struct cnic_sock *csk) | 1254 | static int cnic_cm_offload_pg(struct cnic_sock *csk) |
@@ -2418,21 +2464,45 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev) | |||
2418 | return 0; | 2464 | return 0; |
2419 | } | 2465 | } |
2420 | 2466 | ||
2421 | static int cnic_start_hw(struct cnic_dev *dev) | 2467 | static int cnic_register_netdev(struct cnic_dev *dev) |
2422 | { | 2468 | { |
2423 | struct cnic_local *cp = dev->cnic_priv; | 2469 | struct cnic_local *cp = dev->cnic_priv; |
2424 | struct cnic_eth_dev *ethdev = cp->ethdev; | 2470 | struct cnic_eth_dev *ethdev = cp->ethdev; |
2425 | int err; | 2471 | int err; |
2426 | 2472 | ||
2427 | if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) | 2473 | if (!ethdev) |
2428 | return -EALREADY; | 2474 | return -ENODEV; |
2475 | |||
2476 | if (ethdev->drv_state & CNIC_DRV_STATE_REGD) | ||
2477 | return 0; | ||
2429 | 2478 | ||
2430 | err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev); | 2479 | err = ethdev->drv_register_cnic(dev->netdev, cp->cnic_ops, dev); |
2431 | if (err) { | 2480 | if (err) |
2432 | printk(KERN_ERR PFX "%s: register_cnic failed\n", | 2481 | printk(KERN_ERR PFX "%s: register_cnic failed\n", |
2433 | dev->netdev->name); | 2482 | dev->netdev->name); |
2434 | goto err2; | 2483 | |
2435 | } | 2484 | return err; |
2485 | } | ||
2486 | |||
2487 | static void cnic_unregister_netdev(struct cnic_dev *dev) | ||
2488 | { | ||
2489 | struct cnic_local *cp = dev->cnic_priv; | ||
2490 | struct cnic_eth_dev *ethdev = cp->ethdev; | ||
2491 | |||
2492 | if (!ethdev) | ||
2493 | return; | ||
2494 | |||
2495 | ethdev->drv_unregister_cnic(dev->netdev); | ||
2496 | } | ||
2497 | |||
2498 | static int cnic_start_hw(struct cnic_dev *dev) | ||
2499 | { | ||
2500 | struct cnic_local *cp = dev->cnic_priv; | ||
2501 | struct cnic_eth_dev *ethdev = cp->ethdev; | ||
2502 | int err; | ||
2503 | |||
2504 | if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) | ||
2505 | return -EALREADY; | ||
2436 | 2506 | ||
2437 | dev->regview = ethdev->io_base; | 2507 | dev->regview = ethdev->io_base; |
2438 | cp->chip_id = ethdev->chip_id; | 2508 | cp->chip_id = ethdev->chip_id; |
@@ -2463,18 +2533,13 @@ static int cnic_start_hw(struct cnic_dev *dev) | |||
2463 | return 0; | 2533 | return 0; |
2464 | 2534 | ||
2465 | err1: | 2535 | err1: |
2466 | ethdev->drv_unregister_cnic(dev->netdev); | ||
2467 | cp->free_resc(dev); | 2536 | cp->free_resc(dev); |
2468 | pci_dev_put(dev->pcidev); | 2537 | pci_dev_put(dev->pcidev); |
2469 | err2: | ||
2470 | return err; | 2538 | return err; |
2471 | } | 2539 | } |
2472 | 2540 | ||
2473 | static void cnic_stop_bnx2_hw(struct cnic_dev *dev) | 2541 | static void cnic_stop_bnx2_hw(struct cnic_dev *dev) |
2474 | { | 2542 | { |
2475 | struct cnic_local *cp = dev->cnic_priv; | ||
2476 | struct cnic_eth_dev *ethdev = cp->ethdev; | ||
2477 | |||
2478 | cnic_disable_bnx2_int_sync(dev); | 2543 | cnic_disable_bnx2_int_sync(dev); |
2479 | 2544 | ||
2480 | cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0); | 2545 | cnic_reg_wr_ind(dev, BNX2_CP_SCRATCH + 0x20, 0); |
@@ -2486,8 +2551,6 @@ static void cnic_stop_bnx2_hw(struct cnic_dev *dev) | |||
2486 | cnic_setup_5709_context(dev, 0); | 2551 | cnic_setup_5709_context(dev, 0); |
2487 | cnic_free_irq(dev); | 2552 | cnic_free_irq(dev); |
2488 | 2553 | ||
2489 | ethdev->drv_unregister_cnic(dev->netdev); | ||
2490 | |||
2491 | cnic_free_resc(dev); | 2554 | cnic_free_resc(dev); |
2492 | } | 2555 | } |
2493 | 2556 | ||
@@ -2568,7 +2631,7 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev) | |||
2568 | probe = symbol_get(bnx2_cnic_probe); | 2631 | probe = symbol_get(bnx2_cnic_probe); |
2569 | if (probe) { | 2632 | if (probe) { |
2570 | ethdev = (*probe)(dev); | 2633 | ethdev = (*probe)(dev); |
2571 | symbol_put_addr(probe); | 2634 | symbol_put(bnx2_cnic_probe); |
2572 | } | 2635 | } |
2573 | if (!ethdev) | 2636 | if (!ethdev) |
2574 | return NULL; | 2637 | return NULL; |
@@ -2671,10 +2734,12 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event, | |||
2671 | else if (event == NETDEV_UNREGISTER) | 2734 | else if (event == NETDEV_UNREGISTER) |
2672 | cnic_ulp_exit(dev); | 2735 | cnic_ulp_exit(dev); |
2673 | else if (event == NETDEV_UP) { | 2736 | else if (event == NETDEV_UP) { |
2674 | mutex_lock(&cnic_lock); | 2737 | if (cnic_register_netdev(dev) != 0) { |
2738 | cnic_put(dev); | ||
2739 | goto done; | ||
2740 | } | ||
2675 | if (!cnic_start_hw(dev)) | 2741 | if (!cnic_start_hw(dev)) |
2676 | cnic_ulp_start(dev); | 2742 | cnic_ulp_start(dev); |
2677 | mutex_unlock(&cnic_lock); | ||
2678 | } | 2743 | } |
2679 | 2744 | ||
2680 | rcu_read_lock(); | 2745 | rcu_read_lock(); |
@@ -2693,10 +2758,9 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event, | |||
2693 | rcu_read_unlock(); | 2758 | rcu_read_unlock(); |
2694 | 2759 | ||
2695 | if (event == NETDEV_GOING_DOWN) { | 2760 | if (event == NETDEV_GOING_DOWN) { |
2696 | mutex_lock(&cnic_lock); | ||
2697 | cnic_ulp_stop(dev); | 2761 | cnic_ulp_stop(dev); |
2698 | cnic_stop_hw(dev); | 2762 | cnic_stop_hw(dev); |
2699 | mutex_unlock(&cnic_lock); | 2763 | cnic_unregister_netdev(dev); |
2700 | } else if (event == NETDEV_UNREGISTER) { | 2764 | } else if (event == NETDEV_UNREGISTER) { |
2701 | write_lock(&cnic_dev_lock); | 2765 | write_lock(&cnic_dev_lock); |
2702 | list_del_init(&dev->list); | 2766 | list_del_init(&dev->list); |
@@ -2728,6 +2792,7 @@ static void cnic_release(void) | |||
2728 | } | 2792 | } |
2729 | 2793 | ||
2730 | cnic_ulp_exit(dev); | 2794 | cnic_ulp_exit(dev); |
2795 | cnic_unregister_netdev(dev); | ||
2731 | list_del_init(&dev->list); | 2796 | list_del_init(&dev->list); |
2732 | cnic_free_dev(dev); | 2797 | cnic_free_dev(dev); |
2733 | } | 2798 | } |