Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
[sfrench/cifs-2.6.git] / drivers / infiniband / core / device.c
index 3352a107b4a36756518087eef46615b55372e2a0..9773145dee0996d0d058230bc6ce18f9c138d34f 100644 (file)
@@ -46,6 +46,7 @@
 #include <rdma/rdma_netlink.h>
 #include <rdma/ib_addr.h>
 #include <rdma/ib_cache.h>
+#include <rdma/rdma_counter.h>
 
 #include "core_priv.h"
 #include "restrack.h"
@@ -270,7 +271,7 @@ struct ib_port_data_rcu {
        struct ib_port_data pdata[];
 };
 
-static int ib_device_check_mandatory(struct ib_device *device)
+static void ib_device_check_mandatory(struct ib_device *device)
 {
 #define IB_MANDATORY_FUNC(x) { offsetof(struct ib_device_ops, x), #x }
        static const struct {
@@ -305,8 +306,6 @@ static int ib_device_check_mandatory(struct ib_device *device)
                        break;
                }
        }
-
-       return 0;
 }
 
 /*
@@ -375,7 +374,7 @@ struct ib_device *ib_device_get_by_name(const char *name,
        down_read(&devices_rwsem);
        device = __ib_device_get_by_name(name);
        if (device && driver_id != RDMA_DRIVER_UNKNOWN &&
-           device->driver_id != driver_id)
+           device->ops.driver_id != driver_id)
                device = NULL;
 
        if (device) {
@@ -449,6 +448,15 @@ int ib_device_rename(struct ib_device *ibdev, const char *name)
        return 0;
 }
 
+int ib_device_set_dim(struct ib_device *ibdev, u8 use_dim)
+{
+       if (use_dim > 1)
+               return -EINVAL;
+       ibdev->use_cq_dim = use_dim;
+
+       return 0;
+}
+
 static int alloc_name(struct ib_device *ibdev, const char *name)
 {
        struct ib_device *device;
@@ -494,10 +502,12 @@ static void ib_device_release(struct device *device)
        if (dev->port_data) {
                ib_cache_release_one(dev);
                ib_security_release_port_pkey_list(dev);
+               rdma_counter_release(dev);
                kfree_rcu(container_of(dev->port_data, struct ib_port_data_rcu,
                                       pdata[0]),
                          rcu_head);
        }
+
        xa_destroy(&dev->compat_devs);
        xa_destroy(&dev->client_data);
        kfree_rcu(dev, rcu_head);
@@ -1193,10 +1203,7 @@ static int setup_device(struct ib_device *device)
        int ret;
 
        setup_dma_device(device);
-
-       ret = ib_device_check_mandatory(device);
-       if (ret)
-               return ret;
+       ib_device_check_mandatory(device);
 
        ret = setup_port_data(device);
        if (ret) {
@@ -1321,6 +1328,8 @@ int ib_register_device(struct ib_device *device, const char *name)
 
        ib_device_register_rdmacg(device);
 
+       rdma_counter_init(device);
+
        /*
         * Ensure that ADD uevent is not fired because it
         * is too early amd device is not initialized yet.
@@ -1479,7 +1488,7 @@ void ib_unregister_driver(enum rdma_driver_id driver_id)
 
        down_read(&devices_rwsem);
        xa_for_each (&devices, index, ib_dev) {
-               if (ib_dev->driver_id != driver_id)
+               if (ib_dev->ops.driver_id != driver_id)
                        continue;
 
                get_device(&ib_dev->dev);
@@ -1749,6 +1758,104 @@ void ib_unregister_client(struct ib_client *client)
 }
 EXPORT_SYMBOL(ib_unregister_client);
 
+static int __ib_get_global_client_nl_info(const char *client_name,
+                                         struct ib_client_nl_info *res)
+{
+       struct ib_client *client;
+       unsigned long index;
+       int ret = -ENOENT;
+
+       down_read(&clients_rwsem);
+       xa_for_each_marked (&clients, index, client, CLIENT_REGISTERED) {
+               if (strcmp(client->name, client_name) != 0)
+                       continue;
+               if (!client->get_global_nl_info) {
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+               ret = client->get_global_nl_info(res);
+               if (WARN_ON(ret == -ENOENT))
+                       ret = -EINVAL;
+               if (!ret && res->cdev)
+                       get_device(res->cdev);
+               break;
+       }
+       up_read(&clients_rwsem);
+       return ret;
+}
+
+static int __ib_get_client_nl_info(struct ib_device *ibdev,
+                                  const char *client_name,
+                                  struct ib_client_nl_info *res)
+{
+       unsigned long index;
+       void *client_data;
+       int ret = -ENOENT;
+
+       down_read(&ibdev->client_data_rwsem);
+       xan_for_each_marked (&ibdev->client_data, index, client_data,
+                            CLIENT_DATA_REGISTERED) {
+               struct ib_client *client = xa_load(&clients, index);
+
+               if (!client || strcmp(client->name, client_name) != 0)
+                       continue;
+               if (!client->get_nl_info) {
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
+               ret = client->get_nl_info(ibdev, client_data, res);
+               if (WARN_ON(ret == -ENOENT))
+                       ret = -EINVAL;
+
+               /*
+                * The cdev is guaranteed valid as long as we are inside the
+                * client_data_rwsem as remove_one can't be called. Keep it
+                * valid for the caller.
+                */
+               if (!ret && res->cdev)
+                       get_device(res->cdev);
+               break;
+       }
+       up_read(&ibdev->client_data_rwsem);
+
+       return ret;
+}
+
+/**
+ * ib_get_client_nl_info - Fetch the nl_info from a client
+ * @device - IB device
+ * @client_name - Name of the client
+ * @res - Result of the query
+ */
+int ib_get_client_nl_info(struct ib_device *ibdev, const char *client_name,
+                         struct ib_client_nl_info *res)
+{
+       int ret;
+
+       if (ibdev)
+               ret = __ib_get_client_nl_info(ibdev, client_name, res);
+       else
+               ret = __ib_get_global_client_nl_info(client_name, res);
+#ifdef CONFIG_MODULES
+       if (ret == -ENOENT) {
+               request_module("rdma-client-%s", client_name);
+               if (ibdev)
+                       ret = __ib_get_client_nl_info(ibdev, client_name, res);
+               else
+                       ret = __ib_get_global_client_nl_info(client_name, res);
+       }
+#endif
+       if (ret) {
+               if (ret == -ENOENT)
+                       return -EOPNOTSUPP;
+               return ret;
+       }
+
+       if (WARN_ON(!res->cdev))
+               return -EINVAL;
+       return 0;
+}
+
 /**
  * ib_set_client_data - Set IB client context
  * @device:Device to set context for
@@ -2039,7 +2146,7 @@ struct ib_device *ib_device_get_by_netdev(struct net_device *ndev,
                                    (uintptr_t)ndev) {
                if (rcu_access_pointer(cur->netdev) == ndev &&
                    (driver_id == RDMA_DRIVER_UNKNOWN ||
-                    cur->ib_dev->driver_id == driver_id) &&
+                    cur->ib_dev->ops.driver_id == driver_id) &&
                    ib_device_try_get(cur->ib_dev)) {
                        res = cur->ib_dev;
                        break;
@@ -2344,12 +2451,28 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
 
 #define SET_OBJ_SIZE(ptr, name) SET_DEVICE_OP(ptr, size_##name)
 
+       if (ops->driver_id != RDMA_DRIVER_UNKNOWN) {
+               WARN_ON(dev_ops->driver_id != RDMA_DRIVER_UNKNOWN &&
+                       dev_ops->driver_id != ops->driver_id);
+               dev_ops->driver_id = ops->driver_id;
+       }
+       if (ops->owner) {
+               WARN_ON(dev_ops->owner && dev_ops->owner != ops->owner);
+               dev_ops->owner = ops->owner;
+       }
+       if (ops->uverbs_abi_ver)
+               dev_ops->uverbs_abi_ver = ops->uverbs_abi_ver;
+
+       dev_ops->uverbs_no_driver_id_binding |=
+               ops->uverbs_no_driver_id_binding;
+
        SET_DEVICE_OP(dev_ops, add_gid);
        SET_DEVICE_OP(dev_ops, advise_mr);
        SET_DEVICE_OP(dev_ops, alloc_dm);
        SET_DEVICE_OP(dev_ops, alloc_fmr);
        SET_DEVICE_OP(dev_ops, alloc_hw_stats);
        SET_DEVICE_OP(dev_ops, alloc_mr);
+       SET_DEVICE_OP(dev_ops, alloc_mr_integrity);
        SET_DEVICE_OP(dev_ops, alloc_mw);
        SET_DEVICE_OP(dev_ops, alloc_pd);
        SET_DEVICE_OP(dev_ops, alloc_rdma_netdev);
@@ -2357,6 +2480,11 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
        SET_DEVICE_OP(dev_ops, alloc_xrcd);
        SET_DEVICE_OP(dev_ops, attach_mcast);
        SET_DEVICE_OP(dev_ops, check_mr_status);
+       SET_DEVICE_OP(dev_ops, counter_alloc_stats);
+       SET_DEVICE_OP(dev_ops, counter_bind_qp);
+       SET_DEVICE_OP(dev_ops, counter_dealloc);
+       SET_DEVICE_OP(dev_ops, counter_unbind_qp);
+       SET_DEVICE_OP(dev_ops, counter_update_stats);
        SET_DEVICE_OP(dev_ops, create_ah);
        SET_DEVICE_OP(dev_ops, create_counters);
        SET_DEVICE_OP(dev_ops, create_cq);
@@ -2409,6 +2537,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
        SET_DEVICE_OP(dev_ops, iw_reject);
        SET_DEVICE_OP(dev_ops, iw_rem_ref);
        SET_DEVICE_OP(dev_ops, map_mr_sg);
+       SET_DEVICE_OP(dev_ops, map_mr_sg_pi);
        SET_DEVICE_OP(dev_ops, map_phys_fmr);
        SET_DEVICE_OP(dev_ops, mmap);
        SET_DEVICE_OP(dev_ops, modify_ah);
@@ -2445,6 +2574,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
        SET_DEVICE_OP(dev_ops, unmap_fmr);
 
        SET_OBJ_SIZE(dev_ops, ib_ah);
+       SET_OBJ_SIZE(dev_ops, ib_cq);
        SET_OBJ_SIZE(dev_ops, ib_pd);
        SET_OBJ_SIZE(dev_ops, ib_srq);
        SET_OBJ_SIZE(dev_ops, ib_ucontext);