Commit 59838093 authored by Linus Torvalds's avatar Linus Torvalds

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

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

  Nothing huge in here, just lots of little firmware core changes and
  use of new apis, a libfs fix, a debugfs api change, and some driver
  core deferred probe rework.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'driver-core-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (44 commits)
  Revert "driver core: Set fw_devlink to "permissive" behavior by default"
  driver core: Set fw_devlink to "permissive" behavior by default
  driver core: Replace open-coded list_last_entry()
  driver core: Read atomic counter once in driver_probe_done()
  libfs: fix infoleak in simple_attr_read()
  driver core: Add device links from fwnode only for the primary device
  platform/x86: touchscreen_dmi: Add info for the Chuwi Vi8 Plus tablet
  platform/x86: touchscreen_dmi: Add EFI embedded firmware info support
  Input: icn8505 - Switch to firmware_request_platform for retreiving the fw
  Input: silead - Switch to firmware_request_platform for retreiving the fw
  selftests: firmware: Add firmware_request_platform tests
  test_firmware: add support for firmware_request_platform
  firmware: Add new platform fallback mechanism and firmware_request_platform()
  Revert "drivers: base: power: wakeup.c: Use built-in RCU list checking"
  drivers: base: power: wakeup.c: Use built-in RCU list checking
  component: allow missing unbind callback
  debugfs: remove return value of debugfs_create_file_size()
  debugfs: Check module state before warning in {full/open}_proxy_open()
  firmware: fix a double abort case with fw_load_sysfs_fallback
  arch_topology: Fix putting invalid cpu clk
  ...
