Skip to content

Commit

Permalink
Merge tag 'driver-core-5.7-rc1' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/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
  ...
  • Loading branch information
torvalds committed Mar 30, 2020
2 parents db34c5f + 18555cb commit 5983809
Show file tree
Hide file tree
Showing 48 changed files with 996 additions and 174 deletions.
24 changes: 18 additions & 6 deletions Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,24 @@
can be changed at run time by the max_graph_depth file
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]=
[HW,JOY] Multisystem joystick and NES/SNES/PSX pad
support via parallel port (up to 5 devices per port)
Expand Down Expand Up @@ -3291,12 +3309,6 @@
This can be set from sysctl after boot.
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.
See Documentation/debugging-via-ohci1394.txt for more
info.
Expand Down
103 changes: 103 additions & 0 deletions Documentation/driver-api/firmware/fallback-mechanisms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,106 @@ the following file:

If you echo 0 into it means MAX_JIFFY_OFFSET will be used. The data type
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.
2 changes: 2 additions & 0 deletions Documentation/driver-api/firmware/lookup-order.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ a driver issues a firmware API call.
return it immediately
* The ''Direct filesystem lookup'' is performed next, if found we
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
the sysfs interface is created. After this either a kobject uevent
is issued or the custom firmware loading is relied upon for firmware
Expand Down
5 changes: 5 additions & 0 deletions Documentation/driver-api/firmware/request_firmware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ firmware_request_nowarn
.. kernel-doc:: drivers/base/firmware_loader/main.c
:functions: firmware_request_nowarn

firmware_request_platform
-------------------------
.. kernel-doc:: drivers/base/firmware_loader/main.c
:functions: firmware_request_platform

request_firmware_direct
-----------------------
.. kernel-doc:: drivers/base/firmware_loader/main.c
Expand Down
8 changes: 4 additions & 4 deletions Documentation/filesystems/debugfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ missing.
Create a file with an initial size, the following function can be used
instead::

struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops,
loff_t file_size);
void debugfs_create_file_size(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops,
loff_t file_size);

file_size is the initial file size. The other parameters are the same
as the function debugfs_create_file.
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/platform/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ int __init efi_memblock_x86_reserve_range(void)
efi.memmap.desc_version);

memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size);
set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags);

return 0;
}
Expand Down Expand Up @@ -943,6 +944,7 @@ static void __init __efi_enter_virtual_mode(void)
goto err;
}

efi_check_for_embedded_firmwares();
efi_free_boot_services();

/*
Expand Down
4 changes: 4 additions & 0 deletions arch/x86/platform/efi/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,10 @@ void __init efi_free_boot_services(void)
int num_entries = 0;
void *new, *new_md;

/* Keep all regions for /sys/kernel/debug/efi */
if (efi_enabled(EFI_DBG))
return;

for_each_efi_memory_desc(md) {
unsigned long long start = md->phys_addr;
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
Expand Down
44 changes: 30 additions & 14 deletions drivers/base/arch_topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ static void update_topology_flags_workfn(struct work_struct *work)
update_topology = 0;
}

static u32 capacity_scale;
static DEFINE_PER_CPU(u32, freq_factor) = 1;
static u32 *raw_capacity;

static int free_raw_capacity(void)
Expand All @@ -108,17 +108,23 @@ static int free_raw_capacity(void)
void topology_normalize_cpu_scale(void)
{
u64 capacity;
u64 capacity_scale;
int cpu;

if (!raw_capacity)
return;

pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
capacity_scale = 1;
for_each_possible_cpu(cpu) {
pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
cpu, raw_capacity[cpu]);
capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
/ capacity_scale;
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
capacity_scale = max(capacity, 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);
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
cpu, topology_get_cpu_scale(cpu));
Expand All @@ -127,6 +133,7 @@ void topology_normalize_cpu_scale(void)

bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
{
struct clk *cpu_clk;
static bool cap_parsing_failed;
int ret;
u32 cpu_capacity;
Expand All @@ -146,10 +153,22 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
return false;
}
}
capacity_scale = max(cpu_capacity, capacity_scale);
raw_capacity[cpu] = cpu_capacity;
pr_debug("cpu_capacity: %pOF cpu_capacity=%u (raw)\n",
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 {
if (raw_capacity) {
pr_err("cpu_capacity: missing %pOF raw capacity\n",
Expand Down Expand Up @@ -188,11 +207,8 @@ init_cpu_capacity_callback(struct notifier_block *nb,

cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);

for_each_cpu(cpu, policy->related_cpus) {
raw_capacity[cpu] = topology_get_cpu_scale(cpu) *
policy->cpuinfo.max_freq / 1000UL;
capacity_scale = max(raw_capacity[cpu], capacity_scale);
}
for_each_cpu(cpu, policy->related_cpus)
per_cpu(freq_factor, cpu) = policy->cpuinfo.max_freq / 1000;

if (cpumask_empty(cpus_to_visit)) {
topology_normalize_cpu_scale();
Expand Down Expand Up @@ -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,
int core_id)
{
char name[10];
char name[20];
bool leaf = true;
int i = 0;
int cpu;
Expand Down Expand Up @@ -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)
{
char name[10];
char name[20];
bool leaf = true;
bool has_cores = false;
struct device_node *c;
Expand Down
3 changes: 2 additions & 1 deletion drivers/base/component.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,8 @@ static void component_unbind(struct component *component,
{
WARN_ON(!component->bound);

component->ops->unbind(component->dev, master->dev, data);
if (component->ops && component->ops->unbind)
component->ops->unbind(component->dev, master->dev, data);
component->bound = false;

/* Release all resources claimed in the binding of this component */
Expand Down
Loading

0 comments on commit 5983809

Please sign in to comment.