[PATCHv3 3/3] test: add no_cache to driver_data load tester

From: yi1 . li
Date: Fri Jun 16 2017 - 19:04:40 EST


From: Yi Li <yi1.li@xxxxxxxxxxxxxxx>

Add a platform device to enable PM cache and add cache/no_cache test.

Signed-off-by: Yi Li <yi1.li@xxxxxxxxxxxxxxx>
---
lib/test_driver_data.c | 97 ++++++++++++++++++++++---
tools/testing/selftests/firmware/driver_data.sh | 67 +++++++++++++++++
2 files changed, 154 insertions(+), 10 deletions(-)

diff --git a/lib/test_driver_data.c b/lib/test_driver_data.c
index c176527..cadd122 100644
--- a/lib/test_driver_data.c
+++ b/lib/test_driver_data.c
@@ -44,6 +44,8 @@
#include <linux/async.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>

/* Used for the fallback default to test against */
#define TEST_DRIVER_DATA "test-driver_data.bin"
@@ -73,6 +75,10 @@ int num_test_devs;
* struct driver_data_reg_params @optional field for more information.
* @keep: whether or not we wish to free the driver_data on our own, refer to
* the struct driver_data_req_params @keep field for more information.
+ * @no_cache: whether or not we wish to use the internal caching mechanism
+ * to assist drivers from fetching driver data at resume time after
+ * suspend, refer to the struct driver_data_req_params .req
+ * DRIVER_DATA_REQ_NO_CACHE for more information.
* @enable_opt_cb: whether or not the optional callback should be set
* on a trigger. There is no equivalent setting on the struct
* driver_data_req_params as this is implementation specific, and in
@@ -121,6 +127,7 @@ struct test_config {
bool async;
bool optional;
bool keep;
+ bool no_cache;
bool enable_opt_cb;
bool use_api_versioning;
u8 api_min;
@@ -163,6 +170,7 @@ struct test_driver_data_private {
* a driver might typically use to stuff firmware / driver_data.
* @misc_dev: we use a misc device under the hood
* @dev: pointer to misc_dev's own struct device
+ * @pdev: pointer to platform device's struct device
* @api_found_calls: number of calls a fetch for a driver was found. We use
* for internal use on the api callback.
* @driver_data_mutex: for access into the @driver_data, the fake storage
@@ -181,6 +189,7 @@ struct driver_data_test_device {
struct test_driver_data_private test_driver_data;
struct miscdevice misc_dev;
struct device *dev;
+ struct device *pdev;

u8 api_found_calls;

@@ -346,6 +355,9 @@ static ssize_t config_show(struct device *dev,
len += snprintf(buf+len, PAGE_SIZE,
"keep:\t\t%s\n",
config->keep ? "true" : "false");
+ len += snprintf(buf + len, PAGE_SIZE,
+ "no_cache:\t\t%s\n",
+ config->no_cache ? "true" : "false");

mutex_unlock(&test_dev->config_mutex);

@@ -399,9 +411,9 @@ static int config_req_default(struct driver_data_test_device *test_dev)
config->default_name);

ret = driver_data_request_sync(config->default_name,
- &req_params, test_dev->dev);
+ &req_params, test_dev->pdev);
if (ret)
- dev_info(test_dev->dev,
+ dev_info(test_dev->pdev,
"load of default '%s' failed: %d\n",
config->default_name, ret);

@@ -456,14 +468,17 @@ static int trigger_config_sync(struct driver_data_test_device *test_dev)
(config->optional ?
DRIVER_DATA_REQ_OPTIONAL : 0) |
(config->keep ?
- DRIVER_DATA_REQ_KEEP : 0)),
+ DRIVER_DATA_REQ_KEEP : 0) |
+ (config->no_cache ?
+ DRIVER_DATA_REQ_NO_CACHE : 0)),
};
const struct driver_data_req_params req_params_opt_cb = {
DRIVER_DATA_DEFAULT_SYNC(config_sync_req_cb, test_dev),
DRIVER_DATA_SYNC_OPT_CB(config_sync_req_default_cb,
test_dev),
.reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) |
- (config->keep ? DRIVER_DATA_REQ_KEEP : 0),
+ (config->keep ? DRIVER_DATA_REQ_KEEP : 0) |
+ (config->no_cache ? DRIVER_DATA_REQ_NO_CACHE : 0),
};
const struct driver_data_req_params *req_params;

@@ -472,9 +487,10 @@ static int trigger_config_sync(struct driver_data_test_device *test_dev)
else
req_params = &req_params_default;

