svn commit: r253774 - head/sys/ofed/drivers/net/mlx4

John Baldwin jhb at FreeBSD.org
Mon Jul 29 18:44:53 UTC 2013


Author: jhb
Date: Mon Jul 29 18:44:52 2013
New Revision: 253774
URL: http://svnweb.freebsd.org/changeset/base/253774

Log:
  Various fixes to the mlxen(4) driver:
  - Remove an incorrect assertion that can trigger when downing an interface.
  - Stop the interface during detach to avoid panics when unloading the
    driver.
  - A few locking fixes to be more consistent with other FreeBSD drivers:
    - Protect if_drv_flags with the driver lock, not atomic ops
    - Hold the driver lock when adjusting multicast state.
    - Hold the driver lock while adjusting if_capenable.
  
  PR:		kern/180791 [1,2]
  Submitted by:	Shakar Klein @ Mellanox [1,2]
  MFC after:	3 days

Modified:
  head/sys/ofed/drivers/net/mlx4/en_netdev.c

Modified: head/sys/ofed/drivers/net/mlx4/en_netdev.c
==============================================================================
--- head/sys/ofed/drivers/net/mlx4/en_netdev.c	Mon Jul 29 17:03:42 2013	(r253773)
+++ head/sys/ofed/drivers/net/mlx4/en_netdev.c	Mon Jul 29 18:44:52 2013	(r253774)
@@ -495,11 +495,6 @@ static void mlx4_en_do_get_stats(struct 
 
 		queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
 	}
-	if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) {
-		panic("mlx4_en_do_get_stats: Unexpected mac removed for %d\n",
-		    priv->port);
-		mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0;
-	}
 	mutex_unlock(&mdev->state_lock);
 }
 
@@ -688,8 +683,8 @@ int mlx4_en_start_port(struct net_device
 	mlx4_en_set_multicast(dev);
 
 	/* Enable the queues. */
-	atomic_clear_int(&dev->if_drv_flags, IFF_DRV_OACTIVE);
-	atomic_set_int(&dev->if_drv_flags, IFF_DRV_RUNNING);
+	dev->if_drv_flags &= ~IFF_DRV_OACTIVE;
+	dev->if_drv_flags |= IFF_DRV_RUNNING;
 
 	callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT,
 	    mlx4_en_watchdog_timeout, priv);
@@ -761,7 +756,7 @@ void mlx4_en_stop_port(struct net_device
 
 	callout_stop(&priv->watchdog_timer);
 
-	atomic_clear_int(&dev->if_drv_flags, IFF_DRV_RUNNING);
+	dev->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 }
 
 static void mlx4_en_restart(struct work_struct *work)
@@ -802,19 +797,30 @@ mlx4_en_init(void *arg)
 {
 	struct mlx4_en_priv *priv;
 	struct mlx4_en_dev *mdev;
+
+	priv = arg;
+	mdev = priv->mdev;
+	mutex_lock(&mdev->state_lock);
+	mlx4_en_init_locked(priv);
+	mutex_unlock(&mdev->state_lock);
+}
+
+static void
+mlx4_en_init_locked(struct mlx4_en_priv *priv)
+{
+
+	struct mlx4_en_dev *mdev;
 	struct ifnet *dev;
 	int i;
 
-	priv = arg;
 	dev = priv->dev;
 	mdev = priv->mdev;
-	mutex_lock(&mdev->state_lock);
 	if (dev->if_drv_flags & IFF_DRV_RUNNING)
 		mlx4_en_stop_port(dev);
 
 	if (!mdev->device_up) {
 		en_err(priv, "Cannot open - device down/disabled\n");
-		goto out;
+		return;
 	}
 
 	/* Reset HW statistics and performance counters */
@@ -835,9 +841,6 @@ mlx4_en_init(void *arg)
 	mlx4_en_set_default_moderation(priv);
 	if (mlx4_en_start_port(dev))
 		en_err(priv, "Failed starting port:%d\n", priv->port);
-
-out:
-	mutex_unlock(&mdev->state_lock);
 }
 
 void mlx4_en_free_resources(struct mlx4_en_priv *priv)
@@ -927,9 +930,14 @@ void mlx4_en_destroy_netdev(struct net_d
 	if (priv->sysctl)
 		sysctl_ctx_free(&priv->conf_ctx);
 
+	mutex_lock(&mdev->state_lock);
+	mlx4_en_stop_port(dev);
+	mutex_unlock(&mdev->state_lock);
+
 	cancel_delayed_work(&priv->stats_task);
 	/* flush any pending task for this netdev */
 	flush_workqueue(mdev->workqueue);
+	callout_drain(&priv->watchdog_timer);
 
 	/* Detach the netdev so tasks would not attempt to access it */
 	mutex_lock(&mdev->state_lock);
@@ -1091,31 +1099,32 @@ static int mlx4_en_ioctl(struct ifnet *d
 		error = -mlx4_en_change_mtu(dev, ifr->ifr_mtu);
 		break;
 	case SIOCSIFFLAGS:
+		mutex_lock(&mdev->state_lock);
 		if (dev->if_flags & IFF_UP) {
-			if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) {
-				mutex_lock(&mdev->state_lock);
+			if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0)
 				mlx4_en_start_port(dev);
-				mutex_unlock(&mdev->state_lock);
-			} else
+			else
 				mlx4_en_set_multicast(dev);
 		} else {
-			mutex_lock(&mdev->state_lock);
 			if (dev->if_drv_flags & IFF_DRV_RUNNING) {
 				mlx4_en_stop_port(dev);
 				if_link_state_change(dev, LINK_STATE_DOWN);
 			}
-			mutex_unlock(&mdev->state_lock);
 		}
+		mutex_unlock(&mdev->state_lock);
 		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
+		mutex_lock(&mdev->state_lock);
 		mlx4_en_set_multicast(dev);
+		mutex_unlock(&mdev->state_lock);
 		break;
 	case SIOCSIFMEDIA:
 	case SIOCGIFMEDIA:
 		error = ifmedia_ioctl(dev, ifr, &priv->media, command);
 		break;
 	case SIOCSIFCAP:
+		mutex_lock(&mdev->state_lock);
 		mask = ifr->ifr_reqcap ^ dev->if_capenable;
 		if (mask & IFCAP_HWCSUM)
 			dev->if_capenable ^= IFCAP_HWCSUM;
@@ -1130,7 +1139,8 @@ static int mlx4_en_ioctl(struct ifnet *d
 		if (mask & IFCAP_WOL_MAGIC)
 			dev->if_capenable ^= IFCAP_WOL_MAGIC;
 		if (dev->if_drv_flags & IFF_DRV_RUNNING)
-			mlx4_en_init(priv);
+			mlx4_en_init_locked(priv);
+		mutex_unlock(&mdev->state_lock);
 		VLAN_CAPABILITIES(dev);
 		break;
 	default:


More information about the svn-src-all mailing list