09c434b8a0047 (Thomas Gleixner 2019-05-19 13:08:20 +0100 1) // SPDX-License-Identifier: GPL-2.0-only
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 2) /*
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 3) * This module provides an interface to trigger and test firmware loading.
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 4) *
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 5) * It is designed to be used for basic evaluation of the firmware loading
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 6) * subsystem (for example when validating firmware verification). It lacks
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 7) * any extra dependencies, and will not normally be loaded by the system
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 8) * unless explicitly requested by name.
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 9) */
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 10)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 11) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 12)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 13) #include <linux/init.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 14) #include <linux/module.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 15) #include <linux/printk.h>
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 16) #include <linux/completion.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 17) #include <linux/firmware.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 18) #include <linux/device.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 19) #include <linux/fs.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 20) #include <linux/miscdevice.h>
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 21) #include <linux/sizes.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 22) #include <linux/slab.h>
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 23) #include <linux/uaccess.h>
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 24) #include <linux/delay.h>
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 25) #include <linux/kthread.h>
514c603249601 (Randy Dunlap 2018-04-05 16:25:34 -0700 26) #include <linux/vmalloc.h>
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 27) #include <linux/efi_embedded_fw.h>
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 28)
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 29) MODULE_IMPORT_NS(TEST_FIRMWARE);
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 30)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 31) #define TEST_FIRMWARE_NAME "test-firmware.bin"
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 32) #define TEST_FIRMWARE_NUM_REQS 4
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 33) #define TEST_FIRMWARE_BUF_SIZE SZ_1K
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 34)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 35) static DEFINE_MUTEX(test_fw_mutex);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 36) static const struct firmware *test_firmware;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 37)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 38) struct test_batched_req {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 39) u8 idx;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 40) int rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 41) bool sent;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 42) const struct firmware *fw;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 43) const char *name;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 44) struct completion completion;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 45) struct task_struct *task;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 46) struct device *dev;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 47) };
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 48)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 49) /**
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 50) * test_config - represents configuration for the test for different triggers
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 51) *
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 52) * @name: the name of the firmware file to look for
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 53) * @into_buf: when the into_buf is used if this is true
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 54) * request_firmware_into_buf() will be used instead.
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 55) * @buf_size: size of buf to allocate when into_buf is true
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 56) * @file_offset: file offset to request when calling request_firmware_into_buf
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 57) * @partial: partial read opt when calling request_firmware_into_buf
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 58) * @sync_direct: when the sync trigger is used if this is true
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 59) * request_firmware_direct() will be used instead.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 60) * @send_uevent: whether or not to send a uevent for async requests
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 61) * @num_requests: number of requests to try per test case. This is trigger
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 62) * specific.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 63) * @reqs: stores all requests information
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 64) * @read_fw_idx: index of thread from which we want to read firmware results
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 65) * from through the read_fw trigger.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 66) * @test_result: a test may use this to collect the result from the call
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 67) * of the request_firmware*() calls used in their tests. In order of
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 68) * priority we always keep first any setup error. If no setup errors were
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 69) * found then we move on to the first error encountered while running the
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 70) * API. Note that for async calls this typically will be a successful
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 71) * result (0) unless of course you've used bogus parameters, or the system
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 72) * is out of memory. In the async case the callback is expected to do a
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 73) * bit more homework to figure out what happened, unfortunately the only
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 74) * information passed today on error is the fact that no firmware was
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 75) * found so we can only assume -ENOENT on async calls if the firmware is
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 76) * NULL.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 77) *
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 78) * Errors you can expect:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 79) *
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 80) * API specific:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 81) *
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 82) * 0: success for sync, for async it means request was sent
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 83) * -EINVAL: invalid parameters or request
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 84) * -ENOENT: files not found
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 85) *
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 86) * System environment:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 87) *
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 88) * -ENOMEM: memory pressure on system
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 89) * -ENODEV: out of number of devices to test
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 90) * -EINVAL: an unexpected error has occurred
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 91) * @req_firmware: if @sync_direct is true this is set to
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 92) * request_firmware_direct(), otherwise request_firmware()
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 93) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 94) struct test_config {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 95) char *name;
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 96) bool into_buf;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 97) size_t buf_size;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 98) size_t file_offset;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 99) bool partial;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 100) bool sync_direct;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 101) bool send_uevent;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 102) u8 num_requests;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 103) u8 read_fw_idx;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 104)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 105) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 106) * These below don't belong her but we'll move them once we create
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 107) * a struct fw_test_device and stuff the misc_dev under there later.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 108) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 109) struct test_batched_req *reqs;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 110) int test_result;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 111) int (*req_firmware)(const struct firmware **fw, const char *name,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 112) struct device *device);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 113) };
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 114)
76f8ab1bd1cb0 (Wei Yongjun 2018-01-11 11:13:45 +0000 115) static struct test_config *test_fw_config;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 116)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 117) static ssize_t test_fw_misc_read(struct file *f, char __user *buf,
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 118) size_t size, loff_t *offset)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 119) {
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 120) ssize_t rc = 0;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 121)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 122) mutex_lock(&test_fw_mutex);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 123) if (test_firmware)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 124) rc = simple_read_from_buffer(buf, size, offset,
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 125) test_firmware->data,
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 126) test_firmware->size);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 127) mutex_unlock(&test_fw_mutex);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 128) return rc;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 129) }
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 130)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 131) static const struct file_operations test_fw_fops = {
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 132) .owner = THIS_MODULE,
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 133) .read = test_fw_misc_read,
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 134) };
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 135)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 136) static void __test_release_all_firmware(void)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 137) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 138) struct test_batched_req *req;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 139) u8 i;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 140)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 141) if (!test_fw_config->reqs)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 142) return;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 143)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 144) for (i = 0; i < test_fw_config->num_requests; i++) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 145) req = &test_fw_config->reqs[i];
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 146) if (req->fw)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 147) release_firmware(req->fw);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 148) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 149)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 150) vfree(test_fw_config->reqs);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 151) test_fw_config->reqs = NULL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 152) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 153)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 154) static void test_release_all_firmware(void)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 155) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 156) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 157) __test_release_all_firmware();
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 158) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 159) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 160)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 161)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 162) static void __test_firmware_config_free(void)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 163) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 164) __test_release_all_firmware();
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 165) kfree_const(test_fw_config->name);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 166) test_fw_config->name = NULL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 167) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 168)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 169) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 170) * XXX: move to kstrncpy() once merged.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 171) *
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 172) * Users should use kfree_const() when freeing these.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 173) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 174) static int __kstrncpy(char **dst, const char *name, size_t count, gfp_t gfp)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 175) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 176) *dst = kstrndup(name, count, gfp);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 177) if (!*dst)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 178) return -ENOSPC;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 179) return count;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 180) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 181)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 182) static int __test_firmware_config_init(void)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 183) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 184) int ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 185)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 186) ret = __kstrncpy(&test_fw_config->name, TEST_FIRMWARE_NAME,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 187) strlen(TEST_FIRMWARE_NAME), GFP_KERNEL);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 188) if (ret < 0)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 189) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 190)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 191) test_fw_config->num_requests = TEST_FIRMWARE_NUM_REQS;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 192) test_fw_config->send_uevent = true;
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 193) test_fw_config->into_buf = false;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 194) test_fw_config->buf_size = TEST_FIRMWARE_BUF_SIZE;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 195) test_fw_config->file_offset = 0;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 196) test_fw_config->partial = false;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 197) test_fw_config->sync_direct = false;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 198) test_fw_config->req_firmware = request_firmware;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 199) test_fw_config->test_result = 0;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 200) test_fw_config->reqs = NULL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 201)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 202) return 0;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 203)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 204) out:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 205) __test_firmware_config_free();
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 206) return ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 207) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 208)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 209) static ssize_t reset_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 210) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 211) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 212) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 213) int ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 214)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 215) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 216)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 217) __test_firmware_config_free();
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 218)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 219) ret = __test_firmware_config_init();
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 220) if (ret < 0) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 221) ret = -ENOMEM;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 222) pr_err("could not alloc settings for config trigger: %d\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 223) ret);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 224) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 225) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 226)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 227) pr_info("reset\n");
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 228) ret = count;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 229)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 230) out:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 231) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 232)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 233) return ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 234) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 235) static DEVICE_ATTR_WO(reset);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 236)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 237) static ssize_t config_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 238) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 239) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 240) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 241) int len = 0;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 242)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 243) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 244)
bd17cc5a20ae9 (Dan Carpenter 2019-05-15 12:33:22 +0300 245) len += scnprintf(buf, PAGE_SIZE - len,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 246) "Custom trigger configuration for: %s\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 247) dev_name(dev));
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 248)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 249) if (test_fw_config->name)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 250) len += scnprintf(buf + len, PAGE_SIZE - len,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 251) "name:\t%s\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 252) test_fw_config->name);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 253) else
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 254) len += scnprintf(buf + len, PAGE_SIZE - len,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 255) "name:\tEMTPY\n");
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 256)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 257) len += scnprintf(buf + len, PAGE_SIZE - len,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 258) "num_requests:\t%u\n", test_fw_config->num_requests);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 259)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 260) len += scnprintf(buf + len, PAGE_SIZE - len,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 261) "send_uevent:\t\t%s\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 262) test_fw_config->send_uevent ?
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 263) "FW_ACTION_HOTPLUG" :
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 264) "FW_ACTION_NOHOTPLUG");
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 265) len += scnprintf(buf + len, PAGE_SIZE - len,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 266) "into_buf:\t\t%s\n",
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 267) test_fw_config->into_buf ? "true" : "false");
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 268) len += scnprintf(buf + len, PAGE_SIZE - len,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 269) "buf_size:\t%zu\n", test_fw_config->buf_size);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 270) len += scnprintf(buf + len, PAGE_SIZE - len,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 271) "file_offset:\t%zu\n", test_fw_config->file_offset);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 272) len += scnprintf(buf + len, PAGE_SIZE - len,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 273) "partial:\t\t%s\n",
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 274) test_fw_config->partial ? "true" : "false");
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 275) len += scnprintf(buf + len, PAGE_SIZE - len,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 276) "sync_direct:\t\t%s\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 277) test_fw_config->sync_direct ? "true" : "false");
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 278) len += scnprintf(buf + len, PAGE_SIZE - len,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 279) "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 280)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 281) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 282)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 283) return len;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 284) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 285) static DEVICE_ATTR_RO(config);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 286)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 287) static ssize_t config_name_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 288) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 289) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 290) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 291) int ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 292)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 293) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 294) kfree_const(test_fw_config->name);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 295) ret = __kstrncpy(&test_fw_config->name, buf, count, GFP_KERNEL);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 296) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 297)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 298) return ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 299) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 300)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 301) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 302) * As per sysfs_kf_seq_show() the buf is max PAGE_SIZE.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 303) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 304) static ssize_t config_test_show_str(char *dst,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 305) char *src)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 306) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 307) int len;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 308)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 309) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 310) len = snprintf(dst, PAGE_SIZE, "%s\n", src);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 311) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 312)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 313) return len;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 314) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 315)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 316) static int test_dev_config_update_bool(const char *buf, size_t size,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 317) bool *cfg)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 318) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 319) int ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 320)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 321) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 322) if (strtobool(buf, cfg) < 0)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 323) ret = -EINVAL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 324) else
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 325) ret = size;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 326) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 327)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 328) return ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 329) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 330)
55623260bb33e (Scott Branden 2020-04-14 17:25:17 -0700 331) static ssize_t test_dev_config_show_bool(char *buf, bool val)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 332) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 333) return snprintf(buf, PAGE_SIZE, "%d\n", val);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 334) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 335)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 336) static int test_dev_config_update_size_t(const char *buf,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 337) size_t size,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 338) size_t *cfg)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 339) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 340) int ret;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 341) long new;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 342)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 343) ret = kstrtol(buf, 10, &new);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 344) if (ret)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 345) return ret;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 346)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 347) mutex_lock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 348) *(size_t *)cfg = new;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 349) mutex_unlock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 350)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 351) /* Always return full write size even if we didn't consume all */
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 352) return size;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 353) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 354)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 355) static ssize_t test_dev_config_show_size_t(char *buf, size_t val)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 356) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 357) return snprintf(buf, PAGE_SIZE, "%zu\n", val);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 358) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 359)
55623260bb33e (Scott Branden 2020-04-14 17:25:17 -0700 360) static ssize_t test_dev_config_show_int(char *buf, int val)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 361) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 362) return snprintf(buf, PAGE_SIZE, "%d\n", val);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 363) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 364)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 365) static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 366) {
506dfc9906e5c (Alexey Dobriyan 2020-12-15 20:44:00 -0800 367) u8 val;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 368) int ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 369)
506dfc9906e5c (Alexey Dobriyan 2020-12-15 20:44:00 -0800 370) ret = kstrtou8(buf, 10, &val);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 371) if (ret)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 372) return ret;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 373)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 374) mutex_lock(&test_fw_mutex);
506dfc9906e5c (Alexey Dobriyan 2020-12-15 20:44:00 -0800 375) *(u8 *)cfg = val;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 376) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 377)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 378) /* Always return full write size even if we didn't consume all */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 379) return size;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 380) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 381)
55623260bb33e (Scott Branden 2020-04-14 17:25:17 -0700 382) static ssize_t test_dev_config_show_u8(char *buf, u8 val)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 383) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 384) return snprintf(buf, PAGE_SIZE, "%u\n", val);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 385) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 386)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 387) static ssize_t config_name_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 388) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 389) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 390) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 391) return config_test_show_str(buf, test_fw_config->name);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 392) }
b6b996b6cdeec (Joe Perches 2017-12-19 10:15:07 -0800 393) static DEVICE_ATTR_RW(config_name);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 394)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 395) static ssize_t config_num_requests_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 396) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 397) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 398) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 399) int rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 400)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 401) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 402) if (test_fw_config->reqs) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 403) pr_err("Must call release_all_firmware prior to changing config\n");
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 404) rc = -EINVAL;
a5e1923356505 (Wei Yongjun 2018-01-11 11:12:55 +0000 405) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 406) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 407) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 408) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 409)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 410) rc = test_dev_config_update_u8(buf, count,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 411) &test_fw_config->num_requests);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 412)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 413) out:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 414) return rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 415) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 416)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 417) static ssize_t config_num_requests_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 418) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 419) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 420) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 421) return test_dev_config_show_u8(buf, test_fw_config->num_requests);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 422) }
b6b996b6cdeec (Joe Perches 2017-12-19 10:15:07 -0800 423) static DEVICE_ATTR_RW(config_num_requests);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 424)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 425) static ssize_t config_into_buf_store(struct device *dev,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 426) struct device_attribute *attr,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 427) const char *buf, size_t count)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 428) {
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 429) return test_dev_config_update_bool(buf,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 430) count,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 431) &test_fw_config->into_buf);
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 432) }
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 433)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 434) static ssize_t config_into_buf_show(struct device *dev,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 435) struct device_attribute *attr,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 436) char *buf)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 437) {
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 438) return test_dev_config_show_bool(buf, test_fw_config->into_buf);
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 439) }
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 440) static DEVICE_ATTR_RW(config_into_buf);
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 441)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 442) static ssize_t config_buf_size_store(struct device *dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 443) struct device_attribute *attr,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 444) const char *buf, size_t count)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 445) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 446) int rc;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 447)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 448) mutex_lock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 449) if (test_fw_config->reqs) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 450) pr_err("Must call release_all_firmware prior to changing config\n");
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 451) rc = -EINVAL;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 452) mutex_unlock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 453) goto out;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 454) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 455) mutex_unlock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 456)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 457) rc = test_dev_config_update_size_t(buf, count,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 458) &test_fw_config->buf_size);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 459)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 460) out:
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 461) return rc;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 462) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 463)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 464) static ssize_t config_buf_size_show(struct device *dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 465) struct device_attribute *attr,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 466) char *buf)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 467) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 468) return test_dev_config_show_size_t(buf, test_fw_config->buf_size);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 469) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 470) static DEVICE_ATTR_RW(config_buf_size);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 471)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 472) static ssize_t config_file_offset_store(struct device *dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 473) struct device_attribute *attr,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 474) const char *buf, size_t count)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 475) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 476) int rc;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 477)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 478) mutex_lock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 479) if (test_fw_config->reqs) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 480) pr_err("Must call release_all_firmware prior to changing config\n");
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 481) rc = -EINVAL;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 482) mutex_unlock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 483) goto out;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 484) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 485) mutex_unlock(&test_fw_mutex);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 486)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 487) rc = test_dev_config_update_size_t(buf, count,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 488) &test_fw_config->file_offset);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 489)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 490) out:
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 491) return rc;
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 492) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 493)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 494) static ssize_t config_file_offset_show(struct device *dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 495) struct device_attribute *attr,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 496) char *buf)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 497) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 498) return test_dev_config_show_size_t(buf, test_fw_config->file_offset);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 499) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 500) static DEVICE_ATTR_RW(config_file_offset);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 501)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 502) static ssize_t config_partial_store(struct device *dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 503) struct device_attribute *attr,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 504) const char *buf, size_t count)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 505) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 506) return test_dev_config_update_bool(buf,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 507) count,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 508) &test_fw_config->partial);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 509) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 510)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 511) static ssize_t config_partial_show(struct device *dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 512) struct device_attribute *attr,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 513) char *buf)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 514) {
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 515) return test_dev_config_show_bool(buf, test_fw_config->partial);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 516) }
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 517) static DEVICE_ATTR_RW(config_partial);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 518)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 519) static ssize_t config_sync_direct_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 520) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 521) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 522) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 523) int rc = test_dev_config_update_bool(buf, count,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 524) &test_fw_config->sync_direct);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 525)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 526) if (rc == count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 527) test_fw_config->req_firmware = test_fw_config->sync_direct ?
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 528) request_firmware_direct :
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 529) request_firmware;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 530) return rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 531) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 532)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 533) static ssize_t config_sync_direct_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 534) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 535) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 536) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 537) return test_dev_config_show_bool(buf, test_fw_config->sync_direct);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 538) }
b6b996b6cdeec (Joe Perches 2017-12-19 10:15:07 -0800 539) static DEVICE_ATTR_RW(config_sync_direct);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 540)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 541) static ssize_t config_send_uevent_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 542) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 543) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 544) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 545) return test_dev_config_update_bool(buf, count,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 546) &test_fw_config->send_uevent);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 547) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 548)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 549) static ssize_t config_send_uevent_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 550) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 551) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 552) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 553) return test_dev_config_show_bool(buf, test_fw_config->send_uevent);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 554) }
b6b996b6cdeec (Joe Perches 2017-12-19 10:15:07 -0800 555) static DEVICE_ATTR_RW(config_send_uevent);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 556)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 557) static ssize_t config_read_fw_idx_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 558) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 559) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 560) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 561) return test_dev_config_update_u8(buf, count,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 562) &test_fw_config->read_fw_idx);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 563) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 564)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 565) static ssize_t config_read_fw_idx_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 566) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 567) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 568) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 569) return test_dev_config_show_u8(buf, test_fw_config->read_fw_idx);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 570) }
b6b996b6cdeec (Joe Perches 2017-12-19 10:15:07 -0800 571) static DEVICE_ATTR_RW(config_read_fw_idx);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 572)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 573)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 574) static ssize_t trigger_request_store(struct device *dev,
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 575) struct device_attribute *attr,
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 576) const char *buf, size_t count)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 577) {
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 578) int rc;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 579) char *name;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 580)
be4a1326d12cc (Brian Norris 2015-12-09 14:50:26 -0800 581) name = kstrndup(buf, count, GFP_KERNEL);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 582) if (!name)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 583) return -ENOSPC;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 584)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 585) pr_info("loading '%s'\n", name);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 586)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 587) mutex_lock(&test_fw_mutex);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 588) release_firmware(test_firmware);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 589) test_firmware = NULL;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 590) rc = request_firmware(&test_firmware, name, dev);
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 591) if (rc) {
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 592) pr_info("load of '%s' failed: %d\n", name, rc);
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 593) goto out;
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 594) }
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 595) pr_info("loaded: %zu\n", test_firmware->size);
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 596) rc = count;
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 597)
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 598) out:
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 599) mutex_unlock(&test_fw_mutex);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 600)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 601) kfree(name);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 602)
47e0bbb7fa985 (Brian Norris 2015-12-09 14:50:25 -0800 603) return rc;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 604) }
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 605) static DEVICE_ATTR_WO(trigger_request);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 606)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 607) #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 608) extern struct list_head efi_embedded_fw_list;
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 609) extern bool efi_embedded_fw_checked;
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 610)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 611) static ssize_t trigger_request_platform_store(struct device *dev,
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 612) struct device_attribute *attr,
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 613) const char *buf, size_t count)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 614) {
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 615) static const u8 test_data[] = {
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 616) 0x55, 0xaa, 0x55, 0xaa, 0x01, 0x02, 0x03, 0x04,
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 617) 0x55, 0xaa, 0x55, 0xaa, 0x05, 0x06, 0x07, 0x08,
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 618) 0x55, 0xaa, 0x55, 0xaa, 0x10, 0x20, 0x30, 0x40,
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 619) 0x55, 0xaa, 0x55, 0xaa, 0x50, 0x60, 0x70, 0x80
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 620) };
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 621) struct efi_embedded_fw efi_embedded_fw;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 622) const struct firmware *firmware = NULL;
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 623) bool saved_efi_embedded_fw_checked;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 624) char *name;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 625) int rc;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 626)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 627) name = kstrndup(buf, count, GFP_KERNEL);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 628) if (!name)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 629) return -ENOSPC;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 630)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 631) pr_info("inserting test platform fw '%s'\n", name);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 632) efi_embedded_fw.name = name;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 633) efi_embedded_fw.data = (void *)test_data;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 634) efi_embedded_fw.length = sizeof(test_data);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 635) list_add(&efi_embedded_fw.list, &efi_embedded_fw_list);
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 636) saved_efi_embedded_fw_checked = efi_embedded_fw_checked;
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 637) efi_embedded_fw_checked = true;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 638)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 639) pr_info("loading '%s'\n", name);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 640) rc = firmware_request_platform(&firmware, name, dev);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 641) if (rc) {
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 642) pr_info("load of '%s' failed: %d\n", name, rc);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 643) goto out;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 644) }
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 645) if (firmware->size != sizeof(test_data) ||
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 646) memcmp(firmware->data, test_data, sizeof(test_data)) != 0) {
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 647) pr_info("firmware contents mismatch for '%s'\n", name);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 648) rc = -EINVAL;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 649) goto out;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 650) }
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 651) pr_info("loaded: %zu\n", firmware->size);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 652) rc = count;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 653)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 654) out:
baaabecfc80fa (Kees Cook 2020-09-09 15:53:54 -0700 655) efi_embedded_fw_checked = saved_efi_embedded_fw_checked;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 656) release_firmware(firmware);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 657) list_del(&efi_embedded_fw.list);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 658) kfree(name);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 659)
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 660) return rc;
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 661) }
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 662) static DEVICE_ATTR_WO(trigger_request_platform);
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 663) #endif
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 664)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 665) static DECLARE_COMPLETION(async_fw_done);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 666)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 667) static void trigger_async_request_cb(const struct firmware *fw, void *context)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 668) {
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 669) test_firmware = fw;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 670) complete(&async_fw_done);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 671) }
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 672)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 673) static ssize_t trigger_async_request_store(struct device *dev,
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 674) struct device_attribute *attr,
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 675) const char *buf, size_t count)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 676) {
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 677) int rc;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 678) char *name;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 679)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 680) name = kstrndup(buf, count, GFP_KERNEL);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 681) if (!name)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 682) return -ENOSPC;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 683)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 684) pr_info("loading '%s'\n", name);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 685)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 686) mutex_lock(&test_fw_mutex);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 687) release_firmware(test_firmware);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 688) test_firmware = NULL;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 689) rc = request_firmware_nowait(THIS_MODULE, 1, name, dev, GFP_KERNEL,
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 690) NULL, trigger_async_request_cb);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 691) if (rc) {
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 692) pr_info("async load of '%s' failed: %d\n", name, rc);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 693) kfree(name);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 694) goto out;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 695) }
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 696) /* Free 'name' ASAP, to test for race conditions */
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 697) kfree(name);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 698)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 699) wait_for_completion(&async_fw_done);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 700)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 701) if (test_firmware) {
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 702) pr_info("loaded: %zu\n", test_firmware->size);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 703) rc = count;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 704) } else {
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 705) pr_err("failed to async load firmware\n");
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 706) rc = -ENOMEM;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 707) }
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 708)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 709) out:
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 710) mutex_unlock(&test_fw_mutex);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 711)
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 712) return rc;
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 713) }
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 714) static DEVICE_ATTR_WO(trigger_async_request);
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 715)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 716) static ssize_t trigger_custom_fallback_store(struct device *dev,
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 717) struct device_attribute *attr,
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 718) const char *buf, size_t count)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 719) {
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 720) int rc;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 721) char *name;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 722)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 723) name = kstrndup(buf, count, GFP_KERNEL);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 724) if (!name)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 725) return -ENOSPC;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 726)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 727) pr_info("loading '%s' using custom fallback mechanism\n", name);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 728)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 729) mutex_lock(&test_fw_mutex);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 730) release_firmware(test_firmware);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 731) test_firmware = NULL;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 732) rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, name,
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 733) dev, GFP_KERNEL, NULL,
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 734) trigger_async_request_cb);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 735) if (rc) {
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 736) pr_info("async load of '%s' failed: %d\n", name, rc);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 737) kfree(name);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 738) goto out;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 739) }
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 740) /* Free 'name' ASAP, to test for race conditions */
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 741) kfree(name);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 742)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 743) wait_for_completion(&async_fw_done);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 744)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 745) if (test_firmware) {
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 746) pr_info("loaded: %zu\n", test_firmware->size);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 747) rc = count;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 748) } else {
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 749) pr_err("failed to async load firmware\n");
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 750) rc = -ENODEV;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 751) }
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 752)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 753) out:
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 754) mutex_unlock(&test_fw_mutex);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 755)
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 756) return rc;
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 757) }
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 758) static DEVICE_ATTR_WO(trigger_custom_fallback);
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 759)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 760) static int test_fw_run_batch_request(void *data)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 761) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 762) struct test_batched_req *req = data;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 763)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 764) if (!req) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 765) test_fw_config->test_result = -EINVAL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 766) return -EINVAL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 767) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 768)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 769) if (test_fw_config->into_buf) {
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 770) void *test_buf;
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 771)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 772) test_buf = kzalloc(TEST_FIRMWARE_BUF_SIZE, GFP_KERNEL);
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 773) if (!test_buf)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 774) return -ENOSPC;
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 775)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 776) if (test_fw_config->partial)
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 777) req->rc = request_partial_firmware_into_buf
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 778) (&req->fw,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 779) req->name,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 780) req->dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 781) test_buf,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 782) test_fw_config->buf_size,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 783) test_fw_config->file_offset);
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 784) else
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 785) req->rc = request_firmware_into_buf
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 786) (&req->fw,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 787) req->name,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 788) req->dev,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 789) test_buf,
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 790) test_fw_config->buf_size);
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 791) if (!req->fw)
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 792) kfree(test_buf);
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 793) } else {
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 794) req->rc = test_fw_config->req_firmware(&req->fw,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 795) req->name,
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 796) req->dev);
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 797) }
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 798)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 799) if (req->rc) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 800) pr_info("#%u: batched sync load failed: %d\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 801) req->idx, req->rc);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 802) if (!test_fw_config->test_result)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 803) test_fw_config->test_result = req->rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 804) } else if (req->fw) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 805) req->sent = true;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 806) pr_info("#%u: batched sync loaded %zu\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 807) req->idx, req->fw->size);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 808) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 809) complete(&req->completion);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 810)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 811) req->task = NULL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 812)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 813) return 0;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 814) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 815)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 816) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 817) * We use a kthread as otherwise the kernel serializes all our sync requests
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 818) * and we would not be able to mimic batched requests on a sync call. Batched
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 819) * requests on a sync call can for instance happen on a device driver when
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 820) * multiple cards are used and firmware loading happens outside of probe.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 821) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 822) static ssize_t trigger_batched_requests_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 823) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 824) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 825) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 826) struct test_batched_req *req;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 827) int rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 828) u8 i;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 829)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 830) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 831)
fad953ce0b22c (Kees Cook 2018-06-12 14:27:37 -0700 832) test_fw_config->reqs =
fad953ce0b22c (Kees Cook 2018-06-12 14:27:37 -0700 833) vzalloc(array3_size(sizeof(struct test_batched_req),
fad953ce0b22c (Kees Cook 2018-06-12 14:27:37 -0700 834) test_fw_config->num_requests, 2));
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 835) if (!test_fw_config->reqs) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 836) rc = -ENOMEM;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 837) goto out_unlock;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 838) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 839)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 840) pr_info("batched sync firmware loading '%s' %u times\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 841) test_fw_config->name, test_fw_config->num_requests);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 842)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 843) for (i = 0; i < test_fw_config->num_requests; i++) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 844) req = &test_fw_config->reqs[i];
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 845) req->fw = NULL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 846) req->idx = i;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 847) req->name = test_fw_config->name;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 848) req->dev = dev;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 849) init_completion(&req->completion);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 850) req->task = kthread_run(test_fw_run_batch_request, req,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 851) "%s-%u", KBUILD_MODNAME, req->idx);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 852) if (!req->task || IS_ERR(req->task)) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 853) pr_err("Setting up thread %u failed\n", req->idx);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 854) req->task = NULL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 855) rc = -ENOMEM;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 856) goto out_bail;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 857) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 858) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 859)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 860) rc = count;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 861)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 862) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 863) * We require an explicit release to enable more time and delay of
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 864) * calling release_firmware() to improve our chances of forcing a
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 865) * batched request. If we instead called release_firmware() right away
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 866) * then we might miss on an opportunity of having a successful firmware
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 867) * request pass on the opportunity to be come a batched request.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 868) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 869)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 870) out_bail:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 871) for (i = 0; i < test_fw_config->num_requests; i++) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 872) req = &test_fw_config->reqs[i];
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 873) if (req->task || req->sent)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 874) wait_for_completion(&req->completion);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 875) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 876)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 877) /* Override any worker error if we had a general setup error */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 878) if (rc < 0)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 879) test_fw_config->test_result = rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 880)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 881) out_unlock:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 882) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 883)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 884) return rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 885) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 886) static DEVICE_ATTR_WO(trigger_batched_requests);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 887)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 888) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 889) * We wait for each callback to return with the lock held, no need to lock here
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 890) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 891) static void trigger_batched_cb(const struct firmware *fw, void *context)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 892) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 893) struct test_batched_req *req = context;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 894)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 895) if (!req) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 896) test_fw_config->test_result = -EINVAL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 897) return;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 898) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 899)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 900) /* forces *some* batched requests to queue up */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 901) if (!req->idx)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 902) ssleep(2);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 903)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 904) req->fw = fw;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 905)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 906) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 907) * Unfortunately the firmware API gives us nothing other than a null FW
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 908) * if the firmware was not found on async requests. Best we can do is
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 909) * just assume -ENOENT. A better API would pass the actual return
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 910) * value to the callback.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 911) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 912) if (!fw && !test_fw_config->test_result)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 913) test_fw_config->test_result = -ENOENT;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 914)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 915) complete(&req->completion);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 916) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 917)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 918) static
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 919) ssize_t trigger_batched_requests_async_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 920) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 921) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 922) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 923) struct test_batched_req *req;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 924) bool send_uevent;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 925) int rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 926) u8 i;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 927)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 928) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 929)
fad953ce0b22c (Kees Cook 2018-06-12 14:27:37 -0700 930) test_fw_config->reqs =
fad953ce0b22c (Kees Cook 2018-06-12 14:27:37 -0700 931) vzalloc(array3_size(sizeof(struct test_batched_req),
fad953ce0b22c (Kees Cook 2018-06-12 14:27:37 -0700 932) test_fw_config->num_requests, 2));
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 933) if (!test_fw_config->reqs) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 934) rc = -ENOMEM;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 935) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 936) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 937)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 938) pr_info("batched loading '%s' custom fallback mechanism %u times\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 939) test_fw_config->name, test_fw_config->num_requests);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 940)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 941) send_uevent = test_fw_config->send_uevent ? FW_ACTION_HOTPLUG :
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 942) FW_ACTION_NOHOTPLUG;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 943)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 944) for (i = 0; i < test_fw_config->num_requests; i++) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 945) req = &test_fw_config->reqs[i];
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 946) req->name = test_fw_config->name;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 947) req->fw = NULL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 948) req->idx = i;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 949) init_completion(&req->completion);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 950) rc = request_firmware_nowait(THIS_MODULE, send_uevent,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 951) req->name,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 952) dev, GFP_KERNEL, req,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 953) trigger_batched_cb);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 954) if (rc) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 955) pr_info("#%u: batched async load failed setup: %d\n",
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 956) i, rc);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 957) req->rc = rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 958) goto out_bail;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 959) } else
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 960) req->sent = true;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 961) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 962)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 963) rc = count;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 964)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 965) out_bail:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 966)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 967) /*
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 968) * We require an explicit release to enable more time and delay of
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 969) * calling release_firmware() to improve our chances of forcing a
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 970) * batched request. If we instead called release_firmware() right away
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 971) * then we might miss on an opportunity of having a successful firmware
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 972) * request pass on the opportunity to be come a batched request.
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 973) */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 974)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 975) for (i = 0; i < test_fw_config->num_requests; i++) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 976) req = &test_fw_config->reqs[i];
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 977) if (req->sent)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 978) wait_for_completion(&req->completion);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 979) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 980)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 981) /* Override any worker error if we had a general setup error */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 982) if (rc < 0)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 983) test_fw_config->test_result = rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 984)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 985) out:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 986) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 987)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 988) return rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 989) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 990) static DEVICE_ATTR_WO(trigger_batched_requests_async);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 991)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 992) static ssize_t test_result_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 993) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 994) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 995) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 996) return test_dev_config_show_int(buf, test_fw_config->test_result);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 997) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 998) static DEVICE_ATTR_RO(test_result);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 999)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1000) static ssize_t release_all_firmware_store(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1001) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1002) const char *buf, size_t count)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1003) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1004) test_release_all_firmware();
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1005) return count;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1006) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1007) static DEVICE_ATTR_WO(release_all_firmware);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1008)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1009) static ssize_t read_firmware_show(struct device *dev,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1010) struct device_attribute *attr,
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1011) char *buf)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1012) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1013) struct test_batched_req *req;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1014) u8 idx;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1015) ssize_t rc = 0;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1016)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1017) mutex_lock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1018)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1019) idx = test_fw_config->read_fw_idx;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1020) if (idx >= test_fw_config->num_requests) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1021) rc = -ERANGE;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1022) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1023) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1024)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1025) if (!test_fw_config->reqs) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1026) rc = -EINVAL;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1027) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1028) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1029)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1030) req = &test_fw_config->reqs[idx];
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1031) if (!req->fw) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1032) pr_err("#%u: failed to async load firmware\n", idx);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1033) rc = -ENOENT;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1034) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1035) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1036)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1037) pr_info("#%u: loaded %zu\n", idx, req->fw->size);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1038)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1039) if (req->fw->size > PAGE_SIZE) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1040) pr_err("Testing interface must use PAGE_SIZE firmware for now\n");
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1041) rc = -EINVAL;
8bb0a88600f02 (Colin Ian King 2018-10-19 13:58:01 +0100 1042) goto out;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1043) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1044) memcpy(buf, req->fw->data, req->fw->size);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1045)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1046) rc = req->fw->size;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1047) out:
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1048) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1049)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1050) return rc;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1051) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1052) static DEVICE_ATTR_RO(read_firmware);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1053)
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1054) #define TEST_FW_DEV_ATTR(name) &dev_attr_##name.attr
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1055)
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1056) static struct attribute *test_dev_attrs[] = {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1057) TEST_FW_DEV_ATTR(reset),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1058)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1059) TEST_FW_DEV_ATTR(config),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1060) TEST_FW_DEV_ATTR(config_name),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1061) TEST_FW_DEV_ATTR(config_num_requests),
7feebfa487b92 (Scott Branden 2019-08-22 11:40:04 -0700 1062) TEST_FW_DEV_ATTR(config_into_buf),
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 1063) TEST_FW_DEV_ATTR(config_buf_size),
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 1064) TEST_FW_DEV_ATTR(config_file_offset),
5d90e05c0e83e (Scott Branden 2020-10-02 10:38:28 -0700 1065) TEST_FW_DEV_ATTR(config_partial),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1066) TEST_FW_DEV_ATTR(config_sync_direct),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1067) TEST_FW_DEV_ATTR(config_send_uevent),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1068) TEST_FW_DEV_ATTR(config_read_fw_idx),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1069)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1070) /* These don't use the config at all - they could be ported! */
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1071) TEST_FW_DEV_ATTR(trigger_request),
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1072) TEST_FW_DEV_ATTR(trigger_async_request),
061132d2b9c95 (Luis R. Rodriguez 2017-01-23 08:11:10 -0800 1073) TEST_FW_DEV_ATTR(trigger_custom_fallback),
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 1074) #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 1075) TEST_FW_DEV_ATTR(trigger_request_platform),
548193cba2a7d (Hans de Goede 2020-01-15 17:35:49 +0100 1076) #endif
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1077)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1078) /* These use the config and can use the test_result */
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1079) TEST_FW_DEV_ATTR(trigger_batched_requests),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1080) TEST_FW_DEV_ATTR(trigger_batched_requests_async),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1081)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1082) TEST_FW_DEV_ATTR(release_all_firmware),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1083) TEST_FW_DEV_ATTR(test_result),
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1084) TEST_FW_DEV_ATTR(read_firmware),
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1085) NULL,
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1086) };
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1087)
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1088) ATTRIBUTE_GROUPS(test_dev);
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1089)
67fd553ce0e55 (Luis R. Rodriguez 2017-01-23 08:11:05 -0800 1090) static struct miscdevice test_fw_misc_device = {
67fd553ce0e55 (Luis R. Rodriguez 2017-01-23 08:11:05 -0800 1091) .minor = MISC_DYNAMIC_MINOR,
67fd553ce0e55 (Luis R. Rodriguez 2017-01-23 08:11:05 -0800 1092) .name = "test_firmware",
67fd553ce0e55 (Luis R. Rodriguez 2017-01-23 08:11:05 -0800 1093) .fops = &test_fw_fops,
083a93b0c1f2e (Luis R. Rodriguez 2017-01-23 08:11:06 -0800 1094) .groups = test_dev_groups,
67fd553ce0e55 (Luis R. Rodriguez 2017-01-23 08:11:05 -0800 1095) };
67fd553ce0e55 (Luis R. Rodriguez 2017-01-23 08:11:05 -0800 1096)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1097) static int __init test_firmware_init(void)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1098) {
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1099) int rc;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1100)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1101) test_fw_config = kzalloc(sizeof(struct test_config), GFP_KERNEL);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1102) if (!test_fw_config)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1103) return -ENOMEM;
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1104)
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1105) rc = __test_firmware_config_init();
d4fddac5a51c3 (Wenwen Wang 2019-07-14 01:11:35 -0500 1106) if (rc) {
d4fddac5a51c3 (Wenwen Wang 2019-07-14 01:11:35 -0500 1107) kfree(test_fw_config);
d4fddac5a51c3 (Wenwen Wang 2019-07-14 01:11:35 -0500 1108) pr_err("could not init firmware test config: %d\n", rc);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1109) return rc;
d4fddac5a51c3 (Wenwen Wang 2019-07-14 01:11:35 -0500 1110) }
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1111)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1112) rc = misc_register(&test_fw_misc_device);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1113) if (rc) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1114) kfree(test_fw_config);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1115) pr_err("could not register misc device: %d\n", rc);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1116) return rc;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1117) }
eb910947c82f9 (Brian Norris 2015-12-09 14:50:27 -0800 1118)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1119) pr_warn("interface ready\n");
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1120)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1121) return 0;
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1122) }
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1123)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1124) module_init(test_firmware_init);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1125)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1126) static void __exit test_firmware_exit(void)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1127) {
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1128) mutex_lock(&test_fw_mutex);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1129) release_firmware(test_firmware);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1130) misc_deregister(&test_fw_misc_device);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1131) __test_firmware_config_free();
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1132) kfree(test_fw_config);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1133) mutex_unlock(&test_fw_mutex);
c92316bf8e948 (Luis R. Rodriguez 2017-07-20 13:13:42 -0700 1134)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1135) pr_warn("removed interface\n");
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1136) }
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1137)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1138) module_exit(test_firmware_exit);
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1139)
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1140) MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
0a8adf584759c (Kees Cook 2014-07-14 14:38:12 -0700 1141) MODULE_LICENSE("GPL");