diff options
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_multicast.c')
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 29 | 
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index cecb98a4c66..d4e005720d0 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -386,8 +386,10 @@ static int ipoib_mcast_join_complete(int status,  			mcast->mcmember.mgid.raw, status);  	/* We trap for port events ourselves. */ -	if (status == -ENETRESET) -		return 0; +	if (status == -ENETRESET) { +		status = 0; +		goto out; +	}  	if (!status)  		status = ipoib_mcast_join_finish(mcast, &multicast->rec); @@ -407,7 +409,8 @@ static int ipoib_mcast_join_complete(int status,  		if (mcast == priv->broadcast)  			queue_work(ipoib_workqueue, &priv->carrier_on_task); -		return 0; +		status = 0; +		goto out;  	}  	if (mcast->logcount++ < 20) { @@ -434,7 +437,8 @@ static int ipoib_mcast_join_complete(int status,  				   mcast->backoff * HZ);  	spin_unlock_irq(&priv->lock);  	mutex_unlock(&mcast_mutex); - +out: +	complete(&mcast->done);  	return status;  } @@ -484,11 +488,15 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,  	}  	set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); +	init_completion(&mcast->done); +	set_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags); +  	mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,  					 &rec, comp_mask, GFP_KERNEL,  					 ipoib_mcast_join_complete, mcast);  	if (IS_ERR(mcast->mc)) {  		clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); +		complete(&mcast->done);  		ret = PTR_ERR(mcast->mc);  		ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret); @@ -510,10 +518,18 @@ void ipoib_mcast_join_task(struct work_struct *work)  	struct ipoib_dev_priv *priv =  		container_of(work, struct ipoib_dev_priv, mcast_task.work);  	struct net_device *dev = priv->dev; +	struct ib_port_attr port_attr;  	if (!test_bit(IPOIB_MCAST_RUN, &priv->flags))  		return; +	if (ib_query_port(priv->ca, priv->port, &port_attr) || +	    port_attr.state != IB_PORT_ACTIVE) { +		ipoib_dbg(priv, "port state is not ACTIVE (state = %d) suspending join task\n", +			  port_attr.state); +		return; +	} +  	if (ib_query_gid(priv->ca, priv->port, 0, &priv->local_gid))  		ipoib_warn(priv, "ib_query_gid() failed\n");  	else @@ -751,6 +767,11 @@ void ipoib_mcast_dev_flush(struct net_device *dev)  	spin_unlock_irqrestore(&priv->lock, flags); +	/* seperate between the wait to the leave*/ +	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) +		if (test_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags)) +			wait_for_completion(&mcast->done); +  	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {  		ipoib_mcast_leave(dev, mcast);  		ipoib_mcast_free(mcast);  | 
