devlink is an API to expose device information and resources not directly
 related to any device class, such as chip-wide/switch-ASIC-wide configuration.
 
+Locking
+-------
+
+Driver facing APIs are currently transitioning to allow more explicit
+locking. Drivers can use the existing ``devlink_*`` set of APIs, or
+new APIs prefixed by ``devl_*``. The older APIs handle all the locking
+in devlink core, but don't allow registration of most sub-objects once
+the main devlink object is itself registered. The newer ``devl_*`` APIs assume
+the devlink instance lock is already held. Drivers can take the instance
+lock by calling ``devl_lock()``. It is also held in most of the callbacks.
+Eventually all callbacks will be invoked under the devlink instance lock,
+refer to the use of the ``DEVLINK_NL_FLAG_NO_LOCK`` flag in devlink core
+to find out which callbacks are not converted, yet.
+
+Drivers are encouraged to use the devlink instance lock for their own needs.
+
 Interface documentation
 -----------------------
 
 
        return NULL;
 }
 
+void devl_assert_locked(struct devlink *devlink)
+{
+       lockdep_assert_held(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devl_assert_locked);
+
+#ifdef CONFIG_LOCKDEP
+/* For use in conjunction with LOCKDEP only e.g. rcu_dereference_protected() */
+bool devl_lock_is_held(struct devlink *devlink)
+{
+       return lockdep_is_held(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devl_lock_is_held);
+#endif
+
+void devl_lock(struct devlink *devlink)
+{
+       mutex_lock(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devl_lock);
+
+void devl_unlock(struct devlink *devlink)
+{
+       mutex_unlock(&devlink->lock);
+}
+EXPORT_SYMBOL_GPL(devl_unlock);
+
 static struct devlink *devlink_get_from_attrs(struct net *net,
                                              struct nlattr **attrs)
 {
        cancel_delayed_work_sync(&devlink_port->type_warn_dw);
 }
 
+int devl_port_register(struct devlink *devlink,
+                      struct devlink_port *devlink_port,
+                      unsigned int port_index)
+{
+       lockdep_assert_held(&devlink->lock);
+
+       if (devlink_port_index_exists(devlink, port_index))
+               return -EEXIST;
+
+       WARN_ON(devlink_port->devlink);
+       devlink_port->devlink = devlink;
+       devlink_port->index = port_index;
+       spin_lock_init(&devlink_port->type_lock);
+       INIT_LIST_HEAD(&devlink_port->reporter_list);
+       mutex_init(&devlink_port->reporters_lock);
+       list_add_tail(&devlink_port->list, &devlink->port_list);
+       INIT_LIST_HEAD(&devlink_port->param_list);
+       INIT_LIST_HEAD(&devlink_port->region_list);
+
+       INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
+       devlink_port_type_warn_schedule(devlink_port);
+       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devl_port_register);
+
 /**
  *     devlink_port_register - Register devlink port
  *
                          struct devlink_port *devlink_port,
                          unsigned int port_index)
 {
-       mutex_lock(&devlink->lock);
-       if (devlink_port_index_exists(devlink, port_index)) {
-               mutex_unlock(&devlink->lock);
-               return -EEXIST;
-       }
+       int err;
 
-       WARN_ON(devlink_port->devlink);
-       devlink_port->devlink = devlink;
-       devlink_port->index = port_index;
-       spin_lock_init(&devlink_port->type_lock);
-       INIT_LIST_HEAD(&devlink_port->reporter_list);
-       mutex_init(&devlink_port->reporters_lock);
-       list_add_tail(&devlink_port->list, &devlink->port_list);
-       INIT_LIST_HEAD(&devlink_port->param_list);
-       INIT_LIST_HEAD(&devlink_port->region_list);
+       mutex_lock(&devlink->lock);
+       err = devl_port_register(devlink, devlink_port, port_index);
        mutex_unlock(&devlink->lock);
-       INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
-       devlink_port_type_warn_schedule(devlink_port);
-       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(devlink_port_register);
 
+void devl_port_unregister(struct devlink_port *devlink_port)
+{
+       lockdep_assert_held(&devlink_port->devlink->lock);
+
+       devlink_port_type_warn_cancel(devlink_port);
+       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
+       list_del(&devlink_port->list);
+       WARN_ON(!list_empty(&devlink_port->reporter_list));
+       WARN_ON(!list_empty(&devlink_port->region_list));
+       mutex_destroy(&devlink_port->reporters_lock);
+}
+EXPORT_SYMBOL_GPL(devl_port_unregister);
+
 /**
  *     devlink_port_unregister - Unregister devlink port
  *
 {
        struct devlink *devlink = devlink_port->devlink;
 
-       devlink_port_type_warn_cancel(devlink_port);
-       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
        mutex_lock(&devlink->lock);
-       list_del(&devlink_port->list);
+       devl_port_unregister(devlink_port);
        mutex_unlock(&devlink->lock);
-       WARN_ON(!list_empty(&devlink_port->reporter_list));
-       WARN_ON(!list_empty(&devlink_port->region_list));
-       mutex_destroy(&devlink_port->reporters_lock);
 }
 EXPORT_SYMBOL_GPL(devlink_port_unregister);