From f2d3553cba320f89f5eb6a33ee27a7e3fa4a51ac Mon Sep 17 00:00:00 2001 From: jhb Date: Tue, 6 Aug 2013 20:04:44 +0000 Subject: [PATCH] MFC 253048,253423,253449,253653,253774,253785: - Allow mlx4 devices to switch between Ethernet and Infiniband: - Fix sysfs attribute handling by using sysctl_handle_string() and properly handling trailing newlines in attribute values. - Remove check forbidding requests that would result in one port being set to Ethernet and the subsequent port being set to IB. - Avoid trashing IP fragments by correctly managing hardware checksumming. - Fix panics when downing or unloading the mlx4 driver. PR: kern/179999, kern/174213, kern/180430, kern/180791 Approved by: re (kib) git-svn-id: svn://svn.freebsd.org/base/releng/9.2@254007 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/ofed/drivers/net/mlx4/en_netdev.c | 53 ++++++++++++++++----------- sys/ofed/drivers/net/mlx4/en_tx.c | 8 +++- sys/ofed/drivers/net/mlx4/main.c | 3 -- sys/ofed/include/linux/sysfs.h | 29 ++++++++------- 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/sys/ofed/drivers/net/mlx4/en_netdev.c b/sys/ofed/drivers/net/mlx4/en_netdev.c index 3dca7563..0a59ab44 100644 --- a/sys/ofed/drivers/net/mlx4/en_netdev.c +++ b/sys/ofed/drivers/net/mlx4/en_netdev.c @@ -43,6 +43,7 @@ #include #include +static void mlx4_en_init_locked(struct mlx4_en_priv *priv); static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv); static void mlx4_en_vlan_rx_add_vid(void *arg, struct net_device *dev, u16 vid) @@ -495,11 +496,6 @@ static void mlx4_en_do_get_stats(struct work_struct *work) 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 +684,8 @@ int mlx4_en_start_port(struct net_device *dev) 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 +757,7 @@ void mlx4_en_stop_port(struct net_device *dev) 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 +798,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 +842,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 +931,14 @@ void mlx4_en_destroy_netdev(struct net_device *dev) 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 +1100,32 @@ static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) 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 +1140,8 @@ static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) 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: diff --git a/sys/ofed/drivers/net/mlx4/en_tx.c b/sys/ofed/drivers/net/mlx4/en_tx.c index 4d1690f8..726f3f1e 100644 --- a/sys/ofed/drivers/net/mlx4/en_tx.c +++ b/sys/ofed/drivers/net/mlx4/en_tx.c @@ -780,8 +780,12 @@ retry: tx_desc->ctrl.srcrb_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | MLX4_WQE_CTRL_SOLICITED); if (mb->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP)) { - tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM | - MLX4_WQE_CTRL_TCP_UDP_CSUM); + if (mb->m_pkthdr.csum_flags & CSUM_IP) + tx_desc->ctrl.srcrb_flags |= + cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM); + if (mb->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) + tx_desc->ctrl.srcrb_flags |= + cpu_to_be32(MLX4_WQE_CTRL_TCP_UDP_CSUM); priv->port_stats.tx_chksum_offload++; } diff --git a/sys/ofed/drivers/net/mlx4/main.c b/sys/ofed/drivers/net/mlx4/main.c index fe1f4bfc..b0897bfa 100644 --- a/sys/ofed/drivers/net/mlx4/main.c +++ b/sys/ofed/drivers/net/mlx4/main.c @@ -209,9 +209,6 @@ int mlx4_check_port_params(struct mlx4_dev *dev, "on this HCA, aborting.\n"); return -EINVAL; } - if (port_type[i] == MLX4_PORT_TYPE_ETH && - port_type[i + 1] == MLX4_PORT_TYPE_IB) - return -EINVAL; } } diff --git a/sys/ofed/include/linux/sysfs.h b/sys/ofed/include/linux/sysfs.h index 698f75e1..4a763c82 100644 --- a/sys/ofed/include/linux/sysfs.h +++ b/sys/ofed/include/linux/sysfs.h @@ -75,39 +75,42 @@ sysctl_handle_attr(SYSCTL_HANDLER_ARGS) struct kobject *kobj; struct attribute *attr; const struct sysfs_ops *ops; - void *buf; + char *buf; int error; ssize_t len; kobj = arg1; attr = (struct attribute *)arg2; - buf = (void *)get_zeroed_page(GFP_KERNEL); - len = 1; /* Copy out a NULL byte at least. */ if (kobj->ktype == NULL || kobj->ktype->sysfs_ops == NULL) return (ENODEV); - ops = kobj->ktype->sysfs_ops; + buf = (char *)get_zeroed_page(GFP_KERNEL); if (buf == NULL) return (ENOMEM); + ops = kobj->ktype->sysfs_ops; if (ops->show) { len = ops->show(kobj, attr, buf); /* - * It's valid not to have a 'show' so we just return 1 byte - * of NULL. + * It's valid to not have a 'show' so just return an + * empty string. */ if (len < 0) { error = -len; - len = 1; if (error != EIO) goto out; } + + /* Trim trailing newline. */ + len--; + buf[len] = '\0'; } - error = SYSCTL_OUT(req, buf, len); - if (error || !req->newptr || ops->store == NULL) - goto out; - error = SYSCTL_IN(req, buf, PAGE_SIZE); - if (error) + + /* Leave one trailing byte to append a newline. */ + error = sysctl_handle_string(oidp, buf, PAGE_SIZE - 1, req); + if (error != 0 || req->newptr == NULL || ops->store == NULL) goto out; - len = ops->store(kobj, attr, buf, req->newlen); + len = strlcat(buf, "\n", PAGE_SIZE); + KASSERT(len < PAGE_SIZE, ("new attribute truncated")); + len = ops->store(kobj, attr, buf, len); if (len < 0) error = -len; out: -- 2.45.0