@@ -59,46 +59,33 @@ static int local_close(int fd)
return -1; /* success - return 'closed' */
}
-static void prepare_for_unbind(struct hotunplug *priv, char *buf, int buflen)
+static void prepare(struct hotunplug *priv)
{
- int len;
+ const char *filter = igt_device_filter_get(0), *sysfs_path;
- igt_assert(buflen);
+ igt_assert(filter);
- priv->fd.sysfs_drv = openat(priv->fd.sysfs_dev, "device/driver",
- O_DIRECTORY);
+ priv->dev_bus_addr = strrchr(filter, '/');
+ igt_assert(priv->dev_bus_addr++);
+
+ sysfs_path = strchr(filter, ':');
+ igt_assert(sysfs_path++);
+
+ priv->fd.sysfs_dev = open(sysfs_path, O_DIRECTORY);
+ igt_assert_fd(priv->fd.sysfs_dev);
+
+ priv->fd.sysfs_drv = openat(priv->fd.sysfs_dev, "driver", O_DIRECTORY);
igt_assert_fd(priv->fd.sysfs_drv);
- len = readlinkat(priv->fd.sysfs_dev, "device", buf, buflen - 1);
- buf[len] = '\0';
- priv->dev_bus_addr = strrchr(buf, '/');
- igt_assert(priv->dev_bus_addr++);
+ priv->fd.sysfs_bus = openat(priv->fd.sysfs_dev, "subsystem/devices",
+ O_DIRECTORY);
+ igt_assert_fd(priv->fd.sysfs_bus);
- /* sysfs_dev no longer needed */
priv->fd.sysfs_dev = local_close(priv->fd.sysfs_dev);
igt_assert_f(priv->fd.sysfs_dev == -1,
"Device sysfs node close failed\n");
}
-static void prepare(struct hotunplug *priv, char *buf, int buflen)
-{
- igt_debug("opening device\n");
- priv->fd.drm = __drm_open_driver(DRIVER_ANY);
- igt_assert_fd(priv->fd.drm);
-
- priv->fd.sysfs_dev = igt_sysfs_open(priv->fd.drm);
- igt_assert_fd(priv->fd.sysfs_dev);
-
- if (buf) {
- prepare_for_unbind(priv, buf, buflen);
- } else {
- /* prepare for bus rescan */
- priv->fd.sysfs_bus = openat(priv->fd.sysfs_dev,
- "device/subsystem", O_DIRECTORY);
- igt_assert_fd(priv->fd.sysfs_bus);
- }
-}
-
/* Unbind the driver from the device */
static void driver_unbind(struct hotunplug *priv, const char *prefix)
{
@@ -109,8 +96,6 @@ static void driver_unbind(struct hotunplug *priv, const char *prefix)
igt_sysfs_set(priv->fd.sysfs_drv, "unbind", priv->dev_bus_addr);
igt_reset_timeout();
priv->failure = NULL;
-
- /* don't close fd.sysfs_drv, it will be used for driver rebinding */
}
/* Re-bind the driver to the device */
@@ -123,18 +108,20 @@ static void driver_bind(struct hotunplug *priv)
igt_sysfs_set(priv->fd.sysfs_drv, "bind", priv->dev_bus_addr);
igt_reset_timeout();
priv->failure = NULL;
-
- close(priv->fd.sysfs_drv);
}
/* Remove (virtually unplug) the device from its bus */
static void device_unplug(struct hotunplug *priv, const char *prefix)
{
+ priv->fd.sysfs_dev = openat(priv->fd.sysfs_bus, priv->dev_bus_addr,
+ O_DIRECTORY);
+ igt_assert_fd(priv->fd.sysfs_dev);
+
igt_debug("%sunplugging the device\n", prefix);
priv->failure = "Device unplug timeout!";
igt_set_timeout(60, priv->failure);
- igt_sysfs_set(priv->fd.sysfs_dev, "device/remove", "1");
+ igt_sysfs_set(priv->fd.sysfs_dev, "remove", "1");
igt_reset_timeout();
priv->failure = NULL;
@@ -150,11 +137,9 @@ static void bus_rescan(struct hotunplug *priv)
priv->failure = "Bus rescan timeout!";
igt_set_timeout(60, priv->failure);
- igt_sysfs_set(priv->fd.sysfs_bus, "rescan", "1");
+ igt_sysfs_set(priv->fd.sysfs_bus, "../rescan", "1");
igt_reset_timeout();
priv->failure = NULL;
-
- close(priv->fd.sysfs_bus);
}
static void healthcheck(struct hotunplug *priv)
@@ -209,14 +194,6 @@ static void set_filter_from_device(int fd)
static void unbind_rebind(struct hotunplug *priv)
{
- char buf[PATH_MAX];
-
- prepare(priv, buf, sizeof(buf));
-
- igt_debug("closing the device\n");
- priv->fd.drm = local_close(priv->fd.drm);
- igt_assert_f(priv->fd.drm == -1, "Device close failed\n");
-
driver_unbind(priv, "");
driver_bind(priv);
@@ -226,12 +203,6 @@ static void unbind_rebind(struct hotunplug *priv)
static void unplug_rescan(struct hotunplug *priv)
{
- prepare(priv, NULL, 0);
-
- igt_debug("closing the device\n");
- priv->fd.drm = local_close(priv->fd.drm);
- igt_assert_f(priv->fd.drm == -1, "Device close failed\n");
-
device_unplug(priv, "");
bus_rescan(priv);
@@ -241,9 +212,9 @@ static void unplug_rescan(struct hotunplug *priv)
static void hotunbind_lateclose(struct hotunplug *priv)
{
- char buf[PATH_MAX];
-
- prepare(priv, buf, sizeof(buf));
+ igt_debug("opening device\n");
+ priv->fd.drm = __drm_open_driver(DRIVER_ANY);
+ igt_assert_fd(priv->fd.drm);
driver_unbind(priv, "hot ");
@@ -258,7 +229,9 @@ static void hotunbind_lateclose(struct hotunplug *priv)
static void hotunplug_lateclose(struct hotunplug *priv)
{
- prepare(priv, NULL, 0);
+ igt_debug("opening device\n");
+ priv->fd.drm = __drm_open_driver(DRIVER_ANY);
+ igt_assert_fd(priv->fd.drm);
device_unplug(priv, "hot ");
@@ -298,6 +271,8 @@ igt_main
set_filter_from_device(fd_drm);
igt_fail_on_f(close(fd_drm), "Device close failed\n");
+
+ prepare(&priv);
}
igt_describe("Check if the driver can be cleanly unbound from a device believed to be closed");
@@ -325,6 +300,10 @@ igt_main
igt_subtest("hotunplug-lateclose")
hotunplug_lateclose(&priv);
- igt_fixture
+ igt_fixture {
post_healthcheck(&priv);
+
+ close(priv.fd.sysfs_bus);
+ close(priv.fd.sysfs_drv);
+ }
}