diff options
author | Jan-Bernd Themann <ossthema@de.ibm.com> | 2008-07-03 10:18:51 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-07-04 08:10:41 -0400 |
commit | 2f69ae01c83a94af5dc3c20e8135b974687ed004 (patch) | |
tree | fba9563322f4f0932b0222f4b026cb96485dc0c5 /drivers/net/ehea | |
parent | b0afffe89be619f42ae4215554ed66e67de7bb0e (diff) |
ehea: fix race condition
When ehea_stop is called the function
cancel_work_sync(&port->reset_task) is used to ensure
that the reset task is not running anymore. We need an
additional flag to ensure that it can not be scheduled
after this call again for a certain time.
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/ehea')
-rw-r--r-- | drivers/net/ehea/ehea.h | 6 | ||||
-rw-r--r-- | drivers/net/ehea/ehea_main.c | 17 |
2 files changed, 16 insertions, 7 deletions
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index bf57e1532f5e..e01926b7b5b7 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h | |||
@@ -40,7 +40,7 @@ | |||
40 | #include <asm/io.h> | 40 | #include <asm/io.h> |
41 | 41 | ||
42 | #define DRV_NAME "ehea" | 42 | #define DRV_NAME "ehea" |
43 | #define DRV_VERSION "EHEA_0091" | 43 | #define DRV_VERSION "EHEA_0092" |
44 | 44 | ||
45 | /* eHEA capability flags */ | 45 | /* eHEA capability flags */ |
46 | #define DLPAR_PORT_ADD_REM 1 | 46 | #define DLPAR_PORT_ADD_REM 1 |
@@ -478,6 +478,7 @@ struct ehea_port { | |||
478 | int num_add_tx_qps; | 478 | int num_add_tx_qps; |
479 | int num_mcs; | 479 | int num_mcs; |
480 | int resets; | 480 | int resets; |
481 | u64 flags; | ||
481 | u64 mac_addr; | 482 | u64 mac_addr; |
482 | u32 logical_port_id; | 483 | u32 logical_port_id; |
483 | u32 port_speed; | 484 | u32 port_speed; |
@@ -501,7 +502,8 @@ struct port_res_cfg { | |||
501 | }; | 502 | }; |
502 | 503 | ||
503 | enum ehea_flag_bits { | 504 | enum ehea_flag_bits { |
504 | __EHEA_STOP_XFER | 505 | __EHEA_STOP_XFER, |
506 | __EHEA_DISABLE_PORT_RESET | ||
505 | }; | 507 | }; |
506 | 508 | ||
507 | void ehea_set_ethtool_ops(struct net_device *netdev); | 509 | void ehea_set_ethtool_ops(struct net_device *netdev); |
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 6ebcb221cd5e..49ba6a9a7b06 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c | |||
@@ -138,6 +138,12 @@ void ehea_dump(void *adr, int len, char *msg) | |||
138 | } | 138 | } |
139 | } | 139 | } |
140 | 140 | ||
141 | void ehea_schedule_port_reset(struct ehea_port *port) | ||
142 | { | ||
143 | if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags)) | ||
144 | schedule_work(&port->reset_task); | ||
145 | } | ||
146 | |||
141 | static void ehea_update_firmware_handles(void) | 147 | static void ehea_update_firmware_handles(void) |
142 | { | 148 | { |
143 | struct ehea_fw_handle_entry *arr = NULL; | 149 | struct ehea_fw_handle_entry *arr = NULL; |
@@ -588,7 +594,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, | |||
588 | "Resetting port.", pr->qp->init_attr.qp_nr); | 594 | "Resetting port.", pr->qp->init_attr.qp_nr); |
589 | ehea_dump(cqe, sizeof(*cqe), "CQE"); | 595 | ehea_dump(cqe, sizeof(*cqe), "CQE"); |
590 | } | 596 | } |
591 | schedule_work(&pr->port->reset_task); | 597 | ehea_schedule_port_reset(pr->port); |
592 | return 1; | 598 | return 1; |
593 | } | 599 | } |
594 | 600 | ||
@@ -766,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) | |||
766 | ehea_error("Send Completion Error: Resetting port"); | 772 | ehea_error("Send Completion Error: Resetting port"); |
767 | if (netif_msg_tx_err(pr->port)) | 773 | if (netif_msg_tx_err(pr->port)) |
768 | ehea_dump(cqe, sizeof(*cqe), "Send CQE"); | 774 | ehea_dump(cqe, sizeof(*cqe), "Send CQE"); |
769 | schedule_work(&pr->port->reset_task); | 775 | ehea_schedule_port_reset(pr->port); |
770 | break; | 776 | break; |
771 | } | 777 | } |
772 | 778 | ||
@@ -886,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param) | |||
886 | eqe = ehea_poll_eq(port->qp_eq); | 892 | eqe = ehea_poll_eq(port->qp_eq); |
887 | } | 893 | } |
888 | 894 | ||
889 | schedule_work(&port->reset_task); | 895 | ehea_schedule_port_reset(port); |
890 | 896 | ||
891 | return IRQ_HANDLED; | 897 | return IRQ_HANDLED; |
892 | } | 898 | } |
@@ -2606,13 +2612,14 @@ static int ehea_stop(struct net_device *dev) | |||
2606 | if (netif_msg_ifdown(port)) | 2612 | if (netif_msg_ifdown(port)) |
2607 | ehea_info("disabling port %s", dev->name); | 2613 | ehea_info("disabling port %s", dev->name); |
2608 | 2614 | ||
2615 | set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags); | ||
2609 | cancel_work_sync(&port->reset_task); | 2616 | cancel_work_sync(&port->reset_task); |
2610 | |||
2611 | mutex_lock(&port->port_lock); | 2617 | mutex_lock(&port->port_lock); |
2612 | netif_stop_queue(dev); | 2618 | netif_stop_queue(dev); |
2613 | port_napi_disable(port); | 2619 | port_napi_disable(port); |
2614 | ret = ehea_down(dev); | 2620 | ret = ehea_down(dev); |
2615 | mutex_unlock(&port->port_lock); | 2621 | mutex_unlock(&port->port_lock); |
2622 | clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags); | ||
2616 | return ret; | 2623 | return ret; |
2617 | } | 2624 | } |
2618 | 2625 | ||
@@ -2942,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_device *dev) | |||
2942 | 2949 | ||
2943 | if (netif_carrier_ok(dev) && | 2950 | if (netif_carrier_ok(dev) && |
2944 | !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) | 2951 | !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) |
2945 | schedule_work(&port->reset_task); | 2952 | ehea_schedule_port_reset(port); |
2946 | } | 2953 | } |
2947 | 2954 | ||
2948 | int ehea_sense_adapter_attr(struct ehea_adapter *adapter) | 2955 | int ehea_sense_adapter_attr(struct ehea_adapter *adapter) |