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:
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to