- ret = driver_data_request_sync(config->name, req_params, test_dev->dev);
+ ret = driver_data_request_sync(config->name, req_params,
+ test_dev->pdev);
if (ret)
- dev_err(test_dev->dev, "sync load of '%s' failed: %d\n",
+ dev_err(test_dev->pdev, "sync load of '%s' failed: %d\n",
config->name, ret);

return ret;
@@ -529,19 +545,22 @@ static int trigger_config_async(struct driver_data_test_device *test_dev)
const struct driver_data_req_params req_params_default = {
DRIVER_DATA_DEFAULT_ASYNC(config_async_req_cb, test_dev),
.reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) |
- (config->keep ? DRIVER_DATA_REQ_KEEP : 0),
+ (config->keep ? DRIVER_DATA_REQ_KEEP : 0) |
+ (config->no_cache ? DRIVER_DATA_REQ_NO_CACHE : 0),
};
const struct driver_data_req_params req_params_opt_cb = {
DRIVER_DATA_DEFAULT_ASYNC(config_async_req_cb, test_dev),
DRIVER_DATA_ASYNC_OPT_CB(config_async_req_default_cb, test_dev),
.reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) |
- (config->keep ? DRIVER_DATA_REQ_KEEP : 0),
+ (config->keep ? DRIVER_DATA_REQ_KEEP : 0) |
+ (config->no_cache ? DRIVER_DATA_REQ_NO_CACHE : 0),
};
const struct driver_data_req_params req_params_api = {
DRIVER_DATA_API_CB(config_async_req_api_cb, test_dev),
DRIVER_DATA_API(config->api_min, config->api_max, config->api_name_postfix),
.reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) |
(config->keep ? DRIVER_DATA_REQ_KEEP : 0) |
+ (config->no_cache ? DRIVER_DATA_REQ_NO_CACHE : 0) |
(config->use_api_versioning ? DRIVER_DATA_REQ_USE_API_VERSIONING : 0),
};
const struct driver_data_req_params *req_params;
@@ -555,9 +574,9 @@ static int trigger_config_async(struct driver_data_test_device *test_dev)

test_dev->api_found_calls = 0;
ret = driver_data_request_async(config->name, req_params,
- test_dev->dev);
+ test_dev->pdev);
if (ret) {
- dev_err(test_dev->dev, "async load of '%s' failed: %d\n",
+ dev_err(test_dev->pdev, "async load of '%s' failed: %d\n",
config->name, ret);
goto out;
}
@@ -667,6 +686,7 @@ static int __driver_data_config_init(struct test_config *config)
config->async = false;
config->optional = false;
config->keep = false;
+ config->no_cache = false;
config->enable_opt_cb = false;
config->use_api_versioning = false;
config->api_min = 0;
@@ -986,6 +1006,29 @@ static ssize_t config_keep_show(struct device *dev,
}
static DEVICE_ATTR(config_keep, 0644, config_keep_show, config_keep_store);

+static ssize_t config_no_cache_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct driver_data_test_device *test_dev = dev_to_test_dev(dev);
+ struct test_config *config = &test_dev->config;
+
+ return test_dev_config_update_bool(test_dev, buf, count,
+ &config->no_cache);
+}
+
+static ssize_t config_no_cache_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct driver_data_test_device *test_dev = dev_to_test_dev(dev);
+ struct test_config *config = &test_dev->config;
+
+ return test_dev_config_show_bool(test_dev, buf, config->no_cache);
+}
+static DEVICE_ATTR(config_no_cache, 0644, config_no_cache_show,
+ config_no_cache_store);
+
static ssize_t config_enable_opt_cb_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -1143,6 +1186,7 @@ static struct attribute *test_dev_attrs[] = {
TEST_DRIVER_DATA_DEV_ATTR(config_async),
TEST_DRIVER_DATA_DEV_ATTR(config_optional),
TEST_DRIVER_DATA_DEV_ATTR(config_keep),
+ TEST_DRIVER_DATA_DEV_ATTR(config_no_cache),
TEST_DRIVER_DATA_DEV_ATTR(config_use_api_versioning),
TEST_DRIVER_DATA_DEV_ATTR(config_enable_opt_cb),
TEST_DRIVER_DATA_DEV_ATTR(config_api_min),
@@ -1163,10 +1207,32 @@ void free_test_dev_driver_data(struct driver_data_test_device *test_dev)
vfree(test_dev);
}

+static struct platform_device *driver_data_pdev;
+static int driver_data_test_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int driver_data_test_resume(struct device *dev)
+{
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(driver_test_platform_pm_ops, driver_data_test_suspend,
+ driver_data_test_resume);
+
+static struct platform_driver driver_data_test_driver = {
+ .driver = {
+ .name = "driver_data_test",
+ .pm = &driver_test_platform_pm_ops,
+ }
+};
+
void unregister_test_dev_driver_data(struct driver_data_test_device *test_dev)
{
wait_for_completion_timeout(&test_dev->request_complete, 5 * HZ);
dev_info(test_dev->dev, "removing interface\n");
+ platform_device_unregister(driver_data_pdev);
misc_deregister(&test_dev->misc_dev);
free_test_dev_driver_data(test_dev);
}
@@ -1211,6 +1277,11 @@ struct driver_data_test_device *alloc_test_dev_driver_data(int idx)
return NULL;
}

