Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'driver-core-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core updates from Greg KH:
"Here is the set of driver core changes for 5.19-rc1.

Lots of tiny driver core changes and cleanups happened this cycle, but
the two major things are:

- firmware_loader reorganization and additions including the ability
to have XZ compressed firmware images and the ability for userspace
to initiate the firmware load when it needs to, instead of being
always initiated by the kernel. FPGA devices specifically want this
ability to have their firmware changed over the lifetime of the
system boot, and this allows them to work without having to come up
with yet-another-custom-uapi interface for loading firmware for
them.

- physical location support added to sysfs so that devices that know
this information, can tell userspace where they are located in a
common way. Some ACPI devices already support this today, and more
bus types should support this in the future.

Smaller changes include:

- driver_override api cleanups and fixes

- error path cleanups and fixes

- get_abi script fixes

- deferred probe timeout changes.

It's that last change that I'm the most worried about. It has been
reported to cause boot problems for a number of systems, and I have a
tested patch series that resolves this issue. But I didn't get it
merged into my tree before 5.18-final came out, so it has not gotten
any linux-next testing.

I'll send the fixup patches (there are 2) as a follow-on series to this
pull request.

All have been tested in linux-next for weeks, with no reported issues
other than the above-mentioned boot time-outs"

* tag 'driver-core-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (55 commits)
driver core: fix deadlock in __device_attach
kernfs: Separate kernfs_pr_cont_buf and rename_lock.
topology: Remove unused cpu_cluster_mask()
driver core: Extend deferred probe timeout on driver registration
MAINTAINERS: add Russ Weight as a firmware loader maintainer
driver: base: fix UAF when driver_attach failed
test_firmware: fix end of loop test in upload_read_show()
driver core: location: Add "back" as a possible output for panel
driver core: location: Free struct acpi_pld_info *pld
driver core: Add "*" wildcard support to driver_async_probe cmdline param
driver core: location: Check for allocations failure
arch_topology: Trace the update thermal pressure
kernfs: Rename kernfs_put_open_node to kernfs_unlink_open_file.
export: fix string handling of namespace in EXPORT_SYMBOL_NS
rpmsg: use local 'dev' variable
rpmsg: Fix calling device_lock() on non-initialized device
firmware_loader: describe 'module' parameter of firmware_upload_register()
firmware_loader: Move definitions from sysfs_upload.h to sysfs.h
firmware_loader: Fix configs for sysfs split
selftests: firmware: Add firmware upload selftests
...

