License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 22:07:57 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
|
|
|
|
* (C) Copyright 2002-2004 IBM Corp.
|
|
|
|
* (C) Copyright 2003 Matthew Wilcox
|
|
|
|
* (C) Copyright 2003 Hewlett-Packard
|
|
|
|
* (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
|
|
|
|
* (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
|
|
|
|
*
|
|
|
|
* File attributes for PCI devices
|
|
|
|
*
|
2013-11-15 02:28:18 +08:00
|
|
|
* Modeled after usb's driverfs.c
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
2008-10-03 09:52:51 +08:00
|
|
|
#include <linux/sched.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/stat.h>
|
2011-05-27 21:37:25 +08:00
|
|
|
#include <linux/export.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/topology.h>
|
|
|
|
#include <linux/mm.h>
|
2010-05-14 01:43:07 +08:00
|
|
|
#include <linux/fs.h>
|
2007-07-16 14:40:39 +08:00
|
|
|
#include <linux/capability.h>
|
2011-02-15 09:21:49 +08:00
|
|
|
#include <linux/security.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2012-04-17 04:26:02 +08:00
|
|
|
#include <linux/vgaarb.h>
|
PCI/PM: add PCIe runtime D3cold support
This patch adds runtime D3cold support and corresponding ACPI platform
support. This patch only enables runtime D3cold support; it does not
enable D3cold support during system suspend/hibernate.
D3cold is the deepest power saving state for a PCIe device, where its main
power is removed. While it is in D3cold, you can't access the device at
all, not even its configuration space (which is still accessible in D3hot).
Therefore the PCI PM registers can not be used to transition into/out of
the D3cold state; that must be done by platform logic such as ACPI _PR3.
To support wakeup from D3cold, a system may provide auxiliary power, which
allows a device to request wakeup using a Beacon or the sideband WAKE#
signal. WAKE# is usually connected to platform logic such as ACPI GPE.
This is quite different from other power saving states, where devices
request wakeup via a PME message on the PCIe link.
Some devices, such as those in plug-in slots, have no direct platform
logic. For example, there is usually no ACPI _PR3 for them. D3cold
support for these devices can be done via the PCIe Downstream Port leading
to the device. When the PCIe port is powered on/off, the device is powered
on/off too. Wakeup events from the device will be notified to the
corresponding PCIe port.
For more information about PCIe D3cold and corresponding ACPI support,
please refer to:
- PCI Express Base Specification Revision 2.0
- Advanced Configuration and Power Interface Specification Revision 5.0
[bhelgaas: changelog]
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Originally-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-06-23 10:23:51 +08:00
|
|
|
#include <linux/pm_runtime.h>
|
2021-08-25 18:26:35 +08:00
|
|
|
#include <linux/msi.h>
|
2014-04-18 01:46:15 +08:00
|
|
|
#include <linux/of.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include "pci.h"
|
|
|
|
|
|
|
|
static int sysfs_initialized; /* = 0 */
|
|
|
|
|
|
|
|
/* show configuration fields */
|
|
|
|
#define pci_config_attr(field, format_string) \
|
|
|
|
static ssize_t \
|
2005-05-17 18:42:58 +08:00
|
|
|
field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
|
2005-04-17 06:20:36 +08:00
|
|
|
{ \
|
|
|
|
struct pci_dev *pdev; \
|
|
|
|
\
|
2014-04-19 08:13:49 +08:00
|
|
|
pdev = to_pci_dev(dev); \
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, format_string, pdev->field); \
|
2013-10-07 14:55:40 +08:00
|
|
|
} \
|
|
|
|
static DEVICE_ATTR_RO(field)
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
pci_config_attr(vendor, "0x%04x\n");
|
|
|
|
pci_config_attr(device, "0x%04x\n");
|
|
|
|
pci_config_attr(subsystem_vendor, "0x%04x\n");
|
|
|
|
pci_config_attr(subsystem_device, "0x%04x\n");
|
2016-11-22 06:24:49 +08:00
|
|
|
pci_config_attr(revision, "0x%02x\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
pci_config_attr(class, "0x%06x\n");
|
2021-08-25 18:26:35 +08:00
|
|
|
|
|
|
|
static ssize_t irq_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
|
|
|
#ifdef CONFIG_PCI_MSI
|
|
|
|
/*
|
|
|
|
* For MSI, show the first MSI IRQ; for all other cases including
|
|
|
|
* MSI-X, show the legacy INTx IRQ.
|
|
|
|
*/
|
2021-12-07 06:27:36 +08:00
|
|
|
if (pdev->msi_enabled)
|
|
|
|
return sysfs_emit(buf, "%u\n", pci_irq_vector(pdev, 0));
|
2021-08-25 18:26:35 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return sysfs_emit(buf, "%u\n", pdev->irq);
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(irq);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-06-15 07:59:48 +08:00
|
|
|
static ssize_t broken_parity_status_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", pdev->broken_parity_status);
|
2006-06-15 07:59:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t broken_parity_status_store(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
PCI: Make settable sysfs attributes more consistent
PCI devices have three settable boolean attributes, enable,
broken_parity_status, and msi_bus.
The store functions for these would silently interpret "0x01" as false,
"1llogical" as true, and "true" would be (silently!) ignored and do
nothing.
This is inconsistent with typical sysfs handling of settable attributes,
and just plain doesn't make much sense.
So, use strict_strtoul(), which was created for this purpose. The store
functions will treat a value of 0 as false, non-zero as true, and return
-EINVAL for a parse failure.
Additionally, is_enabled_store() and msi_bus_store() return -EPERM if
CAP_SYS_ADMIN is lacking, rather than silently doing nothing. This is more
typical behavior for sysfs attributes that need a capability.
And msi_bus_store() will only print the "forced subordinate bus ..."
warning if the MSI flag was actually forced to a different value.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2008-12-01 09:10:12 +08:00
|
|
|
unsigned long val;
|
2006-06-15 07:59:48 +08:00
|
|
|
|
2013-06-01 15:25:25 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
PCI: Make settable sysfs attributes more consistent
PCI devices have three settable boolean attributes, enable,
broken_parity_status, and msi_bus.
The store functions for these would silently interpret "0x01" as false,
"1llogical" as true, and "true" would be (silently!) ignored and do
nothing.
This is inconsistent with typical sysfs handling of settable attributes,
and just plain doesn't make much sense.
So, use strict_strtoul(), which was created for this purpose. The store
functions will treat a value of 0 as false, non-zero as true, and return
-EINVAL for a parse failure.
Additionally, is_enabled_store() and msi_bus_store() return -EPERM if
CAP_SYS_ADMIN is lacking, rather than silently doing nothing. This is more
typical behavior for sysfs attributes that need a capability.
And msi_bus_store() will only print the "forced subordinate bus ..."
warning if the MSI flag was actually forced to a different value.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2008-12-01 09:10:12 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
pdev->broken_parity_status = !!val;
|
|
|
|
|
|
|
|
return count;
|
2006-06-15 07:59:48 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RW(broken_parity_status);
|
2006-06-15 07:59:48 +08:00
|
|
|
|
2014-09-30 21:48:22 +08:00
|
|
|
static ssize_t pci_dev_show_local_cpu(struct device *dev, bool list,
|
2014-04-19 08:13:49 +08:00
|
|
|
struct device_attribute *attr, char *buf)
|
2013-09-30 15:02:38 +08:00
|
|
|
{
|
2009-01-04 21:18:01 +08:00
|
|
|
const struct cpumask *mask;
|
2005-09-10 15:25:49 +08:00
|
|
|
|
2009-04-17 18:01:55 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
2021-10-04 21:34:53 +08:00
|
|
|
if (dev_to_node(dev) == NUMA_NO_NODE)
|
|
|
|
mask = cpu_online_mask;
|
|
|
|
else
|
|
|
|
mask = cpumask_of_node(dev_to_node(dev));
|
2009-04-17 18:01:55 +08:00
|
|
|
#else
|
2009-01-04 21:18:01 +08:00
|
|
|
mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
|
2009-04-17 18:01:55 +08:00
|
|
|
#endif
|
2014-09-30 21:48:22 +08:00
|
|
|
return cpumap_print_to_pagebuf(list, buf, mask);
|
2008-04-09 02:43:03 +08:00
|
|
|
}
|
|
|
|
|
2013-09-30 15:02:38 +08:00
|
|
|
static ssize_t local_cpus_show(struct device *dev,
|
2014-04-19 08:13:49 +08:00
|
|
|
struct device_attribute *attr, char *buf)
|
2013-09-30 15:02:38 +08:00
|
|
|
{
|
2014-09-30 21:48:22 +08:00
|
|
|
return pci_dev_show_local_cpu(dev, false, attr, buf);
|
2013-09-30 15:02:38 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RO(local_cpus);
|
2008-04-09 02:43:03 +08:00
|
|
|
|
|
|
|
static ssize_t local_cpulist_show(struct device *dev,
|
2014-04-19 08:13:49 +08:00
|
|
|
struct device_attribute *attr, char *buf)
|
2008-04-09 02:43:03 +08:00
|
|
|
{
|
2014-09-30 21:48:22 +08:00
|
|
|
return pci_dev_show_local_cpu(dev, true, attr, buf);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RO(local_cpulist);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-05-13 08:11:40 +08:00
|
|
|
/*
|
|
|
|
* PCI Bus Class Devices
|
|
|
|
*/
|
2013-07-25 06:05:17 +08:00
|
|
|
static ssize_t cpuaffinity_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2011-05-13 08:11:40 +08:00
|
|
|
{
|
2014-09-30 21:48:22 +08:00
|
|
|
const struct cpumask *cpumask = cpumask_of_pcibus(to_pci_bus(dev));
|
|
|
|
|
|
|
|
return cpumap_print_to_pagebuf(false, buf, cpumask);
|
2011-05-13 08:11:40 +08:00
|
|
|
}
|
2013-07-25 06:05:17 +08:00
|
|
|
static DEVICE_ATTR_RO(cpuaffinity);
|
2011-05-13 08:11:40 +08:00
|
|
|
|
2013-07-25 06:05:17 +08:00
|
|
|
static ssize_t cpulistaffinity_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2011-05-13 08:11:40 +08:00
|
|
|
{
|
2014-09-30 21:48:22 +08:00
|
|
|
const struct cpumask *cpumask = cpumask_of_pcibus(to_pci_bus(dev));
|
|
|
|
|
|
|
|
return cpumap_print_to_pagebuf(true, buf, cpumask);
|
2011-05-13 08:11:40 +08:00
|
|
|
}
|
2013-07-25 06:05:17 +08:00
|
|
|
static DEVICE_ATTR_RO(cpulistaffinity);
|
2011-05-13 08:11:40 +08:00
|
|
|
|
2020-11-02 22:15:20 +08:00
|
|
|
static ssize_t power_state_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%s\n", pci_power_name(pdev->current_state));
|
2020-11-02 22:15:20 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(power_state);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* show resources */
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2014-04-19 08:13:49 +08:00
|
|
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
2005-04-17 06:20:36 +08:00
|
|
|
int i;
|
2008-11-22 02:39:32 +08:00
|
|
|
int max;
|
2006-06-13 08:06:02 +08:00
|
|
|
resource_size_t start, end;
|
2021-04-17 04:58:45 +08:00
|
|
|
size_t len = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (pci_dev->subordinate)
|
|
|
|
max = DEVICE_COUNT_RESOURCE;
|
2008-11-22 02:39:32 +08:00
|
|
|
else
|
|
|
|
max = PCI_BRIDGE_RESOURCES;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
for (i = 0; i < max; i++) {
|
2005-05-13 15:44:10 +08:00
|
|
|
struct resource *res = &pci_dev->resource[i];
|
|
|
|
pci_resource_to_user(pci_dev, i, res, &start, &end);
|
2021-04-17 04:58:45 +08:00
|
|
|
len += sysfs_emit_at(buf, len, "0x%016llx 0x%016llx 0x%016llx\n",
|
|
|
|
(unsigned long long)start,
|
|
|
|
(unsigned long long)end,
|
|
|
|
(unsigned long long)res->flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2021-04-17 04:58:45 +08:00
|
|
|
return len;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RO(resource);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-06-01 17:43:06 +08:00
|
|
|
static ssize_t max_link_speed_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
2018-03-30 20:44:05 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2017-06-01 17:43:06 +08:00
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%s\n",
|
|
|
|
pci_speed_string(pcie_get_speed_cap(pdev)));
|
2017-06-01 17:43:06 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(max_link_speed);
|
|
|
|
|
|
|
|
static ssize_t max_link_width_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
2018-03-30 21:24:36 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2017-06-01 17:43:06 +08:00
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
|
2017-06-01 17:43:06 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(max_link_width);
|
|
|
|
|
|
|
|
static ssize_t current_link_speed_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
|
|
|
u16 linkstat;
|
|
|
|
int err;
|
2020-02-29 05:24:52 +08:00
|
|
|
enum pci_bus_speed speed;
|
2017-06-01 17:43:06 +08:00
|
|
|
|
|
|
|
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
|
|
|
|
if (err)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-02-29 05:24:52 +08:00
|
|
|
speed = pcie_link_speed[linkstat & PCI_EXP_LNKSTA_CLS];
|
2017-06-01 17:43:06 +08:00
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%s\n", pci_speed_string(speed));
|
2017-06-01 17:43:06 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(current_link_speed);
|
|
|
|
|
|
|
|
static ssize_t current_link_width_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
|
|
|
u16 linkstat;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
|
|
|
|
if (err)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n",
|
2017-06-01 17:43:06 +08:00
|
|
|
(linkstat & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT);
|
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(current_link_width);
|
|
|
|
|
|
|
|
static ssize_t secondary_bus_number_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
|
|
|
u8 sec_bus;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
|
|
|
|
if (err)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", sec_bus);
|
2017-06-01 17:43:06 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(secondary_bus_number);
|
|
|
|
|
|
|
|
static ssize_t subordinate_bus_number_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
|
|
|
u8 sub_bus;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
|
|
|
|
if (err)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", sub_bus);
|
2017-06-01 17:43:06 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(subordinate_bus_number);
|
|
|
|
|
2018-01-06 02:51:55 +08:00
|
|
|
static ssize_t ari_enabled_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", pci_ari_enabled(pci_dev->bus));
|
2018-01-06 02:51:55 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(ari_enabled);
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2005-05-06 02:57:25 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X\n",
|
|
|
|
pci_dev->vendor, pci_dev->device,
|
|
|
|
pci_dev->subsystem_vendor, pci_dev->subsystem_device,
|
|
|
|
(u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
|
|
|
|
(u8)(pci_dev->class));
|
2005-05-06 02:57:25 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RO(modalias);
|
PCI: switch pci_{enable,disable}_device() to be nestable
Changes the pci_{enable,disable}_device() functions to work in a
nested basis, so that eg, three calls to enable_device() require three
calls to disable_device().
The reason for this is to simplify PCI drivers for
multi-interface/capability devices. These are devices that cram more
than one interface in a single function. A relevant example of that is
the Wireless [USB] Host Controller Interface (similar to EHCI) [see
http://www.intel.com/technology/comms/wusb/whci.htm].
In these kind of devices, multiple interfaces are accessed through a
single bar and IRQ line. For that, the drivers map only the smallest
area of the bar to access their register banks and use shared IRQ
handlers.
However, because the order at which those drivers load cannot be known
ahead of time, the sequence in which the calls to pci_enable_device()
and pci_disable_device() cannot be predicted. Thus:
1. driverA starts pci_enable_device()
2. driverB starts pci_enable_device()
3. driverA shutdown pci_disable_device()
4. driverB shutdown pci_disable_device()
between steps 3 and 4, driver B would loose access to it's device,
even if it didn't intend to.
By using this modification, the device won't be disabled until all the
callers to enable() have called disable().
This is implemented by replacing 'struct pci_dev->is_enabled' from a
bitfield to an atomic use count. Each caller to enable increments it,
each caller to disable decrements it. When the count increments from 0
to 1, __pci_enable_device() is called to actually enable the
device. When it drops to zero, pci_disable_device() actually does the
disabling.
We keep the backend __pci_enable_device() for pci_default_resume() to
use and also change the sysfs method implementation, so that userspace
enabling/disabling the device doesn't disable it one time too much.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-11-23 04:40:31 +08:00
|
|
|
|
2014-10-31 00:30:28 +08:00
|
|
|
static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
|
2014-04-19 08:13:49 +08:00
|
|
|
const char *buf, size_t count)
|
2006-04-29 16:59:08 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
PCI: Make settable sysfs attributes more consistent
PCI devices have three settable boolean attributes, enable,
broken_parity_status, and msi_bus.
The store functions for these would silently interpret "0x01" as false,
"1llogical" as true, and "true" would be (silently!) ignored and do
nothing.
This is inconsistent with typical sysfs handling of settable attributes,
and just plain doesn't make much sense.
So, use strict_strtoul(), which was created for this purpose. The store
functions will treat a value of 0 as false, non-zero as true, and return
-EINVAL for a parse failure.
Additionally, is_enabled_store() and msi_bus_store() return -EPERM if
CAP_SYS_ADMIN is lacking, rather than silently doing nothing. This is more
typical behavior for sysfs attributes that need a capability.
And msi_bus_store() will only print the "forced subordinate bus ..."
warning if the MSI flag was actually forced to a different value.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2008-12-01 09:10:12 +08:00
|
|
|
unsigned long val;
|
2021-09-16 07:01:26 +08:00
|
|
|
ssize_t result = 0;
|
2006-04-29 16:59:08 +08:00
|
|
|
|
|
|
|
/* this can crash the machine when done on the "wrong" device */
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
PCI: Make settable sysfs attributes more consistent
PCI devices have three settable boolean attributes, enable,
broken_parity_status, and msi_bus.
The store functions for these would silently interpret "0x01" as false,
"1llogical" as true, and "true" would be (silently!) ignored and do
nothing.
This is inconsistent with typical sysfs handling of settable attributes,
and just plain doesn't make much sense.
So, use strict_strtoul(), which was created for this purpose. The store
functions will treat a value of 0 as false, non-zero as true, and return
-EINVAL for a parse failure.
Additionally, is_enabled_store() and msi_bus_store() return -EPERM if
CAP_SYS_ADMIN is lacking, rather than silently doing nothing. This is more
typical behavior for sysfs attributes that need a capability.
And msi_bus_store() will only print the "forced subordinate bus ..."
warning if the MSI flag was actually forced to a different value.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2008-12-01 09:10:12 +08:00
|
|
|
return -EPERM;
|
2006-04-29 16:59:08 +08:00
|
|
|
|
2021-09-16 07:01:26 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
|
|
|
return -EINVAL;
|
2021-09-16 07:01:25 +08:00
|
|
|
|
2018-05-19 00:56:24 +08:00
|
|
|
device_lock(dev);
|
|
|
|
if (dev->driver)
|
|
|
|
result = -EBUSY;
|
|
|
|
else if (val)
|
PCI: switch pci_{enable,disable}_device() to be nestable
Changes the pci_{enable,disable}_device() functions to work in a
nested basis, so that eg, three calls to enable_device() require three
calls to disable_device().
The reason for this is to simplify PCI drivers for
multi-interface/capability devices. These are devices that cram more
than one interface in a single function. A relevant example of that is
the Wireless [USB] Host Controller Interface (similar to EHCI) [see
http://www.intel.com/technology/comms/wusb/whci.htm].
In these kind of devices, multiple interfaces are accessed through a
single bar and IRQ line. For that, the drivers map only the smallest
area of the bar to access their register banks and use shared IRQ
handlers.
However, because the order at which those drivers load cannot be known
ahead of time, the sequence in which the calls to pci_enable_device()
and pci_disable_device() cannot be predicted. Thus:
1. driverA starts pci_enable_device()
2. driverB starts pci_enable_device()
3. driverA shutdown pci_disable_device()
4. driverB shutdown pci_disable_device()
between steps 3 and 4, driver B would loose access to it's device,
even if it didn't intend to.
By using this modification, the device won't be disabled until all the
callers to enable() have called disable().
This is implemented by replacing 'struct pci_dev->is_enabled' from a
bitfield to an atomic use count. Each caller to enable increments it,
each caller to disable decrements it. When the count increments from 0
to 1, __pci_enable_device() is called to actually enable the
device. When it drops to zero, pci_disable_device() actually does the
disabling.
We keep the backend __pci_enable_device() for pci_default_resume() to
use and also change the sysfs method implementation, so that userspace
enabling/disabling the device doesn't disable it one time too much.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-11-23 04:40:31 +08:00
|
|
|
result = pci_enable_device(pdev);
|
2018-05-19 00:56:24 +08:00
|
|
|
else if (pci_is_enabled(pdev))
|
|
|
|
pci_disable_device(pdev);
|
|
|
|
else
|
|
|
|
result = -EIO;
|
|
|
|
device_unlock(dev);
|
2006-04-29 16:59:08 +08:00
|
|
|
|
PCI: switch pci_{enable,disable}_device() to be nestable
Changes the pci_{enable,disable}_device() functions to work in a
nested basis, so that eg, three calls to enable_device() require three
calls to disable_device().
The reason for this is to simplify PCI drivers for
multi-interface/capability devices. These are devices that cram more
than one interface in a single function. A relevant example of that is
the Wireless [USB] Host Controller Interface (similar to EHCI) [see
http://www.intel.com/technology/comms/wusb/whci.htm].
In these kind of devices, multiple interfaces are accessed through a
single bar and IRQ line. For that, the drivers map only the smallest
area of the bar to access their register banks and use shared IRQ
handlers.
However, because the order at which those drivers load cannot be known
ahead of time, the sequence in which the calls to pci_enable_device()
and pci_disable_device() cannot be predicted. Thus:
1. driverA starts pci_enable_device()
2. driverB starts pci_enable_device()
3. driverA shutdown pci_disable_device()
4. driverB shutdown pci_disable_device()
between steps 3 and 4, driver B would loose access to it's device,
even if it didn't intend to.
By using this modification, the device won't be disabled until all the
callers to enable() have called disable().
This is implemented by replacing 'struct pci_dev->is_enabled' from a
bitfield to an atomic use count. Each caller to enable increments it,
each caller to disable decrements it. When the count increments from 0
to 1, __pci_enable_device() is called to actually enable the
device. When it drops to zero, pci_disable_device() actually does the
disabling.
We keep the backend __pci_enable_device() for pci_default_resume() to
use and also change the sysfs method implementation, so that userspace
enabling/disabling the device doesn't disable it one time too much.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-11-23 04:40:31 +08:00
|
|
|
return result < 0 ? result : count;
|
|
|
|
}
|
|
|
|
|
2014-10-31 00:30:28 +08:00
|
|
|
static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
|
2014-04-19 08:13:49 +08:00
|
|
|
char *buf)
|
PCI: switch pci_{enable,disable}_device() to be nestable
Changes the pci_{enable,disable}_device() functions to work in a
nested basis, so that eg, three calls to enable_device() require three
calls to disable_device().
The reason for this is to simplify PCI drivers for
multi-interface/capability devices. These are devices that cram more
than one interface in a single function. A relevant example of that is
the Wireless [USB] Host Controller Interface (similar to EHCI) [see
http://www.intel.com/technology/comms/wusb/whci.htm].
In these kind of devices, multiple interfaces are accessed through a
single bar and IRQ line. For that, the drivers map only the smallest
area of the bar to access their register banks and use shared IRQ
handlers.
However, because the order at which those drivers load cannot be known
ahead of time, the sequence in which the calls to pci_enable_device()
and pci_disable_device() cannot be predicted. Thus:
1. driverA starts pci_enable_device()
2. driverB starts pci_enable_device()
3. driverA shutdown pci_disable_device()
4. driverB shutdown pci_disable_device()
between steps 3 and 4, driver B would loose access to it's device,
even if it didn't intend to.
By using this modification, the device won't be disabled until all the
callers to enable() have called disable().
This is implemented by replacing 'struct pci_dev->is_enabled' from a
bitfield to an atomic use count. Each caller to enable increments it,
each caller to disable decrements it. When the count increments from 0
to 1, __pci_enable_device() is called to actually enable the
device. When it drops to zero, pci_disable_device() actually does the
disabling.
We keep the backend __pci_enable_device() for pci_default_resume() to
use and also change the sysfs method implementation, so that userspace
enabling/disabling the device doesn't disable it one time too much.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-11-23 04:40:31 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev;
|
2006-04-29 16:59:08 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
pdev = to_pci_dev(dev);
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", atomic_read(&pdev->enable_cnt));
|
2006-04-29 16:59:08 +08:00
|
|
|
}
|
2014-10-31 00:30:28 +08:00
|
|
|
static DEVICE_ATTR_RW(enable);
|
2006-04-29 16:59:08 +08:00
|
|
|
|
2007-01-28 17:53:40 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
2014-10-24 02:22:12 +08:00
|
|
|
static ssize_t numa_node_store(struct device *dev,
|
|
|
|
struct device_attribute *attr, const char *buf,
|
|
|
|
size_t count)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2021-09-16 07:01:26 +08:00
|
|
|
int node;
|
2014-10-24 02:22:12 +08:00
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
2021-09-16 07:01:26 +08:00
|
|
|
if (kstrtoint(buf, 0, &node) < 0)
|
|
|
|
return -EINVAL;
|
2014-10-24 02:22:12 +08:00
|
|
|
|
2015-11-10 03:00:27 +08:00
|
|
|
if ((node < 0 && node != NUMA_NO_NODE) || node >= MAX_NUMNODES)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (node != NUMA_NO_NODE && !node_online(node))
|
2014-10-24 02:22:12 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
|
2018-01-19 02:55:24 +08:00
|
|
|
pci_alert(pdev, FW_BUG "Overriding NUMA node to %d. Contact your vendor for updates.",
|
2014-10-24 02:22:12 +08:00
|
|
|
node);
|
|
|
|
|
|
|
|
dev->numa_node = node;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2007-01-28 17:53:40 +08:00
|
|
|
{
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%d\n", dev->numa_node);
|
2007-01-28 17:53:40 +08:00
|
|
|
}
|
2014-10-24 02:22:12 +08:00
|
|
|
static DEVICE_ATTR_RW(numa_node);
|
2007-01-28 17:53:40 +08:00
|
|
|
#endif
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t dma_mask_bits_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
2009-11-25 10:21:21 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%d\n", fls64(pdev->dma_mask));
|
2009-11-25 10:21:21 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RO(dma_mask_bits);
|
2009-11-25 10:21:21 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t consistent_dma_mask_bits_show(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
char *buf)
|
2009-11-25 10:21:21 +08:00
|
|
|
{
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%d\n", fls64(dev->coherent_dma_mask));
|
2009-11-25 10:21:21 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RO(consistent_dma_mask_bits);
|
2009-11-25 10:21:21 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2006-08-31 13:55:15 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2014-09-23 13:27:24 +08:00
|
|
|
struct pci_bus *subordinate = pdev->subordinate;
|
2006-08-31 13:55:15 +08:00
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", subordinate ?
|
|
|
|
!(subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)
|
|
|
|
: !pdev->no_msi);
|
2006-08-31 13:55:15 +08:00
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2006-08-31 13:55:15 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2014-09-23 13:27:24 +08:00
|
|
|
struct pci_bus *subordinate = pdev->subordinate;
|
PCI: Make settable sysfs attributes more consistent
PCI devices have three settable boolean attributes, enable,
broken_parity_status, and msi_bus.
The store functions for these would silently interpret "0x01" as false,
"1llogical" as true, and "true" would be (silently!) ignored and do
nothing.
This is inconsistent with typical sysfs handling of settable attributes,
and just plain doesn't make much sense.
So, use strict_strtoul(), which was created for this purpose. The store
functions will treat a value of 0 as false, non-zero as true, and return
-EINVAL for a parse failure.
Additionally, is_enabled_store() and msi_bus_store() return -EPERM if
CAP_SYS_ADMIN is lacking, rather than silently doing nothing. This is more
typical behavior for sysfs attributes that need a capability.
And msi_bus_store() will only print the "forced subordinate bus ..."
warning if the MSI flag was actually forced to a different value.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2008-12-01 09:10:12 +08:00
|
|
|
unsigned long val;
|
|
|
|
|
2006-08-31 13:55:15 +08:00
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
PCI: Make settable sysfs attributes more consistent
PCI devices have three settable boolean attributes, enable,
broken_parity_status, and msi_bus.
The store functions for these would silently interpret "0x01" as false,
"1llogical" as true, and "true" would be (silently!) ignored and do
nothing.
This is inconsistent with typical sysfs handling of settable attributes,
and just plain doesn't make much sense.
So, use strict_strtoul(), which was created for this purpose. The store
functions will treat a value of 0 as false, non-zero as true, and return
-EINVAL for a parse failure.
Additionally, is_enabled_store() and msi_bus_store() return -EPERM if
CAP_SYS_ADMIN is lacking, rather than silently doing nothing. This is more
typical behavior for sysfs attributes that need a capability.
And msi_bus_store() will only print the "forced subordinate bus ..."
warning if the MSI flag was actually forced to a different value.
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2008-12-01 09:10:12 +08:00
|
|
|
return -EPERM;
|
2006-08-31 13:55:15 +08:00
|
|
|
|
2021-09-16 07:01:25 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-11-15 02:28:18 +08:00
|
|
|
/*
|
2014-09-23 13:27:24 +08:00
|
|
|
* "no_msi" and "bus_flags" only affect what happens when a driver
|
|
|
|
* requests MSI or MSI-X. They don't affect any drivers that have
|
|
|
|
* already requested MSI or MSI-X.
|
2013-11-15 02:28:18 +08:00
|
|
|
*/
|
2014-09-23 13:27:24 +08:00
|
|
|
if (!subordinate) {
|
|
|
|
pdev->no_msi = !val;
|
2018-01-19 02:55:24 +08:00
|
|
|
pci_info(pdev, "MSI/MSI-X %s for future drivers\n",
|
2014-09-23 13:27:24 +08:00
|
|
|
val ? "allowed" : "disallowed");
|
2006-08-31 13:55:15 +08:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-09-23 13:27:24 +08:00
|
|
|
if (val)
|
|
|
|
subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
|
|
|
|
else
|
|
|
|
subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
|
|
|
|
|
|
|
|
dev_info(&subordinate->dev, "MSI/MSI-X %s for future drivers of devices on this bus\n",
|
|
|
|
val ? "allowed" : "disallowed");
|
2006-08-31 13:55:15 +08:00
|
|
|
return count;
|
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RW(msi_bus);
|
2005-05-06 02:57:25 +08:00
|
|
|
|
2018-12-21 15:54:34 +08:00
|
|
|
static ssize_t rescan_store(struct bus_type *bus, const char *buf, size_t count)
|
2009-03-21 04:56:31 +08:00
|
|
|
{
|
|
|
|
unsigned long val;
|
|
|
|
struct pci_bus *b = NULL;
|
|
|
|
|
2013-06-01 15:25:25 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
2009-03-21 04:56:31 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (val) {
|
2014-01-10 22:22:18 +08:00
|
|
|
pci_lock_rescan_remove();
|
2009-03-21 04:56:31 +08:00
|
|
|
while ((b = pci_find_next_bus(b)) != NULL)
|
|
|
|
pci_rescan_bus(b);
|
2014-01-10 22:22:18 +08:00
|
|
|
pci_unlock_rescan_remove();
|
2009-03-21 04:56:31 +08:00
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2018-12-21 15:54:34 +08:00
|
|
|
static BUS_ATTR_WO(rescan);
|
2009-03-21 04:56:31 +08:00
|
|
|
|
2013-09-28 18:12:00 +08:00
|
|
|
static struct attribute *pci_bus_attrs[] = {
|
2013-10-08 04:51:02 +08:00
|
|
|
&bus_attr_rescan.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group pci_bus_group = {
|
|
|
|
.attrs = pci_bus_attrs,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct attribute_group *pci_bus_groups[] = {
|
|
|
|
&pci_bus_group,
|
|
|
|
NULL,
|
2009-03-21 04:56:31 +08:00
|
|
|
};
|
2009-03-21 04:56:36 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t dev_rescan_store(struct device *dev,
|
|
|
|
struct device_attribute *attr, const char *buf,
|
|
|
|
size_t count)
|
2009-03-21 04:56:41 +08:00
|
|
|
{
|
|
|
|
unsigned long val;
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
2013-06-01 15:25:25 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
2009-03-21 04:56:41 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (val) {
|
2014-01-10 22:22:18 +08:00
|
|
|
pci_lock_rescan_remove();
|
2009-03-21 04:56:41 +08:00
|
|
|
pci_rescan_bus(pdev->bus);
|
2014-01-10 22:22:18 +08:00
|
|
|
pci_unlock_rescan_remove();
|
2009-03-21 04:56:41 +08:00
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2020-03-25 23:17:08 +08:00
|
|
|
static struct device_attribute dev_attr_dev_rescan = __ATTR(rescan, 0200, NULL,
|
|
|
|
dev_rescan_store);
|
2009-03-21 04:56:41 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2009-03-21 04:56:36 +08:00
|
|
|
{
|
|
|
|
unsigned long val;
|
|
|
|
|
2013-06-01 15:25:25 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
2009-03-21 04:56:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2014-02-04 03:03:02 +08:00
|
|
|
if (val && device_remove_file_self(dev, attr))
|
|
|
|
pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
|
2009-03-21 04:56:36 +08:00
|
|
|
return count;
|
|
|
|
}
|
2019-08-14 04:45:12 +08:00
|
|
|
static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0220, NULL,
|
PCI: sysfs: Define device attributes with DEVICE_ATTR*()
Device attributes should be defined using DEVICE_ATTR*(_name, _mode, _show,
_store). Convert them all from __ATTR*() to DEVICE_ATTR*(), e.g.,
- struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show,
_store)
+ static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo)
Link: https://lore.kernel.org/r/20190813204513.4790-2-skunberg.kelsey@gmail.com
Signed-off-by: Kelsey Skunberg <skunberg.kelsey@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
2019-08-14 04:45:11 +08:00
|
|
|
remove_store);
|
2011-05-13 08:11:39 +08:00
|
|
|
|
2019-08-15 23:33:52 +08:00
|
|
|
static ssize_t bus_rescan_store(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2011-05-13 08:11:39 +08:00
|
|
|
{
|
|
|
|
unsigned long val;
|
|
|
|
struct pci_bus *bus = to_pci_bus(dev);
|
|
|
|
|
2013-06-01 15:25:25 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
2011-05-13 08:11:39 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (val) {
|
2014-01-10 22:22:18 +08:00
|
|
|
pci_lock_rescan_remove();
|
2012-01-21 18:08:22 +08:00
|
|
|
if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
|
|
|
|
pci_rescan_bus_bridge_resize(bus->self);
|
|
|
|
else
|
|
|
|
pci_rescan_bus(bus);
|
2014-01-10 22:22:18 +08:00
|
|
|
pci_unlock_rescan_remove();
|
2011-05-13 08:11:39 +08:00
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2020-03-25 23:17:08 +08:00
|
|
|
static struct device_attribute dev_attr_bus_rescan = __ATTR(rescan, 0200, NULL,
|
|
|
|
bus_rescan_store);
|
2011-05-13 08:11:39 +08:00
|
|
|
|
2014-11-28 06:16:57 +08:00
|
|
|
#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
|
PCI/PM: add PCIe runtime D3cold support
This patch adds runtime D3cold support and corresponding ACPI platform
support. This patch only enables runtime D3cold support; it does not
enable D3cold support during system suspend/hibernate.
D3cold is the deepest power saving state for a PCIe device, where its main
power is removed. While it is in D3cold, you can't access the device at
all, not even its configuration space (which is still accessible in D3hot).
Therefore the PCI PM registers can not be used to transition into/out of
the D3cold state; that must be done by platform logic such as ACPI _PR3.
To support wakeup from D3cold, a system may provide auxiliary power, which
allows a device to request wakeup using a Beacon or the sideband WAKE#
signal. WAKE# is usually connected to platform logic such as ACPI GPE.
This is quite different from other power saving states, where devices
request wakeup via a PME message on the PCIe link.
Some devices, such as those in plug-in slots, have no direct platform
logic. For example, there is usually no ACPI _PR3 for them. D3cold
support for these devices can be done via the PCIe Downstream Port leading
to the device. When the PCIe port is powered on/off, the device is powered
on/off too. Wakeup events from the device will be notified to the
corresponding PCIe port.
For more information about PCIe D3cold and corresponding ACPI support,
please refer to:
- PCI Express Base Specification Revision 2.0
- Advanced Configuration and Power Interface Specification Revision 5.0
[bhelgaas: changelog]
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Originally-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-06-23 10:23:51 +08:00
|
|
|
static ssize_t d3cold_allowed_store(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
unsigned long val;
|
|
|
|
|
2013-06-01 15:25:25 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
PCI/PM: add PCIe runtime D3cold support
This patch adds runtime D3cold support and corresponding ACPI platform
support. This patch only enables runtime D3cold support; it does not
enable D3cold support during system suspend/hibernate.
D3cold is the deepest power saving state for a PCIe device, where its main
power is removed. While it is in D3cold, you can't access the device at
all, not even its configuration space (which is still accessible in D3hot).
Therefore the PCI PM registers can not be used to transition into/out of
the D3cold state; that must be done by platform logic such as ACPI _PR3.
To support wakeup from D3cold, a system may provide auxiliary power, which
allows a device to request wakeup using a Beacon or the sideband WAKE#
signal. WAKE# is usually connected to platform logic such as ACPI GPE.
This is quite different from other power saving states, where devices
request wakeup via a PME message on the PCIe link.
Some devices, such as those in plug-in slots, have no direct platform
logic. For example, there is usually no ACPI _PR3 for them. D3cold
support for these devices can be done via the PCIe Downstream Port leading
to the device. When the PCIe port is powered on/off, the device is powered
on/off too. Wakeup events from the device will be notified to the
corresponding PCIe port.
For more information about PCIe D3cold and corresponding ACPI support,
please refer to:
- PCI Express Base Specification Revision 2.0
- Advanced Configuration and Power Interface Specification Revision 5.0
[bhelgaas: changelog]
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Originally-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-06-23 10:23:51 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
pdev->d3cold_allowed = !!val;
|
2016-06-02 16:17:12 +08:00
|
|
|
if (pdev->d3cold_allowed)
|
|
|
|
pci_d3cold_enable(pdev);
|
|
|
|
else
|
|
|
|
pci_d3cold_disable(pdev);
|
|
|
|
|
PCI/PM: add PCIe runtime D3cold support
This patch adds runtime D3cold support and corresponding ACPI platform
support. This patch only enables runtime D3cold support; it does not
enable D3cold support during system suspend/hibernate.
D3cold is the deepest power saving state for a PCIe device, where its main
power is removed. While it is in D3cold, you can't access the device at
all, not even its configuration space (which is still accessible in D3hot).
Therefore the PCI PM registers can not be used to transition into/out of
the D3cold state; that must be done by platform logic such as ACPI _PR3.
To support wakeup from D3cold, a system may provide auxiliary power, which
allows a device to request wakeup using a Beacon or the sideband WAKE#
signal. WAKE# is usually connected to platform logic such as ACPI GPE.
This is quite different from other power saving states, where devices
request wakeup via a PME message on the PCIe link.
Some devices, such as those in plug-in slots, have no direct platform
logic. For example, there is usually no ACPI _PR3 for them. D3cold
support for these devices can be done via the PCIe Downstream Port leading
to the device. When the PCIe port is powered on/off, the device is powered
on/off too. Wakeup events from the device will be notified to the
corresponding PCIe port.
For more information about PCIe D3cold and corresponding ACPI support,
please refer to:
- PCI Express Base Specification Revision 2.0
- Advanced Configuration and Power Interface Specification Revision 5.0
[bhelgaas: changelog]
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Originally-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-06-23 10:23:51 +08:00
|
|
|
pm_runtime_resume(dev);
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t d3cold_allowed_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", pdev->d3cold_allowed);
|
PCI/PM: add PCIe runtime D3cold support
This patch adds runtime D3cold support and corresponding ACPI platform
support. This patch only enables runtime D3cold support; it does not
enable D3cold support during system suspend/hibernate.
D3cold is the deepest power saving state for a PCIe device, where its main
power is removed. While it is in D3cold, you can't access the device at
all, not even its configuration space (which is still accessible in D3hot).
Therefore the PCI PM registers can not be used to transition into/out of
the D3cold state; that must be done by platform logic such as ACPI _PR3.
To support wakeup from D3cold, a system may provide auxiliary power, which
allows a device to request wakeup using a Beacon or the sideband WAKE#
signal. WAKE# is usually connected to platform logic such as ACPI GPE.
This is quite different from other power saving states, where devices
request wakeup via a PME message on the PCIe link.
Some devices, such as those in plug-in slots, have no direct platform
logic. For example, there is usually no ACPI _PR3 for them. D3cold
support for these devices can be done via the PCIe Downstream Port leading
to the device. When the PCIe port is powered on/off, the device is powered
on/off too. Wakeup events from the device will be notified to the
corresponding PCIe port.
For more information about PCIe D3cold and corresponding ACPI support,
please refer to:
- PCI Express Base Specification Revision 2.0
- Advanced Configuration and Power Interface Specification Revision 5.0
[bhelgaas: changelog]
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Originally-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-06-23 10:23:51 +08:00
|
|
|
}
|
2013-10-07 14:55:40 +08:00
|
|
|
static DEVICE_ATTR_RW(d3cold_allowed);
|
PCI/PM: add PCIe runtime D3cold support
This patch adds runtime D3cold support and corresponding ACPI platform
support. This patch only enables runtime D3cold support; it does not
enable D3cold support during system suspend/hibernate.
D3cold is the deepest power saving state for a PCIe device, where its main
power is removed. While it is in D3cold, you can't access the device at
all, not even its configuration space (which is still accessible in D3hot).
Therefore the PCI PM registers can not be used to transition into/out of
the D3cold state; that must be done by platform logic such as ACPI _PR3.
To support wakeup from D3cold, a system may provide auxiliary power, which
allows a device to request wakeup using a Beacon or the sideband WAKE#
signal. WAKE# is usually connected to platform logic such as ACPI GPE.
This is quite different from other power saving states, where devices
request wakeup via a PME message on the PCIe link.
Some devices, such as those in plug-in slots, have no direct platform
logic. For example, there is usually no ACPI _PR3 for them. D3cold
support for these devices can be done via the PCIe Downstream Port leading
to the device. When the PCIe port is powered on/off, the device is powered
on/off too. Wakeup events from the device will be notified to the
corresponding PCIe port.
For more information about PCIe D3cold and corresponding ACPI support,
please refer to:
- PCI Express Base Specification Revision 2.0
- Advanced Configuration and Power Interface Specification Revision 5.0
[bhelgaas: changelog]
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Originally-by: Zheng Yan <zheng.z.yan@intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2012-06-23 10:23:51 +08:00
|
|
|
#endif
|
|
|
|
|
2014-04-18 01:46:15 +08:00
|
|
|
#ifdef CONFIG_OF
|
|
|
|
static ssize_t devspec_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
struct device_node *np = pci_device_to_OF_node(pdev);
|
|
|
|
|
2017-07-19 05:43:21 +08:00
|
|
|
if (np == NULL)
|
2014-04-18 01:46:15 +08:00
|
|
|
return 0;
|
2021-06-03 08:01:10 +08:00
|
|
|
return sysfs_emit(buf, "%pOF\n", np);
|
2014-04-18 01:46:15 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(devspec);
|
|
|
|
#endif
|
|
|
|
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
static ssize_t driver_override_store(struct device *dev,
|
|
|
|
struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2017-09-11 15:45:40 +08:00
|
|
|
char *driver_override, *old, *cp;
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
|
2015-02-05 06:38:15 +08:00
|
|
|
/* We need to keep extra room for a newline */
|
|
|
|
if (count >= (PAGE_SIZE - 1))
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
driver_override = kstrndup(buf, count, GFP_KERNEL);
|
|
|
|
if (!driver_override)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
cp = strchr(driver_override, '\n');
|
|
|
|
if (cp)
|
|
|
|
*cp = '\0';
|
|
|
|
|
2017-09-11 15:45:40 +08:00
|
|
|
device_lock(dev);
|
|
|
|
old = pdev->driver_override;
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
if (strlen(driver_override)) {
|
|
|
|
pdev->driver_override = driver_override;
|
|
|
|
} else {
|
|
|
|
kfree(driver_override);
|
|
|
|
pdev->driver_override = NULL;
|
|
|
|
}
|
2017-09-11 15:45:40 +08:00
|
|
|
device_unlock(dev);
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
|
|
|
|
kfree(old);
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t driver_override_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2017-09-11 15:45:40 +08:00
|
|
|
ssize_t len;
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
|
2017-09-11 15:45:40 +08:00
|
|
|
device_lock(dev);
|
2021-04-17 04:58:45 +08:00
|
|
|
len = sysfs_emit(buf, "%s\n", pdev->driver_override);
|
2017-09-11 15:45:40 +08:00
|
|
|
device_unlock(dev);
|
|
|
|
return len;
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RW(driver_override);
|
|
|
|
|
2013-09-28 18:12:00 +08:00
|
|
|
static struct attribute *pci_dev_attrs[] = {
|
2020-11-02 22:15:20 +08:00
|
|
|
&dev_attr_power_state.attr,
|
2013-10-07 14:55:40 +08:00
|
|
|
&dev_attr_resource.attr,
|
|
|
|
&dev_attr_vendor.attr,
|
|
|
|
&dev_attr_device.attr,
|
|
|
|
&dev_attr_subsystem_vendor.attr,
|
|
|
|
&dev_attr_subsystem_device.attr,
|
2016-11-22 06:24:49 +08:00
|
|
|
&dev_attr_revision.attr,
|
2013-10-07 14:55:40 +08:00
|
|
|
&dev_attr_class.attr,
|
|
|
|
&dev_attr_irq.attr,
|
|
|
|
&dev_attr_local_cpus.attr,
|
|
|
|
&dev_attr_local_cpulist.attr,
|
|
|
|
&dev_attr_modalias.attr,
|
2007-01-28 17:53:40 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
2013-10-07 14:55:40 +08:00
|
|
|
&dev_attr_numa_node.attr,
|
2007-01-28 17:53:40 +08:00
|
|
|
#endif
|
2013-10-07 14:55:40 +08:00
|
|
|
&dev_attr_dma_mask_bits.attr,
|
|
|
|
&dev_attr_consistent_dma_mask_bits.attr,
|
2014-10-31 00:30:28 +08:00
|
|
|
&dev_attr_enable.attr,
|
2013-10-07 14:55:40 +08:00
|
|
|
&dev_attr_broken_parity_status.attr,
|
|
|
|
&dev_attr_msi_bus.attr,
|
2014-11-28 06:16:57 +08:00
|
|
|
#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
|
2013-10-07 14:55:40 +08:00
|
|
|
&dev_attr_d3cold_allowed.attr,
|
2014-04-18 01:46:15 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_OF
|
|
|
|
&dev_attr_devspec.attr,
|
2009-03-21 04:56:36 +08:00
|
|
|
#endif
|
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device
rather than relying on the driver to provide a positive match of the
device. This shortcuts the existing process of looking up the vendor and
device ID, adding them to the driver new_id, binding the device, then
removing the ID, but it also provides a couple advantages.
First, the above existing process allows the driver to bind to any device
matching the new_id for the window where it's enabled. This is often not
desired, such as the case of trying to bind a single device to a meta
driver like pci-stub or vfio-pci. Using driver_override we can do this
deterministically using:
echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Previously we could not invoke drivers_probe after adding a device to
new_id for a driver as we get non-deterministic behavior whether the driver
we intend or the standard driver will claim the device. Now it becomes a
deterministic process, only the driver matching driver_override will probe
the device.
To return the device to the standard driver, we simply clear the
driver_override and reprobe the device:
echo > /sys/bus/pci/devices/0000:03:00.0/driver_override
echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind
echo 0000:03:00.0 > /sys/bus/pci/drivers_probe
Another advantage to this approach is that we can specify a driver override
to force a specific binding or prevent any binding. For instance when an
IOMMU group is exposed to userspace through VFIO we require that all
devices within that group are owned by VFIO. However, devices can be
hot-added into an IOMMU group, in which case we want to prevent the device
from binding to any driver (override driver = "none") or perhaps have it
automatically bind to vfio-pci. With driver_override it's a simple matter
for this field to be set internally when the device is first discovered to
prevent driver matches.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-05-20 22:53:21 +08:00
|
|
|
&dev_attr_driver_override.attr,
|
2018-01-06 02:51:55 +08:00
|
|
|
&dev_attr_ari_enabled.attr,
|
2013-10-07 14:55:40 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2017-06-01 17:43:06 +08:00
|
|
|
static struct attribute *pci_bridge_attrs[] = {
|
|
|
|
&dev_attr_subordinate_bus_number.attr,
|
|
|
|
&dev_attr_secondary_bus_number.attr,
|
|
|
|
NULL,
|
2013-10-07 14:55:40 +08:00
|
|
|
};
|
|
|
|
|
2017-06-01 17:43:06 +08:00
|
|
|
static struct attribute *pcie_dev_attrs[] = {
|
|
|
|
&dev_attr_current_link_speed.attr,
|
|
|
|
&dev_attr_current_link_width.attr,
|
|
|
|
&dev_attr_max_link_width.attr,
|
|
|
|
&dev_attr_max_link_speed.attr,
|
2013-10-07 14:55:40 +08:00
|
|
|
NULL,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2013-07-25 06:05:17 +08:00
|
|
|
static struct attribute *pcibus_attrs[] = {
|
PCI: sysfs: Define device attributes with DEVICE_ATTR*()
Device attributes should be defined using DEVICE_ATTR*(_name, _mode, _show,
_store). Convert them all from __ATTR*() to DEVICE_ATTR*(), e.g.,
- struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show,
_store)
+ static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo)
Link: https://lore.kernel.org/r/20190813204513.4790-2-skunberg.kelsey@gmail.com
Signed-off-by: Kelsey Skunberg <skunberg.kelsey@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
2019-08-14 04:45:11 +08:00
|
|
|
&dev_attr_bus_rescan.attr,
|
2013-07-25 06:05:17 +08:00
|
|
|
&dev_attr_cpuaffinity.attr,
|
|
|
|
&dev_attr_cpulistaffinity.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group pcibus_group = {
|
|
|
|
.attrs = pcibus_attrs,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct attribute_group *pcibus_groups[] = {
|
|
|
|
&pcibus_group,
|
|
|
|
NULL,
|
2011-05-13 08:11:39 +08:00
|
|
|
};
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
2009-03-04 13:57:05 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
2012-04-17 04:26:02 +08:00
|
|
|
struct pci_dev *vga_dev = vga_default_device();
|
|
|
|
|
|
|
|
if (vga_dev)
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n", (pdev == vga_dev));
|
2009-03-04 13:57:05 +08:00
|
|
|
|
2021-04-17 04:58:45 +08:00
|
|
|
return sysfs_emit(buf, "%u\n",
|
|
|
|
!!(pdev->resource[PCI_ROM_RESOURCE].flags &
|
|
|
|
IORESOURCE_ROM_SHADOW));
|
2009-03-04 13:57:05 +08:00
|
|
|
}
|
PCI: sysfs: Define device attributes with DEVICE_ATTR*()
Device attributes should be defined using DEVICE_ATTR*(_name, _mode, _show,
_store). Convert them all from __ATTR*() to DEVICE_ATTR*(), e.g.,
- struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show,
_store)
+ static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo)
Link: https://lore.kernel.org/r/20190813204513.4790-2-skunberg.kelsey@gmail.com
Signed-off-by: Kelsey Skunberg <skunberg.kelsey@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
2019-08-14 04:45:11 +08:00
|
|
|
static DEVICE_ATTR_RO(boot_vga);
|
2009-03-04 13:57:05 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *bin_attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned int size = 64;
|
|
|
|
loff_t init_off = off;
|
2014-04-19 08:13:49 +08:00
|
|
|
u8 *data = (u8 *) buf;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Several chips lock up trying to read undefined config space */
|
2016-04-15 03:00:21 +08:00
|
|
|
if (file_ns_capable(filp, &init_user_ns, CAP_SYS_ADMIN))
|
2005-04-17 06:20:36 +08:00
|
|
|
size = dev->cfg_size;
|
2014-04-19 08:13:49 +08:00
|
|
|
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
|
2005-04-17 06:20:36 +08:00
|
|
|
size = 128;
|
|
|
|
|
|
|
|
if (off > size)
|
|
|
|
return 0;
|
|
|
|
if (off + count > size) {
|
|
|
|
size -= off;
|
|
|
|
count = size;
|
|
|
|
} else {
|
|
|
|
size = count;
|
|
|
|
}
|
|
|
|
|
2012-08-15 09:43:03 +08:00
|
|
|
pci_config_pm_runtime_get(dev);
|
|
|
|
|
2005-04-08 13:53:31 +08:00
|
|
|
if ((off & 1) && size) {
|
|
|
|
u8 val;
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_read_config_byte(dev, off, &val);
|
2005-04-08 13:53:31 +08:00
|
|
|
data[off - init_off] = val;
|
2005-04-17 06:20:36 +08:00
|
|
|
off++;
|
2005-04-08 13:53:31 +08:00
|
|
|
size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((off & 3) && size > 2) {
|
|
|
|
u16 val;
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_read_config_word(dev, off, &val);
|
2005-04-08 13:53:31 +08:00
|
|
|
data[off - init_off] = val & 0xff;
|
|
|
|
data[off - init_off + 1] = (val >> 8) & 0xff;
|
|
|
|
off += 2;
|
|
|
|
size -= 2;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
while (size > 3) {
|
2005-04-08 13:53:31 +08:00
|
|
|
u32 val;
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_read_config_dword(dev, off, &val);
|
2005-04-08 13:53:31 +08:00
|
|
|
data[off - init_off] = val & 0xff;
|
|
|
|
data[off - init_off + 1] = (val >> 8) & 0xff;
|
|
|
|
data[off - init_off + 2] = (val >> 16) & 0xff;
|
|
|
|
data[off - init_off + 3] = (val >> 24) & 0xff;
|
2005-04-17 06:20:36 +08:00
|
|
|
off += 4;
|
|
|
|
size -= 4;
|
2020-08-24 13:20:25 +08:00
|
|
|
cond_resched();
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-04-08 13:53:31 +08:00
|
|
|
if (size >= 2) {
|
|
|
|
u16 val;
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_read_config_word(dev, off, &val);
|
2005-04-08 13:53:31 +08:00
|
|
|
data[off - init_off] = val & 0xff;
|
|
|
|
data[off - init_off + 1] = (val >> 8) & 0xff;
|
|
|
|
off += 2;
|
|
|
|
size -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size > 0) {
|
|
|
|
u8 val;
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_read_config_byte(dev, off, &val);
|
2005-04-08 13:53:31 +08:00
|
|
|
data[off - init_off] = val;
|
2005-04-17 06:20:36 +08:00
|
|
|
off++;
|
|
|
|
--size;
|
|
|
|
}
|
|
|
|
|
2012-08-15 09:43:03 +08:00
|
|
|
pci_config_pm_runtime_put(dev);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *bin_attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned int size = count;
|
|
|
|
loff_t init_off = off;
|
2014-04-19 08:13:49 +08:00
|
|
|
u8 *data = (u8 *) buf;
|
2019-08-20 08:17:47 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (off > dev->cfg_size)
|
|
|
|
return 0;
|
|
|
|
if (off + count > dev->cfg_size) {
|
|
|
|
size = dev->cfg_size - off;
|
|
|
|
count = size;
|
|
|
|
}
|
2013-11-15 02:28:18 +08:00
|
|
|
|
2012-08-15 09:43:03 +08:00
|
|
|
pci_config_pm_runtime_get(dev);
|
|
|
|
|
2005-04-08 13:53:31 +08:00
|
|
|
if ((off & 1) && size) {
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_write_config_byte(dev, off, data[off - init_off]);
|
2005-04-17 06:20:36 +08:00
|
|
|
off++;
|
2005-04-08 13:53:31 +08:00
|
|
|
size--;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2013-11-15 02:28:18 +08:00
|
|
|
|
2005-04-08 13:53:31 +08:00
|
|
|
if ((off & 3) && size > 2) {
|
|
|
|
u16 val = data[off - init_off];
|
|
|
|
val |= (u16) data[off - init_off + 1] << 8;
|
2014-04-19 08:13:49 +08:00
|
|
|
pci_user_write_config_word(dev, off, val);
|
|
|
|
off += 2;
|
|
|
|
size -= 2;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
while (size > 3) {
|
2005-04-08 13:53:31 +08:00
|
|
|
u32 val = data[off - init_off];
|
|
|
|
val |= (u32) data[off - init_off + 1] << 8;
|
|
|
|
val |= (u32) data[off - init_off + 2] << 16;
|
|
|
|
val |= (u32) data[off - init_off + 3] << 24;
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_write_config_dword(dev, off, val);
|
2005-04-17 06:20:36 +08:00
|
|
|
off += 4;
|
|
|
|
size -= 4;
|
|
|
|
}
|
2013-11-15 02:28:18 +08:00
|
|
|
|
2005-04-08 13:53:31 +08:00
|
|
|
if (size >= 2) {
|
|
|
|
u16 val = data[off - init_off];
|
|
|
|
val |= (u16) data[off - init_off + 1] << 8;
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_write_config_word(dev, off, val);
|
2005-04-08 13:53:31 +08:00
|
|
|
off += 2;
|
|
|
|
size -= 2;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-04-08 13:53:31 +08:00
|
|
|
if (size) {
|
2005-09-27 16:21:55 +08:00
|
|
|
pci_user_write_config_byte(dev, off, data[off - init_off]);
|
2005-04-17 06:20:36 +08:00
|
|
|
off++;
|
|
|
|
--size;
|
|
|
|
}
|
|
|
|
|
2012-08-15 09:43:03 +08:00
|
|
|
pci_config_pm_runtime_put(dev);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return count;
|
|
|
|
}
|
2021-04-17 04:58:37 +08:00
|
|
|
static BIN_ATTR(config, 0644, pci_read_config, pci_write_config, 0);
|
|
|
|
|
|
|
|
static struct bin_attribute *pci_dev_config_attrs[] = {
|
|
|
|
&bin_attr_config,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static umode_t pci_dev_config_attr_is_visible(struct kobject *kobj,
|
|
|
|
struct bin_attribute *a, int n)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
|
|
|
|
|
|
|
|
a->size = PCI_CFG_SPACE_SIZE;
|
|
|
|
if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
|
|
|
|
a->size = PCI_CFG_SPACE_EXP_SIZE;
|
|
|
|
|
|
|
|
return a->attr.mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct attribute_group pci_dev_config_attr_group = {
|
|
|
|
.bin_attrs = pci_dev_config_attrs,
|
|
|
|
.is_bin_visible = pci_dev_config_attr_is_visible,
|
|
|
|
};
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#ifdef HAVE_PCI_LEGACY
|
|
|
|
/**
|
|
|
|
* pci_read_legacy_io - read byte(s) from legacy I/O port space
|
2010-05-13 09:28:57 +08:00
|
|
|
* @filp: open sysfs file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @kobj: kobject corresponding to file to read from
|
2009-04-11 06:17:50 +08:00
|
|
|
* @bin_attr: struct bin_attribute for this file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @buf: buffer to store results
|
|
|
|
* @off: offset into legacy I/O port space
|
|
|
|
* @count: number of bytes to read
|
|
|
|
*
|
|
|
|
* Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
|
|
|
|
* callback routine (pci_legacy_read).
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *bin_attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
/* Only support 1, 2 or 4 byte accesses */
|
|
|
|
if (count != 1 && count != 2 && count != 4)
|
|
|
|
return -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
return pci_legacy_read(bus, off, (u32 *)buf, count);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* pci_write_legacy_io - write byte(s) to legacy I/O port space
|
2010-05-13 09:28:57 +08:00
|
|
|
* @filp: open sysfs file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @kobj: kobject corresponding to file to read from
|
2009-04-11 06:17:50 +08:00
|
|
|
* @bin_attr: struct bin_attribute for this file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @buf: buffer containing value to be written
|
|
|
|
* @off: offset into legacy I/O port space
|
|
|
|
* @count: number of bytes to write
|
|
|
|
*
|
|
|
|
* Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
|
|
|
|
* callback routine (pci_legacy_write).
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *bin_attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
/* Only support 1, 2 or 4 byte accesses */
|
|
|
|
if (count != 1 && count != 2 && count != 4)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return pci_legacy_write(bus, off, *(u32 *)buf, count);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* pci_mmap_legacy_mem - map legacy PCI memory into user memory space
|
2010-05-13 09:28:57 +08:00
|
|
|
* @filp: open sysfs file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @kobj: kobject corresponding to device to be mapped
|
|
|
|
* @attr: struct bin_attribute for this file
|
|
|
|
* @vma: struct vm_area_struct passed to mmap
|
|
|
|
*
|
2008-10-03 17:49:32 +08:00
|
|
|
* Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap
|
2005-04-17 06:20:36 +08:00
|
|
|
* legacy memory space (first meg of bus space) into application virtual
|
|
|
|
* memory space.
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *attr,
|
|
|
|
struct vm_area_struct *vma)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem);
|
2008-10-03 17:49:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* pci_mmap_legacy_io - map legacy PCI IO into user memory space
|
2010-05-13 09:28:57 +08:00
|
|
|
* @filp: open sysfs file
|
2008-10-03 17:49:32 +08:00
|
|
|
* @kobj: kobject corresponding to device to be mapped
|
|
|
|
* @attr: struct bin_attribute for this file
|
|
|
|
* @vma: struct vm_area_struct passed to mmap
|
|
|
|
*
|
|
|
|
* Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap
|
|
|
|
* legacy IO space (first meg of bus space) into application virtual
|
|
|
|
* memory space. Returns -ENOSYS if the operation isn't supported
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static int pci_mmap_legacy_io(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *attr,
|
|
|
|
struct vm_area_struct *vma)
|
2008-10-03 17:49:32 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
2008-10-03 17:49:32 +08:00
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
|
2008-10-03 17:49:32 +08:00
|
|
|
}
|
|
|
|
|
2009-02-17 18:46:53 +08:00
|
|
|
/**
|
|
|
|
* pci_adjust_legacy_attr - adjustment of legacy file attributes
|
|
|
|
* @b: bus to create files under
|
|
|
|
* @mmap_type: I/O port or memory
|
|
|
|
*
|
|
|
|
* Stub implementation. Can be overridden by arch if necessary.
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
void __weak pci_adjust_legacy_attr(struct pci_bus *b,
|
|
|
|
enum pci_mmap_state mmap_type)
|
2009-02-17 18:46:53 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-10-03 17:49:32 +08:00
|
|
|
/**
|
|
|
|
* pci_create_legacy_files - create legacy I/O port and memory files
|
|
|
|
* @b: bus to create files under
|
|
|
|
*
|
|
|
|
* Some platforms allow access to legacy I/O port and ISA memory space on
|
|
|
|
* a per-bus basis. This routine creates the files and ties them into
|
|
|
|
* their associated read, write and mmap files from pci-sysfs.c
|
|
|
|
*
|
2011-03-31 09:57:33 +08:00
|
|
|
* On error unwind, but don't propagate the error to the caller
|
2008-10-03 17:49:32 +08:00
|
|
|
* as it is ok to set up the PCI bus without these files.
|
|
|
|
*/
|
|
|
|
void pci_create_legacy_files(struct pci_bus *b)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
2021-02-05 21:36:32 +08:00
|
|
|
if (!sysfs_initialized)
|
|
|
|
return;
|
|
|
|
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:03:40 +08:00
|
|
|
b->legacy_io = kcalloc(2, sizeof(struct bin_attribute),
|
2008-10-03 17:49:32 +08:00
|
|
|
GFP_ATOMIC);
|
|
|
|
if (!b->legacy_io)
|
|
|
|
goto kzalloc_err;
|
|
|
|
|
2010-03-01 17:38:36 +08:00
|
|
|
sysfs_bin_attr_init(b->legacy_io);
|
2008-10-03 17:49:32 +08:00
|
|
|
b->legacy_io->attr.name = "legacy_io";
|
|
|
|
b->legacy_io->size = 0xffff;
|
2019-08-14 04:45:12 +08:00
|
|
|
b->legacy_io->attr.mode = 0600;
|
2008-10-03 17:49:32 +08:00
|
|
|
b->legacy_io->read = pci_read_legacy_io;
|
|
|
|
b->legacy_io->write = pci_write_legacy_io;
|
|
|
|
b->legacy_io->mmap = pci_mmap_legacy_io;
|
2021-07-30 07:32:35 +08:00
|
|
|
b->legacy_io->f_mapping = iomem_get_mapping;
|
2009-02-17 18:46:53 +08:00
|
|
|
pci_adjust_legacy_attr(b, pci_mmap_io);
|
2008-10-03 17:49:32 +08:00
|
|
|
error = device_create_bin_file(&b->dev, b->legacy_io);
|
|
|
|
if (error)
|
|
|
|
goto legacy_io_err;
|
|
|
|
|
|
|
|
/* Allocated above after the legacy_io struct */
|
|
|
|
b->legacy_mem = b->legacy_io + 1;
|
2010-03-11 06:48:34 +08:00
|
|
|
sysfs_bin_attr_init(b->legacy_mem);
|
2008-10-03 17:49:32 +08:00
|
|
|
b->legacy_mem->attr.name = "legacy_mem";
|
|
|
|
b->legacy_mem->size = 1024*1024;
|
2019-08-14 04:45:12 +08:00
|
|
|
b->legacy_mem->attr.mode = 0600;
|
2008-10-03 17:49:32 +08:00
|
|
|
b->legacy_mem->mmap = pci_mmap_legacy_mem;
|
Driver core update for 5.15-rc1
Here is the big set of driver core patches for 5.15-rc1.
These do change a number of different things across different
subsystems, and because of that, there were 2 stable tags created that
might have already come into your tree from different pulls that did the
following
- changed the bus remove callback to return void
- sysfs iomem_get_mapping rework
The latter one will cause a tiny merge issue with your tree, as there
was a last-minute fix for this in 5.14 in your tree, but the fixup
should be "obvious". If you want me to provide a fixed merge for this,
please let me know.
Other than those two things, there's only a few small things in here:
- kernfs performance improvements for huge numbers of sysfs
users at once
- tiny api cleanups
- other minor changes
All of these have been in linux-next for a while with no reported
problems, other than the before-mentioned merge issue.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-----BEGIN PGP SIGNATURE-----
iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYS+FLQ8cZ3JlZ0Brcm9h
aC5jb20ACgkQMUfUDdst+ylXuACfWECnysDtXNe66DdETCFs1a1RToYAoMokWeU5
s8VFP1NY2BjmxJbkebLL
=8kVu
-----END PGP SIGNATURE-----
Merge tag 'driver-core-5.15-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 patches for 5.15-rc1.
These do change a number of different things across different
subsystems, and because of that, there were 2 stable tags created that
might have already come into your tree from different pulls that did
the following
- changed the bus remove callback to return void
- sysfs iomem_get_mapping rework
Other than those two things, there's only a few small things in here:
- kernfs performance improvements for huge numbers of sysfs users at
once
- tiny api cleanups
- other minor changes
All of these have been in linux-next for a while with no reported
problems, other than the before-mentioned merge issue"
* tag 'driver-core-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (33 commits)
MAINTAINERS: Add dri-devel for component.[hc]
driver core: platform: Remove platform_device_add_properties()
ARM: tegra: paz00: Handle device properties with software node API
bitmap: extend comment to bitmap_print_bitmask/list_to_buf
drivers/base/node.c: use bin_attribute to break the size limitation of cpumap ABI
topology: use bin_attribute to break the size limitation of cpumap ABI
lib: test_bitmap: add bitmap_print_bitmask/list_to_buf test cases
cpumask: introduce cpumap_print_list/bitmask_to_buf to support large bitmask and list
sysfs: Rename struct bin_attribute member to f_mapping
sysfs: Invoke iomem_get_mapping() from the sysfs open callback
debugfs: Return error during {full/open}_proxy_open() on rmmod
zorro: Drop useless (and hardly used) .driver member in struct zorro_dev
zorro: Simplify remove callback
sh: superhyway: Simplify check in remove callback
nubus: Simplify check in remove callback
nubus: Make struct nubus_driver::remove return void
kernfs: dont call d_splice_alias() under kernfs node lock
kernfs: use i_lock to protect concurrent inode updates
kernfs: switch kernfs to use an rwsem
kernfs: use VFS negative dentry caching
...
2021-09-01 23:44:42 +08:00
|
|
|
b->legacy_mem->f_mapping = iomem_get_mapping;
|
2009-02-17 18:46:53 +08:00
|
|
|
pci_adjust_legacy_attr(b, pci_mmap_mem);
|
2008-10-03 17:49:32 +08:00
|
|
|
error = device_create_bin_file(&b->dev, b->legacy_mem);
|
|
|
|
if (error)
|
|
|
|
goto legacy_mem_err;
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
legacy_mem_err:
|
|
|
|
device_remove_bin_file(&b->dev, b->legacy_io);
|
|
|
|
legacy_io_err:
|
|
|
|
kfree(b->legacy_io);
|
|
|
|
b->legacy_io = NULL;
|
|
|
|
kzalloc_err:
|
2019-05-08 06:37:53 +08:00
|
|
|
dev_warn(&b->dev, "could not create legacy I/O port and ISA memory resources in sysfs\n");
|
2008-10-03 17:49:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void pci_remove_legacy_files(struct pci_bus *b)
|
|
|
|
{
|
|
|
|
if (b->legacy_io) {
|
|
|
|
device_remove_bin_file(&b->dev, b->legacy_io);
|
|
|
|
device_remove_bin_file(&b->dev, b->legacy_mem);
|
|
|
|
kfree(b->legacy_io); /* both are allocated here */
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
#endif /* HAVE_PCI_LEGACY */
|
|
|
|
|
2017-04-12 20:25:59 +08:00
|
|
|
#if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)
|
2008-10-03 09:52:51 +08:00
|
|
|
|
2010-11-10 18:03:21 +08:00
|
|
|
int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
|
|
|
|
enum pci_mmap_api mmap_api)
|
2008-10-03 09:52:51 +08:00
|
|
|
{
|
2017-04-12 20:25:50 +08:00
|
|
|
unsigned long nr, start, size;
|
|
|
|
resource_size_t pci_start = 0, pci_end;
|
2008-10-03 09:52:51 +08:00
|
|
|
|
2010-11-10 18:03:21 +08:00
|
|
|
if (pci_resource_len(pdev, resno) == 0)
|
|
|
|
return 0;
|
2013-04-15 10:48:54 +08:00
|
|
|
nr = vma_pages(vma);
|
2008-10-03 09:52:51 +08:00
|
|
|
start = vma->vm_pgoff;
|
2008-11-04 06:41:16 +08:00
|
|
|
size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
|
2017-04-12 20:25:50 +08:00
|
|
|
if (mmap_api == PCI_MMAP_PROCFS) {
|
|
|
|
pci_resource_to_user(pdev, resno, &pdev->resource[resno],
|
|
|
|
&pci_start, &pci_end);
|
|
|
|
pci_start >>= PAGE_SHIFT;
|
|
|
|
}
|
2010-11-10 18:03:21 +08:00
|
|
|
if (start >= pci_start && start < pci_start + size &&
|
|
|
|
start + nr <= pci_start + size)
|
2008-10-03 09:52:51 +08:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* pci_mmap_resource - map a PCI resource into user memory space
|
|
|
|
* @kobj: kobject for mapping
|
|
|
|
* @attr: struct bin_attribute for the file being mapped
|
|
|
|
* @vma: struct vm_area_struct passed into the mmap
|
2008-03-19 08:00:22 +08:00
|
|
|
* @write_combine: 1 for write_combine mapping
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Use the regular PCI mapping routines to map a PCI resource into userspace.
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
|
|
|
|
struct vm_area_struct *vma, int write_combine)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
|
2017-04-12 20:25:57 +08:00
|
|
|
int bar = (unsigned long)attr->private;
|
2005-04-17 06:20:36 +08:00
|
|
|
enum pci_mmap_state mmap_type;
|
2017-04-12 20:25:57 +08:00
|
|
|
struct resource *res = &pdev->resource[bar];
|
2019-08-20 08:17:47 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2005-05-13 15:44:10 +08:00
|
|
|
|
PCI: Supply CPU physical address (not bus address) to iomem_is_exclusive()
iomem_is_exclusive() requires a CPU physical address, but on some arches we
supplied a PCI bus address instead.
On most arches, pci_resource_to_user(res) returns "res->start", which is a
CPU physical address. But on microblaze, mips, powerpc, and sparc, it
returns the PCI bus address corresponding to "res->start".
The result is that pci_mmap_resource() may fail when it shouldn't (if the
bus address happens to match an existing resource), or it may succeed when
it should fail (if the resource is exclusive but the bus address doesn't
match it).
Call iomem_is_exclusive() with "res->start", which is always a CPU physical
address, not the result of pci_resource_to_user().
Fixes: e8de1481fd71 ("resource: allow MMIO exclusivity for device drivers")
Suggested-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: Arjan van de Ven <arjan@linux.intel.com>
2016-04-08 08:15:14 +08:00
|
|
|
if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-11-30 01:47:29 +08:00
|
|
|
if (!pci_mmap_fits(pdev, bar, vma, PCI_MMAP_SYSFS))
|
2008-10-03 09:52:51 +08:00
|
|
|
return -EINVAL;
|
2017-11-30 01:47:29 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
|
2017-04-12 20:25:59 +08:00
|
|
|
|
|
|
|
return pci_mmap_resource_range(pdev, bar, vma, mmap_type, write_combine);
|
2008-03-19 08:00:22 +08:00
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *attr,
|
|
|
|
struct vm_area_struct *vma)
|
2008-03-19 08:00:22 +08:00
|
|
|
{
|
|
|
|
return pci_mmap_resource(kobj, attr, vma, 0);
|
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static int pci_mmap_resource_wc(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *attr,
|
|
|
|
struct vm_area_struct *vma)
|
2008-03-19 08:00:22 +08:00
|
|
|
{
|
|
|
|
return pci_mmap_resource(kobj, attr, vma, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_resource_io(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *attr, char *buf,
|
|
|
|
loff_t off, size_t count, bool write)
|
2010-07-19 23:45:34 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
|
2017-04-12 20:25:57 +08:00
|
|
|
int bar = (unsigned long)attr->private;
|
2010-07-19 23:45:34 +08:00
|
|
|
unsigned long port = off;
|
|
|
|
|
2017-04-12 20:25:57 +08:00
|
|
|
port += pci_resource_start(pdev, bar);
|
2010-07-19 23:45:34 +08:00
|
|
|
|
2017-04-12 20:25:57 +08:00
|
|
|
if (port > pci_resource_end(pdev, bar))
|
2010-07-19 23:45:34 +08:00
|
|
|
return 0;
|
|
|
|
|
2017-04-12 20:25:57 +08:00
|
|
|
if (port + count - 1 > pci_resource_end(pdev, bar))
|
2010-07-19 23:45:34 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
switch (count) {
|
|
|
|
case 1:
|
|
|
|
if (write)
|
|
|
|
outb(*(u8 *)buf, port);
|
|
|
|
else
|
|
|
|
*(u8 *)buf = inb(port);
|
|
|
|
return 1;
|
|
|
|
case 2:
|
|
|
|
if (write)
|
|
|
|
outw(*(u16 *)buf, port);
|
|
|
|
else
|
|
|
|
*(u16 *)buf = inw(port);
|
|
|
|
return 2;
|
|
|
|
case 4:
|
|
|
|
if (write)
|
|
|
|
outl(*(u32 *)buf, port);
|
|
|
|
else
|
|
|
|
*(u32 *)buf = inl(port);
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_read_resource_io(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2010-07-19 23:45:34 +08:00
|
|
|
{
|
|
|
|
return pci_resource_io(filp, kobj, attr, buf, off, count, false);
|
|
|
|
}
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2010-07-19 23:45:34 +08:00
|
|
|
{
|
2019-08-20 08:17:47 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2010-07-19 23:45:34 +08:00
|
|
|
return pci_resource_io(filp, kobj, attr, buf, off, count, true);
|
|
|
|
}
|
|
|
|
|
2006-08-29 02:43:25 +08:00
|
|
|
/**
|
|
|
|
* pci_remove_resource_files - cleanup resource files
|
2009-04-11 06:17:50 +08:00
|
|
|
* @pdev: dev to cleanup
|
2006-08-29 02:43:25 +08:00
|
|
|
*
|
2009-04-11 06:17:50 +08:00
|
|
|
* If we created resource files for @pdev, remove them from sysfs and
|
2006-08-29 02:43:25 +08:00
|
|
|
* free their resources.
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static void pci_remove_resource_files(struct pci_dev *pdev)
|
2006-08-29 02:43:25 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2019-09-28 07:43:08 +08:00
|
|
|
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
|
2006-08-29 02:43:25 +08:00
|
|
|
struct bin_attribute *res_attr;
|
|
|
|
|
|
|
|
res_attr = pdev->res_attr[i];
|
|
|
|
if (res_attr) {
|
|
|
|
sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
|
|
|
|
kfree(res_attr);
|
|
|
|
}
|
2008-03-19 08:00:22 +08:00
|
|
|
|
|
|
|
res_attr = pdev->res_attr_wc[i];
|
|
|
|
if (res_attr) {
|
|
|
|
sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
|
|
|
|
kfree(res_attr);
|
|
|
|
}
|
2006-08-29 02:43:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-19 08:00:22 +08:00
|
|
|
static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
|
|
|
|
{
|
|
|
|
/* allocate attribute structure, piggyback attribute name */
|
|
|
|
int name_len = write_combine ? 13 : 10;
|
|
|
|
struct bin_attribute *res_attr;
|
2016-03-11 04:36:34 +08:00
|
|
|
char *res_attr_name;
|
2008-03-19 08:00:22 +08:00
|
|
|
int retval;
|
|
|
|
|
|
|
|
res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC);
|
2016-03-11 04:36:34 +08:00
|
|
|
if (!res_attr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
res_attr_name = (char *)(res_attr + 1);
|
|
|
|
|
|
|
|
sysfs_bin_attr_init(res_attr);
|
|
|
|
if (write_combine) {
|
|
|
|
pdev->res_attr_wc[num] = res_attr;
|
|
|
|
sprintf(res_attr_name, "resource%d_wc", num);
|
|
|
|
res_attr->mmap = pci_mmap_resource_wc;
|
|
|
|
} else {
|
|
|
|
pdev->res_attr[num] = res_attr;
|
|
|
|
sprintf(res_attr_name, "resource%d", num);
|
2017-04-12 20:25:56 +08:00
|
|
|
if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
|
|
|
|
res_attr->read = pci_read_resource_io;
|
|
|
|
res_attr->write = pci_write_resource_io;
|
|
|
|
if (arch_can_pci_mmap_io())
|
|
|
|
res_attr->mmap = pci_mmap_resource_uc;
|
|
|
|
} else {
|
|
|
|
res_attr->mmap = pci_mmap_resource_uc;
|
|
|
|
}
|
2016-03-11 04:36:34 +08:00
|
|
|
}
|
PCI: Revoke mappings like devmem
Since 3234ac664a87 ("/dev/mem: Revoke mappings when a driver claims
the region") /dev/kmem zaps PTEs when the kernel requests exclusive
acccess to an iomem region. And with CONFIG_IO_STRICT_DEVMEM, this is
the default for all driver uses.
Except there are two more ways to access PCI BARs: sysfs and proc mmap
support. Let's plug that hole.
For revoke_devmem() to work we need to link our vma into the same
address_space, with consistent vma->vm_pgoff. ->pgoff is already
adjusted, because that's how (io_)remap_pfn_range works, but for the
mapping we need to adjust vma->vm_file->f_mapping. The cleanest way is
to adjust this at at ->open time:
- for sysfs this is easy, now that binary attributes support this. We
just set bin_attr->mapping when mmap is supported
- for procfs it's a bit more tricky, since procfs PCI access has only
one file per device, and access to a specific resource first needs
to be set up with some ioctl calls. But mmap is only supported for
the same resources as sysfs exposes with mmap support, and otherwise
rejected, so we can set the mapping unconditionally at open time
without harm.
A special consideration is for arch_can_pci_mmap_io() - we need to
make sure that the ->f_mapping doesn't alias between ioport and iomem
space. There are only 2 ways in-tree to support mmap of ioports: generic
PCI mmap (ARCH_GENERIC_PCI_MMAP_RESOURCE), and sparc as the single
architecture hand-rolling. Both approaches support ioport mmap through a
special PFN range and not through magic PTE attributes. Aliasing is
therefore not a problem.
The only difference in access checks left is that sysfs PCI mmap does
not check for CAP_RAWIO. I'm not really sure whether that should be
added or not.
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Kees Cook <keescook@chromium.org>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Jérôme Glisse <jglisse@redhat.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-mm@kvack.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-samsung-soc@vger.kernel.org
Cc: linux-media@vger.kernel.org
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-pci@vger.kernel.org
Link: https://patchwork.freedesktop.org/patch/msgid/20210204165831.2703772-3-daniel.vetter@ffwll.ch
2021-02-05 00:58:31 +08:00
|
|
|
if (res_attr->mmap)
|
2021-07-30 07:32:35 +08:00
|
|
|
res_attr->f_mapping = iomem_get_mapping;
|
2016-03-11 04:36:34 +08:00
|
|
|
res_attr->attr.name = res_attr_name;
|
2019-08-14 04:45:12 +08:00
|
|
|
res_attr->attr.mode = 0600;
|
2016-03-11 04:36:34 +08:00
|
|
|
res_attr->size = pci_resource_len(pdev, num);
|
2017-04-12 20:25:57 +08:00
|
|
|
res_attr->private = (void *)(unsigned long)num;
|
2016-03-11 04:36:34 +08:00
|
|
|
retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
|
|
|
|
if (retval)
|
|
|
|
kfree(res_attr);
|
2008-03-19 08:00:22 +08:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* pci_create_resource_files - create resource files in sysfs for @dev
|
2009-04-11 06:17:50 +08:00
|
|
|
* @pdev: dev in question
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2009-04-11 06:17:50 +08:00
|
|
|
* Walk the resources in @pdev creating files for each resource available.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2006-08-29 02:43:25 +08:00
|
|
|
static int pci_create_resource_files(struct pci_dev *pdev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int i;
|
2006-08-29 02:43:25 +08:00
|
|
|
int retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Expose the PCI resources from this device as files */
|
2019-09-28 07:43:08 +08:00
|
|
|
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* skip empty resources */
|
|
|
|
if (!pci_resource_len(pdev, i))
|
|
|
|
continue;
|
|
|
|
|
2008-03-19 08:00:22 +08:00
|
|
|
retval = pci_create_attr(pdev, i, 0);
|
|
|
|
/* for prefetchable resources, create a WC mappable file */
|
2017-04-12 20:25:54 +08:00
|
|
|
if (!retval && arch_can_pci_mmap_wc() &&
|
|
|
|
pdev->resource[i].flags & IORESOURCE_PREFETCH)
|
2008-03-19 08:00:22 +08:00
|
|
|
retval = pci_create_attr(pdev, i, 1);
|
|
|
|
if (retval) {
|
|
|
|
pci_remove_resource_files(pdev);
|
|
|
|
return retval;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
2006-08-29 02:43:25 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2020-08-21 23:51:21 +08:00
|
|
|
#else /* !(defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)) */
|
2009-02-17 18:46:53 +08:00
|
|
|
int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
|
|
|
|
void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
|
2020-08-21 23:51:21 +08:00
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* pci_write_rom - used to enable access to the PCI ROM display
|
2010-05-13 09:28:57 +08:00
|
|
|
* @filp: sysfs file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @kobj: kernel object handle
|
2009-04-11 06:17:50 +08:00
|
|
|
* @bin_attr: struct bin_attribute for this file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @buf: user input
|
|
|
|
* @off: file offset
|
|
|
|
* @count: number of byte in input
|
|
|
|
*
|
|
|
|
* writing anything except 0 enables it
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_write_rom(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *bin_attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if ((off == 0) && (*buf == '0') && (count == 2))
|
|
|
|
pdev->rom_attr_enabled = 0;
|
|
|
|
else
|
|
|
|
pdev->rom_attr_enabled = 1;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* pci_read_rom - read a PCI ROM
|
2010-05-13 09:28:57 +08:00
|
|
|
* @filp: sysfs file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @kobj: kernel object handle
|
2009-04-11 06:17:50 +08:00
|
|
|
* @bin_attr: struct bin_attribute for this file
|
2005-04-17 06:20:36 +08:00
|
|
|
* @buf: where to put the data we read from the ROM
|
|
|
|
* @off: file offset
|
|
|
|
* @count: number of bytes to read
|
|
|
|
*
|
|
|
|
* Put @count bytes starting at @off into @buf from the ROM in the PCI
|
|
|
|
* device corresponding to @kobj.
|
|
|
|
*/
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t pci_read_rom(struct file *filp, struct kobject *kobj,
|
|
|
|
struct bin_attribute *bin_attr, char *buf,
|
|
|
|
loff_t off, size_t count)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
|
2005-04-17 06:20:36 +08:00
|
|
|
void __iomem *rom;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
if (!pdev->rom_attr_enabled)
|
|
|
|
return -EINVAL;
|
2013-11-15 02:28:18 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */
|
2009-01-30 03:12:47 +08:00
|
|
|
if (!rom || !size)
|
|
|
|
return -EIO;
|
2013-11-15 02:28:18 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (off >= size)
|
|
|
|
count = 0;
|
|
|
|
else {
|
|
|
|
if (off + count > size)
|
|
|
|
count = size - off;
|
2013-11-15 02:28:18 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy_fromio(buf, rom + off, count);
|
|
|
|
}
|
|
|
|
pci_unmap_rom(pdev, rom);
|
2013-11-15 02:28:18 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return count;
|
|
|
|
}
|
2021-04-17 04:58:38 +08:00
|
|
|
static BIN_ATTR(rom, 0600, pci_read_rom, pci_write_rom, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2021-04-17 04:58:38 +08:00
|
|
|
static struct bin_attribute *pci_dev_rom_attrs[] = {
|
|
|
|
&bin_attr_rom,
|
|
|
|
NULL,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2021-04-17 04:58:38 +08:00
|
|
|
static umode_t pci_dev_rom_attr_is_visible(struct kobject *kobj,
|
|
|
|
struct bin_attribute *a, int n)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
|
|
|
|
size_t rom_size;
|
|
|
|
|
|
|
|
/* If the device has a ROM, try to expose it in sysfs. */
|
|
|
|
rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
|
|
|
|
if (!rom_size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
a->size = rom_size;
|
|
|
|
|
|
|
|
return a->attr.mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct attribute_group pci_dev_rom_attr_group = {
|
|
|
|
.bin_attrs = pci_dev_rom_attrs,
|
|
|
|
.is_bin_visible = pci_dev_rom_attr_is_visible,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
2009-07-28 04:37:48 +08:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
unsigned long val;
|
2021-09-16 07:01:26 +08:00
|
|
|
ssize_t result;
|
2009-07-28 04:37:48 +08:00
|
|
|
|
2021-09-16 07:01:26 +08:00
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
|
|
|
return -EINVAL;
|
2009-07-28 04:37:48 +08:00
|
|
|
|
|
|
|
if (val != 1)
|
|
|
|
return -EINVAL;
|
2010-05-11 17:44:54 +08:00
|
|
|
|
2018-07-20 06:27:58 +08:00
|
|
|
pm_runtime_get_sync(dev);
|
2010-05-11 17:44:54 +08:00
|
|
|
result = pci_reset_function(pdev);
|
2018-07-20 06:27:58 +08:00
|
|
|
pm_runtime_put(dev);
|
2010-05-11 17:44:54 +08:00
|
|
|
if (result < 0)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
return count;
|
2009-07-28 04:37:48 +08:00
|
|
|
}
|
2021-04-17 04:58:39 +08:00
|
|
|
static DEVICE_ATTR_WO(reset);
|
2009-07-28 04:37:48 +08:00
|
|
|
|
2021-04-17 04:58:39 +08:00
|
|
|
static struct attribute *pci_dev_reset_attrs[] = {
|
|
|
|
&dev_attr_reset.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
2009-07-28 04:37:48 +08:00
|
|
|
|
2021-04-17 04:58:39 +08:00
|
|
|
static umode_t pci_dev_reset_attr_is_visible(struct kobject *kobj,
|
|
|
|
struct attribute *a, int n)
|
2008-10-13 20:01:00 +08:00
|
|
|
{
|
2021-04-17 04:58:39 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
|
2008-10-13 20:01:00 +08:00
|
|
|
|
2021-08-18 02:04:55 +08:00
|
|
|
if (!pci_reset_supported(pdev))
|
2021-04-17 04:58:39 +08:00
|
|
|
return 0;
|
2009-07-28 04:37:48 +08:00
|
|
|
|
2021-04-17 04:58:39 +08:00
|
|
|
return a->mode;
|
2008-10-13 20:01:00 +08:00
|
|
|
}
|
|
|
|
|
2021-04-17 04:58:39 +08:00
|
|
|
static const struct attribute_group pci_dev_reset_attr_group = {
|
|
|
|
.attrs = pci_dev_reset_attrs,
|
|
|
|
.is_visible = pci_dev_reset_attr_is_visible,
|
|
|
|
};
|
|
|
|
|
2014-04-19 08:13:49 +08:00
|
|
|
int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
if (!sysfs_initialized)
|
|
|
|
return -EACCES;
|
|
|
|
|
PCI/sysfs: Convert "index", "acpi_index", "label" to static attributes
The "label", "index", and "acpi_index" sysfs attributes show firmware label
information about the device. If the ACPI Device Name _DSM is implemented
for the device, we have:
label Device name (optional, may be null)
acpi_index Instance number (unique under \_SB scope)
When there is no ACPI _DSM and SMBIOS provides an Onboard Devices structure
for the device, we have:
label Reference Designation, e.g., a silkscreen label
index Device Type Instance
Previously these attributes were dynamically created either by
pci_bus_add_device() or the pci_sysfs_init() initcall, but since they don't
need to be created or removed dynamically, we can use a static attribute so
the device model takes care of addition and removal automatically.
Convert "label", "index", and "acpi_index" to static attributes.
Presence of the ACPI _DSM (device_has_acpi_name()) determines whether the
ACPI information (label, acpi_index) or the SMBIOS information (label,
index) is visible.
[bhelgaas: commit log, split to separate patch, add "pci_dev_" prefix]
Suggested-by: Oliver O'Halloran <oohall@gmail.com>
Link: https://lore.kernel.org/r/20210416205856.3234481-6-kw@linux.com
Signed-off-by: Krzysztof Wilczyński <kw@linux.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2021-04-27 23:49:16 +08:00
|
|
|
return pci_create_resource_files(pdev);
|
2008-10-13 20:01:00 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
|
|
|
|
* @pdev: device whose entries we should free
|
|
|
|
*
|
|
|
|
* Cleanup when @pdev is removed from sysfs.
|
|
|
|
*/
|
|
|
|
void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
|
|
|
|
{
|
2006-11-11 04:27:48 +08:00
|
|
|
if (!sysfs_initialized)
|
|
|
|
return;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
pci_remove_resource_files(pdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init pci_sysfs_init(void)
|
|
|
|
{
|
|
|
|
struct pci_dev *pdev = NULL;
|
2021-02-05 21:36:32 +08:00
|
|
|
struct pci_bus *pbus = NULL;
|
2006-08-29 02:43:25 +08:00
|
|
|
int retval;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
sysfs_initialized = 1;
|
2006-08-29 02:43:25 +08:00
|
|
|
for_each_pci_dev(pdev) {
|
|
|
|
retval = pci_create_sysfs_dev_files(pdev);
|
2007-11-20 15:41:16 +08:00
|
|
|
if (retval) {
|
|
|
|
pci_dev_put(pdev);
|
2006-08-29 02:43:25 +08:00
|
|
|
return retval;
|
2007-11-20 15:41:16 +08:00
|
|
|
}
|
2006-08-29 02:43:25 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2021-02-05 21:36:32 +08:00
|
|
|
while ((pbus = pci_find_next_bus(pbus)))
|
|
|
|
pci_create_legacy_files(pbus);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-03-25 02:03:32 +08:00
|
|
|
late_initcall(pci_sysfs_init);
|
2012-11-06 04:20:34 +08:00
|
|
|
|
|
|
|
static struct attribute *pci_dev_dev_attrs[] = {
|
PCI: sysfs: Define device attributes with DEVICE_ATTR*()
Device attributes should be defined using DEVICE_ATTR*(_name, _mode, _show,
_store). Convert them all from __ATTR*() to DEVICE_ATTR*(), e.g.,
- struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show,
_store)
+ static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo)
Link: https://lore.kernel.org/r/20190813204513.4790-2-skunberg.kelsey@gmail.com
Signed-off-by: Kelsey Skunberg <skunberg.kelsey@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
2019-08-14 04:45:11 +08:00
|
|
|
&dev_attr_boot_vga.attr,
|
2012-11-06 04:20:34 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
|
2014-04-19 08:13:49 +08:00
|
|
|
struct attribute *a, int n)
|
2012-11-06 04:20:34 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct device *dev = kobj_to_dev(kobj);
|
2012-11-06 04:20:35 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
PCI: sysfs: Define device attributes with DEVICE_ATTR*()
Device attributes should be defined using DEVICE_ATTR*(_name, _mode, _show,
_store). Convert them all from __ATTR*() to DEVICE_ATTR*(), e.g.,
- struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show,
_store)
+ static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo)
Link: https://lore.kernel.org/r/20190813204513.4790-2-skunberg.kelsey@gmail.com
Signed-off-by: Kelsey Skunberg <skunberg.kelsey@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
2019-08-14 04:45:11 +08:00
|
|
|
if (a == &dev_attr_boot_vga.attr)
|
2012-11-06 04:20:35 +08:00
|
|
|
if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
|
|
|
|
return 0;
|
|
|
|
|
2012-11-06 04:20:34 +08:00
|
|
|
return a->mode;
|
|
|
|
}
|
|
|
|
|
2013-05-31 12:21:31 +08:00
|
|
|
static struct attribute *pci_dev_hp_attrs[] = {
|
PCI: sysfs: Define device attributes with DEVICE_ATTR*()
Device attributes should be defined using DEVICE_ATTR*(_name, _mode, _show,
_store). Convert them all from __ATTR*() to DEVICE_ATTR*(), e.g.,
- struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show,
_store)
+ static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo)
Link: https://lore.kernel.org/r/20190813204513.4790-2-skunberg.kelsey@gmail.com
Signed-off-by: Kelsey Skunberg <skunberg.kelsey@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
2019-08-14 04:45:11 +08:00
|
|
|
&dev_attr_remove.attr,
|
2019-08-15 23:33:52 +08:00
|
|
|
&dev_attr_dev_rescan.attr,
|
2013-05-31 12:21:31 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj,
|
2014-04-19 08:13:49 +08:00
|
|
|
struct attribute *a, int n)
|
2013-05-31 12:21:31 +08:00
|
|
|
{
|
2015-12-23 20:28:13 +08:00
|
|
|
struct device *dev = kobj_to_dev(kobj);
|
2013-05-31 12:21:31 +08:00
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
|
|
|
if (pdev->is_virtfn)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return a->mode;
|
|
|
|
}
|
|
|
|
|
2017-06-01 17:43:06 +08:00
|
|
|
static umode_t pci_bridge_attrs_are_visible(struct kobject *kobj,
|
|
|
|
struct attribute *a, int n)
|
|
|
|
{
|
|
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
|
|
|
if (pci_is_bridge(pdev))
|
|
|
|
return a->mode;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static umode_t pcie_dev_attrs_are_visible(struct kobject *kobj,
|
|
|
|
struct attribute *a, int n)
|
|
|
|
{
|
|
|
|
struct device *dev = kobj_to_dev(kobj);
|
|
|
|
struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
|
|
|
|
|
if (pci_is_pcie(pdev))
|
|
|
|
return a->mode;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct attribute_group pci_dev_group = {
|
|
|
|
.attrs = pci_dev_attrs,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct attribute_group *pci_dev_groups[] = {
|
|
|
|
&pci_dev_group,
|
2021-04-17 04:58:37 +08:00
|
|
|
&pci_dev_config_attr_group,
|
2021-04-17 04:58:38 +08:00
|
|
|
&pci_dev_rom_attr_group,
|
2021-04-17 04:58:39 +08:00
|
|
|
&pci_dev_reset_attr_group,
|
2021-08-18 02:04:56 +08:00
|
|
|
&pci_dev_reset_method_attr_group,
|
2021-04-17 04:58:40 +08:00
|
|
|
&pci_dev_vpd_attr_group,
|
PCI/sysfs: Convert "index", "acpi_index", "label" to static attributes
The "label", "index", and "acpi_index" sysfs attributes show firmware label
information about the device. If the ACPI Device Name _DSM is implemented
for the device, we have:
label Device name (optional, may be null)
acpi_index Instance number (unique under \_SB scope)
When there is no ACPI _DSM and SMBIOS provides an Onboard Devices structure
for the device, we have:
label Reference Designation, e.g., a silkscreen label
index Device Type Instance
Previously these attributes were dynamically created either by
pci_bus_add_device() or the pci_sysfs_init() initcall, but since they don't
need to be created or removed dynamically, we can use a static attribute so
the device model takes care of addition and removal automatically.
Convert "label", "index", and "acpi_index" to static attributes.
Presence of the ACPI _DSM (device_has_acpi_name()) determines whether the
ACPI information (label, acpi_index) or the SMBIOS information (label,
index) is visible.
[bhelgaas: commit log, split to separate patch, add "pci_dev_" prefix]
Suggested-by: Oliver O'Halloran <oohall@gmail.com>
Link: https://lore.kernel.org/r/20210416205856.3234481-6-kw@linux.com
Signed-off-by: Krzysztof Wilczyński <kw@linux.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
2021-04-27 23:49:16 +08:00
|
|
|
#ifdef CONFIG_DMI
|
|
|
|
&pci_dev_smbios_attr_group,
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_ACPI
|
|
|
|
&pci_dev_acpi_attr_group,
|
|
|
|
#endif
|
2017-06-01 17:43:06 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2017-07-11 17:27:07 +08:00
|
|
|
static const struct attribute_group pci_dev_hp_attr_group = {
|
2013-05-31 12:21:31 +08:00
|
|
|
.attrs = pci_dev_hp_attrs,
|
|
|
|
.is_visible = pci_dev_hp_attrs_are_visible,
|
|
|
|
};
|
|
|
|
|
2017-07-11 17:27:07 +08:00
|
|
|
static const struct attribute_group pci_dev_attr_group = {
|
2012-11-06 04:20:34 +08:00
|
|
|
.attrs = pci_dev_dev_attrs,
|
|
|
|
.is_visible = pci_dev_attrs_are_visible,
|
|
|
|
};
|
|
|
|
|
2017-07-11 17:27:07 +08:00
|
|
|
static const struct attribute_group pci_bridge_attr_group = {
|
2017-06-01 17:43:06 +08:00
|
|
|
.attrs = pci_bridge_attrs,
|
|
|
|
.is_visible = pci_bridge_attrs_are_visible,
|
|
|
|
};
|
|
|
|
|
2017-07-11 17:27:07 +08:00
|
|
|
static const struct attribute_group pcie_dev_attr_group = {
|
2017-06-01 17:43:06 +08:00
|
|
|
.attrs = pcie_dev_attrs,
|
|
|
|
.is_visible = pcie_dev_attrs_are_visible,
|
|
|
|
};
|
|
|
|
|
2012-11-06 04:20:34 +08:00
|
|
|
static const struct attribute_group *pci_dev_attr_groups[] = {
|
|
|
|
&pci_dev_attr_group,
|
2013-05-31 12:21:31 +08:00
|
|
|
&pci_dev_hp_attr_group,
|
2012-11-06 04:20:36 +08:00
|
|
|
#ifdef CONFIG_PCI_IOV
|
2021-04-04 15:22:18 +08:00
|
|
|
&sriov_pf_dev_attr_group,
|
|
|
|
&sriov_vf_dev_attr_group,
|
2012-11-06 04:20:36 +08:00
|
|
|
#endif
|
2017-06-01 17:43:06 +08:00
|
|
|
&pci_bridge_attr_group,
|
|
|
|
&pcie_dev_attr_group,
|
2018-06-22 07:48:28 +08:00
|
|
|
#ifdef CONFIG_PCIEAER
|
|
|
|
&aer_stats_attr_group,
|
2019-10-05 20:07:56 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_PCIEASPM
|
|
|
|
&aspm_ctrl_attr_group,
|
2018-06-22 07:48:28 +08:00
|
|
|
#endif
|
2012-11-06 04:20:34 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2017-09-12 19:13:33 +08:00
|
|
|
const struct device_type pci_dev_type = {
|
2012-11-06 04:20:34 +08:00
|
|
|
.groups = pci_dev_attr_groups,
|
|
|
|
};
|