+static int driver_data_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
static int register_test_dev_driver_data(void)
{
struct driver_data_test_device *test_dev = NULL;
@@ -1230,6 +1301,12 @@ static int register_test_dev_driver_data(void)
goto out;
}

+ driver_data_pdev = platform_create_bundle(
+ &driver_data_test_driver, driver_data_probe, NULL, 0, NULL, 0);
+ if (IS_ERR(driver_data_pdev))
+ return PTR_ERR(driver_data_pdev);
+ test_dev->pdev = &driver_data_pdev->dev;
+
ret = misc_register(&test_dev->misc_dev);
if (ret) {
pr_err("could not register misc device: %d\n", ret);
diff --git a/tools/testing/selftests/firmware/driver_data.sh b/tools/testing/selftests/firmware/driver_data.sh
index dc823ae..15af500 100755
--- a/tools/testing/selftests/firmware/driver_data.sh
+++ b/tools/testing/selftests/firmware/driver_data.sh
@@ -48,6 +48,8 @@ ALL_TESTS="$ALL_TESTS 0010:10:1"
ALL_TESTS="$ALL_TESTS 0011:10:1"
ALL_TESTS="$ALL_TESTS 0012:1:1"
ALL_TESTS="$ALL_TESTS 0013:1:1"
+ALL_TESTS="$ALL_TESTS 0015:1:1"
+ALL_TESTS="$ALL_TESTS 0016:1:1"

# Not yet sure how to automate suspend test well yet. For now we expect a
# manual run. If using qemu you can resume a guest using something like the
@@ -219,6 +221,22 @@ config_disable_keep()
fi
}

+config_set_no_cache()
+{
+ if ! echo -n 1 >$DIR/config_no_cache; then
+ echo "$0: Unable to set to no_cache" >&2
+ exit 1
+ fi
+}
+
+config_disable_no_cache()
+{
+ if ! echo -n 0 >$DIR/config_no_cache; then
+ echo "$0: Unable to disable no_cache option" >&2
+ exit 1
+ fi
+}
+
config_enable_opt_cb()
{
if ! echo -n 1 >$DIR/config_enable_opt_cb; then
@@ -412,6 +430,30 @@ config_default_file_should_not_match()
echo "$1: OK!"
}

+config_expect_cached()
+{
+ echo -n 1 > /sys/kernel/debug/firmware/cache
+ if ! cat /sys/kernel/debug/firmware/cache | grep "cached test-driver_data.bin"; then
+ echo "$1: FAIL to cache firmware" >&2
+ echo -n 0 > /sys/kernel/debug/firmware/cache
+ exit 1
+ fi
+ echo "$1: OK! cache success"
+ echo -n 0 > /sys/kernel/debug/firmware/cache
+}
+
+config_expect_non_cached()
+{
+ echo -n 1 > /sys/kernel/debug/firmware/cache
+ if cat /sys/kernel/debug/firmware/cache | grep "cached driver_data_test_no_cache.bin"; then
+ echo "$1: FAIL, should not cache firmware" >&2
+ echo -n 0 > /sys/kernel/debug/firmware/cache
+ exit 1
+ fi
+ echo "$1: OK! expect non cache success"
+ echo -n 0 > /sys/kernel/debug/firmware/cache
+}
+
config_expect_result()
{
RC=$(config_get_test_result)
@@ -821,6 +863,29 @@ driver_data_test_0014()
driver_data_test_0014a
}

+driver_data_test_0015()
+{
+ driver_data_set_sync_defaults
+ config_disable_no_cache
+ config_trigger ${FUNCNAME[0]}
+ config_expect_cached ${FUNCNAME[0]}
+}
+
+driver_data_test_0016()
+{
+ NAME_PREFIX="driver_data_test_no_cache"
+ NAME_POSTFIX=".bin"
+ NAME="${NAME_PREFIX}${NAME_POSTFIX}"
+
+ config_add_api_file $NAME
+
+ driver_data_set_sync_defaults
+ config_set_name $NAME
+ config_set_no_cache
+ config_trigger ${FUNCNAME[0]}
+ config_expect_non_cached ${FUNCNAME[0]}
+ config_rm_api_file $NAME
+}
list_tests()
{
echo "Test ID list:"
@@ -843,6 +908,8 @@ list_tests()
echo "0012 x $(get_test_count 0012) - Verify api call wills will hunt for files, ignore file"
echo "0013 x $(get_test_count 0013) - Verify api call works"
echo "0014 x $(get_test_count 0013) - Verify api call works with suspend + resume"
+ echo "0015 x $(get_test_count 0016) - Verify cache works"
+ echo "0016 x $(get_test_count 0017) - Verify non-cache works"
}

test_reqs
--
2.7.4