parents db34c5ff 18555cb6
...@@ -1360,6 +1360,24 @@ ...@@ -1360,6 +1360,24 @@
can be changed at run time by the max_graph_depth file can be changed at run time by the max_graph_depth file
in the tracefs tracing directory. default: 0 (no limit) in the tracefs tracing directory. default: 0 (no limit)
fw_devlink= [KNL] Create device links between consumer and supplier
devices by scanning the firmware to infer the
consumer/supplier relationships. This feature is
especially useful when drivers are loaded as modules as
it ensures proper ordering of tasks like device probing
(suppliers first, then consumers), supplier boot state
clean up (only after all consumers have probed),
suspend/resume & runtime PM (consumers first, then
suppliers).
Format: { off | permissive | on | rpm }
off -- Don't create device links from firmware info.
permissive -- Create device links from firmware info
but use it only for ordering boot state clean
up (sync_state() calls).
on -- Create device links from firmware info and use it
to enforce probe and suspend/resume ordering.
rpm -- Like "on", but also use to order runtime PM.
gamecon.map[2|3]= gamecon.map[2|3]=
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad [HW,JOY] Multisystem joystick and NES/SNES/PSX pad
support via parallel port (up to 5 devices per port) support via parallel port (up to 5 devices per port)
...@@ -3291,12 +3309,6 @@ ...@@ -3291,12 +3309,6 @@
This can be set from sysctl after boot. This can be set from sysctl after boot.
See Documentation/admin-guide/sysctl/vm.rst for details. See Documentation/admin-guide/sysctl/vm.rst for details.
of_devlink [OF, KNL] Create device links between consumer and
supplier devices by scanning the devictree to infer the
consumer/supplier relationships. A consumer device
will not be probed until all the supplier devices have
probed successfully.
ohci1394_dma=early [HW] enable debugging via the ohci1394 driver. ohci1394_dma=early [HW] enable debugging via the ohci1394 driver.
See Documentation/debugging-via-ohci1394.txt for more See Documentation/debugging-via-ohci1394.txt for more
info. info.
......
...@@ -202,3 +202,106 @@ the following file: ...@@ -202,3 +202,106 @@ the following file:
If you echo 0 into it means MAX_JIFFY_OFFSET will be used. The data type If you echo 0 into it means MAX_JIFFY_OFFSET will be used. The data type
for the timeout is an int. for the timeout is an int.
EFI embedded firmware fallback mechanism
========================================
On some devices the system's EFI code / ROM may contain an embedded copy
of firmware for some of the system's integrated peripheral devices and
the peripheral's Linux device-driver needs to access this firmware.
Device drivers which need such firmware can use the
firmware_request_platform() function for this, note that this is a
separate fallback mechanism from the other fallback mechanisms and
this does not use the sysfs interface.
A device driver which needs this can describe the firmware it needs
using an efi_embedded_fw_desc struct:
.. kernel-doc:: include/linux/efi_embedded_fw.h
:functions: efi_embedded_fw_desc
The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory
segments for an eight byte sequence matching prefix; if the prefix is found it
then does a sha256 over length bytes and if that matches makes a copy of length
bytes and adds that to its list with found firmwares.
To avoid doing this somewhat expensive scan on all systems, dmi matching is
used. Drivers are expected to export a dmi_system_id array, with each entries'
driver_data pointing to an efi_embedded_fw_desc.
To register this array with the efi-embedded-fw code, a driver needs to:
1. Always be builtin to the kernel or store the dmi_system_id array in a
separate object file which always gets builtin.
2. Add an extern declaration for the dmi_system_id array to
include/linux/efi_embedded_fw.h.
3. Add the dmi_system_id array to the embedded_fw_table in
drivers/firmware/efi/embedded-firmware.c wrapped in a #ifdef testing that
the driver is being builtin.
4. Add "select EFI_EMBEDDED_FIRMWARE if EFI_STUB" to its Kconfig entry.
The firmware_request_platform() function will always first try to load firmware
with the specified name directly from the disk, so the EFI embedded-fw can
always be overridden by placing a file under /lib/firmware.
Note that:
1. The code scanning for EFI embedded-firmware runs near the end
of start_kernel(), just before calling rest_init(). For normal drivers and
subsystems using subsys_initcall() to register themselves this does not
matter. This means that code running earlier cannot use EFI
embedded-firmware.
2. At the moment the EFI embedded-fw code assumes that firmwares always start at
an offset which is a multiple of 8 bytes, if this is not true for your case
send in a patch to fix this.
3. At the moment the EFI embedded-fw code only works on x86 because other archs
free EFI_BOOT_SERVICES_CODE before the EFI embedded-fw code gets a chance to
scan it.
4. The current brute-force scanning of EFI_BOOT_SERVICES_CODE is an ad-hoc
brute-force solution. There has been discussion to use the UEFI Platform
Initialization (PI) spec's Firmware Volume protocol. This has been rejected
because the FV Protocol relies on *internal* interfaces of the PI spec, and:
1. The PI spec does not define peripheral firmware at all
2. The internal interfaces of the PI spec do not guarantee any backward
compatibility. Any implementation details in FV may be subject to change,
and may vary system to system. Supporting the FV Protocol would be
difficult as it is purposely ambiguous.
Example how to check for and extract embedded firmware
------------------------------------------------------
To check for, for example Silead touchscreen controller embedded firmware,
do the following:
1. Boot the system with efi=debug on the kernel commandline
2. cp /sys/kernel/debug/efi/boot_services_code? to your home dir
3. Open the boot_services_code? files in a hex-editor, search for the
magic prefix for Silead firmware: F0 00 00 00 02 00 00 00, this gives you
the beginning address of the firmware inside the boot_services_code? file.
4. The firmware has a specific pattern, it starts with a 8 byte page-address,
typically F0 00 00 00 02 00 00 00 for the first page followed by 32-bit
word-address + 32-bit value pairs. With the word-address incrementing 4
bytes (1 word) for each pair until a page is complete. A complete page is
followed by a new page-address, followed by more word + value pairs. This
leads to a very distinct pattern. Scroll down until this pattern stops,
this gives you the end of the firmware inside the boot_services_code? file.
5. "dd if=boot_services_code? of=firmware bs=1 skip=<begin-addr> count=<len>"
will extract the firmware for you. Inspect the firmware file in a
hexeditor to make sure you got the dd parameters correct.
6. Copy it to /lib/firmware under the expected name to test it.
7. If the extracted firmware works, you can use the found info to fill an
efi_embedded_fw_desc struct to describe it, run "sha256sum firmware"
to get the sha256sum to put in the sha256 field.
...@@ -12,6 +12,8 @@ a driver issues a firmware API call. ...@@ -12,6 +12,8 @@ a driver issues a firmware API call.
return it immediately return it immediately
* The ''Direct filesystem lookup'' is performed next, if found we * The ''Direct filesystem lookup'' is performed next, if found we
return it immediately return it immediately
* The ''Platform firmware fallback'' is performed next, but only when
firmware_request_platform() is used, if found we return it immediately
* If no firmware has been found and the fallback mechanism was enabled * If no firmware has been found and the fallback mechanism was enabled
the sysfs interface is created. After this either a kobject uevent the sysfs interface is created. After this either a kobject uevent
is issued or the custom firmware loading is relied upon for firmware is issued or the custom firmware loading is relied upon for firmware
......
...@@ -25,6 +25,11 @@ firmware_request_nowarn ...@@ -25,6 +25,11 @@ firmware_request_nowarn
.. kernel-doc:: drivers/base/firmware_loader/main.c .. kernel-doc:: drivers/base/firmware_loader/main.c
:functions: firmware_request_nowarn :functions: firmware_request_nowarn
firmware_request_platform
-------------------------
.. kernel-doc:: drivers/base/firmware_loader/main.c
:functions: firmware_request_platform
request_firmware_direct request_firmware_direct
----------------------- -----------------------
.. kernel-doc:: drivers/base/firmware_loader/main.c .. kernel-doc:: drivers/base/firmware_loader/main.c
......
...@@ -62,7 +62,7 @@ missing. ...@@ -62,7 +62,7 @@ missing.
Create a file with an initial size, the following function can be used Create a file with an initial size, the following function can be used
instead:: instead::
struct dentry *debugfs_create_file_size(const char *name, umode_t mode, void debugfs_create_file_size(const char *name, umode_t mode,
struct dentry *parent, void *data, struct dentry *parent, void *data,
const struct file_operations *fops, const struct file_operations *fops,
loff_t file_size); loff_t file_size);
......
...@@ -243,6 +243,7 @@ int __init efi_memblock_x86_reserve_range(void) ...@@ -243,6 +243,7 @@ int __init efi_memblock_x86_reserve_range(void)
efi.memmap.desc_version); efi.memmap.desc_version);
memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size);
set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags);
return 0; return 0;
} }
...@@ -943,6 +944,7 @@ static void __init __efi_enter_virtual_mode(void) ...@@ -943,6 +944,7 @@ static void __init __efi_enter_virtual_mode(void)
goto err; goto err;
} }
efi_check_for_embedded_firmwares();
efi_free_boot_services(); efi_free_boot_services();
/* /*
......
...@@ -410,6 +410,10 @@ void __init efi_free_boot_services(void) ...@@ -410,6 +410,10 @@ void __init efi_free_boot_services(void)
int num_entries = 0; int num_entries = 0;
void *new, *new_md; void *new, *new_md;
/* Keep all regions for /sys/kernel/debug/efi */
if (efi_enabled(EFI_DBG))
return;
for_each_efi_memory_desc(md) { for_each_efi_memory_desc(md) {
unsigned long long start = md->phys_addr; unsigned long long start = md->phys_addr;
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
......
...@@ -94,7 +94,7 @@ static void update_topology_flags_workfn(struct work_struct *work) ...@@ -94,7 +94,7 @@ static void update_topology_flags_workfn(struct work_struct *work)
update_topology = 0; update_topology = 0;
} }
static u32 capacity_scale; static DEFINE_PER_CPU(u32, freq_factor) = 1;
static u32 *raw_capacity; static u32 *raw_capacity;
static int free_raw_capacity(void) static int free_raw_capacity(void)
...@@ -108,17 +108,23 @@ static int free_raw_capacity(void) ...@@ -108,17 +108,23 @@ static int free_raw_capacity(void)
void topology_normalize_cpu_scale(void) void topology_normalize_cpu_scale(void)
{ {
u64 capacity; u64 capacity;
u64 capacity_scale;
int cpu; int cpu;
if (!raw_capacity) if (!raw_capacity)
return; return;
pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale); capacity_scale = 1;
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n", capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
cpu, raw_capacity[cpu]); capacity_scale = max(capacity, capacity_scale);
capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT) }
/ capacity_scale;
pr_debug("cpu_capacity: capacity_scale=%llu\n", capacity_scale);
for_each_possible_cpu(cpu) {
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
capacity = div64_u64(capacity << SCHED_CAPACITY_SHIFT,
capacity_scale);
topology_set_cpu_scale(cpu, capacity); topology_set_cpu_scale(cpu, capacity);
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n", pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
cpu, topology_get_cpu_scale(cpu)); cpu, topology_get_cpu_scale(cpu));
...@@ -127,6 +133,7 @@ void topology_normalize_cpu_scale(void) ...@@ -127,6 +133,7 @@ void topology_normalize_cpu_scale(void)
bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
{ {
struct clk *cpu_clk;
static bool cap_parsing_failed; static bool cap_parsing_failed;
int ret; int ret;
u32 cpu_capacity; u32 cpu_capacity;
...@@ -146,10 +153,22 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) ...@@ -146,10 +153,22 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
return false; return false;
} }
} }
capacity_scale = max(cpu_capacity, capacity_scale);
raw_capacity[cpu] = cpu_capacity; raw_capacity[cpu] = cpu_capacity;
pr_debug("cpu_capacity: %pOF cpu_capacity=%u (raw)\n", pr_debug("cpu_capacity: %pOF cpu_capacity=%u (raw)\n",
cpu_node, raw_capacity[cpu]); cpu_node, raw_capacity[cpu]);
/*
* Update freq_factor for calculating early boot cpu capacities.
* For non-clk CPU DVFS mechanism, there's no way to get the
* frequency value now, assuming they are running at the same
* frequency (by keeping the initial freq_factor value).
*/
cpu_clk = of_clk_get(cpu_node, 0);
if (!PTR_ERR_OR_ZERO(cpu_clk)) {
per_cpu(freq_factor, cpu) =
clk_get_rate(cpu_clk) / 1000;
clk_put(cpu_clk);
}
} else { } else {
if (raw_capacity) { if (raw_capacity) {
pr_err("cpu_capacity: missing %pOF raw capacity\n", pr_err("cpu_capacity: missing %pOF raw capacity\n",
...@@ -188,11 +207,8 @@ init_cpu_capacity_callback(struct notifier_block *nb, ...@@ -188,11 +207,8 @@ init_cpu_capacity_callback(struct notifier_block *nb,
cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus); cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);
for_each_cpu(cpu, policy->related_cpus) { for_each_cpu(cpu, policy->related_cpus)
raw_capacity[cpu] = topology_get_cpu_scale(cpu) * per_cpu(freq_factor, cpu) = policy->cpuinfo.max_freq / 1000;
policy->cpuinfo.max_freq / 1000UL;
capacity_scale = max(raw_capacity[cpu], capacity_scale);
}
if (cpumask_empty(cpus_to_visit)) { if (cpumask_empty(cpus_to_visit)) {
topology_normalize_cpu_scale(); topology_normalize_cpu_scale();
...@@ -281,7 +297,7 @@ static int __init get_cpu_for_node(struct device_node *node) ...@@ -281,7 +297,7 @@ static int __init get_cpu_for_node(struct device_node *node)
static int __init parse_core(struct device_node *core, int package_id, static int __init parse_core(struct device_node *core, int package_id,
int core_id) int core_id)
{ {
char name[10]; char name[20];
bool leaf = true; bool leaf = true;
int i = 0; int i = 0;
int cpu; int cpu;
...@@ -327,7 +343,7 @@ static int __init parse_core(struct device_node *core, int package_id, ...@@ -327,7 +343,7 @@ static int __init parse_core(struct device_node *core, int package_id,
static int __init parse_cluster(struct device_node *cluster, int depth) static int __init parse_cluster(struct device_node *cluster, int depth)
{ {
char name[10]; char name[20];
bool leaf = true; bool leaf = true;
bool has_cores = false; bool has_cores = false;
struct device_node *c; struct device_node *c;
......
...@@ -528,6 +528,7 @@ static void component_unbind(struct component *component, ...@@ -528,6 +528,7 @@ static void component_unbind(struct component *component,
{ {
WARN_ON(!component->bound); WARN_ON(!component->bound);
if (component->ops && component->ops->unbind)
component->ops->unbind(component->dev, master->dev, data); component->ops->unbind(component->dev, master->dev, data);
component->bound = false; component->bound = false;
......
...@@ -64,12 +64,12 @@ static inline void device_links_write_unlock(void) ...@@ -64,12 +64,12 @@ static inline void device_links_write_unlock(void)
mutex_unlock(&device_links_lock); mutex_unlock(&device_links_lock);
} }
int device_links_read_lock(void) int device_links_read_lock(void) __acquires(&device_links_srcu)
{ {
return srcu_read_lock(&device_links_srcu); return srcu_read_lock(&device_links_srcu);
} }
void device_links_read_unlock(int idx) void device_links_read_unlock(int idx) __releases(&device_links_srcu)
{ {
srcu_read_unlock(&device_links_srcu, idx); srcu_read_unlock(&device_links_srcu, idx);
} }
...@@ -523,9 +523,13 @@ static void device_link_add_missing_supplier_links(void) ...@@ -523,9 +523,13 @@ static void device_link_add_missing_supplier_links(void)
mutex_lock(&wfs_lock); mutex_lock(&wfs_lock);
list_for_each_entry_safe(dev, tmp, &wait_for_suppliers, list_for_each_entry_safe(dev, tmp, &wait_for_suppliers,
links.needs_suppliers) links.needs_suppliers) {
if (!fwnode_call_int_op(dev->fwnode, add_links, dev)) int ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
if (!ret)
list_del_init(&dev->links.needs_suppliers); list_del_init(&dev->links.needs_suppliers);
else if (ret != -ENODEV)
dev->links.need_for_probe = false;
}
mutex_unlock(&wfs_lock); mutex_unlock(&wfs_lock);
} }
...@@ -2341,6 +2345,31 @@ static int device_private_init(struct device *dev) ...@@ -2341,6 +2345,31 @@ static int device_private_init(struct device *dev)
return 0; return 0;
} }
static u32 fw_devlink_flags;
static int __init fw_devlink_setup(char *arg)
{
if (!arg)
return -EINVAL;
if (strcmp(arg, "off") == 0) {
fw_devlink_flags = 0;
} else if (strcmp(arg, "permissive") == 0) {
fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
} else if (strcmp(arg, "on") == 0) {
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER;
} else if (strcmp(arg, "rpm") == 0) {
fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER |
DL_FLAG_PM_RUNTIME;
}
return 0;
}
early_param("fw_devlink", fw_devlink_setup);
u32 fw_devlink_get_flags(void)
{
return fw_devlink_flags;
}
/** /**
* device_add - add device to device hierarchy. * device_add - add device to device hierarchy.
* @dev: device. * @dev: device.
...@@ -2375,6 +2404,7 @@ int device_add(struct device *dev) ...@@ -2375,6 +2404,7 @@ int device_add(struct device *dev)
struct class_interface *class_intf; struct class_interface *class_intf;
int error = -EINVAL, fw_ret; int error = -EINVAL, fw_ret;
struct kobject *glue_dir = NULL; struct kobject *glue_dir = NULL;
bool is_fwnode_dev = false;
dev = get_device(dev); dev = get_device(dev);
if (!dev) if (!dev)
...@@ -2472,8 +2502,10 @@ int device_add(struct device *dev) ...@@ -2472,8 +2502,10 @@ int device_add(struct device *dev)
kobject_uevent(&dev->kobj, KOBJ_ADD); kobject_uevent(&dev->kobj, KOBJ_ADD);
if (dev->fwnode && !dev->fwnode->dev) if (dev->fwnode && !dev->fwnode->dev) {
dev->fwnode->dev = dev; dev->fwnode->dev = dev;
is_fwnode_dev = true;
}
/* /*
* Check if any of the other devices (consumers) have been waiting for * Check if any of the other devices (consumers) have been waiting for
...@@ -2489,7 +2521,8 @@ int device_add(struct device *dev) ...@@ -2489,7 +2521,8 @@ int device_add(struct device *dev)
*/ */
device_link_add_missing_supplier_links(); device_link_add_missing_supplier_links();
if (fwnode_has_op(dev->fwnode, add_links)) { if (fw_devlink_flags && is_fwnode_dev &&
fwnode_has_op(dev->fwnode, add_links)) {
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev); fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
if (fw_ret == -ENODEV) if (fw_ret == -ENODEV)
device_link_wait_for_mandatory_supplier(dev); device_link_wait_for_mandatory_supplier(dev);
......
...@@ -231,8 +231,7 @@ static struct cpu_attr cpu_attrs[] = { ...@@ -231,8 +231,7 @@ static struct cpu_attr cpu_attrs[] = {
static ssize_t print_cpus_kernel_max(struct device *dev, static ssize_t print_cpus_kernel_max(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); return sprintf(buf, "%d\n", NR_CPUS - 1);
return n;
} }
static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
...@@ -258,13 +257,13 @@ static ssize_t print_cpus_offline(struct device *dev, ...@@ -258,13 +257,13 @@ static ssize_t print_cpus_offline(struct device *dev,
buf[n++] = ','; buf[n++] = ',';
if (nr_cpu_ids == total_cpus-1) if (nr_cpu_ids == total_cpus-1)
n += snprintf(&buf[n], len - n, "%u", nr_cpu_ids); n += scnprintf(&buf[n], len - n, "%u", nr_cpu_ids);
else else
n += snprintf(&buf[n], len - n, "%u-%d", n += scnprintf(&buf[n], len - n, "%u-%d",
nr_cpu_ids, total_cpus-1); nr_cpu_ids, total_cpus-1);
} }
n += snprintf(&buf[n], len - n, "\n"); n += scnprintf(&buf[n], len - n, "\n");
return n; return n;
} }
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
...@@ -272,7 +271,7 @@ static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); ...@@ -272,7 +271,7 @@ static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
static ssize_t print_cpus_isolated(struct device *dev, static ssize_t print_cpus_isolated(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
int n = 0, len = PAGE_SIZE-2; int n;
cpumask_var_t isolated; cpumask_var_t isolated;
if (!alloc_cpumask_var(&isolated, GFP_KERNEL)) if (!alloc_cpumask_var(&isolated, GFP_KERNEL))
...@@ -280,7 +279,7 @@ static ssize_t print_cpus_isolated(struct device *dev, ...@@ -280,7 +279,7 @@ static ssize_t print_cpus_isolated(struct device *dev,
cpumask_andnot(isolated, cpu_possible_mask, cpumask_andnot(isolated, cpu_possible_mask,
housekeeping_cpumask(HK_FLAG_DOMAIN)); housekeeping_cpumask(HK_FLAG_DOMAIN));
n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(isolated)); n = sprintf(buf, "%*pbl\n", cpumask_pr_args(isolated));
free_cpumask_var(isolated); free_cpumask_var(isolated);
...@@ -292,11 +291,7 @@ static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL); ...@@ -292,11 +291,7 @@ static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
static ssize_t print_cpus_nohz_full(struct device *dev, static ssize_t print_cpus_nohz_full(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
int n = 0, len = PAGE_SIZE-2; return sprintf(buf, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
return n;
} }
static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL); static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
#endif #endif
......
...@@ -224,76 +224,52 @@ static int deferred_devs_show(struct seq_file *s, void *data) ...@@ -224,76 +224,52 @@ static int deferred_devs_show(struct seq_file *s, void *data)
} }
DEFINE_SHOW_ATTRIBUTE(deferred_devs); DEFINE_SHOW_ATTRIBUTE(deferred_devs);
static int deferred_probe_timeout = -1; #ifdef CONFIG_MODULES
/*
* In the case of modules, set the default probe timeout to
* 30 seconds to give userland some time to load needed modules
*/
int driver_deferred_probe_timeout = 30;
#else
/* In the case of !modules, no probe timeout needed */
int driver_deferred_probe_timeout = -1;
#endif
EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout);
static int __init deferred_probe_timeout_setup(char *str) static int __init deferred_probe_timeout_setup(char *str)
{ {
int timeout; int timeout;
if (!kstrtoint(str, 10, &timeout)) if (!kstrtoint(str, 10, &timeout))
deferred_probe_timeout = timeout; driver_deferred_probe_timeout = timeout;
return 1; return 1;
} }
__setup("deferred_probe_timeout=", deferred_probe_timeout_setup); __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
static int __driver_deferred_probe_check_state(struct device *dev)
{
if (!initcalls_done)
return -EPROBE_DEFER;
if (!deferred_probe_timeout) {
dev_WARN(dev, "deferred probe timeout, ignoring dependency");
return -ETIMEDOUT;
}
return 0;
}
/** /**
* driver_deferred_probe_check_state() - Check deferred probe state * driver_deferred_probe_check_state() - Check deferred probe state
* @dev: device to check * @dev: device to check
* *
* Returns -ENODEV if init is done and all built-in drivers have had a chance * Return:
* to probe (i.e. initcalls are done), -ETIMEDOUT if deferred probe debug * -ENODEV if initcalls have completed and modules are disabled.
* timeout has expired, or -EPROBE_DEFER if none of those conditions are met. * -ETIMEDOUT if the deferred probe timeout was set and has expired
* and modules are enabled.
* -EPROBE_DEFER in other cases.
* *
* Drivers or subsystems can opt-in to calling this function instead of directly * Drivers or subsystems can opt-in to calling this function instead of directly
* returning -EPROBE_DEFER. * returning -EPROBE_DEFER.
*/ */
int driver_deferred_probe_check_state(struct device *dev) int driver_deferred_probe_check_state(struct device *dev)
{ {
int ret; if (!IS_ENABLED(CONFIG_MODULES) && initcalls_done) {
ret = __driver_deferred_probe_check_state(dev);
if (ret < 0)
return ret;
dev_warn(dev, "ignoring dependency for device, assuming no driver"); dev_warn(dev, "ignoring dependency for device, assuming no driver");
return -ENODEV; return -ENODEV;
} }
/**
* driver_deferred_probe_check_state_continue() - check deferred probe state
* @dev: device to check
*
* Returns -ETIMEDOUT if deferred probe debug timeout has expired, or
* -EPROBE_DEFER otherwise.
*
* Drivers or subsystems can opt-in to calling this function instead of
* directly returning -EPROBE_DEFER.
*
* This is similar to driver_deferred_probe_check_state(), but it allows the
* subsystem to keep deferring probe after built-in drivers have had a chance
* to probe. One scenario where that is useful is if built-in drivers rely on
* resources that are provided by modular drivers.
*/
int driver_deferred_probe_check_state_continue(struct device *dev)
{
int ret;
ret = __driver_deferred_probe_check_state(dev); if (!driver_deferred_probe_timeout) {
if (ret < 0) dev_WARN(dev, "deferred probe timeout, ignoring dependency");
return ret; return -ETIMEDOUT;
}
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
...@@ -302,7 +278,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work) ...@@ -302,7 +278,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
{ {
struct device_private *private, *p; struct device_private *private, *p;
deferred_probe_timeout = 0; driver_deferred_probe_timeout = 0;
driver_deferred_probe_trigger(); driver_deferred_probe_trigger();
flush_work(&deferred_probe_work); flush_work(&deferred_probe_work);
...@@ -336,9 +312,9 @@ static int deferred_probe_initcall(void) ...@@ -336,9 +312,9 @@ static int deferred_probe_initcall(void)
driver_deferred_probe_trigger(); driver_deferred_probe_trigger();
flush_work(&deferred_probe_work); flush_work(&deferred_probe_work);
if (deferred_probe_timeout > 0) { if (driver_deferred_probe_timeout > 0) {
schedule_delayed_work(&deferred_probe_timeout_work, schedule_delayed_work(&deferred_probe_timeout_work,
deferred_probe_timeout * HZ); driver_deferred_probe_timeout * HZ);
} }
return 0; return 0;
} }
...@@ -668,9 +644,10 @@ static int really_probe_debug(struct device *dev, struct device_driver *drv) ...@@ -668,9 +644,10 @@ static int really_probe_debug(struct device *dev, struct device_driver *drv)
*/ */
int driver_probe_done(void) int driver_probe_done(void)
{ {
pr_debug("%s: probe_count = %d\n", __func__, int local_probe_count = atomic_read(&probe_count);
atomic_read(&probe_count));
if (atomic_read(&probe_count)) pr_debug("%s: probe_count = %d\n", __func__, local_probe_count);
if (local_probe_count)
return -EBUSY; return -EBUSY;
return 0; return 0;
} }
...@@ -1222,7 +1199,7 @@ void driver_detach(struct device_driver *drv) ...@@ -1222,7 +1199,7 @@ void driver_detach(struct device_driver *drv)
spin_unlock(&drv->p->klist_devices.k_lock); spin_unlock(&drv->p->klist_devices.k_lock);
break; break;
} }
dev_prv = list_entry(drv->p->klist_devices.k_list.prev, dev_prv = list_last_entry(&drv->p->klist_devices.k_list,
struct device_private, struct device_private,
knode_driver.n_node); knode_driver.n_node);
dev = dev_prv->device; dev = dev_prv->device;
......
...@@ -5,5 +5,6 @@ obj-$(CONFIG_FW_LOADER_USER_HELPER) += fallback_table.o ...@@ -5,5 +5,6 @@ obj-$(CONFIG_FW_LOADER_USER_HELPER) += fallback_table.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_FW_LOADER) += firmware_class.o
firmware_class-objs := main.o firmware_class-objs := main.o
firmware_class-$(CONFIG_FW_LOADER_USER_HELPER) += fallback.o firmware_class-$(CONFIG_FW_LOADER_USER_HELPER) += fallback.o
firmware_class-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += fallback_platform.o
obj-y += builtin/ obj-y += builtin/
...@@ -525,7 +525,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs, ...@@ -525,7 +525,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs,
} }
retval = fw_sysfs_wait_timeout(fw_priv, timeout); retval = fw_sysfs_wait_timeout(fw_priv, timeout);
if (retval < 0) { if (retval < 0 && retval != -ENOENT) {
mutex_lock(&fw_lock); mutex_lock(&fw_lock);
fw_load_abort(fw_sysfs); fw_load_abort(fw_sysfs);
mutex_unlock(&fw_lock); mutex_unlock(&fw_lock);
......
...@@ -66,4 +66,14 @@ static inline void unregister_sysfs_loader(void) ...@@ -66,4 +66,14 @@ static inline void unregister_sysfs_loader(void)
} }
#endif /* CONFIG_FW_LOADER_USER_HELPER */ #endif /* CONFIG_FW_LOADER_USER_HELPER */
#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
int firmware_fallback_platform(struct fw_priv *fw_priv, enum fw_opt opt_flags);
#else
static inline int firmware_fallback_platform(struct fw_priv *fw_priv,
enum fw_opt opt_flags)
{
return -ENOENT;
}
#endif
#endif /* __FIRMWARE_FALLBACK_H */ #endif /* __FIRMWARE_FALLBACK_H */
// SPDX-License-Identifier: GPL-2.0
#include <linux/efi_embedded_fw.h>
#include <linux/property.h>
#include <linux/security.h>
#include <linux/vmalloc.h>
#include "fallback.h"
#include "firmware.h"
int firmware_fallback_platform(struct fw_priv *fw_priv, enum fw_opt opt_flags)
{
const u8 *data;
size_t size;
int rc;
if (!(opt_flags & FW_OPT_FALLBACK_PLATFORM))
return -ENOENT;
rc = security_kernel_load_data(LOADING_FIRMWARE_EFI_EMBEDDED);
if (rc)
return rc;
rc = efi_get_embedded_fw(fw_priv->fw_name, &data, &size);
if (rc)
return rc; /* rc == -ENOENT when the fw was not found */
fw_priv->data = vmalloc(size);
if (!fw_priv->data)
return -ENOMEM;
memcpy(fw_priv->data, data, size);
fw_priv->size = size;
fw_state_done(fw_priv);
return 0;
}
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
* firmware caching mechanism. * firmware caching mechanism.
* @FW_OPT_NOFALLBACK_SYSFS: Disable the sysfs fallback mechanism. Takes * @FW_OPT_NOFALLBACK_SYSFS: Disable the sysfs fallback mechanism. Takes
* precedence over &FW_OPT_UEVENT and &FW_OPT_USERHELPER. * precedence over &FW_OPT_UEVENT and &FW_OPT_USERHELPER.
* @FW_OPT_FALLBACK_PLATFORM: Enable fallback to device fw copy embedded in
* the platform's main firmware. If both this fallback and the sysfs
* fallback are enabled, then this fallback will be tried first.
*/ */
enum fw_opt { enum fw_opt {
FW_OPT_UEVENT = BIT(0), FW_OPT_UEVENT = BIT(0),
...@@ -37,6 +40,7 @@ enum fw_opt { ...@@ -37,6 +40,7 @@ enum fw_opt {
FW_OPT_NO_WARN = BIT(3), FW_OPT_NO_WARN = BIT(3),
FW_OPT_NOCACHE = BIT(4), FW_OPT_NOCACHE = BIT(4),
FW_OPT_NOFALLBACK_SYSFS = BIT(5), FW_OPT_NOFALLBACK_SYSFS = BIT(5),
FW_OPT_FALLBACK_PLATFORM = BIT(6),
}; };
enum fw_status { enum fw_status {
......
...@@ -493,8 +493,10 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, ...@@ -493,8 +493,10 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
} }
fw_priv->size = 0; fw_priv->size = 0;
rc = kernel_read_file_from_path(path, &buffer, &size,
msize, id); /* load firmware files from the mount namespace of init */
rc = kernel_read_file_from_path_initns(path, &buffer,
&size, msize, id);
if (rc) { if (rc) {
if (rc != -ENOENT) if (rc != -ENOENT)
dev_warn(device, "loading %s failed with error %d\n", dev_warn(device, "loading %s failed with error %d\n",
...@@ -776,6 +778,9 @@ _request_firmware(const struct firmware **firmware_p, const char *name, ...@@ -776,6 +778,9 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
fw_decompress_xz); fw_decompress_xz);
#endif #endif
if (ret == -ENOENT)
ret = firmware_fallback_platform(fw->priv, opt_flags);
if (ret) { if (ret) {
if (!(opt_flags & FW_OPT_NO_WARN)) if (!(opt_flags & FW_OPT_NO_WARN))
dev_warn(device, dev_warn(device,
...@@ -883,6 +888,30 @@ int request_firmware_direct(const struct firmware **firmware_p, ...@@ -883,6 +888,30 @@ int request_firmware_direct(const struct firmware **firmware_p,
} }
EXPORT_SYMBOL_GPL(request_firmware_direct); EXPORT_SYMBOL_GPL(request_firmware_direct);
/**
* firmware_request_platform() - request firmware with platform-fw fallback
* @firmware: pointer to firmware image
* @name: name of firmware file
* @device: device for which firmware is being loaded
*
* This function is similar in behaviour to request_firmware, except that if
* direct filesystem lookup fails, it will fallback to looking for a copy of the
* requested firmware embedded in the platform's main (e.g. UEFI) firmware.
**/
int firmware_request_platform(const struct firmware **firmware,
const char *name, struct device *device)
{
int ret;
/* Need to pin this module until return */
__module_get(THIS_MODULE);
ret = _request_firmware(firmware, name, device, NULL, 0,
FW_OPT_UEVENT | FW_OPT_FALLBACK_PLATFORM);
module_put(THIS_MODULE);
return ret;
}
EXPORT_SYMBOL_GPL(firmware_request_platform);
/** /**
* firmware_request_cache() - cache firmware for suspend so resume can use it * firmware_request_cache() - cache firmware for suspend so resume can use it
* @name: name of firmware file * @name: name of firmware file
......
...@@ -239,6 +239,11 @@ config EFI_DISABLE_PCI_DMA ...@@ -239,6 +239,11 @@ config EFI_DISABLE_PCI_DMA
endmenu endmenu
config EFI_EMBEDDED_FIRMWARE
bool
depends on EFI
select CRYPTO_LIB_SHA256
config UEFI_CPER config UEFI_CPER
bool bool
......
...@@ -26,6 +26,7 @@ obj-$(CONFIG_EFI_TEST) += test/ ...@@ -26,6 +26,7 @@ obj-$(CONFIG_EFI_TEST) += test/
obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o
obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o obj-$(CONFIG_EFI_RCI2_TABLE) += rci2-table.o
obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += embedded-firmware.o
fake_map-y += fake_mem.o fake_map-y += fake_mem.o
fake_map-$(CONFIG_X86) += x86_fake_mem.o fake_map-$(CONFIG_X86) += x86_fake_mem.o
......
...@@ -349,7 +349,7 @@ static int efifb_add_links(const struct fwnode_handle *fwnode, ...@@ -349,7 +349,7 @@ static int efifb_add_links(const struct fwnode_handle *fwnode,
* If this fails, retrying this function at a later point won't * If this fails, retrying this function at a later point won't
* change anything. So, don't return an error after this. * change anything. So, don't return an error after this.
*/ */
if (!device_link_add(dev, sup_dev, 0)) if (!device_link_add(dev, sup_dev, fw_devlink_get_flags()))
dev_warn(dev, "device_link_add() failed\n"); dev_warn(dev, "device_link_add() failed\n");
put_device(sup_dev); put_device(sup_dev);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -325,6 +326,59 @@ static __init int efivar_ssdt_load(void) ...@@ -325,6 +326,59 @@ static __init int efivar_ssdt_load(void)
static inline int efivar_ssdt_load(void) { return 0; } static inline int efivar_ssdt_load(void) { return 0; }
#endif #endif
#ifdef CONFIG_DEBUG_FS
#define EFI_DEBUGFS_MAX_BLOBS 32
static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS];
static void __init efi_debugfs_init(void)
{
struct dentry *efi_debugfs;
efi_memory_desc_t *md;
char name[32];
int type_count[EFI_BOOT_SERVICES_DATA + 1] = {};
int i = 0;
efi_debugfs = debugfs_create_dir("efi", NULL);
if (IS_ERR_OR_NULL(efi_debugfs))
return;
for_each_efi_memory_desc(md) {
switch (md->type) {
case EFI_BOOT_SERVICES_CODE:
snprintf(name, sizeof(name), "boot_services_code%d",
type_count[md->type]++);
break;
case EFI_BOOT_SERVICES_DATA:
snprintf(name, sizeof(name), "boot_services_data%d",
type_count[md->type]++);
break;
default:
continue;
}
if (i >= EFI_DEBUGFS_MAX_BLOBS) {
pr_warn("More then %d EFI boot service segments, only showing first %d in debugfs\n",
EFI_DEBUGFS_MAX_BLOBS, EFI_DEBUGFS_MAX_BLOBS);
break;
}
debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT;
debugfs_blob[i].data = memremap(md->phys_addr,
debugfs_blob[i].size,
MEMREMAP_WB);
if (!debugfs_blob[i].data)
continue;
debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]);
i++;
}
}
#else
static inline void efi_debugfs_init(void) {}
#endif
/* /*
* We register the efi subsystem with the firmware subsystem and the * We register the efi subsystem with the firmware subsystem and the
* efivars subsystem with the efi subsystem, if the system was booted with * efivars subsystem with the efi subsystem, if the system was booted with
...@@ -381,6 +435,9 @@ static int __init efisubsys_init(void) ...@@ -381,6 +435,9 @@ static int __init efisubsys_init(void)
goto err_remove_group; goto err_remove_group;
} }
if (efi_enabled(EFI_DBG) && efi_enabled(EFI_PRESERVE_BS_REGIONS))
efi_debugfs_init();
return 0; return 0;
err_remove_group: err_remove_group:
......
// SPDX-License-Identifier: GPL-2.0
/*
* Support for extracting embedded firmware for peripherals from EFI code,
*
* Copyright (c) 2018 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/dmi.h>
#include <linux/efi.h>
#include <linux/efi_embedded_fw.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <crypto/sha.h>
/* Exported for use by lib/test_firmware.c only */
LIST_HEAD(efi_embedded_fw_list);
EXPORT_SYMBOL_GPL(efi_embedded_fw_list);
static bool checked_for_fw;
static const struct dmi_system_id * const embedded_fw_table[] = {
#ifdef CONFIG_TOUCHSCREEN_DMI
touchscreen_dmi_table,
#endif
NULL
};
/*
* Note the efi_check_for_embedded_firmwares() code currently makes the
* following 2 assumptions. This may needs to be revisited if embedded firmware
* is found where this is not true:
* 1) The firmware is only found in EFI_BOOT_SERVICES_CODE memory segments
* 2) The firmware always starts at an offset which is a multiple of 8 bytes
*/
static int __init efi_check_md_for_embedded_firmware(
efi_memory_desc_t *md, const struct efi_embedded_fw_desc *desc)
{
struct sha256_state sctx;
struct efi_embedded_fw *fw;
u8 sha256[32];
u64 i, size;
u8 *map;
size = md->num_pages << EFI_PAGE_SHIFT;
map = memremap(md->phys_addr, size, MEMREMAP_WB);
if (!map) {
pr_err("Error mapping EFI mem at %#llx\n", md->phys_addr);
return -ENOMEM;
}
for (i = 0; (i + desc->length) <= size; i += 8) {
if (memcmp(map + i, desc->prefix, EFI_EMBEDDED_FW_PREFIX_LEN))
continue;
sha256_init(&sctx);
sha256_update(&sctx, map + i, desc->length);
sha256_final(&sctx, sha256);
if (memcmp(sha256, desc->sha256, 32) == 0)
break;
}
if ((i + desc->length) > size) {
memunmap(map);
return -ENOENT;
}
pr_info("Found EFI embedded fw '%s'\n", desc->name);
fw = kmalloc(sizeof(*fw), GFP_KERNEL);
if (!fw) {
memunmap(map);
return -ENOMEM;
}
fw->data = kmemdup(map + i, desc->length, GFP_KERNEL);
memunmap(map);
if (!fw->data) {
kfree(fw);
return -ENOMEM;
}
fw->name = desc->name;
fw->length = desc->length;
list_add(&fw->list, &efi_embedded_fw_list);
return 0;
}
void __init efi_check_for_embedded_firmwares(void)
{
const struct efi_embedded_fw_desc *fw_desc;
const struct dmi_system_id *dmi_id;
efi_memory_desc_t *md;
int i, r;
for (i = 0; embedded_fw_table[i]; i++) {
dmi_id = dmi_first_match(embedded_fw_table[i]);
if (!dmi_id)
continue;
fw_desc = dmi_id->driver_data;
/*
* In some drivers the struct driver_data contains may contain
* other driver specific data after the fw_desc struct; and
* the fw_desc struct itself may be empty, skip these.
*/
if (!fw_desc->name)
continue;
for_each_efi_memory_desc(md) {
if (md->type != EFI_BOOT_SERVICES_CODE)
continue;
r = efi_check_md_for_embedded_firmware(md, fw_desc);
if (r == 0)
break;
}
}
checked_for_fw = true;
}
int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size)
{
struct efi_embedded_fw *iter, *fw = NULL;
if (!checked_for_fw) {
pr_warn("Warning %s called while we did not check for embedded fw\n",
__func__);
return -ENOENT;
}
list_for_each_entry(iter, &efi_embedded_fw_list, list) {
if (strcmp(name, iter->name) == 0) {
fw = iter;
break;
}
}
if (!fw)
return -ENOENT;
*data = fw->data;
*size = fw->length;
return 0;
}
EXPORT_SYMBOL_GPL(efi_get_embedded_fw);
...@@ -288,7 +288,7 @@ static int icn8505_upload_fw(struct icn8505_data *icn8505) ...@@ -288,7 +288,7 @@ static int icn8505_upload_fw(struct icn8505_data *icn8505)
* we may need it at resume. Having loaded it once will make the * we may need it at resume. Having loaded it once will make the
* firmware class code cache it at suspend/resume. * firmware class code cache it at suspend/resume.
*/ */
error = request_firmware(&fw, icn8505->firmware_name, dev); error = firmware_request_platform(&fw, icn8505->firmware_name, dev);
if (error) { if (error) {
dev_err(dev, "Firmware request error %d\n", error); dev_err(dev, "Firmware request error %d\n", error);
return error; return error;
......
...@@ -288,7 +288,7 @@ static int silead_ts_load_fw(struct i2c_client *client) ...@@ -288,7 +288,7 @@ static int silead_ts_load_fw(struct i2c_client *client)
dev_dbg(dev, "Firmware file name: %s", data->fw_name); dev_dbg(dev, "Firmware file name: %s", data->fw_name);
error = request_firmware(&fw, data->fw_name, dev); error = firmware_request_platform(&fw, data->fw_name, dev);
if (error) { if (error) {
dev_err(dev, "Firmware request error %d\n", error); dev_err(dev, "Firmware request error %d\n", error);
return error; return error;
......
...@@ -1262,7 +1262,7 @@ static int of_link_property(struct device *dev, struct device_node *con_np, ...@@ -1262,7 +1262,7 @@ static int of_link_property(struct device *dev, struct device_node *con_np,
u32 dl_flags; u32 dl_flags;
if (dev->of_node == con_np) if (dev->of_node == con_np)
dl_flags = DL_FLAG_AUTOPROBE_CONSUMER; dl_flags = fw_devlink_get_flags();
else else
dl_flags = DL_FLAG_SYNC_STATE_ONLY; dl_flags = DL_FLAG_SYNC_STATE_ONLY;
...@@ -1299,15 +1299,9 @@ static int of_link_to_suppliers(struct device *dev, ...@@ -1299,15 +1299,9 @@ static int of_link_to_suppliers(struct device *dev,
return ret; return ret;
} }
static bool of_devlink;
core_param(of_devlink, of_devlink, bool, 0);
static int of_fwnode_add_links(const struct fwnode_handle *fwnode, static int of_fwnode_add_links(const struct fwnode_handle *fwnode,
struct device *dev) struct device *dev)
{ {
if (!of_devlink)
return 0;
if (unlikely(!is_of_node(fwnode))) if (unlikely(!is_of_node(fwnode)))
return 0; return 0;
......
...@@ -127,11 +127,12 @@ static int dt_to_map_one_config(struct pinctrl *p, ...@@ -127,11 +127,12 @@ static int dt_to_map_one_config(struct pinctrl *p,
np_pctldev = of_get_next_parent(np_pctldev); np_pctldev = of_get_next_parent(np_pctldev);
if (!np_pctldev || of_node_is_root(np_pctldev)) { if (!np_pctldev || of_node_is_root(np_pctldev)) {
of_node_put(np_pctldev); of_node_put(np_pctldev);
ret = driver_deferred_probe_check_state(p->dev);
/* keep deferring if modules are enabled unless we've timed out */ /* keep deferring if modules are enabled unless we've timed out */
if (IS_ENABLED(CONFIG_MODULES) && !allow_default) if (IS_ENABLED(CONFIG_MODULES) && !allow_default &&
return driver_deferred_probe_check_state_continue(p->dev); (ret == -ENODEV))
ret = -EPROBE_DEFER;
return driver_deferred_probe_check_state(p->dev); return ret;
} }
/* If we're creating a hog we can use the passed pctldev */ /* If we're creating a hog we can use the passed pctldev */
if (hog_pctldev && (np_pctldev == p->dev->of_node)) { if (hog_pctldev && (np_pctldev == p->dev->of_node)) {
......
...@@ -1252,6 +1252,7 @@ config INTEL_TURBO_MAX_3 ...@@ -1252,6 +1252,7 @@ config INTEL_TURBO_MAX_3
config TOUCHSCREEN_DMI config TOUCHSCREEN_DMI
bool "DMI based touchscreen configuration info" bool "DMI based touchscreen configuration info"
depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD
select EFI_EMBEDDED_FIRMWARE if EFI
---help--- ---help---
Certain ACPI based tablets with e.g. Silead or Chipone touchscreens Certain ACPI based tablets with e.g. Silead or Chipone touchscreens
do not have enough data in ACPI tables for the touchscreen driver to do not have enough data in ACPI tables for the touchscreen driver to
......
...@@ -11,12 +11,15 @@ ...@@ -11,12 +11,15 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/efi_embedded_fw.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/string.h> #include <linux/string.h>
struct ts_dmi_data { struct ts_dmi_data {
/* The EFI embedded-fw code expects this to be the first member! */
struct efi_embedded_fw_desc embedded_fw;
const char *acpi_name; const char *acpi_name;
const struct property_entry *properties; const struct property_entry *properties;
}; };
...@@ -64,6 +67,15 @@ static const struct property_entry chuwi_hi8_pro_props[] = { ...@@ -64,6 +67,15 @@ static const struct property_entry chuwi_hi8_pro_props[] = {
}; };
static const struct ts_dmi_data chuwi_hi8_pro_data = { static const struct ts_dmi_data chuwi_hi8_pro_data = {
.embedded_fw = {
.name = "silead/gsl3680-chuwi-hi8-pro.fw",
.prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
.length = 39864,
.sha256 = { 0xc0, 0x88, 0xc5, 0xef, 0xd1, 0x70, 0x77, 0x59,
0x4e, 0xe9, 0xc4, 0xd8, 0x2e, 0xcd, 0xbf, 0x95,
0x32, 0xd9, 0x03, 0x28, 0x0d, 0x48, 0x9f, 0x92,
0x35, 0x37, 0xf6, 0x8b, 0x2a, 0xe4, 0x73, 0xff },
},
.acpi_name = "MSSL1680:00", .acpi_name = "MSSL1680:00",
.properties = chuwi_hi8_pro_props, .properties = chuwi_hi8_pro_props,
}; };
...@@ -120,6 +132,18 @@ static const struct ts_dmi_data chuwi_vi8_data = { ...@@ -120,6 +132,18 @@ static const struct ts_dmi_data chuwi_vi8_data = {
.properties = chuwi_vi8_props, .properties = chuwi_vi8_props,
}; };
static const struct ts_dmi_data chuwi_vi8_plus_data = {
.embedded_fw = {
.name = "chipone/icn8505-HAMP0002.fw",
.prefix = { 0xb0, 0x07, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00 },
.length = 35012,
.sha256 = { 0x93, 0xe5, 0x49, 0xe0, 0xb6, 0xa2, 0xb4, 0xb3,
0x88, 0x96, 0x34, 0x97, 0x5e, 0xa8, 0x13, 0x78,
0x72, 0x98, 0xb8, 0x29, 0xeb, 0x5c, 0xa7, 0xf1,
0x25, 0x13, 0x43, 0xf4, 0x30, 0x7c, 0xfc, 0x7c },
},
};
static const struct property_entry chuwi_vi10_props[] = { static const struct property_entry chuwi_vi10_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-x", 0), PROPERTY_ENTRY_U32("touchscreen-min-x", 0),
PROPERTY_ENTRY_U32("touchscreen-min-y", 4), PROPERTY_ENTRY_U32("touchscreen-min-y", 4),
...@@ -181,6 +205,15 @@ static const struct property_entry cube_iwork8_air_props[] = { ...@@ -181,6 +205,15 @@ static const struct property_entry cube_iwork8_air_props[] = {
}; };
static const struct ts_dmi_data cube_iwork8_air_data = { static const struct ts_dmi_data cube_iwork8_air_data = {
.embedded_fw = {
.name = "silead/gsl3670-cube-iwork8-air.fw",
.prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
.length = 38808,
.sha256 = { 0xff, 0x62, 0x2d, 0xd1, 0x8a, 0x78, 0x04, 0x7b,
0x33, 0x06, 0xb0, 0x4f, 0x7f, 0x02, 0x08, 0x9c,
0x96, 0xd4, 0x9f, 0x04, 0xe1, 0x47, 0x25, 0x25,
0x60, 0x77, 0x41, 0x33, 0xeb, 0x12, 0x82, 0xfc },
},
.acpi_name = "MSSL1680:00", .acpi_name = "MSSL1680:00",
.properties = cube_iwork8_air_props, .properties = cube_iwork8_air_props,
}; };
...@@ -387,6 +420,15 @@ static const struct property_entry onda_v80_plus_v3_props[] = { ...@@ -387,6 +420,15 @@ static const struct property_entry onda_v80_plus_v3_props[] = {
}; };
static const struct ts_dmi_data onda_v80_plus_v3_data = { static const struct ts_dmi_data onda_v80_plus_v3_data = {
.embedded_fw = {
.name = "silead/gsl3676-onda-v80-plus-v3.fw",
.prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
.length = 37224,
.sha256 = { 0x8f, 0xbd, 0x8f, 0x0c, 0x6b, 0xba, 0x5b, 0xf5,
0xa3, 0xc7, 0xa3, 0xc0, 0x4f, 0xcd, 0xdf, 0x32,
0xcc, 0xe4, 0x70, 0xd6, 0x46, 0x9c, 0xd7, 0xa7,
0x4b, 0x82, 0x3f, 0xab, 0xc7, 0x90, 0xea, 0x23 },
},
.acpi_name = "MSSL1680:00", .acpi_name = "MSSL1680:00",
.properties = onda_v80_plus_v3_props, .properties = onda_v80_plus_v3_props,
}; };
...@@ -449,6 +491,15 @@ static const struct property_entry pipo_w2s_props[] = { ...@@ -449,6 +491,15 @@ static const struct property_entry pipo_w2s_props[] = {
}; };
static const struct ts_dmi_data pipo_w2s_data = { static const struct ts_dmi_data pipo_w2s_data = {
.embedded_fw = {
.name = "silead/gsl1680-pipo-w2s.fw",
.prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
.length = 39072,
.sha256 = { 0xd0, 0x58, 0xc4, 0x7d, 0x55, 0x2d, 0x62, 0x18,
0xd1, 0x6a, 0x71, 0x73, 0x0b, 0x3f, 0xbe, 0x60,
0xbb, 0x45, 0x8c, 0x52, 0x27, 0xb7, 0x18, 0xf4,
0x31, 0x00, 0x6a, 0x49, 0x76, 0xd8, 0x7c, 0xd3 },
},
.acpi_name = "MSSL1680:00", .acpi_name = "MSSL1680:00",
.properties = pipo_w2s_props, .properties = pipo_w2s_props,
}; };
...@@ -641,7 +692,7 @@ static const struct ts_dmi_data trekstor_surftab_wintron70_data = { ...@@ -641,7 +692,7 @@ static const struct ts_dmi_data trekstor_surftab_wintron70_data = {
}; };
/* NOTE: Please keep this table sorted alphabetically */ /* NOTE: Please keep this table sorted alphabetically */
static const struct dmi_system_id touchscreen_dmi_table[] = { const struct dmi_system_id touchscreen_dmi_table[] = {
{ {
/* Chuwi Hi8 */ /* Chuwi Hi8 */
.driver_data = (void *)&chuwi_hi8_data, .driver_data = (void *)&chuwi_hi8_data,
...@@ -703,6 +754,15 @@ static const struct dmi_system_id touchscreen_dmi_table[] = { ...@@ -703,6 +754,15 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"),
}, },
}, },
{
/* Chuwi Vi8 Plus (CWI519) */
.driver_data = (void *)&chuwi_vi8_plus_data,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"),
DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
},
},
{ {
/* Chuwi Vi10 (CWI505) */ /* Chuwi Vi10 (CWI505) */
.driver_data = (void *)&chuwi_vi10_data, .driver_data = (void *)&chuwi_vi10_data,
...@@ -1106,6 +1166,9 @@ static int __init ts_dmi_init(void) ...@@ -1106,6 +1166,9 @@ static int __init ts_dmi_init(void)
return 0; /* Not an error */ return 0; /* Not an error */
ts_data = dmi_id->driver_data; ts_data = dmi_id->driver_data;
/* Some dmi table entries only provide an efi_embedded_fw_desc */
if (!ts_data->properties)
return 0;
error = bus_register_notifier(&i2c_bus_type, &ts_dmi_notifier); error = bus_register_notifier(&i2c_bus_type, &ts_dmi_notifier);
if (error) if (error)
......
...@@ -5757,6 +5757,10 @@ static DECLARE_DELAYED_WORK(regulator_init_complete_work, ...@@ -5757,6 +5757,10 @@ static DECLARE_DELAYED_WORK(regulator_init_complete_work,
static int __init regulator_init_complete(void) static int __init regulator_init_complete(void)
{ {
int delay = driver_deferred_probe_timeout;
if (delay < 0)
delay = 0;
/* /*
* Since DT doesn't provide an idiomatic mechanism for * Since DT doesn't provide an idiomatic mechanism for
* enabling full constraints and since it's much more natural * enabling full constraints and since it's much more natural
...@@ -5767,18 +5771,17 @@ static int __init regulator_init_complete(void) ...@@ -5767,18 +5771,17 @@ static int __init regulator_init_complete(void)
has_full_constraints = true; has_full_constraints = true;
/* /*
* We punt completion for an arbitrary amount of time since * If driver_deferred_probe_timeout is set, we punt
* systems like distros will load many drivers from userspace * completion for that many seconds since systems like
* so consumers might not always be ready yet, this is * distros will load many drivers from userspace so consumers
* particularly an issue with laptops where this might bounce * might not always be ready yet, this is particularly an
* the display off then on. Ideally we'd get a notification * issue with laptops where this might bounce the display off
* from userspace when this happens but we don't so just wait * then on. Ideally we'd get a notification from userspace
* a bit and hope we waited long enough. It'd be better if * when this happens but we don't so just wait a bit and hope
* we'd only do this on systems that need it, and a kernel * we waited long enough. It'd be better if we'd only do
* command line option might be useful. * this on systems that need it.
*/ */
schedule_delayed_work(&regulator_init_complete_work, schedule_delayed_work(&regulator_init_complete_work, delay * HZ);
msecs_to_jiffies(30000));
return 0; return 0;
} }
......
...@@ -175,8 +175,13 @@ static int open_proxy_open(struct inode *inode, struct file *filp) ...@@ -175,8 +175,13 @@ static int open_proxy_open(struct inode *inode, struct file *filp)
if (r) if (r)
goto out; goto out;
real_fops = fops_get(real_fops); if (!fops_get(real_fops)) {
if (!real_fops) { #ifdef MODULE
if (real_fops->owner &&
real_fops->owner->state == MODULE_STATE_GOING)
goto out;
#endif
/* Huh? Module did not clean up after itself at exit? */ /* Huh? Module did not clean up after itself at exit? */
WARN(1, "debugfs file owner did not clean up at exit: %pd", WARN(1, "debugfs file owner did not clean up at exit: %pd",
dentry); dentry);
...@@ -305,8 +310,13 @@ static int full_proxy_open(struct inode *inode, struct file *filp) ...@@ -305,8 +310,13 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
if (r) if (r)
goto out; goto out;
real_fops = fops_get(real_fops); if (!fops_get(real_fops)) {
if (!real_fops) { #ifdef MODULE
if (real_fops->owner &&
real_fops->owner->state == MODULE_STATE_GOING)
goto out;
#endif
/* Huh? Module did not cleanup after itself at exit? */ /* Huh? Module did not cleanup after itself at exit? */
WARN(1, "debugfs file owner did not clean up at exit: %pd", WARN(1, "debugfs file owner did not clean up at exit: %pd",
dentry); dentry);
......
...@@ -501,17 +501,8 @@ EXPORT_SYMBOL_GPL(debugfs_create_file_unsafe); ...@@ -501,17 +501,8 @@ EXPORT_SYMBOL_GPL(debugfs_create_file_unsafe);
* wide range of flexibility in creating a file, or a directory (if you want * wide range of flexibility in creating a file, or a directory (if you want
* to create a directory, the debugfs_create_dir() function is * to create a directory, the debugfs_create_dir() function is
* recommended to be used instead.) * recommended to be used instead.)
*
* This function will return a pointer to a dentry if it succeeds. This
* pointer must be passed to the debugfs_remove() function when the file is
* to be removed (no automatic cleanup happens if your module is unloaded,
* you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be
* returned.
*
* If debugfs is not enabled in the kernel, the value -%ENODEV will be
* returned.
*/ */
struct dentry *debugfs_create_file_size(const char *name, umode_t mode, void debugfs_create_file_size(const char *name, umode_t mode,
struct dentry *parent, void *data, struct dentry *parent, void *data,
const struct file_operations *fops, const struct file_operations *fops,
loff_t file_size) loff_t file_size)
...@@ -520,7 +511,6 @@ struct dentry *debugfs_create_file_size(const char *name, umode_t mode, ...@@ -520,7 +511,6 @@ struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
if (de) if (de)
d_inode(de)->i_size = file_size; d_inode(de)->i_size = file_size;
return de;
} }
EXPORT_SYMBOL_GPL(debugfs_create_file_size); EXPORT_SYMBOL_GPL(debugfs_create_file_size);
......
...@@ -985,6 +985,32 @@ int kernel_read_file_from_path(const char *path, void **buf, loff_t *size, ...@@ -985,6 +985,32 @@ int kernel_read_file_from_path(const char *path, void **buf, loff_t *size,
} }
EXPORT_SYMBOL_GPL(kernel_read_file_from_path); EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
int kernel_read_file_from_path_initns(const char *path, void **buf,
loff_t *size, loff_t max_size,
enum kernel_read_file_id id)
{
struct file *file;
struct path root;
int ret;
if (!path || !*path)
return -EINVAL;
task_lock(&init_task);
get_fs_root(init_task.fs, &root);
task_unlock(&init_task);
file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
path_put(&root);
if (IS_ERR(file))
return PTR_ERR(file);
ret = kernel_read_file(file, buf, size, max_size, id);
fput(file);
return ret;
}
EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);
int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size, int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
enum kernel_read_file_id id) enum kernel_read_file_id id)
{ {
......
...@@ -891,7 +891,7 @@ int simple_attr_open(struct inode *inode, struct file *file, ...@@ -891,7 +891,7 @@ int simple_attr_open(struct inode *inode, struct file *file,
{ {
struct simple_attr *attr; struct simple_attr *attr;
attr = kmalloc(sizeof(*attr), GFP_KERNEL); attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) if (!attr)
return -ENOMEM; return -ENOMEM;
...@@ -931,9 +931,11 @@ ssize_t simple_attr_read(struct file *file, char __user *buf, ...@@ -931,9 +931,11 @@ ssize_t simple_attr_read(struct file *file, char __user *buf,
if (ret) if (ret)
return ret; return ret;
if (*ppos) { /* continued read */ if (*ppos && attr->get_buf[0]) {
/* continued read */
size = strlen(attr->get_buf); size = strlen(attr->get_buf);
} else { /* first read */ } else {
/* first read */
u64 val; u64 val;
ret = attr->get(attr->data, &val); ret = attr->get(attr->data, &val);
if (ret) if (ret)
......
...@@ -16,9 +16,7 @@ bool topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu); ...@@ -16,9 +16,7 @@ bool topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
DECLARE_PER_CPU(unsigned long, cpu_scale); DECLARE_PER_CPU(unsigned long, cpu_scale);
struct sched_domain; static inline unsigned long topology_get_cpu_scale(int cpu)
static inline
unsigned long topology_get_cpu_scale(int cpu)
{ {
return per_cpu(cpu_scale, cpu); return per_cpu(cpu_scale, cpu);
} }
...@@ -27,8 +25,7 @@ void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity); ...@@ -27,8 +25,7 @@ void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity);
DECLARE_PER_CPU(unsigned long, freq_scale); DECLARE_PER_CPU(unsigned long, freq_scale);
static inline static inline unsigned long topology_get_freq_scale(int cpu)
unsigned long topology_get_freq_scale(int cpu)
{ {
return per_cpu(freq_scale, cpu); return per_cpu(freq_scale, cpu);
} }
......
...@@ -67,7 +67,7 @@ struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode, ...@@ -67,7 +67,7 @@ struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
struct dentry *parent, void *data, struct dentry *parent, void *data,
const struct file_operations *fops); const struct file_operations *fops);
struct dentry *debugfs_create_file_size(const char *name, umode_t mode, void debugfs_create_file_size(const char *name, umode_t mode,
struct dentry *parent, void *data, struct dentry *parent, void *data,
const struct file_operations *fops, const struct file_operations *fops,
loff_t file_size); loff_t file_size);
...@@ -181,13 +181,11 @@ static inline struct dentry *debugfs_create_file_unsafe(const char *name, ...@@ -181,13 +181,11 @@ static inline struct dentry *debugfs_create_file_unsafe(const char *name,
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static inline struct dentry *debugfs_create_file_size(const char *name, umode_t mode, static inline void debugfs_create_file_size(const char *name, umode_t mode,
struct dentry *parent, void *data, struct dentry *parent, void *data,
const struct file_operations *fops, const struct file_operations *fops,
loff_t file_size) loff_t file_size)
{ { }
return ERR_PTR(-ENODEV);
}
static inline struct dentry *debugfs_create_dir(const char *name, static inline struct dentry *debugfs_create_dir(const char *name,
struct dentry *parent) struct dentry *parent)
......
...@@ -236,9 +236,9 @@ driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev) ...@@ -236,9 +236,9 @@ driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev)
} }
#endif #endif
extern int driver_deferred_probe_timeout;
void driver_deferred_probe_add(struct device *dev); void driver_deferred_probe_add(struct device *dev);
int driver_deferred_probe_check_state(struct device *dev); int driver_deferred_probe_check_state(struct device *dev);
int driver_deferred_probe_check_state_continue(struct device *dev);
void driver_init(void); void driver_init(void);
/** /**
......
...@@ -1124,6 +1124,7 @@ extern int __init efi_setup_pcdp_console(char *); ...@@ -1124,6 +1124,7 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ #define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */
#define EFI_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */ #define EFI_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */
#define EFI_MEM_NO_SOFT_RESERVE 11 /* Is the kernel configured to ignore soft reservations? */ #define EFI_MEM_NO_SOFT_RESERVE 11 /* Is the kernel configured to ignore soft reservations? */
#define EFI_PRESERVE_BS_REGIONS 12 /* Are EFI boot-services memory segments available? */
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
/* /*
...@@ -1553,6 +1554,12 @@ static inline void ...@@ -1553,6 +1554,12 @@ static inline void
efi_enable_reset_attack_mitigation(void) { } efi_enable_reset_attack_mitigation(void) { }
#endif #endif
#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
void efi_check_for_embedded_firmwares(void);
#else
static inline void efi_check_for_embedded_firmwares(void) { }
#endif
efi_status_t efi_random_get_seed(void); efi_status_t efi_random_get_seed(void);
void efi_retrieve_tpm2_eventlog(void); void efi_retrieve_tpm2_eventlog(void);
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_EFI_EMBEDDED_FW_H
#define _LINUX_EFI_EMBEDDED_FW_H
#include <linux/list.h>
#include <linux/mod_devicetable.h>
#define EFI_EMBEDDED_FW_PREFIX_LEN 8
/*
* This struct and efi_embedded_fw_list are private to the efi-embedded fw
* implementation they are in this header for use by lib/test_firmware.c only!
*/
struct efi_embedded_fw {
struct list_head list;
const char *name;
const u8 *data;
size_t length;
};
extern struct list_head efi_embedded_fw_list;
/**
* struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw
* code to search for embedded firmwares.
*
* @name: Name to register the firmware with if found
* @prefix: First 8 bytes of the firmware
* @length: Length of the firmware in bytes including prefix
* @sha256: SHA256 of the firmware
*/
struct efi_embedded_fw_desc {
const char *name;
u8 prefix[EFI_EMBEDDED_FW_PREFIX_LEN];
u32 length;
u8 sha256[32];
};
extern const struct dmi_system_id touchscreen_dmi_table[];
int efi_get_embedded_fw(const char *name, const u8 **dat, size_t *sz);
#endif
...@@ -44,6 +44,8 @@ int request_firmware(const struct firmware **fw, const char *name, ...@@ -44,6 +44,8 @@ int request_firmware(const struct firmware **fw, const char *name,
struct device *device); struct device *device);
int firmware_request_nowarn(const struct firmware **fw, const char *name, int firmware_request_nowarn(const struct firmware **fw, const char *name,
struct device *device); struct device *device);
int firmware_request_platform(const struct firmware **fw, const char *name,
struct device *device);
int request_firmware_nowait( int request_firmware_nowait(
struct module *module, bool uevent, struct module *module, bool uevent,
const char *name, struct device *device, gfp_t gfp, void *context, const char *name, struct device *device, gfp_t gfp, void *context,
...@@ -69,6 +71,13 @@ static inline int firmware_request_nowarn(const struct firmware **fw, ...@@ -69,6 +71,13 @@ static inline int firmware_request_nowarn(const struct firmware **fw,
return -EINVAL; return -EINVAL;
} }
static inline int firmware_request_platform(const struct firmware **fw,
const char *name,
struct device *device)
{
return -EINVAL;
}
static inline int request_firmware_nowait( static inline int request_firmware_nowait(
struct module *module, bool uevent, struct module *module, bool uevent,
const char *name, struct device *device, gfp_t gfp, void *context, const char *name, struct device *device, gfp_t gfp, void *context,
......
...@@ -2982,6 +2982,7 @@ extern int do_pipe_flags(int *, int); ...@@ -2982,6 +2982,7 @@ extern int do_pipe_flags(int *, int);
id(UNKNOWN, unknown) \ id(UNKNOWN, unknown) \
id(FIRMWARE, firmware) \ id(FIRMWARE, firmware) \
id(FIRMWARE_PREALLOC_BUFFER, firmware) \ id(FIRMWARE_PREALLOC_BUFFER, firmware) \
id(FIRMWARE_EFI_EMBEDDED, firmware) \
id(MODULE, kernel-module) \ id(MODULE, kernel-module) \
id(KEXEC_IMAGE, kexec-image) \ id(KEXEC_IMAGE, kexec-image) \
id(KEXEC_INITRAMFS, kexec-initramfs) \ id(KEXEC_INITRAMFS, kexec-initramfs) \
...@@ -3012,6 +3013,8 @@ extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, ...@@ -3012,6 +3013,8 @@ extern int kernel_read_file(struct file *, void **, loff_t *, loff_t,
enum kernel_read_file_id); enum kernel_read_file_id);
extern int kernel_read_file_from_path(const char *, void **, loff_t *, loff_t, extern int kernel_read_file_from_path(const char *, void **, loff_t *, loff_t,
enum kernel_read_file_id); enum kernel_read_file_id);
extern int kernel_read_file_from_path_initns(const char *, void **, loff_t *, loff_t,
enum kernel_read_file_id);
extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t, extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t,
enum kernel_read_file_id); enum kernel_read_file_id);
extern ssize_t kernel_read(struct file *, void *, size_t, loff_t *); extern ssize_t kernel_read(struct file *, void *, size_t, loff_t *);
......
...@@ -170,4 +170,6 @@ struct fwnode_operations { ...@@ -170,4 +170,6 @@ struct fwnode_operations {
} while (false) } while (false)
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev) #define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
extern u32 fw_devlink_get_flags(void);
#endif #endif
...@@ -92,7 +92,7 @@ struct platform_device_info { ...@@ -92,7 +92,7 @@ struct platform_device_info {
size_t size_data; size_t size_data;
u64 dma_mask; u64 dma_mask;
struct property_entry *properties; const struct property_entry *properties;
}; };
extern struct platform_device *platform_device_register_full( extern struct platform_device *platform_device_register_full(
const struct platform_device_info *pdevinfo); const struct platform_device_info *pdevinfo);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/efi_embedded_fw.h>
#define TEST_FIRMWARE_NAME "test-firmware.bin" #define TEST_FIRMWARE_NAME "test-firmware.bin"
#define TEST_FIRMWARE_NUM_REQS 4 #define TEST_FIRMWARE_NUM_REQS 4
...@@ -507,6 +508,57 @@ static ssize_t trigger_request_store(struct device *dev, ...@@ -507,6 +508,57 @@ static ssize_t trigger_request_store(struct device *dev,
} }
static DEVICE_ATTR_WO(trigger_request); static DEVICE_ATTR_WO(trigger_request);
#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
static ssize_t trigger_request_platform_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
static const u8 test_data[] = {
0x55, 0xaa, 0x55, 0xaa, 0x01, 0x02, 0x03, 0x04,
0x55, 0xaa, 0x55, 0xaa, 0x05, 0x06, 0x07, 0x08,
0x55, 0xaa, 0x55, 0xaa, 0x10, 0x20, 0x30, 0x40,
0x55, 0xaa, 0x55, 0xaa, 0x50, 0x60, 0x70, 0x80
};
struct efi_embedded_fw efi_embedded_fw;
const struct firmware *firmware = NULL;
char *name;
int rc;
name = kstrndup(buf, count, GFP_KERNEL);
if (!name)
return -ENOSPC;
pr_info("inserting test platform fw '%s'\n", name);
efi_embedded_fw.name = name;
efi_embedded_fw.data = (void *)test_data;
efi_embedded_fw.length = sizeof(test_data);
list_add(&efi_embedded_fw.list, &efi_embedded_fw_list);
pr_info("loading '%s'\n", name);
rc = firmware_request_platform(&firmware, name, dev);
if (rc) {
pr_info("load of '%s' failed: %d\n", name, rc);
goto out;
}
if (firmware->size != sizeof(test_data) ||
memcmp(firmware->data, test_data, sizeof(test_data)) != 0) {
pr_info("firmware contents mismatch for '%s'\n", name);
rc = -EINVAL;
goto out;
}
pr_info("loaded: %zu\n", firmware->size);
rc = count;
out:
release_firmware(firmware);
list_del(&efi_embedded_fw.list);
kfree(name);
return rc;
}
static DEVICE_ATTR_WO(trigger_request_platform);
#endif
static DECLARE_COMPLETION(async_fw_done); static DECLARE_COMPLETION(async_fw_done);
static void trigger_async_request_cb(const struct firmware *fw, void *context) static void trigger_async_request_cb(const struct firmware *fw, void *context)
...@@ -903,6 +955,9 @@ static struct attribute *test_dev_attrs[] = { ...@@ -903,6 +955,9 @@ static struct attribute *test_dev_attrs[] = {
TEST_FW_DEV_ATTR(trigger_request), TEST_FW_DEV_ATTR(trigger_request),
TEST_FW_DEV_ATTR(trigger_async_request), TEST_FW_DEV_ATTR(trigger_async_request),
TEST_FW_DEV_ATTR(trigger_custom_fallback), TEST_FW_DEV_ATTR(trigger_custom_fallback),
#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
TEST_FW_DEV_ATTR(trigger_request_platform),
#endif
/* These use the config and can use the test_result */ /* These use the config and can use the test_result */
TEST_FW_DEV_ATTR(trigger_batched_requests), TEST_FW_DEV_ATTR(trigger_batched_requests),
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
# Makefile for firmware loading selftests # Makefile for firmware loading selftests
CFLAGS = -Wall \
# No binaries, but make sure arg-less "make" doesn't trigger "run_tests" -O2
all:
TEST_PROGS := fw_run_tests.sh TEST_PROGS := fw_run_tests.sh
TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_lib.sh TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_lib.sh
TEST_GEN_FILES := fw_namespace
include ../lib.mk include ../lib.mk
# Nothing to clean up.
clean:
...@@ -86,6 +86,29 @@ else ...@@ -86,6 +86,29 @@ else
fi fi
fi fi
# Try platform (EFI embedded fw) loading too
if [ ! -e "$DIR"/trigger_request_platform ]; then
echo "$0: firmware loading: platform trigger not present, ignoring test" >&2
else
if printf '\000' >"$DIR"/trigger_request_platform 2> /dev/null; then
echo "$0: empty filename should not succeed (platform)" >&2
exit 1
fi
# Note we echo a non-existing name, since files on the file-system
# are preferred over firmware embedded inside the platform's firmware
# The test adds a fake entry with the requested name to the platform's
# fw list, so the name does not matter as long as it does not exist
if ! echo -n "nope-$NAME" >"$DIR"/trigger_request_platform ; then
echo "$0: could not trigger request platform" >&2
exit 1
fi
# The test verifies itself that the loaded firmware contents matches
# the contents for the fake platform fw entry it added.
echo "$0: platform loading works"
fi
### Batched requests tests ### Batched requests tests
test_config_present() test_config_present()
{ {
......
// SPDX-License-Identifier: GPL-2.0
/* Test triggering of loading of firmware from different mount
* namespaces. Expect firmware to be always loaded from the mount
* namespace of PID 1. */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#ifndef CLONE_NEWNS
# define CLONE_NEWNS 0x00020000
#endif
static char *fw_path = NULL;
static void die(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fw_path)
unlink(fw_path);
umount("/lib/firmware");
exit(EXIT_FAILURE);
}
static void trigger_fw(const char *fw_name, const char *sys_path)
{
int fd;
fd = open(sys_path, O_WRONLY);
if (fd < 0)
die("open failed: %s\n",
strerror(errno));
if (write(fd, fw_name, strlen(fw_name)) != strlen(fw_name))
exit(EXIT_FAILURE);
close(fd);
}
static void setup_fw(const char *fw_path)
{
int fd;
const char fw[] = "ABCD0123";
fd = open(fw_path, O_WRONLY | O_CREAT, 0600);
if (fd < 0)
die("open failed: %s\n",
strerror(errno));
if (write(fd, fw, sizeof(fw) -1) != sizeof(fw) -1)
die("write failed: %s\n",
strerror(errno));
close(fd);
}
static bool test_fw_in_ns(const char *fw_name, const char *sys_path, bool block_fw_in_parent_ns)
{
pid_t child;
if (block_fw_in_parent_ns)
if (mount("test", "/lib/firmware", "tmpfs", MS_RDONLY, NULL) == -1)
die("blocking firmware in parent ns failed\n");
child = fork();
if (child == -1) {
die("fork failed: %s\n",
strerror(errno));
}
if (child != 0) { /* parent */
pid_t pid;
int status;
pid = waitpid(child, &status, 0);
if (pid == -1) {
die("waitpid failed: %s\n",
strerror(errno));
}
if (pid != child) {
die("waited for %d got %d\n",
child, pid);
}
if (!WIFEXITED(status)) {
die("child did not terminate cleanly\n");
}
if (block_fw_in_parent_ns)
umount("/lib/firmware");
return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false;
}
if (unshare(CLONE_NEWNS) != 0) {
die("unshare(CLONE_NEWNS) failed: %s\n",
strerror(errno));
}
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) == -1)
die("remount root in child ns failed\n");
if (!block_fw_in_parent_ns) {
if (mount("test", "/lib/firmware", "tmpfs", MS_RDONLY, NULL) == -1)
die("blocking firmware in child ns failed\n");
} else
umount("/lib/firmware");
trigger_fw(fw_name, sys_path);
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
const char *fw_name = "test-firmware.bin";
char *sys_path;
if (argc != 2)
die("usage: %s sys_path\n", argv[0]);
/* Mount tmpfs to /lib/firmware so we don't have to assume
that it is writable for us.*/
if (mount("test", "/lib/firmware", "tmpfs", 0, NULL) == -1)
die("mounting tmpfs to /lib/firmware failed\n");
sys_path = argv[1];
asprintf(&fw_path, "/lib/firmware/%s", fw_name);
setup_fw(fw_path);
setvbuf(stdout, NULL, _IONBF, 0);
/* Positive case: firmware in PID1 mount namespace */
printf("Testing with firmware in parent namespace (assumed to be same file system as PID1)\n");
if (!test_fw_in_ns(fw_name, sys_path, false))
die("error: failed to access firmware\n");
/* Negative case: firmware in child mount namespace, expected to fail */
printf("Testing with firmware in child namespace\n");
if (test_fw_in_ns(fw_name, sys_path, true))
die("error: firmware access did not fail\n");
unlink(fw_path);
free(fw_path);
umount("/lib/firmware");
exit(EXIT_SUCCESS);
}
...@@ -61,6 +61,10 @@ run_test_config_0003() ...@@ -61,6 +61,10 @@ run_test_config_0003()
check_mods check_mods
check_setup check_setup
echo "Running namespace test: "
$TEST_DIR/fw_namespace $DIR/trigger_request
echo "OK"
if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
run_test_config_0001 run_test_config_0001
run_test_config_0002 run_test_config_0002
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment