#include <rdma/ib_cache.h>
 #include <rdma/ib_cm.h>
 #include "cm_msgs.h"
+#include "core_priv.h"
 
 MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("InfiniBand CM");
 struct cm_device {
        struct list_head list;
        struct ib_device *ib_device;
-       struct device *device;
        u8 ack_delay;
        int going_down;
        struct cm_port *port[0];
        .default_attrs = cm_counter_default_attrs
 };
 
-static void cm_release_port_obj(struct kobject *obj)
-{
-       struct cm_port *cm_port;
-
-       cm_port = container_of(obj, struct cm_port, port_obj);
-       kfree(cm_port);
-}
-
-static struct kobj_type cm_port_obj_type = {
-       .release = cm_release_port_obj
-};
-
 static char *cm_devnode(struct device *dev, umode_t *mode)
 {
        if (mode)
 {
        int i, ret;
 
-       ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type,
-                                  &port->cm_dev->device->kobj,
-                                  "%d", port->port_num);
-       if (ret) {
-               kfree(port);
-               return ret;
-       }
-
        for (i = 0; i < CM_COUNTER_GROUPS; i++) {
-               ret = kobject_init_and_add(&port->counter_group[i].obj,
-                                          &cm_counter_obj_type,
-                                          &port->port_obj,
-                                          "%s", counter_group_names[i]);
+               ret = ib_port_register_module_stat(port->cm_dev->ib_device,
+                                                  port->port_num,
+                                                  &port->counter_group[i].obj,
+                                                  &cm_counter_obj_type,
+                                                  counter_group_names[i]);
                if (ret)
                        goto error;
        }
 
 error:
        while (i--)
-               kobject_put(&port->counter_group[i].obj);
-       kobject_put(&port->port_obj);
+               ib_port_unregister_module_stat(&port->counter_group[i].obj);
        return ret;
 
 }
        int i;
 
        for (i = 0; i < CM_COUNTER_GROUPS; i++)
-               kobject_put(&port->counter_group[i].obj);
+               ib_port_unregister_module_stat(&port->counter_group[i].obj);
 
-       kobject_put(&port->port_obj);
 }
 
 static void cm_add_one(struct ib_device *ib_device)
        cm_dev->ib_device = ib_device;
        cm_dev->ack_delay = ib_device->attrs.local_ca_ack_delay;
        cm_dev->going_down = 0;
-       cm_dev->device = device_create(&cm_class, &ib_device->dev,
-                                      MKDEV(0, 0), NULL,
-                                      "%s", dev_name(&ib_device->dev));
-       if (IS_ERR(cm_dev->device)) {
-               kfree(cm_dev);
-               return;
-       }
 
        set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
        for (i = 1; i <= ib_device->phys_port_cnt; i++) {
                cm_remove_port_fs(port);
        }
 free:
-       device_unregister(cm_dev->device);
        kfree(cm_dev);
 }
 
                cm_remove_port_fs(port);
        }
 
-       device_unregister(cm_dev->device);
        kfree(cm_dev);
 }
 
 
 
        ib_free_port_attrs(&device->coredev);
 }
+
+/**
+ * ib_port_register_module_stat - add module counters under relevant port
+ *  of IB device.
+ *
+ * @device: IB device to add counters
+ * @port_num: valid port number
+ * @kobj: pointer to the kobject to initialize
+ * @ktype: pointer to the ktype for this kobject.
+ * @name: the name of the kobject
+ */
+int ib_port_register_module_stat(struct ib_device *device, u8 port_num,
+                                struct kobject *kobj, struct kobj_type *ktype,
+                                const char *name)
+{
+       struct kobject *p, *t;
+       int ret;
+
+       list_for_each_entry_safe(p, t, &device->coredev.port_list, entry) {
+               struct ib_port *port = container_of(p, struct ib_port, kobj);
+
+               if (port->port_num != port_num)
+                       continue;
+
+               ret = kobject_init_and_add(kobj, ktype, &port->kobj, "%s",
+                                          name);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(ib_port_register_module_stat);
+
+/**
+ * ib_port_unregister_module_stat - release module counters
+ * @kobj: pointer to the kobject to release
+ */
+void ib_port_unregister_module_stat(struct kobject *kobj)
+{
+       kobject_put(kobj);
+}
+EXPORT_SYMBOL(ib_port_unregister_module_stat);