forked from Minki/linux
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>
This commit is contained in:
parent
b0afffe89b
commit
2f69ae01c8
@ -40,7 +40,7 @@
|
|||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
#define DRV_NAME "ehea"
|
#define DRV_NAME "ehea"
|
||||||
#define DRV_VERSION "EHEA_0091"
|
#define DRV_VERSION "EHEA_0092"
|
||||||
|
|
||||||
/* eHEA capability flags */
|
/* eHEA capability flags */
|
||||||
#define DLPAR_PORT_ADD_REM 1
|
#define DLPAR_PORT_ADD_REM 1
|
||||||
@ -478,6 +478,7 @@ struct ehea_port {
|
|||||||
int num_add_tx_qps;
|
int num_add_tx_qps;
|
||||||
int num_mcs;
|
int num_mcs;
|
||||||
int resets;
|
int resets;
|
||||||
|
u64 flags;
|
||||||
u64 mac_addr;
|
u64 mac_addr;
|
||||||
u32 logical_port_id;
|
u32 logical_port_id;
|
||||||
u32 port_speed;
|
u32 port_speed;
|
||||||
@ -501,7 +502,8 @@ struct port_res_cfg {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum ehea_flag_bits {
|
enum ehea_flag_bits {
|
||||||
__EHEA_STOP_XFER
|
__EHEA_STOP_XFER,
|
||||||
|
__EHEA_DISABLE_PORT_RESET
|
||||||
};
|
};
|
||||||
|
|
||||||
void ehea_set_ethtool_ops(struct net_device *netdev);
|
void ehea_set_ethtool_ops(struct net_device *netdev);
|
||||||
|
@ -138,6 +138,12 @@ void ehea_dump(void *adr, int len, char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ehea_schedule_port_reset(struct ehea_port *port)
|
||||||
|
{
|
||||||
|
if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
|
||||||
|
schedule_work(&port->reset_task);
|
||||||
|
}
|
||||||
|
|
||||||
static void ehea_update_firmware_handles(void)
|
static void ehea_update_firmware_handles(void)
|
||||||
{
|
{
|
||||||
struct ehea_fw_handle_entry *arr = NULL;
|
struct ehea_fw_handle_entry *arr = NULL;
|
||||||
@ -588,7 +594,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
|
|||||||
"Resetting port.", pr->qp->init_attr.qp_nr);
|
"Resetting port.", pr->qp->init_attr.qp_nr);
|
||||||
ehea_dump(cqe, sizeof(*cqe), "CQE");
|
ehea_dump(cqe, sizeof(*cqe), "CQE");
|
||||||
}
|
}
|
||||||
schedule_work(&pr->port->reset_task);
|
ehea_schedule_port_reset(pr->port);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
|
|||||||
ehea_error("Send Completion Error: Resetting port");
|
ehea_error("Send Completion Error: Resetting port");
|
||||||
if (netif_msg_tx_err(pr->port))
|
if (netif_msg_tx_err(pr->port))
|
||||||
ehea_dump(cqe, sizeof(*cqe), "Send CQE");
|
ehea_dump(cqe, sizeof(*cqe), "Send CQE");
|
||||||
schedule_work(&pr->port->reset_task);
|
ehea_schedule_port_reset(pr->port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -886,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
|
|||||||
eqe = ehea_poll_eq(port->qp_eq);
|
eqe = ehea_poll_eq(port->qp_eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule_work(&port->reset_task);
|
ehea_schedule_port_reset(port);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@ -2606,13 +2612,14 @@ static int ehea_stop(struct net_device *dev)
|
|||||||
if (netif_msg_ifdown(port))
|
if (netif_msg_ifdown(port))
|
||||||
ehea_info("disabling port %s", dev->name);
|
ehea_info("disabling port %s", dev->name);
|
||||||
|
|
||||||
|
set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
|
||||||
cancel_work_sync(&port->reset_task);
|
cancel_work_sync(&port->reset_task);
|
||||||
|
|
||||||
mutex_lock(&port->port_lock);
|
mutex_lock(&port->port_lock);
|
||||||
netif_stop_queue(dev);
|
netif_stop_queue(dev);
|
||||||
port_napi_disable(port);
|
port_napi_disable(port);
|
||||||
ret = ehea_down(dev);
|
ret = ehea_down(dev);
|
||||||
mutex_unlock(&port->port_lock);
|
mutex_unlock(&port->port_lock);
|
||||||
|
clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2942,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_device *dev)
|
|||||||
|
|
||||||
if (netif_carrier_ok(dev) &&
|
if (netif_carrier_ok(dev) &&
|
||||||
!test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
|
!test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
|
||||||
schedule_work(&port->reset_task);
|
ehea_schedule_port_reset(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
|
int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
|
||||||
|
Loading…
Reference in New Issue
Block a user