diff options
author | David S. Miller <davem@davemloft.net> | 2018-10-16 06:49:56 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-10-16 06:49:56 +0200 |
commit | 1986647c2fc369b1865fb9bc9a213b48444580cb (patch) | |
tree | 4337680a4e505bf264f45098d983bc06609c578f /drivers/infiniband | |
parent | Merge branch 'defza-fddi' (diff) | |
parent | net/mlx5e: Do not ignore netdevice TX/RX queues number (diff) | |
download | linux-1986647c2fc369b1865fb9bc9a213b48444580cb.tar.xz linux-1986647c2fc369b1865fb9bc9a213b48444580cb.zip |
Merge tag 'mlx5e-updates-2018-10-10' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux
Saeed Mahameed says:
====================
mlx5e-updates-2018-10-10
IPoIB netlink support and mlx5e pre-allocated netdevice initialization
IP link was broken due to the changes in IPoIB for the rdma_netdev
support after commit cd565b4b51e5
("IB/IPoIB: Support acceleration options callbacks").
This patchset fixes IPoIB pkey creation and removal using rtnetlink by
adding support in both IPoIB ULP layer and mlx5 layer:
From Jason and Denis:
1) Introduces changes in the RDMA netdev code in order to
allow allocation of the netdev to be done by the rtnl netdev code.
2) Reworks IPoIB initialization to use the two step rdma_netdev
creation.
From Feras and Saeed, mlx5e netdev layer refactoring to allow accepting
pre-allocated netdevs:
3) Adds support to initialize/cleanup netdevs that are not created
by mlx5 driver.
4) Change mlx5e netdevice layer to accept the pre-allocated netdevice
queue number.
5) Initialize mlx5e generic structures in one place to be used for all
netdevs types NIC/representors/IPoIB (both mlx5 allocated and
pre-allocted).
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/core/verbs.c | 46 | ||||
-rw-r--r-- | drivers/infiniband/hw/mlx5/main.c | 23 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 8 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 132 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 23 | ||||
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 19 |
6 files changed, 164 insertions, 87 deletions
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 6ee03d6089eb..8ec7418e99f0 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2621,3 +2621,49 @@ void ib_drain_qp(struct ib_qp *qp) ib_drain_rq(qp); } EXPORT_SYMBOL(ib_drain_qp); + +struct net_device *rdma_alloc_netdev(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, const char *name, + unsigned char name_assign_type, + void (*setup)(struct net_device *)) +{ + struct rdma_netdev_alloc_params params; + struct net_device *netdev; + int rc; + + if (!device->rdma_netdev_get_params) + return ERR_PTR(-EOPNOTSUPP); + + rc = device->rdma_netdev_get_params(device, port_num, type, ¶ms); + if (rc) + return ERR_PTR(rc); + + netdev = alloc_netdev_mqs(params.sizeof_priv, name, name_assign_type, + setup, params.txqs, params.rxqs); + if (!netdev) + return ERR_PTR(-ENOMEM); + + return netdev; +} +EXPORT_SYMBOL(rdma_alloc_netdev); + +int rdma_init_netdev(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, const char *name, + unsigned char name_assign_type, + void (*setup)(struct net_device *), + struct net_device *netdev) +{ + struct rdma_netdev_alloc_params params; + int rc; + + if (!device->rdma_netdev_get_params) + return -EOPNOTSUPP; + + rc = device->rdma_netdev_get_params(device, port_num, type, ¶ms); + if (rc) + return rc; + + return params.initialize_rdma_netdev(device, port_num, + netdev, params.param); +} +EXPORT_SYMBOL(rdma_init_netdev); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index c414f3809e5c..5d9b7f62a0ba 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -5163,22 +5163,14 @@ done: return num_counters; } -static struct net_device* -mlx5_ib_alloc_rdma_netdev(struct ib_device *hca, - u8 port_num, - enum rdma_netdev_t type, - const char *name, - unsigned char name_assign_type, - void (*setup)(struct net_device *)) +static int mlx5_ib_rn_get_params(struct ib_device *device, u8 port_num, + enum rdma_netdev_t type, + struct rdma_netdev_alloc_params *params) { - struct net_device *netdev; - if (type != RDMA_NETDEV_IPOIB) - return ERR_PTR(-EOPNOTSUPP); + return -EOPNOTSUPP; - netdev = mlx5_rdma_netdev_alloc(to_mdev(hca)->mdev, hca, - name, setup); - return netdev; + return mlx5_rdma_rn_get_params(to_mdev(device)->mdev, device, params); } static void delay_drop_debugfs_cleanup(struct mlx5_ib_dev *dev) @@ -5824,8 +5816,9 @@ int mlx5_ib_stage_caps_init(struct mlx5_ib_dev *dev) dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; dev->ib_dev.get_dev_fw_str = get_dev_fw_str; dev->ib_dev.get_vector_affinity = mlx5_ib_get_vector_affinity; - if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads)) - dev->ib_dev.alloc_rdma_netdev = mlx5_ib_alloc_rdma_netdev; + if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads) && + IS_ENABLED(CONFIG_MLX5_CORE_IPOIB)) + dev->ib_dev.rdma_netdev_get_params = mlx5_ib_rn_get_params; if (mlx5_core_is_pf(mdev)) { dev->ib_dev.get_vf_config = mlx5_ib_get_vf_config; diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 1abe3c62f106..1da119d901a9 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -499,8 +499,10 @@ void ipoib_reap_ah(struct work_struct *work); struct ipoib_path *__path_find(struct net_device *dev, void *gid); void ipoib_mark_paths_invalid(struct net_device *dev); void ipoib_flush_paths(struct net_device *dev); -struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port, - const char *format); +struct net_device *ipoib_intf_alloc(struct ib_device *hca, u8 port, + const char *format); +int ipoib_intf_init(struct ib_device *hca, u8 port, const char *format, + struct net_device *dev); void ipoib_ib_tx_timer_func(struct timer_list *t); void ipoib_ib_dev_flush_light(struct work_struct *work); void ipoib_ib_dev_flush_normal(struct work_struct *work); @@ -531,6 +533,8 @@ int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req); void ipoib_dma_unmap_tx(struct ipoib_dev_priv *priv, struct ipoib_tx_buf *tx_req); +struct rtnl_link_ops *ipoib_get_link_ops(void); + static inline void ipoib_build_sge(struct ipoib_dev_priv *priv, struct ipoib_tx_buf *tx_req) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e3d28f9ad9c0..8baa75a705c5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -2115,82 +2115,58 @@ static const struct net_device_ops ipoib_netdev_default_pf = { .ndo_stop = ipoib_ib_dev_stop_default, }; -static struct net_device -*ipoib_create_netdev_default(struct ib_device *hca, - const char *name, - unsigned char name_assign_type, - void (*setup)(struct net_device *)) +static struct net_device *ipoib_alloc_netdev(struct ib_device *hca, u8 port, + const char *name) { struct net_device *dev; - struct rdma_netdev *rn; - dev = alloc_netdev((int)sizeof(struct rdma_netdev), - name, - name_assign_type, setup); - if (!dev) - return NULL; - - rn = netdev_priv(dev); - - rn->send = ipoib_send; - rn->attach_mcast = ipoib_mcast_attach; - rn->detach_mcast = ipoib_mcast_detach; - rn->hca = hca; - dev->netdev_ops = &ipoib_netdev_default_pf; - - return dev; -} - -static struct net_device *ipoib_get_netdev(struct ib_device *hca, u8 port, - const char *name) -{ - struct net_device *dev; - - if (hca->alloc_rdma_netdev) { - dev = hca->alloc_rdma_netdev(hca, port, - RDMA_NETDEV_IPOIB, name, - NET_NAME_UNKNOWN, - ipoib_setup_common); - if (IS_ERR_OR_NULL(dev) && PTR_ERR(dev) != -EOPNOTSUPP) - return NULL; - } - - if (!hca->alloc_rdma_netdev || PTR_ERR(dev) == -EOPNOTSUPP) - dev = ipoib_create_netdev_default(hca, name, NET_NAME_UNKNOWN, - ipoib_setup_common); + dev = rdma_alloc_netdev(hca, port, RDMA_NETDEV_IPOIB, name, + NET_NAME_UNKNOWN, ipoib_setup_common); + if (!IS_ERR(dev) || PTR_ERR(dev) != -EOPNOTSUPP) + return dev; + dev = alloc_netdev(sizeof(struct rdma_netdev), name, NET_NAME_UNKNOWN, + ipoib_setup_common); + if (!dev) + return ERR_PTR(-ENOMEM); return dev; } -struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port, - const char *name) +int ipoib_intf_init(struct ib_device *hca, u8 port, const char *name, + struct net_device *dev) { - struct net_device *dev; + struct rdma_netdev *rn = netdev_priv(dev); struct ipoib_dev_priv *priv; - struct rdma_netdev *rn; + int rc; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) - return NULL; + return -ENOMEM; priv->ca = hca; priv->port = port; - dev = ipoib_get_netdev(hca, port, name); - if (!dev) - goto free_priv; + rc = rdma_init_netdev(hca, port, RDMA_NETDEV_IPOIB, name, + NET_NAME_UNKNOWN, ipoib_setup_common, dev); + if (rc) { + if (rc != -EOPNOTSUPP) + goto out; + + dev->netdev_ops = &ipoib_netdev_default_pf; + rn->send = ipoib_send; + rn->attach_mcast = ipoib_mcast_attach; + rn->detach_mcast = ipoib_mcast_detach; + rn->hca = hca; + } priv->rn_ops = dev->netdev_ops; - /* fixme : should be after the query_cap */ - if (priv->hca_caps & IB_DEVICE_VIRTUAL_FUNCTION) + if (hca->attrs.device_cap_flags & IB_DEVICE_VIRTUAL_FUNCTION) dev->netdev_ops = &ipoib_netdev_ops_vf; else dev->netdev_ops = &ipoib_netdev_ops_pf; - rn = netdev_priv(dev); rn->clnt_priv = priv; - /* * Only the child register_netdev flows can handle priv_destructor * being set, so we force it to NULL here and handle manually until it @@ -2201,10 +2177,35 @@ struct ipoib_dev_priv *ipoib_intf_alloc(struct ib_device *hca, u8 port, ipoib_build_priv(dev); - return priv; -free_priv: + return 0; + +out: kfree(priv); - return NULL; + return rc; +} + +struct net_device *ipoib_intf_alloc(struct ib_device *hca, u8 port, + const char *name) +{ + struct net_device *dev; + int rc; + + dev = ipoib_alloc_netdev(hca, port, name); + if (IS_ERR(dev)) + return dev; + + rc = ipoib_intf_init(hca, port, name, dev); + if (rc) { + free_netdev(dev); + return ERR_PTR(rc); + } + + /* + * Upon success the caller must ensure ipoib_intf_free is called or + * register_netdevice succeed'd and priv_destructor is set to + * ipoib_intf_free. + */ + return dev; } void ipoib_intf_free(struct net_device *dev) @@ -2387,16 +2388,19 @@ int ipoib_add_pkey_attr(struct net_device *dev) static struct net_device *ipoib_add_port(const char *format, struct ib_device *hca, u8 port) { + struct rtnl_link_ops *ops = ipoib_get_link_ops(); + struct rdma_netdev_alloc_params params; struct ipoib_dev_priv *priv; struct net_device *ndev; int result; - priv = ipoib_intf_alloc(hca, port, format); - if (!priv) { - pr_warn("%s, %d: ipoib_intf_alloc failed\n", hca->name, port); - return ERR_PTR(-ENOMEM); + ndev = ipoib_intf_alloc(hca, port, format); + if (IS_ERR(ndev)) { + pr_warn("%s, %d: ipoib_intf_alloc failed %ld\n", hca->name, port, + PTR_ERR(ndev)); + return ndev; } - ndev = priv->dev; + priv = ipoib_priv(ndev); INIT_IB_EVENT_HANDLER(&priv->event_handler, priv->ca, ipoib_event); @@ -2417,6 +2421,14 @@ static struct net_device *ipoib_add_port(const char *format, return ERR_PTR(result); } + if (hca->rdma_netdev_get_params) { + int rc = hca->rdma_netdev_get_params(hca, port, + RDMA_NETDEV_IPOIB, + ¶ms); + + if (!rc && ops->priv_size < params.sizeof_priv) + ops->priv_size = params.sizeof_priv; + } /* * We cannot set priv_destructor before register_netdev because we * need priv to be always valid during the error flow to execute diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c index d4d553a51fa9..38c984d16996 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c @@ -122,12 +122,26 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev, } else child_pkey = nla_get_u16(data[IFLA_IPOIB_PKEY]); + err = ipoib_intf_init(ppriv->ca, ppriv->port, dev->name, dev); + if (err) { + ipoib_warn(ppriv, "failed to initialize pkey device\n"); + return err; + } + err = __ipoib_vlan_add(ppriv, ipoib_priv(dev), child_pkey, IPOIB_RTNL_CHILD); + if (err) + return err; - if (!err && data) + if (data) { err = ipoib_changelink(dev, tb, data, extack); - return err; + if (err) { + unregister_netdevice(dev); + return err; + } + } + + return 0; } static size_t ipoib_get_size(const struct net_device *dev) @@ -149,6 +163,11 @@ static struct rtnl_link_ops ipoib_link_ops __read_mostly = { .fill_info = ipoib_fill_info, }; +struct rtnl_link_ops *ipoib_get_link_ops(void) +{ + return &ipoib_link_ops; +} + int __init ipoib_netlink_init(void) { return rtnl_link_register(&ipoib_link_ops); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 341753fbda54..8ac8e18fbe0c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -85,7 +85,7 @@ static bool is_child_unique(struct ipoib_dev_priv *ppriv, /* * NOTE: If this function fails then the priv->dev will remain valid, however - * priv can have been freed and must not be touched by caller in the error + * priv will have been freed and must not be touched by caller in the error * case. * * If (ndev->reg_state == NETREG_UNINITIALIZED) then it is up to the caller to @@ -101,6 +101,12 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, ASSERT_RTNL(); /* + * We do not need to touch priv if register_netdevice fails, so just + * always use this flow. + */ + ndev->priv_destructor = ipoib_intf_free; + + /* * Racing with unregister of the parent must be prevented by the * caller. */ @@ -120,9 +126,6 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, goto out_early; } - /* We do not need to touch priv if register_netdevice fails */ - ndev->priv_destructor = ipoib_intf_free; - result = register_netdevice(ndev); if (result) { ipoib_warn(priv, "failed to initialize; error %i", result); @@ -182,12 +185,12 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) snprintf(intf_name, sizeof(intf_name), "%s.%04x", ppriv->dev->name, pkey); - priv = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); - if (!priv) { - result = -ENOMEM; + ndev = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name); + if (IS_ERR(ndev)) { + result = PTR_ERR(ndev); goto out; } - ndev = priv->dev; + priv = ipoib_priv(ndev); result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD); |