mei: bus: move hw module get/put to probe/release
authorAlexander Usyskin <alexander.usyskin@intel.com>
Mon, 25 Feb 2019 09:09:28 +0000 (11:09 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 26 Feb 2019 10:53:56 +0000 (11:53 +0100)
Fix unbalanced module reference counting during internal reset, which
prevents the drivers unloading.
Tracking mei_me/txe modules on mei client bus via
mei_cldev_enable/disable is error prone due to possible internal
reset flow, where clients are disconnected underneath.
Moving reference counting to probe and release of mei bus client
driver solves this issue in simplest way, as each client provides only
a single connection to a client bus driver.

Cc: <stable@vger.kernel.org>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/bus.c

index e5456faf00e650f4cd16ade1367efff32e1c9546..65bec998eb6ecd8a52e9b3e5fa9e860f7c9e55e4 100644 (file)
@@ -540,17 +540,9 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
                goto out;
        }
 
-       if (!mei_cl_bus_module_get(cldev)) {
-               dev_err(&cldev->dev, "get hw module failed");
-               ret = -ENODEV;
-               goto out;
-       }
-
        ret = mei_cl_connect(cl, cldev->me_cl, NULL);
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&cldev->dev, "cannot connect\n");
-               mei_cl_bus_module_put(cldev);
-       }
 
 out:
        mutex_unlock(&bus->device_lock);
@@ -613,7 +605,6 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
        if (err < 0)
                dev_err(bus->dev, "Could not disconnect from the ME client\n");
 
-       mei_cl_bus_module_put(cldev);
 out:
        /* Flush queues and remove any pending read */
        mei_cl_flush_queues(cl, NULL);
@@ -724,9 +715,16 @@ static int mei_cl_device_probe(struct device *dev)
        if (!id)
                return -ENODEV;
 
+       if (!mei_cl_bus_module_get(cldev)) {
+               dev_err(&cldev->dev, "get hw module failed");
+               return -ENODEV;
+       }
+
        ret = cldrv->probe(cldev, id);
-       if (ret)
+       if (ret) {
+               mei_cl_bus_module_put(cldev);
                return ret;
+       }
 
        __module_get(THIS_MODULE);
        return 0;
@@ -754,6 +752,7 @@ static int mei_cl_device_remove(struct device *dev)
 
        mei_cldev_unregister_callbacks(cldev);
 
+       mei_cl_bus_module_put(cldev);
        module_put(THIS_MODULE);
        dev->driver = NULL;
        return ret;