+2728 -847
+77
Documentation/ABI/testing/sysfs-class-firmware
··· 1 + What: /sys/class/firmware/.../data 2 + Date: July 2022 3 + KernelVersion: 5.19 4 + Contact: Russ Weight <russell.h.weight@intel.com> 5 + Description: The data sysfs file is used for firmware-fallback and for 6 + firmware uploads. Cat a firmware image to this sysfs file 7 + after you echo 1 to the loading sysfs file. When the firmware 8 + image write is complete, echo 0 to the loading sysfs file. This 9 + sequence will signal the completion of the firmware write and 10 + signal the lower-level driver that the firmware data is 11 + available. 12 + 13 + What: /sys/class/firmware/.../cancel 14 + Date: July 2022 15 + KernelVersion: 5.19 16 + Contact: Russ Weight <russell.h.weight@intel.com> 17 + Description: Write-only. For firmware uploads, write a "1" to this file to 18 + request that the transfer of firmware data to the lower-level 19 + device be canceled. This request will be rejected (EBUSY) if 20 + the update cannot be canceled (e.g. a FLASH write is in 21 + progress) or (ENODEV) if there is no firmware update in progress. 22 + 23 + What: /sys/class/firmware/.../error 24 + Date: July 2022 25 + KernelVersion: 5.19 26 + Contact: Russ Weight <russell.h.weight@intel.com> 27 + Description: Read-only. Returns a string describing a failed firmware 28 + upload. This string will be in the form of <STATUS>:<ERROR>, 29 + where <STATUS> will be one of the status strings described 30 + for the status sysfs file and <ERROR> will be one of the 31 + following: "hw-error", "timeout", "user-abort", "device-busy", 32 + "invalid-file-size", "read-write-error", "flash-wearout". The 33 + error sysfs file is only meaningful when the current firmware 34 + upload status is "idle". If this file is read while a firmware 35 + transfer is in progress, then the read will fail with EBUSY. 36 + 37 + What: /sys/class/firmware/.../loading 38 + Date: July 2022 39 + KernelVersion: 5.19 40 + Contact: Russ Weight <russell.h.weight@intel.com> 41 + Description: The loading sysfs file is used for both firmware-fallback and 42 + for firmware uploads. Echo 1 onto the loading file to indicate 43 + you are writing a firmware file to the data sysfs node. Echo 44 + -1 onto this file to abort the data write or echo 0 onto this 45 + file to indicate that the write is complete. For firmware 46 + uploads, the zero value also triggers the transfer of the 47 + firmware data to the lower-level device driver. 48 + 49 + What: /sys/class/firmware/.../remaining_size 50 + Date: July 2022 51 + KernelVersion: 5.19 52 + Contact: Russ Weight <russell.h.weight@intel.com> 53 + Description: Read-only. For firmware upload, this file contains the size 54 + of the firmware data that remains to be transferred to the 55 + lower-level device driver. The size value is initialized to 56 + the full size of the firmware image that was previously 57 + written to the data sysfs file. This value is periodically 58 + updated during the "transferring" phase of the firmware 59 + upload. 60 + Format: "%u". 61 + 62 + What: /sys/class/firmware/.../status 63 + Date: July 2022 64 + KernelVersion: 5.19 65 + Contact: Russ Weight <russell.h.weight@intel.com> 66 + Description: Read-only. Returns a string describing the current status of 67 + a firmware upload. The string will be one of the following: 68 + idle, "receiving", "preparing", "transferring", "programming". 69 + 70 + What: /sys/class/firmware/.../timeout 71 + Date: July 2022 72 + KernelVersion: 5.19 73 + Contact: Russ Weight <russell.h.weight@intel.com> 74 + Description: This file supports the timeout mechanism for firmware 75 + fallback. This file has no affect on firmware uploads. For 76 + more information on timeouts please see the documentation 77 + for firmware fallback.
+42
Documentation/ABI/testing/sysfs-devices-physical_location
··· 1 + What: /sys/devices/.../physical_location 2 + Date: March 2022 3 + Contact: Won Chung <wonchung@google.com> 4 + Description: 5 + This directory contains information on physical location of 6 + the device connection point with respect to the system's 7 + housing. 8 + 9 + What: /sys/devices/.../physical_location/panel 10 + Date: March 2022 11 + Contact: Won Chung <wonchung@google.com> 12 + Description: 13 + Describes which panel surface of the system’s housing the 14 + device connection point resides on. 15 + 16 + What: /sys/devices/.../physical_location/vertical_position 17 + Date: March 2022 18 + Contact: Won Chung <wonchung@google.com> 19 + Description: 20 + Describes vertical position of the device connection point on 21 + the panel surface. 22 + 23 + What: /sys/devices/.../physical_location/horizontal_position 24 + Date: March 2022 25 + Contact: Won Chung <wonchung@google.com> 26 + Description: 27 + Describes horizontal position of the device connection point on 28 + the panel surface. 29 + 30 + What: /sys/devices/.../physical_location/dock 31 + Date: March 2022 32 + Contact: Won Chung <wonchung@google.com> 33 + Description: 34 + "Yes" if the device connection point resides in a docking 35 + station or a port replicator. "No" otherwise. 36 + 37 + What: /sys/devices/.../physical_location/lid 38 + Date: March 2022 39 + Contact: Won Chung <wonchung@google.com> 40 + Description: 41 + "Yes" if the device connection point resides on the lid of 42 + laptop system. "No" otherwise.
+8 -3
Documentation/admin-guide/kernel-parameters.txt
··· 979 979 [KNL] Debugging option to set a timeout in seconds for 980 980 deferred probe to give up waiting on dependencies to 981 981 probe. Only specific dependencies (subsystems or 982 - drivers) that have opted in will be ignored. A timeout of 0 983 - will timeout at the end of initcalls. This option will also 982 + drivers) that have opted in will be ignored. A timeout 983 + of 0 will timeout at the end of initcalls. If the time 984 + out hasn't expired, it'll be restarted by each 985 + successful driver registration. This option will also 984 986 dump out devices still on the deferred probe list after 985 987 retrying. 986 988 ··· 1103 1101 driver later using sysfs. 1104 1102 1105 1103 driver_async_probe= [KNL] 1106 - List of driver names to be probed asynchronously. 1104 + List of driver names to be probed asynchronously. * 1105 + matches with all driver names. If * is specified, the 1106 + rest of the listed driver names are those that will NOT 1107 + match the *. 1107 1108 Format: <driver_name1>,<driver_name2>... 1108 1109 1109 1110 drm.edid_firmware=[<connector>:]<file>[,[<connector>:]<file>]
+126
Documentation/driver-api/firmware/fw_upload.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + =================== 4 + Firmware Upload API 5 + =================== 6 + 7 + A device driver that registers with the firmware loader will expose 8 + persistent sysfs nodes to enable users to initiate firmware updates for 9 + that device. It is the responsibility of the device driver and/or the 10 + device itself to perform any validation on the data received. Firmware 11 + upload uses the same *loading* and *data* sysfs files described in the 12 + documentation for firmware fallback. It also adds additional sysfs files 13 + to provide status on the transfer of the firmware image to the device. 14 + 15 + Register for firmware upload 16 + ============================ 17 + 18 + A device driver registers for firmware upload by calling 19 + firmware_upload_register(). Among the parameter list is a name to 20 + identify the device under /sys/class/firmware. A user may initiate a 21 + firmware upload by echoing a 1 to the *loading* sysfs file for the target 22 + device. Next, the user writes the firmware image to the *data* sysfs 23 + file. After writing the firmware data, the user echos 0 to the *loading* 24 + sysfs file to signal completion. Echoing 0 to *loading* also triggers the 25 + transfer of the firmware to the lower-lever device driver in the context 26 + of a kernel worker thread. 27 + 28 + To use the firmware upload API, write a driver that implements a set of 29 + ops. The probe function calls firmware_upload_register() and the remove 30 + function calls firmware_upload_unregister() such as:: 31 + 32 + static const struct fw_upload_ops m10bmc_ops = { 33 + .prepare = m10bmc_sec_prepare, 34 + .write = m10bmc_sec_write, 35 + .poll_complete = m10bmc_sec_poll_complete, 36 + .cancel = m10bmc_sec_cancel, 37 + .cleanup = m10bmc_sec_cleanup, 38 + }; 39 + 40 + static int m10bmc_sec_probe(struct platform_device *pdev) 41 + { 42 + const char *fw_name, *truncate; 43 + struct m10bmc_sec *sec; 44 + struct fw_upload *fwl; 45 + unsigned int len; 46 + 47 + sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL); 48 + if (!sec) 49 + return -ENOMEM; 50 + 51 + sec->dev = &pdev->dev; 52 + sec->m10bmc = dev_get_drvdata(pdev->dev.parent); 53 + dev_set_drvdata(&pdev->dev, sec); 54 + 55 + fw_name = dev_name(sec->dev); 56 + truncate = strstr(fw_name, ".auto"); 57 + len = (truncate) ? truncate - fw_name : strlen(fw_name); 58 + sec->fw_name = kmemdup_nul(fw_name, len, GFP_KERNEL); 59 + 60 + fwl = firmware_upload_register(sec->dev, sec->fw_name, &m10bmc_ops, sec); 61 + if (IS_ERR(fwl)) { 62 + dev_err(sec->dev, "Firmware Upload driver failed to start\n"); 63 + kfree(sec->fw_name); 64 + return PTR_ERR(fwl); 65 + } 66 + 67 + sec->fwl = fwl; 68 + return 0; 69 + } 70 + 71 + static int m10bmc_sec_remove(struct platform_device *pdev) 72 + { 73 + struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev); 74 + 75 + firmware_upload_unregister(sec->fwl); 76 + kfree(sec->fw_name); 77 + return 0; 78 + } 79 + 80 + firmware_upload_register 81 + ------------------------ 82 + .. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c 83 + :identifiers: firmware_upload_register 84 + 85 + firmware_upload_unregister 86 + -------------------------- 87 + .. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.c 88 + :identifiers: firmware_upload_unregister 89 + 90 + Firmware Upload Ops 91 + ------------------- 92 + .. kernel-doc:: include/linux/firmware.h 93 + :identifiers: fw_upload_ops 94 + 95 + Firmware Upload Progress Codes 96 + ------------------------------ 97 + The following progress codes are used internally by the firmware loader. 98 + Corresponding strings are reported through the status sysfs node that 99 + is described below and are documented in the ABI documentation. 100 + 101 + .. kernel-doc:: drivers/base/firmware_loader/sysfs_upload.h 102 + :identifiers: fw_upload_prog 103 + 104 + Firmware Upload Error Codes 105 + --------------------------- 106 + The following error codes may be returned by the driver ops in case of 107 + failure: 108 + 109 + .. kernel-doc:: include/linux/firmware.h 110 + :identifiers: fw_upload_err 111 + 112 + Sysfs Attributes 113 + ================ 114 + 115 + In addition to the *loading* and *data* sysfs files, there are additional 116 + sysfs files to monitor the status of the data transfer to the target 117 + device and to determine the final pass/fail status of the transfer. 118 + Depending on the device and the size of the firmware image, a firmware 119 + update could take milliseconds or minutes. 120 + 121 + The additional sysfs files are: 122 + 123 + * status - provides an indication of the progress of a firmware update 124 + * error - provides error information for a failed firmware update 125 + * remaining_size - tracks the data transfer portion of an update 126 + * cancel - echo 1 to this file to cancel the update
+1
Documentation/driver-api/firmware/index.rst
··· 8 8 core 9 9 efi/index 10 10 request_firmware 11 + fw_upload 11 12 other_interfaces 12 13 13 14 .. only:: subproject and html
+1
MAINTAINERS
··· 7727 7727 7728 7728 FIRMWARE LOADER (request_firmware) 7729 7729 M: Luis Chamberlain <mcgrof@kernel.org> 7730 + M: Russ Weight <russell.h.weight@intel.com> 7730 7731 L: linux-kernel@vger.kernel.org 7731 7732 S: Maintained 7732 7733 F: Documentation/firmware_class/
+4 -24
drivers/amba/bus.c
··· 98 98 const char *buf, size_t count) 99 99 { 100 100 struct amba_device *dev = to_amba_device(_dev); 101 - char *driver_override, *old, *cp; 101 + int ret; 102 102 103 - /* We need to keep extra room for a newline */ 104 - if (count >= (PAGE_SIZE - 1)) 105 - return -EINVAL; 106 - 107 - driver_override = kstrndup(buf, count, GFP_KERNEL); 108 - if (!driver_override) 109 - return -ENOMEM; 110 - 111 - cp = strchr(driver_override, '\n'); 112 - if (cp) 113 - *cp = '\0'; 114 - 115 - device_lock(_dev); 116 - old = dev->driver_override; 117 - if (strlen(driver_override)) { 118 - dev->driver_override = driver_override; 119 - } else { 120 - kfree(driver_override); 121 - dev->driver_override = NULL; 122 - } 123 - device_unlock(_dev); 124 - 125 - kfree(old); 103 + ret = driver_set_override(_dev, &dev->driver_override, buf, count); 104 + if (ret) 105 + return ret; 126 106 127 107 return count; 128 108 }
+1
drivers/base/Makefile
··· 25 25 obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o 26 26 obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o 27 27 obj-$(CONFIG_GENERIC_ARCH_NUMA) += arch_numa.o 28 + obj-$(CONFIG_ACPI) += physical_location.o 28 29 29 30 obj-y += test/ 30 31
+5
drivers/base/arch_topology.c
··· 19 19 #include <linux/rcupdate.h> 20 20 #include <linux/sched.h> 21 21 22 + #define CREATE_TRACE_POINTS 23 + #include <trace/events/thermal_pressure.h> 24 + 22 25 static DEFINE_PER_CPU(struct scale_freq_data __rcu *, sft_data); 23 26 static struct cpumask scale_freq_counters_mask; 24 27 static bool scale_freq_invariant; ··· 197 194 capacity = mult_frac(max_capacity, capped_freq, max_freq); 198 195 199 196 th_pressure = max_capacity - capacity; 197 + 198 + trace_thermal_pressure_update(cpu, th_pressure); 200 199 201 200 for_each_cpu(cpu, cpus) 202 201 WRITE_ONCE(per_cpu(thermal_pressure, cpu), th_pressure);
+1
drivers/base/base.h
··· 159 159 extern int devres_release_all(struct device *dev); 160 160 extern void device_block_probing(void); 161 161 extern void device_unblock_probing(void); 162 + extern void deferred_probe_extend_timeout(void); 162 163 163 164 /* /sys/devices directory */ 164 165 extern struct kset *devices_kset;
+3 -1
drivers/base/bus.c
··· 617 617 if (drv->bus->p->drivers_autoprobe) { 618 618 error = driver_attach(drv); 619 619 if (error) 620 - goto out_unregister; 620 + goto out_del_list; 621 621 } 622 622 module_add_driver(drv->owner, drv); 623 623 ··· 644 644 645 645 return 0; 646 646 647 + out_del_list: 648 + klist_del(&priv->knode_bus); 647 649 out_unregister: 648 650 kobject_put(&priv->kobj); 649 651 /* drv->p is freed in driver_release() */
+15
drivers/base/core.c
··· 32 32 #include <linux/dma-map-ops.h> /* for dma_default_coherent */ 33 33 34 34 #include "base.h" 35 + #include "physical_location.h" 35 36 #include "power/power.h" 36 37 37 38 #ifdef CONFIG_SYSFS_DEPRECATED ··· 2650 2649 goto err_remove_dev_waiting_for_supplier; 2651 2650 } 2652 2651 2652 + if (dev_add_physical_location(dev)) { 2653 + error = device_add_group(dev, 2654 + &dev_attr_physical_location_group); 2655 + if (error) 2656 + goto err_remove_dev_removable; 2657 + } 2658 + 2653 2659 return 0; 2654 2660 2661 + err_remove_dev_removable: 2662 + device_remove_file(dev, &dev_attr_removable); 2655 2663 err_remove_dev_waiting_for_supplier: 2656 2664 device_remove_file(dev, &dev_attr_waiting_for_supplier); 2657 2665 err_remove_dev_online: ··· 2681 2671 { 2682 2672 struct class *class = dev->class; 2683 2673 const struct device_type *type = dev->type; 2674 + 2675 + if (dev->physical_location) { 2676 + device_remove_group(dev, &dev_attr_physical_location_group); 2677 + kfree(dev->physical_location); 2678 + } 2684 2679 2685 2680 device_remove_file(dev, &dev_attr_removable); 2686 2681 device_remove_file(dev, &dev_attr_waiting_for_supplier);
+37 -7
drivers/base/dd.c
··· 60 60 /* Save the async probe drivers' name from kernel cmdline */ 61 61 #define ASYNC_DRV_NAMES_MAX_LEN 256 62 62 static char async_probe_drv_names[ASYNC_DRV_NAMES_MAX_LEN]; 63 + static bool async_probe_default; 63 64 64 65 /* 65 66 * In some cases, like suspend to RAM or hibernation, It might be reasonable ··· 256 255 } 257 256 DEFINE_SHOW_ATTRIBUTE(deferred_devs); 258 257 258 + #ifdef CONFIG_MODULES 259 + int driver_deferred_probe_timeout = 10; 260 + #else 259 261 int driver_deferred_probe_timeout; 262 + #endif 263 + 260 264 EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout); 261 265 static DECLARE_WAIT_QUEUE_HEAD(probe_timeout_waitqueue); 262 266 ··· 280 274 * @dev: device to check 281 275 * 282 276 * Return: 283 - * -ENODEV if initcalls have completed and modules are disabled. 284 - * -ETIMEDOUT if the deferred probe timeout was set and has expired 285 - * and modules are enabled. 286 - * -EPROBE_DEFER in other cases. 277 + * * -ENODEV if initcalls have completed and modules are disabled. 278 + * * -ETIMEDOUT if the deferred probe timeout was set and has expired 279 + * and modules are enabled. 280 + * * -EPROBE_DEFER in other cases. 287 281 * 288 282 * Drivers or subsystems can opt-in to calling this function instead of directly 289 283 * returning -EPROBE_DEFER. ··· 321 315 wake_up_all(&probe_timeout_waitqueue); 322 316 } 323 317 static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func); 318 + 319 + void deferred_probe_extend_timeout(void) 320 + { 321 + /* 322 + * If the work hasn't been queued yet or if the work expired, don't 323 + * start a new one. 324 + */ 325 + if (cancel_delayed_work(&deferred_probe_timeout_work)) { 326 + schedule_delayed_work(&deferred_probe_timeout_work, 327 + driver_deferred_probe_timeout * HZ); 328 + pr_debug("Extended deferred probe timeout by %d secs\n", 329 + driver_deferred_probe_timeout); 330 + } 331 + } 324 332 325 333 /** 326 334 * deferred_probe_initcall() - Enable probing of deferred devices ··· 819 799 820 800 static inline bool cmdline_requested_async_probing(const char *drv_name) 821 801 { 822 - return parse_option_str(async_probe_drv_names, drv_name); 802 + bool async_drv; 803 + 804 + async_drv = parse_option_str(async_probe_drv_names, drv_name); 805 + 806 + return (async_probe_default != async_drv); 823 807 } 824 808 825 809 /* The option format is "driver_async_probe=drv_name1,drv_name2,..." */ ··· 833 809 pr_warn("Too long list of driver names for 'driver_async_probe'!\n"); 834 810 835 811 strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN); 812 + async_probe_default = parse_option_str(async_probe_drv_names, "*"); 813 + 836 814 return 1; 837 815 } 838 816 __setup("driver_async_probe=", save_async_options); ··· 969 943 static int __device_attach(struct device *dev, bool allow_async) 970 944 { 971 945 int ret = 0; 946 + bool async = false; 972 947 973 948 device_lock(dev); 974 949 if (dev->p->dead) { ··· 1008 981 */ 1009 982 dev_dbg(dev, "scheduling asynchronous probe\n"); 1010 983 get_device(dev); 1011 - async_schedule_dev(__device_attach_async_helper, dev); 984 + async = true; 1012 985 } else { 1013 986 pm_request_idle(dev); 1014 987 } ··· 1018 991 } 1019 992 out_unlock: 1020 993 device_unlock(dev); 994 + if (async) 995 + async_schedule_dev(__device_attach_async_helper, dev); 1021 996 return ret; 1022 997 } 1023 998 ··· 1113 1084 1114 1085 __device_driver_lock(dev, dev->parent); 1115 1086 drv = dev->p->async_driver; 1087 + dev->p->async_driver = NULL; 1116 1088 ret = driver_probe_device(drv, dev); 1117 1089 __device_driver_unlock(dev, dev->parent); 1118 1090 ··· 1160 1130 */ 1161 1131 dev_dbg(dev, "probing driver %s asynchronously\n", drv->name); 1162 1132 device_lock(dev); 1163 - if (!dev->driver) { 1133 + if (!dev->driver && !dev->p->async_driver) { 1164 1134 get_device(dev); 1165 1135 dev->p->async_driver = drv; 1166 1136 async_schedule_dev(__driver_attach_async_helper, dev);
+70
drivers/base/driver.c
··· 31 31 } 32 32 33 33 /** 34 + * driver_set_override() - Helper to set or clear driver override. 35 + * @dev: Device to change 36 + * @override: Address of string to change (e.g. &device->driver_override); 37 + * The contents will be freed and hold newly allocated override. 38 + * @s: NUL-terminated string, new driver name to force a match, pass empty 39 + * string to clear it ("" or "\n", where the latter is only for sysfs 40 + * interface). 41 + * @len: length of @s 42 + * 43 + * Helper to set or clear driver override in a device, intended for the cases 44 + * when the driver_override field is allocated by driver/bus code. 45 + * 46 + * Returns: 0 on success or a negative error code on failure. 47 + */ 48 + int driver_set_override(struct device *dev, const char **override, 49 + const char *s, size_t len) 50 + { 51 + const char *new, *old; 52 + char *cp; 53 + 54 + if (!override || !s) 55 + return -EINVAL; 56 + 57 + /* 58 + * The stored value will be used in sysfs show callback (sysfs_emit()), 59 + * which has a length limit of PAGE_SIZE and adds a trailing newline. 60 + * Thus we can store one character less to avoid truncation during sysfs 61 + * show. 62 + */ 63 + if (len >= (PAGE_SIZE - 1)) 64 + return -EINVAL; 65 + 66 + if (!len) { 67 + /* Empty string passed - clear override */ 68 + device_lock(dev); 69 + old = *override; 70 + *override = NULL; 71 + device_unlock(dev); 72 + kfree(old); 73 + 74 + return 0; 75 + } 76 + 77 + cp = strnchr(s, len, '\n'); 78 + if (cp) 79 + len = cp - s; 80 + 81 + new = kstrndup(s, len, GFP_KERNEL); 82 + if (!new) 83 + return -ENOMEM; 84 + 85 + device_lock(dev); 86 + old = *override; 87 + if (cp != s) { 88 + *override = new; 89 + } else { 90 + /* "\n" passed - clear override */ 91 + kfree(new); 92 + *override = NULL; 93 + } 94 + device_unlock(dev); 95 + 96 + kfree(old); 97 + 98 + return 0; 99 + } 100 + EXPORT_SYMBOL_GPL(driver_set_override); 101 + 102 + /** 34 103 * driver_for_each_device - Iterator for devices bound to a driver. 35 104 * @drv: Driver we're iterating. 36 105 * @start: Device to begin with ··· 246 177 return ret; 247 178 } 248 179 kobject_uevent(&drv->p->kobj, KOBJ_ADD); 180 + deferred_probe_extend_timeout(); 249 181 250 182 return ret; 251 183 }
+36 -6
drivers/base/firmware_loader/Kconfig
··· 29 29 config FW_LOADER_PAGED_BUF 30 30 bool 31 31 32 + config FW_LOADER_SYSFS 33 + bool 34 + 32 35 config EXTRA_FIRMWARE 33 36 string "Build named firmware blobs into the kernel binary" 34 37 help ··· 75 72 76 73 config FW_LOADER_USER_HELPER 77 74 bool "Enable the firmware sysfs fallback mechanism" 75 + select FW_LOADER_SYSFS 78 76 select FW_LOADER_PAGED_BUF 79 77 help 80 78 This option enables a sysfs loading facility to enable firmware ··· 163 159 164 160 config FW_LOADER_COMPRESS 165 161 bool "Enable compressed firmware support" 166 - select FW_LOADER_PAGED_BUF 167 - select XZ_DEC 168 162 help 169 163 This option enables the support for loading compressed firmware 170 164 files. The caller of firmware API receives the decompressed file 171 165 content. The compressed file is loaded as a fallback, only after 172 166 loading the raw file failed at first. 173 167 174 - Currently only XZ-compressed files are supported, and they have to 175 - be compressed with either none or crc32 integrity check type (pass 176 - "-C crc32" option to xz command). 177 - 178 168 Compressed firmware support does not apply to firmware images 179 169 that are built into the kernel image (CONFIG_EXTRA_FIRMWARE). 170 + 171 + if FW_LOADER_COMPRESS 172 + config FW_LOADER_COMPRESS_XZ 173 + bool "Enable XZ-compressed firmware support" 174 + select FW_LOADER_PAGED_BUF 175 + select XZ_DEC 176 + help 177 + This option adds the support for XZ-compressed files. 178 + The files have to be compressed with either none or crc32 179 + integrity check type (pass "-C crc32" option to xz command). 180 + 181 + config FW_LOADER_COMPRESS_ZSTD 182 + bool "Enable ZSTD-compressed firmware support" 183 + select ZSTD_DECOMPRESS 184 + help 185 + This option adds the support for ZSTD-compressed files. 186 + 187 + endif # FW_LOADER_COMPRESS 180 188 181 189 config FW_CACHE 182 190 bool "Enable firmware caching during suspend" ··· 201 185 option. 202 186 203 187 If unsure, say Y. 188 + 189 + config FW_UPLOAD 190 + bool "Enable users to initiate firmware updates using sysfs" 191 + select FW_LOADER_SYSFS 192 + select FW_LOADER_PAGED_BUF 193 + help 194 + Enabling this option will allow device drivers to expose a persistent 195 + sysfs interface that allows firmware updates to be initiated from 196 + userspace. For example, FPGA based PCIe cards load firmware and FPGA 197 + images from local FLASH when the card boots. The images in FLASH may 198 + be updated with new images provided by the user. Enable this device 199 + to support cards that rely on user-initiated updates for firmware files. 200 + 201 + If unsure, say N. 204 202 205 203 endif # FW_LOADER 206 204 endmenu
+2
drivers/base/firmware_loader/Makefile
··· 6 6 firmware_class-objs := main.o 7 7 firmware_class-$(CONFIG_FW_LOADER_USER_HELPER) += fallback.o 8 8 firmware_class-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += fallback_platform.o 9 + firmware_class-$(CONFIG_FW_LOADER_SYSFS) += sysfs.o 10 + firmware_class-$(CONFIG_FW_UPLOAD) += sysfs_upload.o 9 11 10 12 obj-y += builtin/
-430
drivers/base/firmware_loader/fallback.c
··· 3 3 #include <linux/types.h> 4 4 #include <linux/kconfig.h> 5 5 #include <linux/list.h> 6 - #include <linux/slab.h> 7 6 #include <linux/security.h> 8 - #include <linux/highmem.h> 9 7 #include <linux/umh.h> 10 8 #include <linux/sysctl.h> 11 - #include <linux/vmalloc.h> 12 9 #include <linux/module.h> 13 10 14 11 #include "fallback.h" ··· 14 17 /* 15 18 * firmware fallback mechanism 16 19 */ 17 - 18 - MODULE_IMPORT_NS(FIRMWARE_LOADER_PRIVATE); 19 - 20 - extern struct firmware_fallback_config fw_fallback_config; 21 - 22 - /* These getters are vetted to use int properly */ 23 - static inline int __firmware_loading_timeout(void) 24 - { 25 - return fw_fallback_config.loading_timeout; 26 - } 27 - 28 - /* These setters are vetted to use int properly */ 29 - static void __fw_fallback_set_timeout(int timeout) 30 - { 31 - fw_fallback_config.loading_timeout = timeout; 32 - } 33 20 34 21 /* 35 22 * use small loading timeout for caching devices' firmware because all these ··· 39 58 __firmware_loading_timeout() * HZ : MAX_JIFFY_OFFSET; 40 59 } 41 60 42 - static inline bool fw_sysfs_done(struct fw_priv *fw_priv) 43 - { 44 - return __fw_state_check(fw_priv, FW_STATUS_DONE); 45 - } 46 - 47 - static inline bool fw_sysfs_loading(struct fw_priv *fw_priv) 48 - { 49 - return __fw_state_check(fw_priv, FW_STATUS_LOADING); 50 - } 51 - 52 61 static inline int fw_sysfs_wait_timeout(struct fw_priv *fw_priv, long timeout) 53 62 { 54 63 return __fw_state_wait_common(fw_priv, timeout); 55 - } 56 - 57 - struct fw_sysfs { 58 - bool nowait; 59 - struct device dev; 60 - struct fw_priv *fw_priv; 61 - struct firmware *fw; 62 - }; 63 - 64 - static struct fw_sysfs *to_fw_sysfs(struct device *dev) 65 - { 66 - return container_of(dev, struct fw_sysfs, dev); 67 - } 68 - 69 - static void __fw_load_abort(struct fw_priv *fw_priv) 70 - { 71 - /* 72 - * There is a small window in which user can write to 'loading' 73 - * between loading done/aborted and disappearance of 'loading' 74 - */ 75 - if (fw_state_is_aborted(fw_priv) || fw_sysfs_done(fw_priv)) 76 - return; 77 - 78 - fw_state_aborted(fw_priv); 79 - } 80 - 81 - static void fw_load_abort(struct fw_sysfs *fw_sysfs) 82 - { 83 - struct fw_priv *fw_priv = fw_sysfs->fw_priv; 84 - 85 - __fw_load_abort(fw_priv); 86 64 } 87 65 88 66 static LIST_HEAD(pending_fw_head); ··· 58 118 __fw_load_abort(fw_priv); 59 119 } 60 120 mutex_unlock(&fw_lock); 61 - } 62 - 63 - static ssize_t timeout_show(struct class *class, struct class_attribute *attr, 64 - char *buf) 65 - { 66 - return sysfs_emit(buf, "%d\n", __firmware_loading_timeout()); 67 - } 68 - 69 - /** 70 - * timeout_store() - set number of seconds to wait for firmware 71 - * @class: device class pointer 72 - * @attr: device attribute pointer 73 - * @buf: buffer to scan for timeout value 74 - * @count: number of bytes in @buf 75 - * 76 - * Sets the number of seconds to wait for the firmware. Once 77 - * this expires an error will be returned to the driver and no 78 - * firmware will be provided. 79 - * 80 - * Note: zero means 'wait forever'. 81 - **/ 82 - static ssize_t timeout_store(struct class *class, struct class_attribute *attr, 83 - const char *buf, size_t count) 84 - { 85 - int tmp_loading_timeout = simple_strtol(buf, NULL, 10); 86 - 87 - if (tmp_loading_timeout < 0) 88 - tmp_loading_timeout = 0; 89 - 90 - __fw_fallback_set_timeout(tmp_loading_timeout); 91 - 92 - return count; 93 - } 94 - static CLASS_ATTR_RW(timeout); 95 - 96 - static struct attribute *firmware_class_attrs[] = { 97 - &class_attr_timeout.attr, 98 - NULL, 99 - }; 100 - ATTRIBUTE_GROUPS(firmware_class); 101 - 102 - static void fw_dev_release(struct device *dev) 103 - { 104 - struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 105 - 106 - kfree(fw_sysfs); 107 - } 108 - 109 - static int do_firmware_uevent(struct fw_sysfs *fw_sysfs, struct kobj_uevent_env *env) 110 - { 111 - if (add_uevent_var(env, "FIRMWARE=%s", fw_sysfs->fw_priv->fw_name)) 112 - return -ENOMEM; 113 - if (add_uevent_var(env, "TIMEOUT=%i", __firmware_loading_timeout())) 114 - return -ENOMEM; 115 - if (add_uevent_var(env, "ASYNC=%d", fw_sysfs->nowait)) 116 - return -ENOMEM; 117 - 118 - return 0; 119 - } 120 - 121 - static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) 122 - { 123 - struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 124 - int err = 0; 125 - 126 - mutex_lock(&fw_lock); 127 - if (fw_sysfs->fw_priv) 128 - err = do_firmware_uevent(fw_sysfs, env); 129 - mutex_unlock(&fw_lock); 130 - return err; 131 - } 132 - 133 - static struct class firmware_class = { 134 - .name = "firmware", 135 - .class_groups = firmware_class_groups, 136 - .dev_uevent = firmware_uevent, 137 - .dev_release = fw_dev_release, 138 - }; 139 - 140 - int register_sysfs_loader(void) 141 - { 142 - int ret = class_register(&firmware_class); 143 - 144 - if (ret != 0) 145 - return ret; 146 - return register_firmware_config_sysctl(); 147 - } 148 - 149 - void unregister_sysfs_loader(void) 150 - { 151 - unregister_firmware_config_sysctl(); 152 - class_unregister(&firmware_class); 153 - } 154 - 155 - static ssize_t firmware_loading_show(struct device *dev, 156 - struct device_attribute *attr, char *buf) 157 - { 158 - struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 159 - int loading = 0; 160 - 161 - mutex_lock(&fw_lock); 162 - if (fw_sysfs->fw_priv) 163 - loading = fw_sysfs_loading(fw_sysfs->fw_priv); 164 - mutex_unlock(&fw_lock); 165 - 166 - return sysfs_emit(buf, "%d\n", loading); 167 - } 168 - 169 - /** 170 - * firmware_loading_store() - set value in the 'loading' control file 171 - * @dev: device pointer 172 - * @attr: device attribute pointer 173 - * @buf: buffer to scan for loading control value 174 - * @count: number of bytes in @buf 175 - * 176 - * The relevant values are: 177 - * 178 - * 1: Start a load, discarding any previous partial load. 179 - * 0: Conclude the load and hand the data to the driver code. 180 - * -1: Conclude the load with an error and discard any written data. 181 - **/ 182 - static ssize_t firmware_loading_store(struct device *dev, 183 - struct device_attribute *attr, 184 - const char *buf, size_t count) 185 - { 186 - struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 187 - struct fw_priv *fw_priv; 188 - ssize_t written = count; 189 - int loading = simple_strtol(buf, NULL, 10); 190 - 191 - mutex_lock(&fw_lock); 192 - fw_priv = fw_sysfs->fw_priv; 193 - if (fw_state_is_aborted(fw_priv)) 194 - goto out; 195 - 196 - switch (loading) { 197 - case 1: 198 - /* discarding any previous partial load */ 199 - if (!fw_sysfs_done(fw_priv)) { 200 - fw_free_paged_buf(fw_priv); 201 - fw_state_start(fw_priv); 202 - } 203 - break; 204 - case 0: 205 - if (fw_sysfs_loading(fw_priv)) { 206 - int rc; 207 - 208 - /* 209 - * Several loading requests may be pending on 210 - * one same firmware buf, so let all requests 211 - * see the mapped 'buf->data' once the loading 212 - * is completed. 213 - * */ 214 - rc = fw_map_paged_buf(fw_priv); 215 - if (rc) 216 - dev_err(dev, "%s: map pages failed\n", 217 - __func__); 218 - else 219 - rc = security_kernel_post_load_data(fw_priv->data, 220 - fw_priv->size, 221 - LOADING_FIRMWARE, "blob"); 222 - 223 - /* 224 - * Same logic as fw_load_abort, only the DONE bit 225 - * is ignored and we set ABORT only on failure. 226 - */ 227 - if (rc) { 228 - fw_state_aborted(fw_priv); 229 - written = rc; 230 - } else { 231 - fw_state_done(fw_priv); 232 - } 233 - break; 234 - } 235 - fallthrough; 236 - default: 237 - dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading); 238 - fallthrough; 239 - case -1: 240 - fw_load_abort(fw_sysfs); 241 - break; 242 - } 243 - out: 244 - mutex_unlock(&fw_lock); 245 - return written; 246 - } 247 - 248 - static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); 249 - 250 - static void firmware_rw_data(struct fw_priv *fw_priv, char *buffer, 251 - loff_t offset, size_t count, bool read) 252 - { 253 - if (read) 254 - memcpy(buffer, fw_priv->data + offset, count); 255 - else 256 - memcpy(fw_priv->data + offset, buffer, count); 257 - } 258 - 259 - static void firmware_rw(struct fw_priv *fw_priv, char *buffer, 260 - loff_t offset, size_t count, bool read) 261 - { 262 - while (count) { 263 - void *page_data; 264 - int page_nr = offset >> PAGE_SHIFT; 265 - int page_ofs = offset & (PAGE_SIZE-1); 266 - int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); 267 - 268 - page_data = kmap(fw_priv->pages[page_nr]); 269 - 270 - if (read) 271 - memcpy(buffer, page_data + page_ofs, page_cnt); 272 - else 273 - memcpy(page_data + page_ofs, buffer, page_cnt); 274 - 275 - kunmap(fw_priv->pages[page_nr]); 276 - buffer += page_cnt; 277 - offset += page_cnt; 278 - count -= page_cnt; 279 - } 280 - } 281 - 282 - static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, 283 - struct bin_attribute *bin_attr, 284 - char *buffer, loff_t offset, size_t count) 285 - { 286 - struct device *dev = kobj_to_dev(kobj); 287 - struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 288 - struct fw_priv *fw_priv; 289 - ssize_t ret_count; 290 - 291 - mutex_lock(&fw_lock); 292 - fw_priv = fw_sysfs->fw_priv; 293 - if (!fw_priv || fw_sysfs_done(fw_priv)) { 294 - ret_count = -ENODEV; 295 - goto out; 296 - } 297 - if (offset > fw_priv->size) { 298 - ret_count = 0; 299 - goto out; 300 - } 301 - if (count > fw_priv->size - offset) 302 - count = fw_priv->size - offset; 303 - 304 - ret_count = count; 305 - 306 - if (fw_priv->data) 307 - firmware_rw_data(fw_priv, buffer, offset, count, true); 308 - else 309 - firmware_rw(fw_priv, buffer, offset, count, true); 310 - 311 - out: 312 - mutex_unlock(&fw_lock); 313 - return ret_count; 314 - } 315 - 316 - static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) 317 - { 318 - int err; 319 - 320 - err = fw_grow_paged_buf(fw_sysfs->fw_priv, 321 - PAGE_ALIGN(min_size) >> PAGE_SHIFT); 322 - if (err) 323 - fw_load_abort(fw_sysfs); 324 - return err; 325 - } 326 - 327 - /** 328 - * firmware_data_write() - write method for firmware 329 - * @filp: open sysfs file 330 - * @kobj: kobject for the device 331 - * @bin_attr: bin_attr structure 332 - * @buffer: buffer being written 333 - * @offset: buffer offset for write in total data store area 334 - * @count: buffer size 335 - * 336 - * Data written to the 'data' attribute will be later handed to 337 - * the driver as a firmware image. 338 - **/ 339 - static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, 340 - struct bin_attribute *bin_attr, 341 - char *buffer, loff_t offset, size_t count) 342 - { 343 - struct device *dev = kobj_to_dev(kobj); 344 - struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 345 - struct fw_priv *fw_priv; 346 - ssize_t retval; 347 - 348 - if (!capable(CAP_SYS_RAWIO)) 349 - return -EPERM; 350 - 351 - mutex_lock(&fw_lock); 352 - fw_priv = fw_sysfs->fw_priv; 353 - if (!fw_priv || fw_sysfs_done(fw_priv)) { 354 - retval = -ENODEV; 355 - goto out; 356 - } 357 - 358 - if (fw_priv->data) { 359 - if (offset + count > fw_priv->allocated_size) { 360 - retval = -ENOMEM; 361 - goto out; 362 - } 363 - firmware_rw_data(fw_priv, buffer, offset, count, false); 364 - retval = count; 365 - } else { 366 - retval = fw_realloc_pages(fw_sysfs, offset + count); 367 - if (retval) 368 - goto out; 369 - 370 - retval = count; 371 - firmware_rw(fw_priv, buffer, offset, count, false); 372 - } 373 - 374 - fw_priv->size = max_t(size_t, offset + count, fw_priv->size); 375 - out: 376 - mutex_unlock(&fw_lock); 377 - return retval; 378 - } 379 - 380 - static struct bin_attribute firmware_attr_data = { 381 - .attr = { .name = "data", .mode = 0644 }, 382 - .size = 0, 383 - .read = firmware_data_read, 384 - .write = firmware_data_write, 385 - }; 386 - 387 - static struct attribute *fw_dev_attrs[] = { 388 - &dev_attr_loading.attr, 389 - NULL 390 - }; 391 - 392 - static struct bin_attribute *fw_dev_bin_attrs[] = { 393 - &firmware_attr_data, 394 - NULL 395 - }; 396 - 397 - static const struct attribute_group fw_dev_attr_group = { 398 - .attrs = fw_dev_attrs, 399 - .bin_attrs = fw_dev_bin_attrs, 400 - }; 401 - 402 - static const struct attribute_group *fw_dev_attr_groups[] = { 403 - &fw_dev_attr_group, 404 - NULL 405 - }; 406 - 407 - static struct fw_sysfs * 408 - fw_create_instance(struct firmware *firmware, const char *fw_name, 409 - struct device *device, u32 opt_flags) 410 - { 411 - struct fw_sysfs *fw_sysfs; 412 - struct device *f_dev; 413 - 414 - fw_sysfs = kzalloc(sizeof(*fw_sysfs), GFP_KERNEL); 415 - if (!fw_sysfs) { 416 - fw_sysfs = ERR_PTR(-ENOMEM); 417 - goto exit; 418 - } 419 - 420 - fw_sysfs->nowait = !!(opt_flags & FW_OPT_NOWAIT); 421 - fw_sysfs->fw = firmware; 422 - f_dev = &fw_sysfs->dev; 423 - 424 - device_initialize(f_dev); 425 - dev_set_name(f_dev, "%s", fw_name); 426 - f_dev->parent = device; 427 - f_dev->class = &firmware_class; 428 - f_dev->groups = fw_dev_attr_groups; 429 - exit: 430 - return fw_sysfs; 431 121 } 432 122 433 123 /**
+1 -45
drivers/base/firmware_loader/fallback.h
··· 6 6 #include <linux/device.h> 7 7 8 8 #include "firmware.h" 9 - 10 - /** 11 - * struct firmware_fallback_config - firmware fallback configuration settings 12 - * 13 - * Helps describe and fine tune the fallback mechanism. 14 - * 15 - * @force_sysfs_fallback: force the sysfs fallback mechanism to be used 16 - * as if one had enabled CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y. 17 - * Useful to help debug a CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y 18 - * functionality on a kernel where that config entry has been disabled. 19 - * @ignore_sysfs_fallback: force to disable the sysfs fallback mechanism. 20 - * This emulates the behaviour as if we had set the kernel 21 - * config CONFIG_FW_LOADER_USER_HELPER=n. 22 - * @old_timeout: for internal use 23 - * @loading_timeout: the timeout to wait for the fallback mechanism before 24 - * giving up, in seconds. 25 - */ 26 - struct firmware_fallback_config { 27 - unsigned int force_sysfs_fallback; 28 - unsigned int ignore_sysfs_fallback; 29 - int old_timeout; 30 - int loading_timeout; 31 - }; 9 + #include "sysfs.h" 32 10 33 11 #ifdef CONFIG_FW_LOADER_USER_HELPER 34 12 int firmware_fallback_sysfs(struct firmware *fw, const char *name, ··· 17 39 18 40 void fw_fallback_set_cache_timeout(void); 19 41 void fw_fallback_set_default_timeout(void); 20 - 21 - int register_sysfs_loader(void); 22 - void unregister_sysfs_loader(void); 23 - #ifdef CONFIG_SYSCTL 24 - extern int register_firmware_config_sysctl(void); 25 - extern void unregister_firmware_config_sysctl(void); 26 - #else 27 - static inline int register_firmware_config_sysctl(void) 28 - { 29 - return 0; 30 - } 31 - static inline void unregister_firmware_config_sysctl(void) { } 32 - #endif /* CONFIG_SYSCTL */ 33 42 34 43 #else /* CONFIG_FW_LOADER_USER_HELPER */ 35 44 static inline int firmware_fallback_sysfs(struct firmware *fw, const char *name, ··· 31 66 static inline void kill_pending_fw_fallback_reqs(bool only_kill_custom) { } 32 67 static inline void fw_fallback_set_cache_timeout(void) { } 33 68 static inline void fw_fallback_set_default_timeout(void) { } 34 - 35 - static inline int register_sysfs_loader(void) 36 - { 37 - return 0; 38 - } 39 - 40 - static inline void unregister_sysfs_loader(void) 41 - { 42 - } 43 69 #endif /* CONFIG_FW_LOADER_USER_HELPER */ 44 70 45 71 #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
+16
drivers/base/firmware_loader/firmware.h
··· 87 87 }; 88 88 89 89 extern struct mutex fw_lock; 90 + extern struct firmware_cache fw_cache; 90 91 91 92 static inline bool __fw_state_check(struct fw_priv *fw_priv, 92 93 enum fw_status status) ··· 150 149 __fw_state_set(fw_priv, FW_STATUS_DONE); 151 150 } 152 151 152 + static inline bool fw_state_is_done(struct fw_priv *fw_priv) 153 + { 154 + return __fw_state_check(fw_priv, FW_STATUS_DONE); 155 + } 156 + 157 + static inline bool fw_state_is_loading(struct fw_priv *fw_priv) 158 + { 159 + return __fw_state_check(fw_priv, FW_STATUS_LOADING); 160 + } 161 + 162 + int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, 163 + struct fw_priv **fw_priv, void *dbuf, size_t size, 164 + size_t offset, u32 opt_flags); 153 165 int assign_fw(struct firmware *fw, struct device *device); 166 + void free_fw_priv(struct fw_priv *fw_priv); 167 + void fw_state_init(struct fw_priv *fw_priv); 154 168 155 169 #ifdef CONFIG_FW_LOADER 156 170 bool firmware_is_builtin(const struct firmware *fw);
+81 -13
drivers/base/firmware_loader/main.c
··· 35 35 #include <linux/syscore_ops.h> 36 36 #include <linux/reboot.h> 37 37 #include <linux/security.h> 38 + #include <linux/zstd.h> 38 39 #include <linux/xz.h> 39 40 40 41 #include <generated/utsrelease.h> ··· 92 91 * guarding for corner cases a global lock should be OK */ 93 92 DEFINE_MUTEX(fw_lock); 94 93 95 - static struct firmware_cache fw_cache; 94 + struct firmware_cache fw_cache; 96 95 97 - static void fw_state_init(struct fw_priv *fw_priv) 96 + void fw_state_init(struct fw_priv *fw_priv) 98 97 { 99 98 struct fw_state *fw_st = &fw_priv->fw_st; 100 99 ··· 164 163 } 165 164 166 165 /* Returns 1 for batching firmware requests with the same name */ 167 - static int alloc_lookup_fw_priv(const char *fw_name, 168 - struct firmware_cache *fwc, 169 - struct fw_priv **fw_priv, 170 - void *dbuf, 171 - size_t size, 172 - size_t offset, 173 - u32 opt_flags) 166 + int alloc_lookup_fw_priv(const char *fw_name, struct firmware_cache *fwc, 167 + struct fw_priv **fw_priv, void *dbuf, size_t size, 168 + size_t offset, u32 opt_flags) 174 169 { 175 170 struct fw_priv *tmp; 176 171 ··· 221 224 kfree(fw_priv); 222 225 } 223 226 224 - static void free_fw_priv(struct fw_priv *fw_priv) 227 + void free_fw_priv(struct fw_priv *fw_priv) 225 228 { 226 229 struct firmware_cache *fwc = fw_priv->fwc; 227 230 spin_lock(&fwc->lock); ··· 250 253 fw_priv->pages = NULL; 251 254 fw_priv->page_array_size = 0; 252 255 fw_priv->nr_pages = 0; 256 + fw_priv->data = NULL; 257 + fw_priv->size = 0; 253 258 } 254 259 255 260 int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) ··· 304 305 #endif 305 306 306 307 /* 308 + * ZSTD-compressed firmware support 309 + */ 310 + #ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD 311 + static int fw_decompress_zstd(struct device *dev, struct fw_priv *fw_priv, 312 + size_t in_size, const void *in_buffer) 313 + { 314 + size_t len, out_size, workspace_size; 315 + void *workspace, *out_buf; 316 + zstd_dctx *ctx; 317 + int err; 318 + 319 + if (fw_priv->allocated_size) { 320 + out_size = fw_priv->allocated_size; 321 + out_buf = fw_priv->data; 322 + } else { 323 + zstd_frame_header params; 324 + 325 + if (zstd_get_frame_header(&params, in_buffer, in_size) || 326 + params.frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN) { 327 + dev_dbg(dev, "%s: invalid zstd header\n", __func__); 328 + return -EINVAL; 329 + } 330 + out_size = params.frameContentSize; 331 + out_buf = vzalloc(out_size); 332 + if (!out_buf) 333 + return -ENOMEM; 334 + } 335 + 336 + workspace_size = zstd_dctx_workspace_bound(); 337 + workspace = kvzalloc(workspace_size, GFP_KERNEL); 338 + if (!workspace) { 339 + err = -ENOMEM; 340 + goto error; 341 + } 342 + 343 + ctx = zstd_init_dctx(workspace, workspace_size); 344 + if (!ctx) { 345 + dev_dbg(dev, "%s: failed to initialize context\n", __func__); 346 + err = -EINVAL; 347 + goto error; 348 + } 349 + 350 + len = zstd_decompress_dctx(ctx, out_buf, out_size, in_buffer, in_size); 351 + if (zstd_is_error(len)) { 352 + dev_dbg(dev, "%s: failed to decompress: %d\n", __func__, 353 + zstd_get_error_code(len)); 354 + err = -EINVAL; 355 + goto error; 356 + } 357 + 358 + if (!fw_priv->allocated_size) 359 + fw_priv->data = out_buf; 360 + fw_priv->size = len; 361 + err = 0; 362 + 363 + error: 364 + kvfree(workspace); 365 + if (err && !fw_priv->allocated_size) 366 + vfree(out_buf); 367 + return err; 368 + } 369 + #endif /* CONFIG_FW_LOADER_COMPRESS_ZSTD */ 370 + 371 + /* 307 372 * XZ-compressed firmware support 308 373 */ 309 - #ifdef CONFIG_FW_LOADER_COMPRESS 374 + #ifdef CONFIG_FW_LOADER_COMPRESS_XZ 310 375 /* show an error and return the standard error code */ 311 376 static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret) 312 377 { ··· 464 401 else 465 402 return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer); 466 403 } 467 - #endif /* CONFIG_FW_LOADER_COMPRESS */ 404 + #endif /* CONFIG_FW_LOADER_COMPRESS_XZ */ 468 405 469 406 /* direct firmware loading support */ 470 407 static char fw_path_para[256]; ··· 834 771 if (!(opt_flags & FW_OPT_PARTIAL)) 835 772 nondirect = true; 836 773 837 - #ifdef CONFIG_FW_LOADER_COMPRESS 774 + #ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD 775 + if (ret == -ENOENT && nondirect) 776 + ret = fw_get_filesystem_firmware(device, fw->priv, ".zst", 777 + fw_decompress_zstd); 778 + #endif 779 + #ifdef CONFIG_FW_LOADER_COMPRESS_XZ 838 780 if (ret == -ENOENT && nondirect) 839 781 ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", 840 782 fw_decompress_xz);
+422
drivers/base/firmware_loader/sysfs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/highmem.h> 4 + #include <linux/module.h> 5 + #include <linux/security.h> 6 + #include <linux/slab.h> 7 + #include <linux/types.h> 8 + 9 + #include "sysfs.h" 10 + 11 + /* 12 + * sysfs support for firmware loader 13 + */ 14 + 15 + void __fw_load_abort(struct fw_priv *fw_priv) 16 + { 17 + /* 18 + * There is a small window in which user can write to 'loading' 19 + * between loading done/aborted and disappearance of 'loading' 20 + */ 21 + if (fw_state_is_aborted(fw_priv) || fw_state_is_done(fw_priv)) 22 + return; 23 + 24 + fw_state_aborted(fw_priv); 25 + } 26 + 27 + #ifdef CONFIG_FW_LOADER_USER_HELPER 28 + static ssize_t timeout_show(struct class *class, struct class_attribute *attr, 29 + char *buf) 30 + { 31 + return sysfs_emit(buf, "%d\n", __firmware_loading_timeout()); 32 + } 33 + 34 + /** 35 + * timeout_store() - set number of seconds to wait for firmware 36 + * @class: device class pointer 37 + * @attr: device attribute pointer 38 + * @buf: buffer to scan for timeout value 39 + * @count: number of bytes in @buf 40 + * 41 + * Sets the number of seconds to wait for the firmware. Once 42 + * this expires an error will be returned to the driver and no 43 + * firmware will be provided. 44 + * 45 + * Note: zero means 'wait forever'. 46 + **/ 47 + static ssize_t timeout_store(struct class *class, struct class_attribute *attr, 48 + const char *buf, size_t count) 49 + { 50 + int tmp_loading_timeout = simple_strtol(buf, NULL, 10); 51 + 52 + if (tmp_loading_timeout < 0) 53 + tmp_loading_timeout = 0; 54 + 55 + __fw_fallback_set_timeout(tmp_loading_timeout); 56 + 57 + return count; 58 + } 59 + static CLASS_ATTR_RW(timeout); 60 + 61 + static struct attribute *firmware_class_attrs[] = { 62 + &class_attr_timeout.attr, 63 + NULL, 64 + }; 65 + ATTRIBUTE_GROUPS(firmware_class); 66 + 67 + static int do_firmware_uevent(struct fw_sysfs *fw_sysfs, struct kobj_uevent_env *env) 68 + { 69 + if (add_uevent_var(env, "FIRMWARE=%s", fw_sysfs->fw_priv->fw_name)) 70 + return -ENOMEM; 71 + if (add_uevent_var(env, "TIMEOUT=%i", __firmware_loading_timeout())) 72 + return -ENOMEM; 73 + if (add_uevent_var(env, "ASYNC=%d", fw_sysfs->nowait)) 74 + return -ENOMEM; 75 + 76 + return 0; 77 + } 78 + 79 + static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) 80 + { 81 + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 82 + int err = 0; 83 + 84 + mutex_lock(&fw_lock); 85 + if (fw_sysfs->fw_priv) 86 + err = do_firmware_uevent(fw_sysfs, env); 87 + mutex_unlock(&fw_lock); 88 + return err; 89 + } 90 + #endif /* CONFIG_FW_LOADER_USER_HELPER */ 91 + 92 + static void fw_dev_release(struct device *dev) 93 + { 94 + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 95 + 96 + if (fw_sysfs->fw_upload_priv) { 97 + free_fw_priv(fw_sysfs->fw_priv); 98 + kfree(fw_sysfs->fw_upload_priv); 99 + } 100 + kfree(fw_sysfs); 101 + } 102 + 103 + static struct class firmware_class = { 104 + .name = "firmware", 105 + #ifdef CONFIG_FW_LOADER_USER_HELPER 106 + .class_groups = firmware_class_groups, 107 + .dev_uevent = firmware_uevent, 108 + #endif 109 + .dev_release = fw_dev_release, 110 + }; 111 + 112 + int register_sysfs_loader(void) 113 + { 114 + int ret = class_register(&firmware_class); 115 + 116 + if (ret != 0) 117 + return ret; 118 + return register_firmware_config_sysctl(); 119 + } 120 + 121 + void unregister_sysfs_loader(void) 122 + { 123 + unregister_firmware_config_sysctl(); 124 + class_unregister(&firmware_class); 125 + } 126 + 127 + static ssize_t firmware_loading_show(struct device *dev, 128 + struct device_attribute *attr, char *buf) 129 + { 130 + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 131 + int loading = 0; 132 + 133 + mutex_lock(&fw_lock); 134 + if (fw_sysfs->fw_priv) 135 + loading = fw_state_is_loading(fw_sysfs->fw_priv); 136 + mutex_unlock(&fw_lock); 137 + 138 + return sysfs_emit(buf, "%d\n", loading); 139 + } 140 + 141 + /** 142 + * firmware_loading_store() - set value in the 'loading' control file 143 + * @dev: device pointer 144 + * @attr: device attribute pointer 145 + * @buf: buffer to scan for loading control value 146 + * @count: number of bytes in @buf 147 + * 148 + * The relevant values are: 149 + * 150 + * 1: Start a load, discarding any previous partial load. 151 + * 0: Conclude the load and hand the data to the driver code. 152 + * -1: Conclude the load with an error and discard any written data. 153 + **/ 154 + static ssize_t firmware_loading_store(struct device *dev, 155 + struct device_attribute *attr, 156 + const char *buf, size_t count) 157 + { 158 + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 159 + struct fw_priv *fw_priv; 160 + ssize_t written = count; 161 + int loading = simple_strtol(buf, NULL, 10); 162 + 163 + mutex_lock(&fw_lock); 164 + fw_priv = fw_sysfs->fw_priv; 165 + if (fw_state_is_aborted(fw_priv) || fw_state_is_done(fw_priv)) 166 + goto out; 167 + 168 + switch (loading) { 169 + case 1: 170 + /* discarding any previous partial load */ 171 + fw_free_paged_buf(fw_priv); 172 + fw_state_start(fw_priv); 173 + break; 174 + case 0: 175 + if (fw_state_is_loading(fw_priv)) { 176 + int rc; 177 + 178 + /* 179 + * Several loading requests may be pending on 180 + * one same firmware buf, so let all requests 181 + * see the mapped 'buf->data' once the loading 182 + * is completed. 183 + */ 184 + rc = fw_map_paged_buf(fw_priv); 185 + if (rc) 186 + dev_err(dev, "%s: map pages failed\n", 187 + __func__); 188 + else 189 + rc = security_kernel_post_load_data(fw_priv->data, 190 + fw_priv->size, 191 + LOADING_FIRMWARE, 192 + "blob"); 193 + 194 + /* 195 + * Same logic as fw_load_abort, only the DONE bit 196 + * is ignored and we set ABORT only on failure. 197 + */ 198 + if (rc) { 199 + fw_state_aborted(fw_priv); 200 + written = rc; 201 + } else { 202 + fw_state_done(fw_priv); 203 + 204 + /* 205 + * If this is a user-initiated firmware upload 206 + * then start the upload in a worker thread now. 207 + */ 208 + rc = fw_upload_start(fw_sysfs); 209 + if (rc) 210 + written = rc; 211 + } 212 + break; 213 + } 214 + fallthrough; 215 + default: 216 + dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading); 217 + fallthrough; 218 + case -1: 219 + fw_load_abort(fw_sysfs); 220 + if (fw_sysfs->fw_upload_priv) 221 + fw_state_init(fw_sysfs->fw_priv); 222 + 223 + break; 224 + } 225 + out: 226 + mutex_unlock(&fw_lock); 227 + return written; 228 + } 229 + 230 + DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); 231 + 232 + static void firmware_rw_data(struct fw_priv *fw_priv, char *buffer, 233 + loff_t offset, size_t count, bool read) 234 + { 235 + if (read) 236 + memcpy(buffer, fw_priv->data + offset, count); 237 + else 238 + memcpy(fw_priv->data + offset, buffer, count); 239 + } 240 + 241 + static void firmware_rw(struct fw_priv *fw_priv, char *buffer, 242 + loff_t offset, size_t count, bool read) 243 + { 244 + while (count) { 245 + void *page_data; 246 + int page_nr = offset >> PAGE_SHIFT; 247 + int page_ofs = offset & (PAGE_SIZE - 1); 248 + int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); 249 + 250 + page_data = kmap(fw_priv->pages[page_nr]); 251 + 252 + if (read) 253 + memcpy(buffer, page_data + page_ofs, page_cnt); 254 + else 255 + memcpy(page_data + page_ofs, buffer, page_cnt); 256 + 257 + kunmap(fw_priv->pages[page_nr]); 258 + buffer += page_cnt; 259 + offset += page_cnt; 260 + count -= page_cnt; 261 + } 262 + } 263 + 264 + static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, 265 + struct bin_attribute *bin_attr, 266 + char *buffer, loff_t offset, size_t count) 267 + { 268 + struct device *dev = kobj_to_dev(kobj); 269 + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 270 + struct fw_priv *fw_priv; 271 + ssize_t ret_count; 272 + 273 + mutex_lock(&fw_lock); 274 + fw_priv = fw_sysfs->fw_priv; 275 + if (!fw_priv || fw_state_is_done(fw_priv)) { 276 + ret_count = -ENODEV; 277 + goto out; 278 + } 279 + if (offset > fw_priv->size) { 280 + ret_count = 0; 281 + goto out; 282 + } 283 + if (count > fw_priv->size - offset) 284 + count = fw_priv->size - offset; 285 + 286 + ret_count = count; 287 + 288 + if (fw_priv->data) 289 + firmware_rw_data(fw_priv, buffer, offset, count, true); 290 + else 291 + firmware_rw(fw_priv, buffer, offset, count, true); 292 + 293 + out: 294 + mutex_unlock(&fw_lock); 295 + return ret_count; 296 + } 297 + 298 + static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size) 299 + { 300 + int err; 301 + 302 + err = fw_grow_paged_buf(fw_sysfs->fw_priv, 303 + PAGE_ALIGN(min_size) >> PAGE_SHIFT); 304 + if (err) 305 + fw_load_abort(fw_sysfs); 306 + return err; 307 + } 308 + 309 + /** 310 + * firmware_data_write() - write method for firmware 311 + * @filp: open sysfs file 312 + * @kobj: kobject for the device 313 + * @bin_attr: bin_attr structure 314 + * @buffer: buffer being written 315 + * @offset: buffer offset for write in total data store area 316 + * @count: buffer size 317 + * 318 + * Data written to the 'data' attribute will be later handed to 319 + * the driver as a firmware image. 320 + **/ 321 + static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, 322 + struct bin_attribute *bin_attr, 323 + char *buffer, loff_t offset, size_t count) 324 + { 325 + struct device *dev = kobj_to_dev(kobj); 326 + struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 327 + struct fw_priv *fw_priv; 328 + ssize_t retval; 329 + 330 + if (!capable(CAP_SYS_RAWIO)) 331 + return -EPERM; 332 + 333 + mutex_lock(&fw_lock); 334 + fw_priv = fw_sysfs->fw_priv; 335 + if (!fw_priv || fw_state_is_done(fw_priv)) { 336 + retval = -ENODEV; 337 + goto out; 338 + } 339 + 340 + if (fw_priv->data) { 341 + if (offset + count > fw_priv->allocated_size) { 342 + retval = -ENOMEM; 343 + goto out; 344 + } 345 + firmware_rw_data(fw_priv, buffer, offset, count, false); 346 + retval = count; 347 + } else { 348 + retval = fw_realloc_pages(fw_sysfs, offset + count); 349 + if (retval) 350 + goto out; 351 + 352 + retval = count; 353 + firmware_rw(fw_priv, buffer, offset, count, false); 354 + } 355 + 356 + fw_priv->size = max_t(size_t, offset + count, fw_priv->size); 357 + out: 358 + mutex_unlock(&fw_lock); 359 + return retval; 360 + } 361 + 362 + static struct bin_attribute firmware_attr_data = { 363 + .attr = { .name = "data", .mode = 0644 }, 364 + .size = 0, 365 + .read = firmware_data_read, 366 + .write = firmware_data_write, 367 + }; 368 + 369 + static struct attribute *fw_dev_attrs[] = { 370 + &dev_attr_loading.attr, 371 + #ifdef CONFIG_FW_UPLOAD 372 + &dev_attr_cancel.attr, 373 + &dev_attr_status.attr, 374 + &dev_attr_error.attr, 375 + &dev_attr_remaining_size.attr, 376 + #endif 377 + NULL 378 + }; 379 + 380 + static struct bin_attribute *fw_dev_bin_attrs[] = { 381 + &firmware_attr_data, 382 + NULL 383 + }; 384 + 385 + static const struct attribute_group fw_dev_attr_group = { 386 + .attrs = fw_dev_attrs, 387 + .bin_attrs = fw_dev_bin_attrs, 388 + #ifdef CONFIG_FW_UPLOAD 389 + .is_visible = fw_upload_is_visible, 390 + #endif 391 + }; 392 + 393 + static const struct attribute_group *fw_dev_attr_groups[] = { 394 + &fw_dev_attr_group, 395 + NULL 396 + }; 397 + 398 + struct fw_sysfs * 399 + fw_create_instance(struct firmware *firmware, const char *fw_name, 400 + struct device *device, u32 opt_flags) 401 + { 402 + struct fw_sysfs *fw_sysfs; 403 + struct device *f_dev; 404 + 405 + fw_sysfs = kzalloc(sizeof(*fw_sysfs), GFP_KERNEL); 406 + if (!fw_sysfs) { 407 + fw_sysfs = ERR_PTR(-ENOMEM); 408 + goto exit; 409 + } 410 + 411 + fw_sysfs->nowait = !!(opt_flags & FW_OPT_NOWAIT); 412 + fw_sysfs->fw = firmware; 413 + f_dev = &fw_sysfs->dev; 414 + 415 + device_initialize(f_dev); 416 + dev_set_name(f_dev, "%s", fw_name); 417 + f_dev->parent = device; 418 + f_dev->class = &firmware_class; 419 + f_dev->groups = fw_dev_attr_groups; 420 + exit: 421 + return fw_sysfs; 422 + }
+117
drivers/base/firmware_loader/sysfs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __FIRMWARE_SYSFS_H 3 + #define __FIRMWARE_SYSFS_H 4 + 5 + #include <linux/device.h> 6 + 7 + #include "firmware.h" 8 + 9 + MODULE_IMPORT_NS(FIRMWARE_LOADER_PRIVATE); 10 + 11 + extern struct firmware_fallback_config fw_fallback_config; 12 + extern struct device_attribute dev_attr_loading; 13 + 14 + #ifdef CONFIG_FW_LOADER_USER_HELPER 15 + /** 16 + * struct firmware_fallback_config - firmware fallback configuration settings 17 + * 18 + * Helps describe and fine tune the fallback mechanism. 19 + * 20 + * @force_sysfs_fallback: force the sysfs fallback mechanism to be used 21 + * as if one had enabled CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y. 22 + * Useful to help debug a CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y 23 + * functionality on a kernel where that config entry has been disabled. 24 + * @ignore_sysfs_fallback: force to disable the sysfs fallback mechanism. 25 + * This emulates the behaviour as if we had set the kernel 26 + * config CONFIG_FW_LOADER_USER_HELPER=n. 27 + * @old_timeout: for internal use 28 + * @loading_timeout: the timeout to wait for the fallback mechanism before 29 + * giving up, in seconds. 30 + */ 31 + struct firmware_fallback_config { 32 + unsigned int force_sysfs_fallback; 33 + unsigned int ignore_sysfs_fallback; 34 + int old_timeout; 35 + int loading_timeout; 36 + }; 37 + 38 + /* These getters are vetted to use int properly */ 39 + static inline int __firmware_loading_timeout(void) 40 + { 41 + return fw_fallback_config.loading_timeout; 42 + } 43 + 44 + /* These setters are vetted to use int properly */ 45 + static inline void __fw_fallback_set_timeout(int timeout) 46 + { 47 + fw_fallback_config.loading_timeout = timeout; 48 + } 49 + #endif 50 + 51 + #ifdef CONFIG_FW_LOADER_SYSFS 52 + int register_sysfs_loader(void); 53 + void unregister_sysfs_loader(void); 54 + #if defined(CONFIG_FW_LOADER_USER_HELPER) && defined(CONFIG_SYSCTL) 55 + int register_firmware_config_sysctl(void); 56 + void unregister_firmware_config_sysctl(void); 57 + #else 58 + static inline int register_firmware_config_sysctl(void) 59 + { 60 + return 0; 61 + } 62 + 63 + static inline void unregister_firmware_config_sysctl(void) { } 64 + #endif /* CONFIG_FW_LOADER_USER_HELPER && CONFIG_SYSCTL */ 65 + #else /* CONFIG_FW_LOADER_SYSFS */ 66 + static inline int register_sysfs_loader(void) 67 + { 68 + return 0; 69 + } 70 + 71 + static inline void unregister_sysfs_loader(void) 72 + { 73 + } 74 + #endif /* CONFIG_FW_LOADER_SYSFS */ 75 + 76 + struct fw_sysfs { 77 + bool nowait; 78 + struct device dev; 79 + struct fw_priv *fw_priv; 80 + struct firmware *fw; 81 + void *fw_upload_priv; 82 + }; 83 + 84 + static inline struct fw_sysfs *to_fw_sysfs(struct device *dev) 85 + { 86 + return container_of(dev, struct fw_sysfs, dev); 87 + } 88 + 89 + void __fw_load_abort(struct fw_priv *fw_priv); 90 + 91 + static inline void fw_load_abort(struct fw_sysfs *fw_sysfs) 92 + { 93 + struct fw_priv *fw_priv = fw_sysfs->fw_priv; 94 + 95 + __fw_load_abort(fw_priv); 96 + } 97 + 98 + struct fw_sysfs * 99 + fw_create_instance(struct firmware *firmware, const char *fw_name, 100 + struct device *device, u32 opt_flags); 101 + 102 + #ifdef CONFIG_FW_UPLOAD 103 + extern struct device_attribute dev_attr_status; 104 + extern struct device_attribute dev_attr_error; 105 + extern struct device_attribute dev_attr_cancel; 106 + extern struct device_attribute dev_attr_remaining_size; 107 + 108 + int fw_upload_start(struct fw_sysfs *fw_sysfs); 109 + umode_t fw_upload_is_visible(struct kobject *kobj, struct attribute *attr, int n); 110 + #else 111 + static inline int fw_upload_start(struct fw_sysfs *fw_sysfs) 112 + { 113 + return 0; 114 + } 115 + #endif 116 + 117 + #endif /* __FIRMWARE_SYSFS_H */
+397
drivers/base/firmware_loader/sysfs_upload.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/firmware.h> 4 + #include <linux/module.h> 5 + #include <linux/slab.h> 6 + 7 + #include "sysfs_upload.h" 8 + 9 + /* 10 + * Support for user-space to initiate a firmware upload to a device. 11 + */ 12 + 13 + static const char * const fw_upload_prog_str[] = { 14 + [FW_UPLOAD_PROG_IDLE] = "idle", 15 + [FW_UPLOAD_PROG_RECEIVING] = "receiving", 16 + [FW_UPLOAD_PROG_PREPARING] = "preparing", 17 + [FW_UPLOAD_PROG_TRANSFERRING] = "transferring", 18 + [FW_UPLOAD_PROG_PROGRAMMING] = "programming" 19 + }; 20 + 21 + static const char * const fw_upload_err_str[] = { 22 + [FW_UPLOAD_ERR_NONE] = "none", 23 + [FW_UPLOAD_ERR_HW_ERROR] = "hw-error", 24 + [FW_UPLOAD_ERR_TIMEOUT] = "timeout", 25 + [FW_UPLOAD_ERR_CANCELED] = "user-abort", 26 + [FW_UPLOAD_ERR_BUSY] = "device-busy", 27 + [FW_UPLOAD_ERR_INVALID_SIZE] = "invalid-file-size", 28 + [FW_UPLOAD_ERR_RW_ERROR] = "read-write-error", 29 + [FW_UPLOAD_ERR_WEAROUT] = "flash-wearout", 30 + }; 31 + 32 + static const char *fw_upload_progress(struct device *dev, 33 + enum fw_upload_prog prog) 34 + { 35 + const char *status = "unknown-status"; 36 + 37 + if (prog < FW_UPLOAD_PROG_MAX) 38 + status = fw_upload_prog_str[prog]; 39 + else 40 + dev_err(dev, "Invalid status during secure update: %d\n", prog); 41 + 42 + return status; 43 + } 44 + 45 + static const char *fw_upload_error(struct device *dev, 46 + enum fw_upload_err err_code) 47 + { 48 + const char *error = "unknown-error"; 49 + 50 + if (err_code < FW_UPLOAD_ERR_MAX) 51 + error = fw_upload_err_str[err_code]; 52 + else 53 + dev_err(dev, "Invalid error code during secure update: %d\n", 54 + err_code); 55 + 56 + return error; 57 + } 58 + 59 + static ssize_t 60 + status_show(struct device *dev, struct device_attribute *attr, char *buf) 61 + { 62 + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; 63 + 64 + return sysfs_emit(buf, "%s\n", fw_upload_progress(dev, fwlp->progress)); 65 + } 66 + DEVICE_ATTR_RO(status); 67 + 68 + static ssize_t 69 + error_show(struct device *dev, struct device_attribute *attr, char *buf) 70 + { 71 + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; 72 + int ret; 73 + 74 + mutex_lock(&fwlp->lock); 75 + 76 + if (fwlp->progress != FW_UPLOAD_PROG_IDLE) 77 + ret = -EBUSY; 78 + else if (!fwlp->err_code) 79 + ret = 0; 80 + else 81 + ret = sysfs_emit(buf, "%s:%s\n", 82 + fw_upload_progress(dev, fwlp->err_progress), 83 + fw_upload_error(dev, fwlp->err_code)); 84 + 85 + mutex_unlock(&fwlp->lock); 86 + 87 + return ret; 88 + } 89 + DEVICE_ATTR_RO(error); 90 + 91 + static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, 92 + const char *buf, size_t count) 93 + { 94 + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; 95 + int ret = count; 96 + bool cancel; 97 + 98 + if (kstrtobool(buf, &cancel) || !cancel) 99 + return -EINVAL; 100 + 101 + mutex_lock(&fwlp->lock); 102 + if (fwlp->progress == FW_UPLOAD_PROG_IDLE) 103 + ret = -ENODEV; 104 + 105 + fwlp->ops->cancel(fwlp->fw_upload); 106 + mutex_unlock(&fwlp->lock); 107 + 108 + return ret; 109 + } 110 + DEVICE_ATTR_WO(cancel); 111 + 112 + static ssize_t remaining_size_show(struct device *dev, 113 + struct device_attribute *attr, char *buf) 114 + { 115 + struct fw_upload_priv *fwlp = to_fw_sysfs(dev)->fw_upload_priv; 116 + 117 + return sysfs_emit(buf, "%u\n", fwlp->remaining_size); 118 + } 119 + DEVICE_ATTR_RO(remaining_size); 120 + 121 + umode_t 122 + fw_upload_is_visible(struct kobject *kobj, struct attribute *attr, int n) 123 + { 124 + static struct fw_sysfs *fw_sysfs; 125 + 126 + fw_sysfs = to_fw_sysfs(kobj_to_dev(kobj)); 127 + 128 + if (fw_sysfs->fw_upload_priv || attr == &dev_attr_loading.attr) 129 + return attr->mode; 130 + 131 + return 0; 132 + } 133 + 134 + static void fw_upload_update_progress(struct fw_upload_priv *fwlp, 135 + enum fw_upload_prog new_progress) 136 + { 137 + mutex_lock(&fwlp->lock); 138 + fwlp->progress = new_progress; 139 + mutex_unlock(&fwlp->lock); 140 + } 141 + 142 + static void fw_upload_set_error(struct fw_upload_priv *fwlp, 143 + enum fw_upload_err err_code) 144 + { 145 + mutex_lock(&fwlp->lock); 146 + fwlp->err_progress = fwlp->progress; 147 + fwlp->err_code = err_code; 148 + mutex_unlock(&fwlp->lock); 149 + } 150 + 151 + static void fw_upload_prog_complete(struct fw_upload_priv *fwlp) 152 + { 153 + mutex_lock(&fwlp->lock); 154 + fwlp->progress = FW_UPLOAD_PROG_IDLE; 155 + mutex_unlock(&fwlp->lock); 156 + } 157 + 158 + static void fw_upload_main(struct work_struct *work) 159 + { 160 + struct fw_upload_priv *fwlp; 161 + struct fw_sysfs *fw_sysfs; 162 + u32 written = 0, offset = 0; 163 + enum fw_upload_err ret; 164 + struct device *fw_dev; 165 + struct fw_upload *fwl; 166 + 167 + fwlp = container_of(work, struct fw_upload_priv, work); 168 + fwl = fwlp->fw_upload; 169 + fw_sysfs = (struct fw_sysfs *)fwl->priv; 170 + fw_dev = &fw_sysfs->dev; 171 + 172 + fw_upload_update_progress(fwlp, FW_UPLOAD_PROG_PREPARING); 173 + ret = fwlp->ops->prepare(fwl, fwlp->data, fwlp->remaining_size); 174 + if (ret != FW_UPLOAD_ERR_NONE) { 175 + fw_upload_set_error(fwlp, ret); 176 + goto putdev_exit; 177 + } 178 + 179 + fw_upload_update_progress(fwlp, FW_UPLOAD_PROG_TRANSFERRING); 180 + while (fwlp->remaining_size) { 181 + ret = fwlp->ops->write(fwl, fwlp->data, offset, 182 + fwlp->remaining_size, &written); 183 + if (ret != FW_UPLOAD_ERR_NONE || !written) { 184 + if (ret == FW_UPLOAD_ERR_NONE) { 185 + dev_warn(fw_dev, "write-op wrote zero data\n"); 186 + ret = FW_UPLOAD_ERR_RW_ERROR; 187 + } 188 + fw_upload_set_error(fwlp, ret); 189 + goto done; 190 + } 191 + 192 + fwlp->remaining_size -= written; 193 + offset += written; 194 + } 195 + 196 + fw_upload_update_progress(fwlp, FW_UPLOAD_PROG_PROGRAMMING); 197 + ret = fwlp->ops->poll_complete(fwl); 198 + if (ret != FW_UPLOAD_ERR_NONE) 199 + fw_upload_set_error(fwlp, ret); 200 + 201 + done: 202 + if (fwlp->ops->cleanup) 203 + fwlp->ops->cleanup(fwl); 204 + 205 + putdev_exit: 206 + put_device(fw_dev->parent); 207 + 208 + /* 209 + * Note: fwlp->remaining_size is left unmodified here to provide 210 + * additional information on errors. It will be reinitialized when 211 + * the next firmeware upload begins. 212 + */ 213 + mutex_lock(&fw_lock); 214 + fw_free_paged_buf(fw_sysfs->fw_priv); 215 + fw_state_init(fw_sysfs->fw_priv); 216 + mutex_unlock(&fw_lock); 217 + fwlp->data = NULL; 218 + fw_upload_prog_complete(fwlp); 219 + } 220 + 221 + /* 222 + * Start a worker thread to upload data to the parent driver. 223 + * Must be called with fw_lock held. 224 + */ 225 + int fw_upload_start(struct fw_sysfs *fw_sysfs) 226 + { 227 + struct fw_priv *fw_priv = fw_sysfs->fw_priv; 228 + struct device *fw_dev = &fw_sysfs->dev; 229 + struct fw_upload_priv *fwlp; 230 + 231 + if (!fw_sysfs->fw_upload_priv) 232 + return 0; 233 + 234 + if (!fw_priv->size) { 235 + fw_free_paged_buf(fw_priv); 236 + fw_state_init(fw_sysfs->fw_priv); 237 + return 0; 238 + } 239 + 240 + fwlp = fw_sysfs->fw_upload_priv; 241 + mutex_lock(&fwlp->lock); 242 + 243 + /* Do not interfere with an on-going fw_upload */ 244 + if (fwlp->progress != FW_UPLOAD_PROG_IDLE) { 245 + mutex_unlock(&fwlp->lock); 246 + return -EBUSY; 247 + } 248 + 249 + get_device(fw_dev->parent); /* released in fw_upload_main */ 250 + 251 + fwlp->progress = FW_UPLOAD_PROG_RECEIVING; 252 + fwlp->err_code = 0; 253 + fwlp->remaining_size = fw_priv->size; 254 + fwlp->data = fw_priv->data; 255 + 256 + pr_debug("%s: fw-%s fw_priv=%p data=%p size=%u\n", 257 + __func__, fw_priv->fw_name, 258 + fw_priv, fw_priv->data, 259 + (unsigned int)fw_priv->size); 260 + 261 + queue_work(system_long_wq, &fwlp->work); 262 + mutex_unlock(&fwlp->lock); 263 + 264 + return 0; 265 + } 266 + 267 + /** 268 + * firmware_upload_register() - register for the firmware upload sysfs API 269 + * @module: kernel module of this device 270 + * @parent: parent device instantiating firmware upload 271 + * @name: firmware name to be associated with this device 272 + * @ops: pointer to structure of firmware upload ops 273 + * @dd_handle: pointer to parent driver private data 274 + * 275 + * @name must be unique among all users of firmware upload. The firmware 276 + * sysfs files for this device will be found at /sys/class/firmware/@name. 277 + * 278 + * Return: struct fw_upload pointer or ERR_PTR() 279 + * 280 + **/ 281 + struct fw_upload * 282 + firmware_upload_register(struct module *module, struct device *parent, 283 + const char *name, const struct fw_upload_ops *ops, 284 + void *dd_handle) 285 + { 286 + u32 opt_flags = FW_OPT_NOCACHE; 287 + struct fw_upload *fw_upload; 288 + struct fw_upload_priv *fw_upload_priv; 289 + struct fw_sysfs *fw_sysfs; 290 + struct fw_priv *fw_priv; 291 + struct device *fw_dev; 292 + int ret; 293 + 294 + if (!name || name[0] == '\0') 295 + return ERR_PTR(-EINVAL); 296 + 297 + if (!ops || !ops->cancel || !ops->prepare || 298 + !ops->write || !ops->poll_complete) { 299 + dev_err(parent, "Attempt to register without all required ops\n"); 300 + return ERR_PTR(-EINVAL); 301 + } 302 + 303 + if (!try_module_get(module)) 304 + return ERR_PTR(-EFAULT); 305 + 306 + fw_upload = kzalloc(sizeof(*fw_upload), GFP_KERNEL); 307 + if (!fw_upload) { 308 + ret = -ENOMEM; 309 + goto exit_module_put; 310 + } 311 + 312 + fw_upload_priv = kzalloc(sizeof(*fw_upload_priv), GFP_KERNEL); 313 + if (!fw_upload_priv) { 314 + ret = -ENOMEM; 315 + goto free_fw_upload; 316 + } 317 + 318 + fw_upload_priv->fw_upload = fw_upload; 319 + fw_upload_priv->ops = ops; 320 + mutex_init(&fw_upload_priv->lock); 321 + fw_upload_priv->module = module; 322 + fw_upload_priv->name = name; 323 + fw_upload_priv->err_code = 0; 324 + fw_upload_priv->progress = FW_UPLOAD_PROG_IDLE; 325 + INIT_WORK(&fw_upload_priv->work, fw_upload_main); 326 + fw_upload->dd_handle = dd_handle; 327 + 328 + fw_sysfs = fw_create_instance(NULL, name, parent, opt_flags); 329 + if (IS_ERR(fw_sysfs)) { 330 + ret = PTR_ERR(fw_sysfs); 331 + goto free_fw_upload_priv; 332 + } 333 + fw_upload->priv = fw_sysfs; 334 + fw_sysfs->fw_upload_priv = fw_upload_priv; 335 + fw_dev = &fw_sysfs->dev; 336 + 337 + ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, NULL, 0, 0, 338 + FW_OPT_NOCACHE); 339 + if (ret != 0) { 340 + if (ret > 0) 341 + ret = -EINVAL; 342 + goto free_fw_sysfs; 343 + } 344 + fw_priv->is_paged_buf = true; 345 + fw_sysfs->fw_priv = fw_priv; 346 + 347 + ret = device_add(fw_dev); 348 + if (ret) { 349 + dev_err(fw_dev, "%s: device_register failed\n", __func__); 350 + put_device(fw_dev); 351 + goto exit_module_put; 352 + } 353 + 354 + return fw_upload; 355 + 356 + free_fw_sysfs: 357 + kfree(fw_sysfs); 358 + 359 + free_fw_upload_priv: 360 + kfree(fw_upload_priv); 361 + 362 + free_fw_upload: 363 + kfree(fw_upload); 364 + 365 + exit_module_put: 366 + module_put(module); 367 + 368 + return ERR_PTR(ret); 369 + } 370 + EXPORT_SYMBOL_GPL(firmware_upload_register); 371 + 372 + /** 373 + * firmware_upload_unregister() - Unregister firmware upload interface 374 + * @fw_upload: pointer to struct fw_upload 375 + **/ 376 + void firmware_upload_unregister(struct fw_upload *fw_upload) 377 + { 378 + struct fw_sysfs *fw_sysfs = fw_upload->priv; 379 + struct fw_upload_priv *fw_upload_priv = fw_sysfs->fw_upload_priv; 380 + 381 + mutex_lock(&fw_upload_priv->lock); 382 + if (fw_upload_priv->progress == FW_UPLOAD_PROG_IDLE) { 383 + mutex_unlock(&fw_upload_priv->lock); 384 + goto unregister; 385 + } 386 + 387 + fw_upload_priv->ops->cancel(fw_upload); 388 + mutex_unlock(&fw_upload_priv->lock); 389 + 390 + /* Ensure lower-level device-driver is finished */ 391 + flush_work(&fw_upload_priv->work); 392 + 393 + unregister: 394 + device_unregister(&fw_sysfs->dev); 395 + module_put(fw_upload_priv->module); 396 + } 397 + EXPORT_SYMBOL_GPL(firmware_upload_unregister);
+41
drivers/base/firmware_loader/sysfs_upload.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __SYSFS_UPLOAD_H 3 + #define __SYSFS_UPLOAD_H 4 + 5 + #include <linux/device.h> 6 + 7 + #include "sysfs.h" 8 + 9 + /** 10 + * enum fw_upload_prog - firmware upload progress codes 11 + * @FW_UPLOAD_PROG_IDLE: there is no firmware upload in progress 12 + * @FW_UPLOAD_PROG_RECEIVING: worker thread is receiving firmware data 13 + * @FW_UPLOAD_PROG_PREPARING: target device is preparing for firmware upload 14 + * @FW_UPLOAD_PROG_TRANSFERRING: data is being copied to the device 15 + * @FW_UPLOAD_PROG_PROGRAMMING: device is performing the firmware update 16 + * @FW_UPLOAD_PROG_MAX: Maximum progress code marker 17 + */ 18 + enum fw_upload_prog { 19 + FW_UPLOAD_PROG_IDLE, 20 + FW_UPLOAD_PROG_RECEIVING, 21 + FW_UPLOAD_PROG_PREPARING, 22 + FW_UPLOAD_PROG_TRANSFERRING, 23 + FW_UPLOAD_PROG_PROGRAMMING, 24 + FW_UPLOAD_PROG_MAX 25 + }; 26 + 27 + struct fw_upload_priv { 28 + struct fw_upload *fw_upload; 29 + struct module *module; 30 + const char *name; 31 + const struct fw_upload_ops *ops; 32 + struct mutex lock; /* protect data structure contents */ 33 + struct work_struct work; 34 + const u8 *data; /* pointer to update data */ 35 + u32 remaining_size; /* size remaining to transfer */ 36 + enum fw_upload_prog progress; 37 + enum fw_upload_prog err_progress; /* progress at time of failure */ 38 + enum fw_upload_err err_code; /* security manager error code */ 39 + }; 40 + 41 + #endif /* __SYSFS_UPLOAD_H */
+143
drivers/base/physical_location.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Device physical location support 4 + * 5 + * Author: Won Chung <wonchung@google.com> 6 + */ 7 + 8 + #include <linux/acpi.h> 9 + #include <linux/sysfs.h> 10 + 11 + #include "physical_location.h" 12 + 13 + bool dev_add_physical_location(struct device *dev) 14 + { 15 + struct acpi_pld_info *pld; 16 + acpi_status status; 17 + 18 + if (!has_acpi_companion(dev)) 19 + return false; 20 + 21 + status = acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld); 22 + if (ACPI_FAILURE(status)) 23 + return false; 24 + 25 + dev->physical_location = 26 + kzalloc(sizeof(*dev->physical_location), GFP_KERNEL); 27 + if (!dev->physical_location) 28 + return false; 29 + dev->physical_location->panel = pld->panel; 30 + dev->physical_location->vertical_position = pld->vertical_position; 31 + dev->physical_location->horizontal_position = pld->horizontal_position; 32 + dev->physical_location->dock = pld->dock; 33 + dev->physical_location->lid = pld->lid; 34 + 35 + ACPI_FREE(pld); 36 + return true; 37 + } 38 + 39 + static ssize_t panel_show(struct device *dev, struct device_attribute *attr, 40 + char *buf) 41 + { 42 + const char *panel; 43 + 44 + switch (dev->physical_location->panel) { 45 + case DEVICE_PANEL_TOP: 46 + panel = "top"; 47 + break; 48 + case DEVICE_PANEL_BOTTOM: 49 + panel = "bottom"; 50 + break; 51 + case DEVICE_PANEL_LEFT: 52 + panel = "left"; 53 + break; 54 + case DEVICE_PANEL_RIGHT: 55 + panel = "right"; 56 + break; 57 + case DEVICE_PANEL_FRONT: 58 + panel = "front"; 59 + break; 60 + case DEVICE_PANEL_BACK: 61 + panel = "back"; 62 + break; 63 + default: 64 + panel = "unknown"; 65 + } 66 + return sysfs_emit(buf, "%s\n", panel); 67 + } 68 + static DEVICE_ATTR_RO(panel); 69 + 70 + static ssize_t vertical_position_show(struct device *dev, 71 + struct device_attribute *attr, char *buf) 72 + { 73 + const char *vertical_position; 74 + 75 + switch (dev->physical_location->vertical_position) { 76 + case DEVICE_VERT_POS_UPPER: 77 + vertical_position = "upper"; 78 + break; 79 + case DEVICE_VERT_POS_CENTER: 80 + vertical_position = "center"; 81 + break; 82 + case DEVICE_VERT_POS_LOWER: 83 + vertical_position = "lower"; 84 + break; 85 + default: 86 + vertical_position = "unknown"; 87 + } 88 + return sysfs_emit(buf, "%s\n", vertical_position); 89 + } 90 + static DEVICE_ATTR_RO(vertical_position); 91 + 92 + static ssize_t horizontal_position_show(struct device *dev, 93 + struct device_attribute *attr, char *buf) 94 + { 95 + const char *horizontal_position; 96 + 97 + switch (dev->physical_location->horizontal_position) { 98 + case DEVICE_HORI_POS_LEFT: 99 + horizontal_position = "left"; 100 + break; 101 + case DEVICE_HORI_POS_CENTER: 102 + horizontal_position = "center"; 103 + break; 104 + case DEVICE_HORI_POS_RIGHT: 105 + horizontal_position = "right"; 106 + break; 107 + default: 108 + horizontal_position = "unknown"; 109 + } 110 + return sysfs_emit(buf, "%s\n", horizontal_position); 111 + } 112 + static DEVICE_ATTR_RO(horizontal_position); 113 + 114 + static ssize_t dock_show(struct device *dev, struct device_attribute *attr, 115 + char *buf) 116 + { 117 + return sysfs_emit(buf, "%s\n", 118 + dev->physical_location->dock ? "yes" : "no"); 119 + } 120 + static DEVICE_ATTR_RO(dock); 121 + 122 + static ssize_t lid_show(struct device *dev, struct device_attribute *attr, 123 + char *buf) 124 + { 125 + return sysfs_emit(buf, "%s\n", 126 + dev->physical_location->lid ? "yes" : "no"); 127 + } 128 + static DEVICE_ATTR_RO(lid); 129 + 130 + static struct attribute *dev_attr_physical_location[] = { 131 + &dev_attr_panel.attr, 132 + &dev_attr_vertical_position.attr, 133 + &dev_attr_horizontal_position.attr, 134 + &dev_attr_dock.attr, 135 + &dev_attr_lid.attr, 136 + NULL, 137 + }; 138 + 139 + const struct attribute_group dev_attr_physical_location_group = { 140 + .name = "physical_location", 141 + .attrs = dev_attr_physical_location, 142 + }; 143 +
+16
drivers/base/physical_location.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Device physical location support 4 + * 5 + * Author: Won Chung <wonchung@google.com> 6 + */ 7 + 8 + #include <linux/device.h> 9 + 10 + #ifdef CONFIG_ACPI 11 + extern bool dev_add_physical_location(struct device *dev); 12 + extern const struct attribute_group dev_attr_physical_location_group; 13 + #else 14 + static inline bool dev_add_physical_location(struct device *dev) { return false; }; 15 + static const struct attribute_group dev_attr_physical_location_group = {}; 16 + #endif
+8 -26
drivers/base/platform.c
··· 233 233 out_not_found: 234 234 ret = -ENXIO; 235 235 out: 236 - WARN(ret == 0, "0 is an invalid IRQ number\n"); 236 + if (WARN(!ret, "0 is an invalid IRQ number\n")) 237 + return -EINVAL; 237 238 return ret; 238 239 } 239 240 EXPORT_SYMBOL_GPL(platform_get_irq_optional); ··· 449 448 450 449 r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); 451 450 if (r) { 452 - WARN(r->start == 0, "0 is an invalid IRQ number\n"); 451 + if (WARN(!r->start, "0 is an invalid IRQ number\n")) 452 + return -EINVAL; 453 453 return r->start; 454 454 } 455 455 ··· 1279 1277 const char *buf, size_t count) 1280 1278 { 1281 1279 struct platform_device *pdev = to_platform_device(dev); 1282 - char *driver_override, *old, *cp; 1280 + int ret; 1283 1281 1284 - /* We need to keep extra room for a newline */ 1285 - if (count >= (PAGE_SIZE - 1)) 1286 - return -EINVAL; 1287 - 1288 - driver_override = kstrndup(buf, count, GFP_KERNEL); 1289 - if (!driver_override) 1290 - return -ENOMEM; 1291 - 1292 - cp = strchr(driver_override, '\n'); 1293 - if (cp) 1294 - *cp = '\0'; 1295 - 1296 - device_lock(dev); 1297 - old = pdev->driver_override; 1298 - if (strlen(driver_override)) { 1299 - pdev->driver_override = driver_override; 1300 - } else { 1301 - kfree(driver_override); 1302 - pdev->driver_override = NULL; 1303 - } 1304 - device_unlock(dev); 1305 - 1306 - kfree(old); 1282 + ret = driver_set_override(dev, &pdev->driver_override, buf, count); 1283 + if (ret) 1284 + return ret; 1307 1285 1308 1286 return count; 1309 1287 }
+4 -21
drivers/bus/fsl-mc/fsl-mc-bus.c
··· 185 185 const char *buf, size_t count) 186 186 { 187 187 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 188 - char *driver_override, *old = mc_dev->driver_override; 189 - char *cp; 188 + int ret; 190 189 191 190 if (WARN_ON(dev->bus != &fsl_mc_bus_type)) 192 191 return -EINVAL; 193 192 194 - if (count >= (PAGE_SIZE - 1)) 195 - return -EINVAL; 196 - 197 - driver_override = kstrndup(buf, count, GFP_KERNEL); 198 - if (!driver_override) 199 - return -ENOMEM; 200 - 201 - cp = strchr(driver_override, '\n'); 202 - if (cp) 203 - *cp = '\0'; 204 - 205 - if (strlen(driver_override)) { 206 - mc_dev->driver_override = driver_override; 207 - } else { 208 - kfree(driver_override); 209 - mc_dev->driver_override = NULL; 210 - } 211 - 212 - kfree(old); 193 + ret = driver_set_override(dev, &mc_dev->driver_override, buf, count); 194 + if (ret) 195 + return ret; 213 196 214 197 return count; 215 198 }
+6 -1
drivers/clk/imx/clk-scu.c
··· 683 683 return ERR_PTR(ret); 684 684 } 685 685 686 - pdev->driver_override = "imx-scu-clk"; 686 + ret = driver_set_override(&pdev->dev, &pdev->driver_override, 687 + "imx-scu-clk", strlen("imx-scu-clk")); 688 + if (ret) { 689 + platform_device_put(pdev); 690 + return ERR_PTR(ret); 691 + } 687 692 688 693 ret = imx_clk_scu_attach_pd(&pdev->dev, rsrc_id); 689 694 if (ret)
+4 -24
drivers/hv/vmbus_drv.c
··· 575 575 const char *buf, size_t count) 576 576 { 577 577 struct hv_device *hv_dev = device_to_hv_device(dev); 578 - char *driver_override, *old, *cp; 578 + int ret; 579 579 580 - /* We need to keep extra room for a newline */ 581 - if (count >= (PAGE_SIZE - 1)) 582 - return -EINVAL; 583 - 584 - driver_override = kstrndup(buf, count, GFP_KERNEL); 585 - if (!driver_override) 586 - return -ENOMEM; 587 - 588 - cp = strchr(driver_override, '\n'); 589 - if (cp) 590 - *cp = '\0'; 591 - 592 - device_lock(dev); 593 - old = hv_dev->driver_override; 594 - if (strlen(driver_override)) { 595 - hv_dev->driver_override = driver_override; 596 - } else { 597 - kfree(driver_override); 598 - hv_dev->driver_override = NULL; 599 - } 600 - device_unlock(dev); 601 - 602 - kfree(old); 580 + ret = driver_set_override(dev, &hv_dev->driver_override, buf, count); 581 + if (ret) 582 + return ret; 603 583 604 584 return count; 605 585 }
+4 -24
drivers/pci/pci-sysfs.c
··· 567 567 const char *buf, size_t count) 568 568 { 569 569 struct pci_dev *pdev = to_pci_dev(dev); 570 - char *driver_override, *old, *cp; 570 + int ret; 571 571 572 - /* We need to keep extra room for a newline */ 573 - if (count >= (PAGE_SIZE - 1)) 574 - return -EINVAL; 575 - 576 - driver_override = kstrndup(buf, count, GFP_KERNEL); 577 - if (!driver_override) 578 - return -ENOMEM; 579 - 580 - cp = strchr(driver_override, '\n'); 581 - if (cp) 582 - *cp = '\0'; 583 - 584 - device_lock(dev); 585 - old = pdev->driver_override; 586 - if (strlen(driver_override)) { 587 - pdev->driver_override = driver_override; 588 - } else { 589 - kfree(driver_override); 590 - pdev->driver_override = NULL; 591 - } 592 - device_unlock(dev); 593 - 594 - kfree(old); 572 + ret = driver_set_override(dev, &pdev->driver_override, buf, count); 573 + if (ret) 574 + return ret; 595 575 596 576 return count; 597 577 }
+35 -7
drivers/rpmsg/rpmsg_core.c
··· 400 400 const char *buf, size_t sz) \ 401 401 { \ 402 402 struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ 403 - char *new, *old; \ 403 + const char *old; \ 404 + char *new; \ 404 405 \ 405 406 new = kstrndup(buf, sz, GFP_KERNEL); \ 406 407 if (!new) \ ··· 593 592 .remove = rpmsg_dev_remove, 594 593 }; 595 594 596 - int rpmsg_register_device(struct rpmsg_device *rpdev) 595 + /* 596 + * A helper for registering rpmsg device with driver override and name. 597 + * Drivers should not be using it, but instead rpmsg_register_device(). 598 + */ 599 + int rpmsg_register_device_override(struct rpmsg_device *rpdev, 600 + const char *driver_override) 597 601 { 598 602 struct device *dev = &rpdev->dev; 599 603 int ret; 600 604 601 - dev_set_name(&rpdev->dev, "%s.%s.%d.%d", dev_name(dev->parent), 605 + if (driver_override) 606 + strcpy(rpdev->id.name, driver_override); 607 + 608 + dev_set_name(dev, "%s.%s.%d.%d", dev_name(dev->parent), 602 609 rpdev->id.name, rpdev->src, rpdev->dst); 603 610 604 - rpdev->dev.bus = &rpmsg_bus; 611 + dev->bus = &rpmsg_bus; 605 612 606 - ret = device_register(&rpdev->dev); 613 + device_initialize(dev); 614 + if (driver_override) { 615 + ret = driver_set_override(dev, &rpdev->driver_override, 616 + driver_override, 617 + strlen(driver_override)); 618 + if (ret) { 619 + dev_err(dev, "device_set_override failed: %d\n", ret); 620 + return ret; 621 + } 622 + } 623 + 624 + ret = device_add(dev); 607 625 if (ret) { 608 - dev_err(dev, "device_register failed: %d\n", ret); 609 - put_device(&rpdev->dev); 626 + dev_err(dev, "device_add failed: %d\n", ret); 627 + kfree(rpdev->driver_override); 628 + rpdev->driver_override = NULL; 629 + put_device(dev); 610 630 } 611 631 612 632 return ret; 633 + } 634 + EXPORT_SYMBOL(rpmsg_register_device_override); 635 + 636 + int rpmsg_register_device(struct rpmsg_device *rpdev) 637 + { 638 + return rpmsg_register_device_override(rpdev, NULL); 613 639 } 614 640 EXPORT_SYMBOL(rpmsg_register_device); 615 641
+1 -4
drivers/rpmsg/rpmsg_internal.h
··· 94 94 */ 95 95 static inline int rpmsg_ctrldev_register_device(struct rpmsg_device *rpdev) 96 96 { 97 - strcpy(rpdev->id.name, "rpmsg_ctrl"); 98 - rpdev->driver_override = "rpmsg_ctrl"; 99 - 100 - return rpmsg_register_device(rpdev); 97 + return rpmsg_register_device_override(rpdev, "rpmsg_ctrl"); 101 98 } 102 99 103 100 #endif
+1 -3
drivers/rpmsg/rpmsg_ns.c
··· 20 20 */ 21 21 int rpmsg_ns_register_device(struct rpmsg_device *rpdev) 22 22 { 23 - strcpy(rpdev->id.name, "rpmsg_ns"); 24 - rpdev->driver_override = "rpmsg_ns"; 25 23 rpdev->src = RPMSG_NS_ADDR; 26 24 rpdev->dst = RPMSG_NS_ADDR; 27 25 28 - return rpmsg_register_device(rpdev); 26 + return rpmsg_register_device_override(rpdev, "rpmsg_ns"); 29 27 } 30 28 EXPORT_SYMBOL(rpmsg_ns_register_device); 31 29
+5 -1
drivers/s390/cio/cio.h
··· 103 103 struct work_struct todo_work; 104 104 struct schib_config config; 105 105 u64 dma_mask; 106 - char *driver_override; /* Driver name to force a match */ 106 + /* 107 + * Driver name to force a match. Do not set directly, because core 108 + * frees it. Use driver_set_override() to set or clear it. 109 + */ 110 + const char *driver_override; 107 111 } __attribute__ ((aligned(8))); 108 112 109 113 DECLARE_PER_CPU_ALIGNED(struct irb, cio_irb);
+4 -24
drivers/s390/cio/css.c
··· 338 338 const char *buf, size_t count) 339 339 { 340 340 struct subchannel *sch = to_subchannel(dev); 341 - char *driver_override, *old, *cp; 341 + int ret; 342 342 343 - /* We need to keep extra room for a newline */ 344 - if (count >= (PAGE_SIZE - 1)) 345 - return -EINVAL; 346 - 347 - driver_override = kstrndup(buf, count, GFP_KERNEL); 348 - if (!driver_override) 349 - return -ENOMEM; 350 - 351 - cp = strchr(driver_override, '\n'); 352 - if (cp) 353 - *cp = '\0'; 354 - 355 - device_lock(dev); 356 - old = sch->driver_override; 357 - if (strlen(driver_override)) { 358 - sch->driver_override = driver_override; 359 - } else { 360 - kfree(driver_override); 361 - sch->driver_override = NULL; 362 - } 363 - device_unlock(dev); 364 - 365 - kfree(old); 343 + ret = driver_set_override(dev, &sch->driver_override, buf, count); 344 + if (ret) 345 + return ret; 366 346 367 347 return count; 368 348 }
+12 -1
drivers/slimbus/qcom-ngd-ctrl.c
··· 1434 1434 const struct of_device_id *match; 1435 1435 struct device_node *node; 1436 1436 u32 id; 1437 + int ret; 1437 1438 1438 1439 match = of_match_node(qcom_slim_ngd_dt_match, parent->of_node); 1439 1440 data = match->data; ··· 1456 1455 } 1457 1456 ngd->id = id; 1458 1457 ngd->pdev->dev.parent = parent; 1459 - ngd->pdev->driver_override = QCOM_SLIM_NGD_DRV_NAME; 1458 + 1459 + ret = driver_set_override(&ngd->pdev->dev, 1460 + &ngd->pdev->driver_override, 1461 + QCOM_SLIM_NGD_DRV_NAME, 1462 + strlen(QCOM_SLIM_NGD_DRV_NAME)); 1463 + if (ret) { 1464 + platform_device_put(ngd->pdev); 1465 + kfree(ngd); 1466 + of_node_put(node); 1467 + return ret; 1468 + } 1460 1469 ngd->pdev->dev.of_node = node; 1461 1470 ctrl->ngd = ngd; 1462 1471
+4 -22
drivers/spi/spi.c
··· 71 71 const char *buf, size_t count) 72 72 { 73 73 struct spi_device *spi = to_spi_device(dev); 74 - const char *end = memchr(buf, '\n', count); 75 - const size_t len = end ? end - buf : count; 76 - const char *driver_override, *old; 74 + int ret; 77 75 78 - /* We need to keep extra room for a newline when displaying value */ 79 - if (len >= (PAGE_SIZE - 1)) 80 - return -EINVAL; 81 - 82 - driver_override = kstrndup(buf, len, GFP_KERNEL); 83 - if (!driver_override) 84 - return -ENOMEM; 85 - 86 - device_lock(dev); 87 - old = spi->driver_override; 88 - if (len) { 89 - spi->driver_override = driver_override; 90 - } else { 91 - /* Empty string, disable driver override */ 92 - spi->driver_override = NULL; 93 - kfree(driver_override); 94 - } 95 - device_unlock(dev); 96 - kfree(old); 76 + ret = driver_set_override(dev, &spi->driver_override, buf, count); 77 + if (ret) 78 + return ret; 97 79 98 80 return count; 99 81 }
+4 -25
drivers/vdpa/vdpa.c
··· 77 77 const char *buf, size_t count) 78 78 { 79 79 struct vdpa_device *vdev = dev_to_vdpa(dev); 80 - const char *driver_override, *old; 81 - char *cp; 80 + int ret; 82 81 83 - /* We need to keep extra room for a newline */ 84 - if (count >= (PAGE_SIZE - 1)) 85 - return -EINVAL; 86 - 87 - driver_override = kstrndup(buf, count, GFP_KERNEL); 88 - if (!driver_override) 89 - return -ENOMEM; 90 - 91 - cp = strchr(driver_override, '\n'); 92 - if (cp) 93 - *cp = '\0'; 94 - 95 - device_lock(dev); 96 - old = vdev->driver_override; 97 - if (strlen(driver_override)) { 98 - vdev->driver_override = driver_override; 99 - } else { 100 - kfree(driver_override); 101 - vdev->driver_override = NULL; 102 - } 103 - device_unlock(dev); 104 - 105 - kfree(old); 82 + ret = driver_set_override(dev, &vdev->driver_override, buf, count); 83 + if (ret) 84 + return ret; 106 85 107 86 return count; 108 87 }
+19 -12
fs/kernfs/dir.c
··· 18 18 #include "kernfs-internal.h" 19 19 20 20 static DEFINE_SPINLOCK(kernfs_rename_lock); /* kn->parent and ->name */ 21 - static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by rename_lock */ 21 + /* 22 + * Don't use rename_lock to piggy back on pr_cont_buf. We don't want to 23 + * call pr_cont() while holding rename_lock. Because sometimes pr_cont() 24 + * will perform wakeups when releasing console_sem. Holding rename_lock 25 + * will introduce deadlock if the scheduler reads the kernfs_name in the 26 + * wakeup path. 27 + */ 28 + static DEFINE_SPINLOCK(kernfs_pr_cont_lock); 29 + static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by pr_cont_lock */ 22 30 static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */ 23 31 24 32 #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) ··· 237 229 { 238 230 unsigned long flags; 239 231 240 - spin_lock_irqsave(&kernfs_rename_lock, flags); 232 + spin_lock_irqsave(&kernfs_pr_cont_lock, flags); 241 233 242 - kernfs_name_locked(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf)); 234 + kernfs_name(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf)); 243 235 pr_cont("%s", kernfs_pr_cont_buf); 244 236 245 - spin_unlock_irqrestore(&kernfs_rename_lock, flags); 237 + spin_unlock_irqrestore(&kernfs_pr_cont_lock, flags); 246 238 } 247 239 248 240 /** ··· 256 248 unsigned long flags; 257 249 int sz; 258 250 259 - spin_lock_irqsave(&kernfs_rename_lock, flags); 251 + spin_lock_irqsave(&kernfs_pr_cont_lock, flags); 260 252 261 - sz = kernfs_path_from_node_locked(kn, NULL, kernfs_pr_cont_buf, 262 - sizeof(kernfs_pr_cont_buf)); 253 + sz = kernfs_path_from_node(kn, NULL, kernfs_pr_cont_buf, 254 + sizeof(kernfs_pr_cont_buf)); 263 255 if (sz < 0) { 264 256 pr_cont("(error)"); 265 257 goto out; ··· 273 265 pr_cont("%s", kernfs_pr_cont_buf); 274 266 275 267 out: 276 - spin_unlock_irqrestore(&kernfs_rename_lock, flags); 268 + spin_unlock_irqrestore(&kernfs_pr_cont_lock, flags); 277 269 } 278 270 279 271 /** ··· 831 823 832 824 lockdep_assert_held_read(&kernfs_root(parent)->kernfs_rwsem); 833 825 834 - /* grab kernfs_rename_lock to piggy back on kernfs_pr_cont_buf */ 835 - spin_lock_irq(&kernfs_rename_lock); 826 + spin_lock_irq(&kernfs_pr_cont_lock); 836 827 837 828 len = strlcpy(kernfs_pr_cont_buf, path, sizeof(kernfs_pr_cont_buf)); 838 829 839 830 if (len >= sizeof(kernfs_pr_cont_buf)) { 840 - spin_unlock_irq(&kernfs_rename_lock); 831 + spin_unlock_irq(&kernfs_pr_cont_lock); 841 832 return NULL; 842 833 } 843 834 ··· 848 841 parent = kernfs_find_ns(parent, name, ns); 849 842 } 850 843 851 - spin_unlock_irq(&kernfs_rename_lock); 844 + spin_unlock_irq(&kernfs_pr_cont_lock); 852 845 853 846 return parent; 854 847 }
+26 -21
fs/kernfs/file.c
··· 33 33 static DEFINE_MUTEX(kernfs_open_file_mutex); 34 34 35 35 struct kernfs_open_node { 36 - atomic_t refcnt; 37 36 atomic_t event; 38 37 wait_queue_head_t poll; 39 38 struct list_head files; /* goes through kernfs_open_file.list */ ··· 529 530 } 530 531 531 532 on = kn->attr.open; 532 - if (on) { 533 - atomic_inc(&on->refcnt); 533 + if (on) 534 534 list_add_tail(&of->list, &on->files); 535 - } 536 535 537 536 spin_unlock_irq(&kernfs_open_node_lock); 538 537 mutex_unlock(&kernfs_open_file_mutex); ··· 545 548 if (!new_on) 546 549 return -ENOMEM; 547 550 548 - atomic_set(&new_on->refcnt, 0); 549 551 atomic_set(&new_on->event, 1); 550 552 init_waitqueue_head(&new_on->poll); 551 553 INIT_LIST_HEAD(&new_on->files); ··· 552 556 } 553 557 554 558 /** 555 - * kernfs_put_open_node - put kernfs_open_node 556 - * @kn: target kernfs_nodet 559 + * kernfs_unlink_open_file - Unlink @of from @kn. 560 + * 561 + * @kn: target kernfs_node 557 562 * @of: associated kernfs_open_file 558 563 * 559 - * Put @kn->attr.open and unlink @of from the files list. If 560 - * reference count reaches zero, disassociate and free it. 564 + * Unlink @of from list of @kn's associated open files. If list of 565 + * associated open files becomes empty, disassociate and free 566 + * kernfs_open_node. 561 567 * 562 568 * LOCKING: 563 569 * None. 564 570 */ 565 - static void kernfs_put_open_node(struct kernfs_node *kn, 571 + static void kernfs_unlink_open_file(struct kernfs_node *kn, 566 572 struct kernfs_open_file *of) 567 573 { 568 574 struct kernfs_open_node *on = kn->attr.open; ··· 576 578 if (of) 577 579 list_del(&of->list); 578 580 579 - if (atomic_dec_and_test(&on->refcnt)) 581 + if (list_empty(&on->files)) 580 582 kn->attr.open = NULL; 581 583 else 582 584 on = NULL; ··· 704 706 return 0; 705 707 706 708 err_put_node: 707 - kernfs_put_open_node(kn, of); 709 + kernfs_unlink_open_file(kn, of); 708 710 err_seq_release: 709 711 seq_release(inode, file); 710 712 err_free: ··· 750 752 mutex_unlock(&kernfs_open_file_mutex); 751 753 } 752 754 753 - kernfs_put_open_node(kn, of); 755 + kernfs_unlink_open_file(kn, of); 754 756 seq_release(inode, filp); 755 757 kfree(of->prealloc_buf); 756 758 kfree(of); ··· 766 768 if (!(kn->flags & (KERNFS_HAS_MMAP | KERNFS_HAS_RELEASE))) 767 769 return; 768 770 769 - spin_lock_irq(&kernfs_open_node_lock); 770 - on = kn->attr.open; 771 - if (on) 772 - atomic_inc(&on->refcnt); 773 - spin_unlock_irq(&kernfs_open_node_lock); 774 - if (!on) 771 + /* 772 + * lockless opportunistic check is safe below because no one is adding to 773 + * ->attr.open at this point of time. This check allows early bail out 774 + * if ->attr.open is already NULL. kernfs_unlink_open_file makes 775 + * ->attr.open NULL only while holding kernfs_open_file_mutex so below 776 + * check under kernfs_open_file_mutex will ensure bailing out if 777 + * ->attr.open became NULL while waiting for the mutex. 778 + */ 779 + if (!kn->attr.open) 775 780 return; 776 781 777 782 mutex_lock(&kernfs_open_file_mutex); 783 + if (!kn->attr.open) { 784 + mutex_unlock(&kernfs_open_file_mutex); 785 + return; 786 + } 787 + 788 + on = kn->attr.open; 778 789 779 790 list_for_each_entry(of, &on->files, list) { 780 791 struct inode *inode = file_inode(of->file); ··· 796 789 } 797 790 798 791 mutex_unlock(&kernfs_open_file_mutex); 799 - 800 - kernfs_put_open_node(kn, NULL); 801 792 } 802 793 803 794 /*
+5 -1
include/linux/amba/bus.h
··· 70 70 unsigned int cid; 71 71 struct amba_cs_uci_id uci; 72 72 unsigned int irq[AMBA_NR_IRQS]; 73 - char *driver_override; 73 + /* 74 + * Driver name to force a match. Do not set directly, because core 75 + * frees it. Use driver_set_override() to set or clear it. 76 + */ 77 + const char *driver_override; 74 78 }; 75 79 76 80 struct amba_driver {
+73
include/linux/device.h
··· 387 387 }; 388 388 389 389 /** 390 + * enum device_physical_location_panel - Describes which panel surface of the 391 + * system's housing the device connection point resides on. 392 + * @DEVICE_PANEL_TOP: Device connection point is on the top panel. 393 + * @DEVICE_PANEL_BOTTOM: Device connection point is on the bottom panel. 394 + * @DEVICE_PANEL_LEFT: Device connection point is on the left panel. 395 + * @DEVICE_PANEL_RIGHT: Device connection point is on the right panel. 396 + * @DEVICE_PANEL_FRONT: Device connection point is on the front panel. 397 + * @DEVICE_PANEL_BACK: Device connection point is on the back panel. 398 + * @DEVICE_PANEL_UNKNOWN: The panel with device connection point is unknown. 399 + */ 400 + enum device_physical_location_panel { 401 + DEVICE_PANEL_TOP, 402 + DEVICE_PANEL_BOTTOM, 403 + DEVICE_PANEL_LEFT, 404 + DEVICE_PANEL_RIGHT, 405 + DEVICE_PANEL_FRONT, 406 + DEVICE_PANEL_BACK, 407 + DEVICE_PANEL_UNKNOWN, 408 + }; 409 + 410 + /** 411 + * enum device_physical_location_vertical_position - Describes vertical 412 + * position of the device connection point on the panel surface. 413 + * @DEVICE_VERT_POS_UPPER: Device connection point is at upper part of panel. 414 + * @DEVICE_VERT_POS_CENTER: Device connection point is at center part of panel. 415 + * @DEVICE_VERT_POS_LOWER: Device connection point is at lower part of panel. 416 + */ 417 + enum device_physical_location_vertical_position { 418 + DEVICE_VERT_POS_UPPER, 419 + DEVICE_VERT_POS_CENTER, 420 + DEVICE_VERT_POS_LOWER, 421 + }; 422 + 423 + /** 424 + * enum device_physical_location_horizontal_position - Describes horizontal 425 + * position of the device connection point on the panel surface. 426 + * @DEVICE_HORI_POS_LEFT: Device connection point is at left part of panel. 427 + * @DEVICE_HORI_POS_CENTER: Device connection point is at center part of panel. 428 + * @DEVICE_HORI_POS_RIGHT: Device connection point is at right part of panel. 429 + */ 430 + enum device_physical_location_horizontal_position { 431 + DEVICE_HORI_POS_LEFT, 432 + DEVICE_HORI_POS_CENTER, 433 + DEVICE_HORI_POS_RIGHT, 434 + }; 435 + 436 + /** 437 + * struct device_physical_location - Device data related to physical location 438 + * of the device connection point. 439 + * @panel: Panel surface of the system's housing that the device connection 440 + * point resides on. 441 + * @vertical_position: Vertical position of the device connection point within 442 + * the panel. 443 + * @horizontal_position: Horizontal position of the device connection point 444 + * within the panel. 445 + * @dock: Set if the device connection point resides in a docking station or 446 + * port replicator. 447 + * @lid: Set if this device connection point resides on the lid of laptop 448 + * system. 449 + */ 450 + struct device_physical_location { 451 + enum device_physical_location_panel panel; 452 + enum device_physical_location_vertical_position vertical_position; 453 + enum device_physical_location_horizontal_position horizontal_position; 454 + bool dock; 455 + bool lid; 456 + }; 457 + 458 + /** 390 459 * struct device - The basic device structure 391 460 * @parent: The device's "parent" device, the device to which it is attached. 392 461 * In most cases, a parent device is some sort of bus or host ··· 520 451 * device (i.e. the bus driver that discovered the device). 521 452 * @iommu_group: IOMMU group the device belongs to. 522 453 * @iommu: Per device generic IOMMU runtime data 454 + * @physical_location: Describes physical location of the device connection 455 + * point in the system housing. 523 456 * @removable: Whether the device can be removed from the system. This 524 457 * should be set by the subsystem / bus driver that discovered 525 458 * the device. ··· 632 561 void (*release)(struct device *dev); 633 562 struct iommu_group *iommu_group; 634 563 struct dev_iommu *iommu; 564 + 565 + struct device_physical_location *physical_location; 635 566 636 567 enum device_removable removable; 637 568
+2
include/linux/device/driver.h
··· 151 151 extern void driver_remove_file(struct device_driver *driver, 152 152 const struct driver_attribute *attr); 153 153 154 + int driver_set_override(struct device *dev, const char **override, 155 + const char *s, size_t len); 154 156 extern int __must_check driver_for_each_device(struct device_driver *drv, 155 157 struct device *start, 156 158 void *data,
+4 -3
include/linux/export.h
··· 2 2 #ifndef _LINUX_EXPORT_H 3 3 #define _LINUX_EXPORT_H 4 4 5 + #include <linux/stringify.h> 6 + 5 7 /* 6 8 * Export symbols from the kernel to modules. Forked from module.h 7 9 * to reduce the amount of pointless cruft we feed to gcc when only ··· 142 140 #endif /* CONFIG_MODULES */ 143 141 144 142 #ifdef DEFAULT_SYMBOL_NAMESPACE 145 - #include <linux/stringify.h> 146 143 #define _EXPORT_SYMBOL(sym, sec) __EXPORT_SYMBOL(sym, sec, __stringify(DEFAULT_SYMBOL_NAMESPACE)) 147 144 #else 148 145 #define _EXPORT_SYMBOL(sym, sec) __EXPORT_SYMBOL(sym, sec, "") ··· 149 148 150 149 #define EXPORT_SYMBOL(sym) _EXPORT_SYMBOL(sym, "") 151 150 #define EXPORT_SYMBOL_GPL(sym) _EXPORT_SYMBOL(sym, "_gpl") 152 - #define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", #ns) 153 - #define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", #ns) 151 + #define EXPORT_SYMBOL_NS(sym, ns) __EXPORT_SYMBOL(sym, "", __stringify(ns)) 152 + #define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", __stringify(ns)) 154 153 155 154 #endif /* !__ASSEMBLY__ */ 156 155
+82
include/linux/firmware.h
··· 17 17 void *priv; 18 18 }; 19 19 20 + /** 21 + * enum fw_upload_err - firmware upload error codes 22 + * @FW_UPLOAD_ERR_NONE: returned to indicate success 23 + * @FW_UPLOAD_ERR_HW_ERROR: error signalled by hardware, see kernel log 24 + * @FW_UPLOAD_ERR_TIMEOUT: SW timed out on handshake with HW/firmware 25 + * @FW_UPLOAD_ERR_CANCELED: upload was cancelled by the user 26 + * @FW_UPLOAD_ERR_BUSY: there is an upload operation already in progress 27 + * @FW_UPLOAD_ERR_INVALID_SIZE: invalid firmware image size 28 + * @FW_UPLOAD_ERR_RW_ERROR: read or write to HW failed, see kernel log 29 + * @FW_UPLOAD_ERR_WEAROUT: FLASH device is approaching wear-out, wait & retry 30 + * @FW_UPLOAD_ERR_MAX: Maximum error code marker 31 + */ 32 + enum fw_upload_err { 33 + FW_UPLOAD_ERR_NONE, 34 + FW_UPLOAD_ERR_HW_ERROR, 35 + FW_UPLOAD_ERR_TIMEOUT, 36 + FW_UPLOAD_ERR_CANCELED, 37 + FW_UPLOAD_ERR_BUSY, 38 + FW_UPLOAD_ERR_INVALID_SIZE, 39 + FW_UPLOAD_ERR_RW_ERROR, 40 + FW_UPLOAD_ERR_WEAROUT, 41 + FW_UPLOAD_ERR_MAX 42 + }; 43 + 44 + struct fw_upload { 45 + void *dd_handle; /* reference to parent driver */ 46 + void *priv; /* firmware loader private fields */ 47 + }; 48 + 49 + /** 50 + * struct fw_upload_ops - device specific operations to support firmware upload 51 + * @prepare: Required: Prepare secure update 52 + * @write: Required: The write() op receives the remaining 53 + * size to be written and must return the actual 54 + * size written or a negative error code. The write() 55 + * op will be called repeatedly until all data is 56 + * written. 57 + * @poll_complete: Required: Check for the completion of the 58 + * HW authentication/programming process. 59 + * @cancel: Required: Request cancellation of update. This op 60 + * is called from the context of a different kernel 61 + * thread, so race conditions need to be considered. 62 + * @cleanup: Optional: Complements the prepare() 63 + * function and is called at the completion 64 + * of the update, on success or failure, if the 65 + * prepare function succeeded. 66 + */ 67 + struct fw_upload_ops { 68 + enum fw_upload_err (*prepare)(struct fw_upload *fw_upload, 69 + const u8 *data, u32 size); 70 + enum fw_upload_err (*write)(struct fw_upload *fw_upload, 71 + const u8 *data, u32 offset, 72 + u32 size, u32 *written); 73 + enum fw_upload_err (*poll_complete)(struct fw_upload *fw_upload); 74 + void (*cancel)(struct fw_upload *fw_upload); 75 + void (*cleanup)(struct fw_upload *fw_upload); 76 + }; 77 + 20 78 struct module; 21 79 struct device; 22 80 ··· 166 108 void *buf, size_t size, size_t offset) 167 109 { 168 110 return -EINVAL; 111 + } 112 + 113 + #endif 114 + 115 + #ifdef CONFIG_FW_UPLOAD 116 + 117 + struct fw_upload * 118 + firmware_upload_register(struct module *module, struct device *parent, 119 + const char *name, const struct fw_upload_ops *ops, 120 + void *dd_handle); 121 + void firmware_upload_unregister(struct fw_upload *fw_upload); 122 + 123 + #else 124 + 125 + static inline struct fw_upload * 126 + firmware_upload_register(struct module *module, struct device *parent, 127 + const char *name, const struct fw_upload_ops *ops, 128 + void *dd_handle) 129 + { 130 + return ERR_PTR(-EINVAL); 131 + } 132 + 133 + static inline void firmware_upload_unregister(struct fw_upload *fw_upload) 134 + { 169 135 } 170 136 171 137 #endif
+4 -2
include/linux/fsl/mc.h
··· 178 178 * @regions: pointer to array of MMIO region entries 179 179 * @irqs: pointer to array of pointers to interrupts allocated to this device 180 180 * @resource: generic resource associated with this MC object device, if any. 181 - * @driver_override: driver name to force a match 181 + * @driver_override: driver name to force a match; do not set directly, 182 + * because core frees it; use driver_set_override() to 183 + * set or clear it. 182 184 * 183 185 * Generic device object for MC object devices that are "attached" to a 184 186 * MC bus. ··· 214 212 struct fsl_mc_device_irq **irqs; 215 213 struct fsl_mc_resource *resource; 216 214 struct device_link *consumer_link; 217 - char *driver_override; 215 + const char *driver_override; 218 216 }; 219 217 220 218 #define to_fsl_mc_device(_dev) \
+5 -1
include/linux/hyperv.h
··· 1292 1292 u16 device_id; 1293 1293 1294 1294 struct device device; 1295 - char *driver_override; /* Driver name to force a match */ 1295 + /* 1296 + * Driver name to force a match. Do not set directly, because core 1297 + * frees it. Use driver_set_override() to set or clear it. 1298 + */ 1299 + const char *driver_override; 1296 1300 1297 1301 struct vmbus_channel *channel; 1298 1302 struct kset *channels_kset;
+5 -1
include/linux/pci.h
··· 512 512 u16 acs_cap; /* ACS Capability offset */ 513 513 phys_addr_t rom; /* Physical address if not from BAR */ 514 514 size_t romlen; /* Length if not from BAR */ 515 - char *driver_override; /* Driver name to force a match */ 515 + /* 516 + * Driver name to force a match. Do not set directly, because core 517 + * frees it. Use driver_set_override() to set or clear it. 518 + */ 519 + const char *driver_override; 516 520 517 521 unsigned long priv_flags; /* Private flags for the PCI driver */ 518 522
+5 -1
include/linux/platform_device.h
··· 31 31 struct resource *resource; 32 32 33 33 const struct platform_device_id *id_entry; 34 - char *driver_override; /* Driver name to force a match */ 34 + /* 35 + * Driver name to force a match. Do not set directly, because core 36 + * frees it. Use driver_set_override() to set or clear it. 37 + */ 38 + const char *driver_override; 35 39 36 40 /* MFD cell pointer */ 37 41 struct mfd_cell *mfd_cell;
+12 -2
include/linux/rpmsg.h
··· 41 41 * rpmsg_device - device that belong to the rpmsg bus 42 42 * @dev: the device struct 43 43 * @id: device id (used to match between rpmsg drivers and devices) 44 - * @driver_override: driver name to force a match 44 + * @driver_override: driver name to force a match; do not set directly, 45 + * because core frees it; use driver_set_override() to 46 + * set or clear it. 45 47 * @src: local address 46 48 * @dst: destination address 47 49 * @ept: the rpmsg endpoint of this channel ··· 53 51 struct rpmsg_device { 54 52 struct device dev; 55 53 struct rpmsg_device_id id; 56 - char *driver_override; 54 + const char *driver_override; 57 55 u32 src; 58 56 u32 dst; 59 57 struct rpmsg_endpoint *ept; ··· 165 163 166 164 #if IS_ENABLED(CONFIG_RPMSG) 167 165 166 + int rpmsg_register_device_override(struct rpmsg_device *rpdev, 167 + const char *driver_override); 168 168 int rpmsg_register_device(struct rpmsg_device *rpdev); 169 169 int rpmsg_unregister_device(struct device *parent, 170 170 struct rpmsg_channel_info *chinfo); ··· 193 189 ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept); 194 190 195 191 #else 192 + 193 + static inline int rpmsg_register_device_override(struct rpmsg_device *rpdev, 194 + const char *driver_override) 195 + { 196 + return -ENXIO; 197 + } 196 198 197 199 static inline int rpmsg_register_device(struct rpmsg_device *rpdev) 198 200 {
+2
include/linux/spi/spi.h
··· 138 138 * for driver coldplugging, and in uevents used for hotplugging 139 139 * @driver_override: If the name of a driver is written to this attribute, then 140 140 * the device will bind to the named driver and only the named driver. 141 + * Do not set directly, because core frees it; use driver_set_override() to 142 + * set or clear it. 141 143 * @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when 142 144 * not using a GPIO line) 143 145 * @word_delay: delay to be inserted between consecutive
+3 -1
include/linux/vdpa.h
··· 64 64 * struct vdpa_device - representation of a vDPA device 65 65 * @dev: underlying device 66 66 * @dma_dev: the actual device that is performing DMA 67 - * @driver_override: driver name to force a match 67 + * @driver_override: driver name to force a match; do not set directly, 68 + * because core frees it; use driver_set_override() to 69 + * set or clear it. 68 70 * @config: the configuration ops for this device. 69 71 * @cf_lock: Protects get and set access to configuration layout. 70 72 * @index: device index
+29
include/trace/events/thermal_pressure.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #undef TRACE_SYSTEM 3 + #define TRACE_SYSTEM thermal_pressure 4 + 5 + #if !defined(_TRACE_THERMAL_PRESSURE_H) || defined(TRACE_HEADER_MULTI_READ) 6 + #define _TRACE_THERMAL_PRESSURE_H 7 + 8 + #include <linux/tracepoint.h> 9 + 10 + TRACE_EVENT(thermal_pressure_update, 11 + TP_PROTO(int cpu, unsigned long thermal_pressure), 12 + TP_ARGS(cpu, thermal_pressure), 13 + 14 + TP_STRUCT__entry( 15 + __field(unsigned long, thermal_pressure) 16 + __field(int, cpu) 17 + ), 18 + 19 + TP_fast_assign( 20 + __entry->thermal_pressure = thermal_pressure; 21 + __entry->cpu = cpu; 22 + ), 23 + 24 + TP_printk("cpu=%d thermal_pressure=%lu", __entry->cpu, __entry->thermal_pressure) 25 + ); 26 + #endif /* _TRACE_THERMAL_PRESSURE_H */ 27 + 28 + /* This part must be outside protection */ 29 + #include <trace/define_trace.h>
+381
lib/test_firmware.c
··· 31 31 #define TEST_FIRMWARE_NAME "test-firmware.bin" 32 32 #define TEST_FIRMWARE_NUM_REQS 4 33 33 #define TEST_FIRMWARE_BUF_SIZE SZ_1K 34 + #define TEST_UPLOAD_MAX_SIZE SZ_2K 35 + #define TEST_UPLOAD_BLK_SIZE 37 /* Avoid powers of two in testing */ 34 36 35 37 static DEFINE_MUTEX(test_fw_mutex); 36 38 static const struct firmware *test_firmware; 39 + static LIST_HEAD(test_upload_list); 37 40 38 41 struct test_batched_req { 39 42 u8 idx; ··· 66 63 * @reqs: stores all requests information 67 64 * @read_fw_idx: index of thread from which we want to read firmware results 68 65 * from through the read_fw trigger. 66 + * @upload_name: firmware name to be used with upload_read sysfs node 69 67 * @test_result: a test may use this to collect the result from the call 70 68 * of the request_firmware*() calls used in their tests. In order of 71 69 * priority we always keep first any setup error. If no setup errors were ··· 105 101 bool send_uevent; 106 102 u8 num_requests; 107 103 u8 read_fw_idx; 104 + char *upload_name; 108 105 109 106 /* 110 107 * These below don't belong her but we'll move them once we create ··· 117 112 struct device *device); 118 113 }; 119 114 115 + struct upload_inject_err { 116 + const char *prog; 117 + enum fw_upload_err err_code; 118 + }; 119 + 120 + struct test_firmware_upload { 121 + char *name; 122 + struct list_head node; 123 + char *buf; 124 + size_t size; 125 + bool cancel_request; 126 + struct upload_inject_err inject; 127 + struct fw_upload *fwl; 128 + }; 129 + 120 130 static struct test_config *test_fw_config; 131 + 132 + static struct test_firmware_upload *upload_lookup_name(const char *name) 133 + { 134 + struct test_firmware_upload *tst; 135 + 136 + list_for_each_entry(tst, &test_upload_list, node) 137 + if (strncmp(name, tst->name, strlen(tst->name)) == 0) 138 + return tst; 139 + 140 + return NULL; 141 + } 121 142 122 143 static ssize_t test_fw_misc_read(struct file *f, char __user *buf, 123 144 size_t size, loff_t *offset) ··· 229 198 test_fw_config->req_firmware = request_firmware; 230 199 test_fw_config->test_result = 0; 231 200 test_fw_config->reqs = NULL; 201 + test_fw_config->upload_name = NULL; 232 202 233 203 return 0; 234 204 ··· 309 277 test_fw_config->sync_direct ? "true" : "false"); 310 278 len += scnprintf(buf + len, PAGE_SIZE - len, 311 279 "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx); 280 + if (test_fw_config->upload_name) 281 + len += scnprintf(buf + len, PAGE_SIZE - len, 282 + "upload_name:\t%s\n", 283 + test_fw_config->upload_name); 284 + else 285 + len += scnprintf(buf + len, PAGE_SIZE - len, 286 + "upload_name:\tEMTPY\n"); 312 287 313 288 mutex_unlock(&test_fw_mutex); 314 289 ··· 430 391 return config_test_show_str(buf, test_fw_config->name); 431 392 } 432 393 static DEVICE_ATTR_RW(config_name); 394 + 395 + static ssize_t config_upload_name_store(struct device *dev, 396 + struct device_attribute *attr, 397 + const char *buf, size_t count) 398 + { 399 + struct test_firmware_upload *tst; 400 + int ret = count; 401 + 402 + mutex_lock(&test_fw_mutex); 403 + tst = upload_lookup_name(buf); 404 + if (tst) 405 + test_fw_config->upload_name = tst->name; 406 + else 407 + ret = -EINVAL; 408 + mutex_unlock(&test_fw_mutex); 409 + 410 + return ret; 411 + } 412 + 413 + static ssize_t config_upload_name_show(struct device *dev, 414 + struct device_attribute *attr, 415 + char *buf) 416 + { 417 + return config_test_show_str(buf, test_fw_config->upload_name); 418 + } 419 + static DEVICE_ATTR_RW(config_upload_name); 433 420 434 421 static ssize_t config_num_requests_store(struct device *dev, 435 422 struct device_attribute *attr, ··· 1054 989 } 1055 990 static DEVICE_ATTR_WO(trigger_batched_requests_async); 1056 991 992 + static void upload_release(struct test_firmware_upload *tst) 993 + { 994 + firmware_upload_unregister(tst->fwl); 995 + kfree(tst->buf); 996 + kfree(tst->name); 997 + kfree(tst); 998 + } 999 + 1000 + static void upload_release_all(void) 1001 + { 1002 + struct test_firmware_upload *tst, *tmp; 1003 + 1004 + list_for_each_entry_safe(tst, tmp, &test_upload_list, node) { 1005 + list_del(&tst->node); 1006 + upload_release(tst); 1007 + } 1008 + test_fw_config->upload_name = NULL; 1009 + } 1010 + 1011 + /* 1012 + * This table is replicated from .../firmware_loader/sysfs_upload.c 1013 + * and needs to be kept in sync. 1014 + */ 1015 + static const char * const fw_upload_err_str[] = { 1016 + [FW_UPLOAD_ERR_NONE] = "none", 1017 + [FW_UPLOAD_ERR_HW_ERROR] = "hw-error", 1018 + [FW_UPLOAD_ERR_TIMEOUT] = "timeout", 1019 + [FW_UPLOAD_ERR_CANCELED] = "user-abort", 1020 + [FW_UPLOAD_ERR_BUSY] = "device-busy", 1021 + [FW_UPLOAD_ERR_INVALID_SIZE] = "invalid-file-size", 1022 + [FW_UPLOAD_ERR_RW_ERROR] = "read-write-error", 1023 + [FW_UPLOAD_ERR_WEAROUT] = "flash-wearout", 1024 + }; 1025 + 1026 + static void upload_err_inject_error(struct test_firmware_upload *tst, 1027 + const u8 *p, const char *prog) 1028 + { 1029 + enum fw_upload_err err; 1030 + 1031 + for (err = FW_UPLOAD_ERR_NONE + 1; err < FW_UPLOAD_ERR_MAX; err++) { 1032 + if (strncmp(p, fw_upload_err_str[err], 1033 + strlen(fw_upload_err_str[err])) == 0) { 1034 + tst->inject.prog = prog; 1035 + tst->inject.err_code = err; 1036 + return; 1037 + } 1038 + } 1039 + } 1040 + 1041 + static void upload_err_inject_prog(struct test_firmware_upload *tst, 1042 + const u8 *p) 1043 + { 1044 + static const char * const progs[] = { 1045 + "preparing:", "transferring:", "programming:" 1046 + }; 1047 + int i; 1048 + 1049 + for (i = 0; i < ARRAY_SIZE(progs); i++) { 1050 + if (strncmp(p, progs[i], strlen(progs[i])) == 0) { 1051 + upload_err_inject_error(tst, p + strlen(progs[i]), 1052 + progs[i]); 1053 + return; 1054 + } 1055 + } 1056 + } 1057 + 1058 + #define FIVE_MINUTES_MS (5 * 60 * 1000) 1059 + static enum fw_upload_err 1060 + fw_upload_wait_on_cancel(struct test_firmware_upload *tst) 1061 + { 1062 + int ms_delay; 1063 + 1064 + for (ms_delay = 0; ms_delay < FIVE_MINUTES_MS; ms_delay += 100) { 1065 + msleep(100); 1066 + if (tst->cancel_request) 1067 + return FW_UPLOAD_ERR_CANCELED; 1068 + } 1069 + return FW_UPLOAD_ERR_NONE; 1070 + } 1071 + 1072 + static enum fw_upload_err test_fw_upload_prepare(struct fw_upload *fwl, 1073 + const u8 *data, u32 size) 1074 + { 1075 + struct test_firmware_upload *tst = fwl->dd_handle; 1076 + enum fw_upload_err ret = FW_UPLOAD_ERR_NONE; 1077 + const char *progress = "preparing:"; 1078 + 1079 + tst->cancel_request = false; 1080 + 1081 + if (!size || size > TEST_UPLOAD_MAX_SIZE) { 1082 + ret = FW_UPLOAD_ERR_INVALID_SIZE; 1083 + goto err_out; 1084 + } 1085 + 1086 + if (strncmp(data, "inject:", strlen("inject:")) == 0) 1087 + upload_err_inject_prog(tst, data + strlen("inject:")); 1088 + 1089 + memset(tst->buf, 0, TEST_UPLOAD_MAX_SIZE); 1090 + tst->size = size; 1091 + 1092 + if (tst->inject.err_code == FW_UPLOAD_ERR_NONE || 1093 + strncmp(tst->inject.prog, progress, strlen(progress)) != 0) 1094 + return FW_UPLOAD_ERR_NONE; 1095 + 1096 + if (tst->inject.err_code == FW_UPLOAD_ERR_CANCELED) 1097 + ret = fw_upload_wait_on_cancel(tst); 1098 + else 1099 + ret = tst->inject.err_code; 1100 + 1101 + err_out: 1102 + /* 1103 + * The cleanup op only executes if the prepare op succeeds. 1104 + * If the prepare op fails, it must do it's own clean-up. 1105 + */ 1106 + tst->inject.err_code = FW_UPLOAD_ERR_NONE; 1107 + tst->inject.prog = NULL; 1108 + 1109 + return ret; 1110 + } 1111 + 1112 + static enum fw_upload_err test_fw_upload_write(struct fw_upload *fwl, 1113 + const u8 *data, u32 offset, 1114 + u32 size, u32 *written) 1115 + { 1116 + struct test_firmware_upload *tst = fwl->dd_handle; 1117 + const char *progress = "transferring:"; 1118 + u32 blk_size; 1119 + 1120 + if (tst->cancel_request) 1121 + return FW_UPLOAD_ERR_CANCELED; 1122 + 1123 + blk_size = min_t(u32, TEST_UPLOAD_BLK_SIZE, size); 1124 + memcpy(tst->buf + offset, data + offset, blk_size); 1125 + 1126 + *written = blk_size; 1127 + 1128 + if (tst->inject.err_code == FW_UPLOAD_ERR_NONE || 1129 + strncmp(tst->inject.prog, progress, strlen(progress)) != 0) 1130 + return FW_UPLOAD_ERR_NONE; 1131 + 1132 + if (tst->inject.err_code == FW_UPLOAD_ERR_CANCELED) 1133 + return fw_upload_wait_on_cancel(tst); 1134 + 1135 + return tst->inject.err_code; 1136 + } 1137 + 1138 + static enum fw_upload_err test_fw_upload_complete(struct fw_upload *fwl) 1139 + { 1140 + struct test_firmware_upload *tst = fwl->dd_handle; 1141 + const char *progress = "programming:"; 1142 + 1143 + if (tst->cancel_request) 1144 + return FW_UPLOAD_ERR_CANCELED; 1145 + 1146 + if (tst->inject.err_code == FW_UPLOAD_ERR_NONE || 1147 + strncmp(tst->inject.prog, progress, strlen(progress)) != 0) 1148 + return FW_UPLOAD_ERR_NONE; 1149 + 1150 + if (tst->inject.err_code == FW_UPLOAD_ERR_CANCELED) 1151 + return fw_upload_wait_on_cancel(tst); 1152 + 1153 + return tst->inject.err_code; 1154 + } 1155 + 1156 + static void test_fw_upload_cancel(struct fw_upload *fwl) 1157 + { 1158 + struct test_firmware_upload *tst = fwl->dd_handle; 1159 + 1160 + tst->cancel_request = true; 1161 + } 1162 + 1163 + static void test_fw_cleanup(struct fw_upload *fwl) 1164 + { 1165 + struct test_firmware_upload *tst = fwl->dd_handle; 1166 + 1167 + tst->inject.err_code = FW_UPLOAD_ERR_NONE; 1168 + tst->inject.prog = NULL; 1169 + } 1170 + 1171 + static const struct fw_upload_ops upload_test_ops = { 1172 + .prepare = test_fw_upload_prepare, 1173 + .write = test_fw_upload_write, 1174 + .poll_complete = test_fw_upload_complete, 1175 + .cancel = test_fw_upload_cancel, 1176 + .cleanup = test_fw_cleanup 1177 + }; 1178 + 1179 + static ssize_t upload_register_store(struct device *dev, 1180 + struct device_attribute *attr, 1181 + const char *buf, size_t count) 1182 + { 1183 + struct test_firmware_upload *tst; 1184 + struct fw_upload *fwl; 1185 + char *name; 1186 + int ret; 1187 + 1188 + name = kstrndup(buf, count, GFP_KERNEL); 1189 + if (!name) 1190 + return -ENOMEM; 1191 + 1192 + mutex_lock(&test_fw_mutex); 1193 + tst = upload_lookup_name(name); 1194 + if (tst) { 1195 + ret = -EEXIST; 1196 + goto free_name; 1197 + } 1198 + 1199 + tst = kzalloc(sizeof(*tst), GFP_KERNEL); 1200 + if (!tst) { 1201 + ret = -ENOMEM; 1202 + goto free_name; 1203 + } 1204 + 1205 + tst->name = name; 1206 + tst->buf = kzalloc(TEST_UPLOAD_MAX_SIZE, GFP_KERNEL); 1207 + if (!tst->buf) { 1208 + ret = -ENOMEM; 1209 + goto free_tst; 1210 + } 1211 + 1212 + fwl = firmware_upload_register(THIS_MODULE, dev, tst->name, 1213 + &upload_test_ops, tst); 1214 + if (IS_ERR(fwl)) { 1215 + ret = PTR_ERR(fwl); 1216 + goto free_buf; 1217 + } 1218 + 1219 + tst->fwl = fwl; 1220 + list_add_tail(&tst->node, &test_upload_list); 1221 + mutex_unlock(&test_fw_mutex); 1222 + return count; 1223 + 1224 + free_buf: 1225 + kfree(tst->buf); 1226 + 1227 + free_tst: 1228 + kfree(tst); 1229 + 1230 + free_name: 1231 + mutex_unlock(&test_fw_mutex); 1232 + kfree(name); 1233 + 1234 + return ret; 1235 + } 1236 + static DEVICE_ATTR_WO(upload_register); 1237 + 1238 + static ssize_t upload_unregister_store(struct device *dev, 1239 + struct device_attribute *attr, 1240 + const char *buf, size_t count) 1241 + { 1242 + struct test_firmware_upload *tst; 1243 + int ret = count; 1244 + 1245 + mutex_lock(&test_fw_mutex); 1246 + tst = upload_lookup_name(buf); 1247 + if (!tst) { 1248 + ret = -EINVAL; 1249 + goto out; 1250 + } 1251 + 1252 + if (test_fw_config->upload_name == tst->name) 1253 + test_fw_config->upload_name = NULL; 1254 + 1255 + list_del(&tst->node); 1256 + upload_release(tst); 1257 + 1258 + out: 1259 + mutex_unlock(&test_fw_mutex); 1260 + return ret; 1261 + } 1262 + static DEVICE_ATTR_WO(upload_unregister); 1263 + 1057 1264 static ssize_t test_result_show(struct device *dev, 1058 1265 struct device_attribute *attr, 1059 1266 char *buf) ··· 1388 1051 } 1389 1052 static DEVICE_ATTR_RO(read_firmware); 1390 1053 1054 + static ssize_t upload_read_show(struct device *dev, 1055 + struct device_attribute *attr, 1056 + char *buf) 1057 + { 1058 + struct test_firmware_upload *tst = NULL; 1059 + struct test_firmware_upload *tst_iter; 1060 + int ret = -EINVAL; 1061 + 1062 + if (!test_fw_config->upload_name) { 1063 + pr_err("Set config_upload_name before using upload_read\n"); 1064 + return -EINVAL; 1065 + } 1066 + 1067 + mutex_lock(&test_fw_mutex); 1068 + list_for_each_entry(tst_iter, &test_upload_list, node) 1069 + if (tst_iter->name == test_fw_config->upload_name) { 1070 + tst = tst_iter; 1071 + break; 1072 + } 1073 + 1074 + if (!tst) { 1075 + pr_err("Firmware name not found: %s\n", 1076 + test_fw_config->upload_name); 1077 + goto out; 1078 + } 1079 + 1080 + if (tst->size > PAGE_SIZE) { 1081 + pr_err("Testing interface must use PAGE_SIZE firmware for now\n"); 1082 + goto out; 1083 + } 1084 + 1085 + memcpy(buf, tst->buf, tst->size); 1086 + ret = tst->size; 1087 + out: 1088 + mutex_unlock(&test_fw_mutex); 1089 + return ret; 1090 + } 1091 + static DEVICE_ATTR_RO(upload_read); 1092 + 1391 1093 #define TEST_FW_DEV_ATTR(name) &dev_attr_##name.attr 1392 1094 1393 1095 static struct attribute *test_dev_attrs[] = { ··· 1442 1066 TEST_FW_DEV_ATTR(config_sync_direct), 1443 1067 TEST_FW_DEV_ATTR(config_send_uevent), 1444 1068 TEST_FW_DEV_ATTR(config_read_fw_idx), 1069 + TEST_FW_DEV_ATTR(config_upload_name), 1445 1070 1446 1071 /* These don't use the config at all - they could be ported! */ 1447 1072 TEST_FW_DEV_ATTR(trigger_request), ··· 1459 1082 TEST_FW_DEV_ATTR(release_all_firmware), 1460 1083 TEST_FW_DEV_ATTR(test_result), 1461 1084 TEST_FW_DEV_ATTR(read_firmware), 1085 + TEST_FW_DEV_ATTR(upload_read), 1086 + TEST_FW_DEV_ATTR(upload_register), 1087 + TEST_FW_DEV_ATTR(upload_unregister), 1462 1088 NULL, 1463 1089 }; 1464 1090 ··· 1508 1128 mutex_lock(&test_fw_mutex); 1509 1129 release_firmware(test_firmware); 1510 1130 misc_deregister(&test_fw_misc_device); 1131 + upload_release_all(); 1511 1132 __test_firmware_config_free(); 1512 1133 kfree(test_fw_config); 1513 1134 mutex_unlock(&test_fw_mutex);
+2 -2
scripts/get_abi.pl
··· 981 981 982 982 =head1 NAME 983 983 984 - abi_book.pl - parse the Linux ABI files and produce a ReST book. 984 + get_abi.pl - parse the Linux ABI files and produce a ReST book. 985 985 986 986 =head1 SYNOPSIS 987 987 988 - B<abi_book.pl> [--debug <level>] [--enable-lineno] [--man] [--help] 988 + B<get_abi.pl> [--debug <level>] [--enable-lineno] [--man] [--help] 989 989 [--(no-)rst-source] [--dir=<dir>] [--show-hints] 990 990 [--search-string <regex>] 991 991 <COMMAND> [<ARGUMENT>]
+1 -1
tools/testing/selftests/firmware/Makefile
··· 4 4 -O2 5 5 6 6 TEST_PROGS := fw_run_tests.sh 7 - TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_lib.sh 7 + TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_upload.sh fw_lib.sh 8 8 TEST_GEN_FILES := fw_namespace 9 9 10 10 include ../lib.mk
+1
tools/testing/selftests/firmware/config
··· 3 3 CONFIG_FW_LOADER_USER_HELPER=y 4 4 CONFIG_IKCONFIG=y 5 5 CONFIG_IKCONFIG_PROC=y 6 + CONFIG_FW_UPLOAD=y
+78 -84
tools/testing/selftests/firmware/fw_filesystem.sh
··· 11 11 TEST_DIR=$(dirname $0) 12 12 source $TEST_DIR/fw_lib.sh 13 13 14 + RUN_XZ="xz -C crc32 --lzma2=dict=2MiB" 15 + RUN_ZSTD="zstd -q" 16 + 14 17 check_mods 15 18 check_setup 16 19 verify_reqs ··· 214 211 else 215 212 fwfile="$FW" 216 213 fi 217 - if [ "$1" = "xzonly" ]; then 214 + if [ "$1" = "componly" ]; then 218 215 fwfile="${fwfile}-orig" 219 216 fi 220 217 for i in $(seq 0 3); do ··· 238 235 fwfile="${FW}" 239 236 fi 240 237 241 - if [ "$1" = "xzonly" ]; then 238 + if [ "$1" = "componly" ]; then 242 239 fwfile="${fwfile}-orig" 243 240 fi 244 241 ··· 412 409 config_unset_uevent 413 410 RANDOM_FILE_PATH=$(setup_random_file) 414 411 RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" 415 - if [ "$2" = "both" ]; then 416 - xz -9 -C crc32 -k $RANDOM_FILE_PATH 417 - elif [ "$2" = "xzonly" ]; then 418 - xz -9 -C crc32 $RANDOM_FILE_PATH 412 + if [ -n "$2" -a "$2" != "normal" ]; then 413 + compress_"$2"_"$COMPRESS_FORMAT" $RANDOM_FILE_PATH 419 414 fi 420 415 config_set_name $RANDOM_FILE 421 416 config_trigger_async ··· 436 435 echo "OK" 437 436 } 438 437 438 + do_tests () 439 + { 440 + mode="$1" 441 + suffix="$2" 442 + 443 + for i in $(seq 1 5); do 444 + test_batched_request_firmware$suffix $i $mode 445 + done 446 + 447 + for i in $(seq 1 5); do 448 + test_batched_request_firmware_into_buf$suffix $i $mode 449 + done 450 + 451 + for i in $(seq 1 5); do 452 + test_batched_request_firmware_direct$suffix $i $mode 453 + done 454 + 455 + for i in $(seq 1 5); do 456 + test_request_firmware_nowait_uevent$suffix $i $mode 457 + done 458 + 459 + for i in $(seq 1 5); do 460 + test_request_firmware_nowait_custom$suffix $i $mode 461 + done 462 + } 463 + 439 464 # Only continue if batched request triggers are present on the 440 465 # test-firmware driver 441 466 test_config_present ··· 469 442 # test with the file present 470 443 echo 471 444 echo "Testing with the file present..." 472 - for i in $(seq 1 5); do 473 - test_batched_request_firmware $i normal 474 - done 475 - 476 - for i in $(seq 1 5); do 477 - test_batched_request_firmware_into_buf $i normal 478 - done 479 - 480 - for i in $(seq 1 5); do 481 - test_batched_request_firmware_direct $i normal 482 - done 483 - 484 - for i in $(seq 1 5); do 485 - test_request_firmware_nowait_uevent $i normal 486 - done 487 - 488 - for i in $(seq 1 5); do 489 - test_request_firmware_nowait_custom $i normal 490 - done 445 + do_tests normal 491 446 492 447 # Partial loads cannot use fallback, so do not repeat tests. 493 448 test_request_partial_firmware_into_buf 0 10 ··· 481 472 # a hung task, which would require a hard reset. 482 473 echo 483 474 echo "Testing with the file missing..." 484 - for i in $(seq 1 5); do 485 - test_batched_request_firmware_nofile $i 486 - done 487 - 488 - for i in $(seq 1 5); do 489 - test_batched_request_firmware_into_buf_nofile $i 490 - done 491 - 492 - for i in $(seq 1 5); do 493 - test_batched_request_firmware_direct_nofile $i 494 - done 495 - 496 - for i in $(seq 1 5); do 497 - test_request_firmware_nowait_uevent_nofile $i 498 - done 499 - 500 - for i in $(seq 1 5); do 501 - test_request_firmware_nowait_custom_nofile $i 502 - done 475 + do_tests nofile _nofile 503 476 504 477 # Partial loads cannot use fallback, so do not repeat tests. 505 478 test_request_partial_firmware_into_buf_nofile 0 10 ··· 489 498 test_request_partial_firmware_into_buf_nofile 1 6 490 499 test_request_partial_firmware_into_buf_nofile 2 10 491 500 492 - test "$HAS_FW_LOADER_COMPRESS" != "yes" && exit 0 501 + test_request_firmware_compressed () 502 + { 503 + export COMPRESS_FORMAT="$1" 493 504 494 - # test with both files present 495 - xz -9 -C crc32 -k $FW 496 - config_set_name $NAME 497 - echo 498 - echo "Testing with both plain and xz files present..." 499 - for i in $(seq 1 5); do 500 - test_batched_request_firmware $i both 501 - done 505 + # test with both files present 506 + compress_both_"$COMPRESS_FORMAT" $FW 507 + compress_both_"$COMPRESS_FORMAT" $FW_INTO_BUF 502 508 503 - for i in $(seq 1 5); do 504 - test_batched_request_firmware_into_buf $i both 505 - done 509 + config_set_name $NAME 510 + echo 511 + echo "Testing with both plain and $COMPRESS_FORMAT files present..." 512 + do_tests both 506 513 507 - for i in $(seq 1 5); do 508 - test_batched_request_firmware_direct $i both 509 - done 514 + # test with only compressed file present 515 + mv "$FW" "${FW}-orig" 516 + mv "$FW_INTO_BUF" "${FW_INTO_BUF}-orig" 510 517 511 - for i in $(seq 1 5); do 512 - test_request_firmware_nowait_uevent $i both 513 - done 518 + config_set_name $NAME 519 + echo 520 + echo "Testing with only $COMPRESS_FORMAT file present..." 521 + do_tests componly 514 522 515 - for i in $(seq 1 5); do 516 - test_request_firmware_nowait_custom $i both 517 - done 523 + mv "${FW}-orig" "$FW" 524 + mv "${FW_INTO_BUF}-orig" "$FW_INTO_BUF" 525 + } 518 526 519 - # test with only xz file present 520 - mv "$FW" "${FW}-orig" 521 - echo 522 - echo "Testing with only xz file present..." 523 - for i in $(seq 1 5); do 524 - test_batched_request_firmware $i xzonly 525 - done 527 + compress_both_XZ () 528 + { 529 + $RUN_XZ -k "$@" 530 + } 526 531 527 - for i in $(seq 1 5); do 528 - test_batched_request_firmware_into_buf $i xzonly 529 - done 532 + compress_componly_XZ () 533 + { 534 + $RUN_XZ "$@" 535 + } 530 536 531 - for i in $(seq 1 5); do 532 - test_batched_request_firmware_direct $i xzonly 533 - done 537 + compress_both_ZSTD () 538 + { 539 + $RUN_ZSTD -k "$@" 540 + } 534 541 535 - for i in $(seq 1 5); do 536 - test_request_firmware_nowait_uevent $i xzonly 537 - done 542 + compress_componly_ZSTD () 543 + { 544 + $RUN_ZSTD --rm "$@" 545 + } 538 546 539 - for i in $(seq 1 5); do 540 - test_request_firmware_nowait_custom $i xzonly 541 - done 547 + if test "$HAS_FW_LOADER_COMPRESS_XZ" = "yes"; then 548 + test_request_firmware_compressed XZ 549 + fi 550 + 551 + if test "$HAS_FW_LOADER_COMPRESS_ZSTD" = "yes"; then 552 + test_request_firmware_compressed ZSTD 553 + fi 542 554 543 555 exit 0
+16 -3
tools/testing/selftests/firmware/fw_lib.sh
··· 62 62 { 63 63 HAS_FW_LOADER_USER_HELPER="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y)" 64 64 HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)" 65 - HAS_FW_LOADER_COMPRESS="$(kconfig_has CONFIG_FW_LOADER_COMPRESS=y)" 65 + HAS_FW_LOADER_COMPRESS_XZ="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_XZ=y)" 66 + HAS_FW_LOADER_COMPRESS_ZSTD="$(kconfig_has CONFIG_FW_LOADER_COMPRESS_ZSTD=y)" 67 + HAS_FW_UPLOAD="$(kconfig_has CONFIG_FW_UPLOAD=y)" 66 68 PROC_FW_IGNORE_SYSFS_FALLBACK="0" 67 69 PROC_FW_FORCE_SYSFS_FALLBACK="0" 68 70 ··· 100 98 101 99 OLD_FWPATH="$(cat /sys/module/firmware_class/parameters/path)" 102 100 103 - if [ "$HAS_FW_LOADER_COMPRESS" = "yes" ]; then 101 + if [ "$HAS_FW_LOADER_COMPRESS_XZ" = "yes" ]; then 104 102 if ! which xz 2> /dev/null > /dev/null; then 105 - HAS_FW_LOADER_COMPRESS="" 103 + HAS_FW_LOADER_COMPRESS_XZ="" 104 + fi 105 + fi 106 + if [ "$HAS_FW_LOADER_COMPRESS_ZSTD" = "yes" ]; then 107 + if ! which zstd 2> /dev/null > /dev/null; then 108 + HAS_FW_LOADER_COMPRESS_ZSTD="" 106 109 fi 107 110 fi 108 111 } ··· 117 110 if [ "$TEST_REQS_FW_SYSFS_FALLBACK" = "yes" ]; then 118 111 if [ ! "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then 119 112 echo "usermode helper disabled so ignoring test" 113 + exit 0 114 + fi 115 + fi 116 + if [ "$TEST_REQS_FW_UPLOAD" = "yes" ]; then 117 + if [ ! "$HAS_FW_UPLOAD" = "yes" ]; then 118 + echo "firmware upload disabled so ignoring test" 120 119 exit 0 121 120 fi 122 121 fi
+4
tools/testing/selftests/firmware/fw_run_tests.sh
··· 22 22 proc_set_force_sysfs_fallback $1 23 23 proc_set_ignore_sysfs_fallback $2 24 24 $TEST_DIR/fw_fallback.sh 25 + 26 + proc_set_force_sysfs_fallback $1 27 + proc_set_ignore_sysfs_fallback $2 28 + $TEST_DIR/fw_upload.sh 25 29 } 26 30 27 31 run_test_config_0001()
+214
tools/testing/selftests/firmware/fw_upload.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # This validates the user-initiated fw upload mechanism of the firmware 4 + # loader. It verifies that one or more firmware devices can be created 5 + # for a device driver. It also verifies the data transfer, the 6 + # cancellation support, and the error flows. 7 + set -e 8 + 9 + TEST_REQS_FW_UPLOAD="yes" 10 + TEST_DIR=$(dirname $0) 11 + 12 + progress_states="preparing transferring programming" 13 + errors="hw-error 14 + timeout 15 + device-busy 16 + invalid-file-size 17 + read-write-error 18 + flash-wearout" 19 + error_abort="user-abort" 20 + fwname1=fw1 21 + fwname2=fw2 22 + fwname3=fw3 23 + 24 + source $TEST_DIR/fw_lib.sh 25 + 26 + check_mods 27 + check_setup 28 + verify_reqs 29 + 30 + trap "upload_finish" EXIT 31 + 32 + upload_finish() { 33 + local fwdevs="$fwname1 $fwname2 $fwname3" 34 + 35 + for name in $fwdevs; do 36 + if [ -e "$DIR/$name" ]; then 37 + echo -n "$name" > "$DIR"/upload_unregister 38 + fi 39 + done 40 + } 41 + 42 + upload_fw() { 43 + local name="$1" 44 + local file="$2" 45 + 46 + echo 1 > "$DIR"/"$name"/loading 47 + cat "$file" > "$DIR"/"$name"/data 48 + echo 0 > "$DIR"/"$name"/loading 49 + } 50 + 51 + verify_fw() { 52 + local name="$1" 53 + local file="$2" 54 + 55 + echo -n "$name" > "$DIR"/config_upload_name 56 + if ! cmp "$file" "$DIR"/upload_read > /dev/null 2>&1; then 57 + echo "$0: firmware compare for $name did not match" >&2 58 + exit 1 59 + fi 60 + 61 + echo "$0: firmware upload for $name works" >&2 62 + return 0 63 + } 64 + 65 + inject_error() { 66 + local name="$1" 67 + local status="$2" 68 + local error="$3" 69 + 70 + echo 1 > "$DIR"/"$name"/loading 71 + echo -n "inject":"$status":"$error" > "$DIR"/"$name"/data 72 + echo 0 > "$DIR"/"$name"/loading 73 + } 74 + 75 + await_status() { 76 + local name="$1" 77 + local expected="$2" 78 + local status 79 + local i 80 + 81 + let i=0 82 + while [ $i -lt 50 ]; do 83 + status=$(cat "$DIR"/"$name"/status) 84 + if [ "$status" = "$expected" ]; then 85 + return 0; 86 + fi 87 + sleep 1e-03 88 + let i=$i+1 89 + done 90 + 91 + echo "$0: Invalid status: Expected $expected, Actual $status" >&2 92 + return 1; 93 + } 94 + 95 + await_idle() { 96 + local name="$1" 97 + 98 + await_status "$name" "idle" 99 + return $? 100 + } 101 + 102 + expect_error() { 103 + local name="$1" 104 + local expected="$2" 105 + local error=$(cat "$DIR"/"$name"/error) 106 + 107 + if [ "$error" != "$expected" ]; then 108 + echo "Invalid error: Expected $expected, Actual $error" >&2 109 + return 1 110 + fi 111 + 112 + return 0 113 + } 114 + 115 + random_firmware() { 116 + local bs="$1" 117 + local count="$2" 118 + local file=$(mktemp -p /tmp uploadfwXXX.bin) 119 + 120 + dd if=/dev/urandom of="$file" bs="$bs" count="$count" > /dev/null 2>&1 121 + echo "$file" 122 + } 123 + 124 + test_upload_cancel() { 125 + local name="$1" 126 + local status 127 + 128 + for status in $progress_states; do 129 + inject_error $name $status $error_abort 130 + if ! await_status $name $status; then 131 + exit 1 132 + fi 133 + 134 + echo 1 > "$DIR"/"$name"/cancel 135 + 136 + if ! await_idle $name; then 137 + exit 1 138 + fi 139 + 140 + if ! expect_error $name "$status":"$error_abort"; then 141 + exit 1 142 + fi 143 + done 144 + 145 + echo "$0: firmware upload cancellation works" 146 + return 0 147 + } 148 + 149 + test_error_handling() { 150 + local name=$1 151 + local status 152 + local error 153 + 154 + for status in $progress_states; do 155 + for error in $errors; do 156 + inject_error $name $status $error 157 + 158 + if ! await_idle $name; then 159 + exit 1 160 + fi 161 + 162 + if ! expect_error $name "$status":"$error"; then 163 + exit 1 164 + fi 165 + 166 + done 167 + done 168 + echo "$0: firmware upload error handling works" 169 + } 170 + 171 + test_fw_too_big() { 172 + local name=$1 173 + local fw_too_big=`random_firmware 512 5` 174 + local expected="preparing:invalid-file-size" 175 + 176 + upload_fw $name $fw_too_big 177 + rm -f $fw_too_big 178 + 179 + if ! await_idle $name; then 180 + exit 1 181 + fi 182 + 183 + if ! expect_error $name $expected; then 184 + exit 1 185 + fi 186 + 187 + echo "$0: oversized firmware error handling works" 188 + } 189 + 190 + echo -n "$fwname1" > "$DIR"/upload_register 191 + echo -n "$fwname2" > "$DIR"/upload_register 192 + echo -n "$fwname3" > "$DIR"/upload_register 193 + 194 + test_upload_cancel $fwname1 195 + test_error_handling $fwname1 196 + test_fw_too_big $fwname1 197 + 198 + fw_file1=`random_firmware 512 4` 199 + fw_file2=`random_firmware 512 3` 200 + fw_file3=`random_firmware 512 2` 201 + 202 + upload_fw $fwname1 $fw_file1 203 + upload_fw $fwname2 $fw_file2 204 + upload_fw $fwname3 $fw_file3 205 + 206 + verify_fw ${fwname1} ${fw_file1} 207 + verify_fw ${fwname2} ${fw_file2} 208 + verify_fw ${fwname3} ${fw_file3} 209 + 210 + echo -n "$fwname1" > "$DIR"/upload_unregister 211 + echo -n "$fwname2" > "$DIR"/upload_unregister 212 + echo -n "$fwname3" > "$DIR"/upload_unregister 213 + 214 + exit 0