usb: fixes for v4.12-rc4
A fix to a really old synchronization bug on mass storage gadget. Support for Meson8 SoCs on dwc2 Synchronization fixes on renesas USB driver. -----BEGIN PGP SIGNATURE----- iQJRBAABCAA7FiEElLzh7wn96CXwjh2IzL64meEamQYFAlkxNXodHGZlbGlwZS5i YWxiaUBsaW51eC5pbnRlbC5jb20ACgkQzL64meEamQabXRAAtmCv+PiuOAZ+IvVd pvKVgdRpp68WG7OBFuRgz34NEvTNO61aunSBHY8DjxDohgu7ukwP57cb2lU0qPvi 32Ih1Xvtxj6fZK6eCa9XVibHVayX1lIB4N00JbKKVPn/yUdbI2hE8JdaMrmz/U2j 13mwiCUyxWB8pfl7nA3EefyMquMLj5NFLA+sNtExFWW3nuHE+SYibv8xWMkZrqzp 4ghy/LYgWcRflkAxNShm9YZ6zDG1MzsDH1jhhXvQdAl5FdaB/+28T6SYyd3Vaj+S 6NgGST84/7oilBk2qVwKX5NTQw+KHT1I9Tyo+/uwyz0Vf5x/TNj9T1FKBiDZ9HPW fNsXtSkH4f1W3Mofnrw9wFo+L8LV2qb3N4fw/KMH2rBLePQBBBei/0nntxa+k12j YH7f+mLgDdEcx9xjQyoCDVkL6bfV/WLDNG1nSt1mUZpZSA2fNFPW3bUPDIP5ly3T OMUtga9AVPmlOGgEimvjxNf+y6mdbjsDHdDthycWahzraOwdjQ97+Q6ppbLHevZL U81C36YCg28uf8cAxWwVDHLoxkD/fkLdG8pDJg4wdYFR+nBIApAdhOfefARnBsWG +lwC9OZZuk8gkNiuAbCNV4NwhUaF4bVW7WW21a23Y/5jRsIj0Er1zyqPWiQesLTP 6+zvMrY4lebqNut5pH6KXT7iQig= =P1Tt -----END PGP SIGNATURE----- Merge tag 'fixes-for-v4.12-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-linus Felipe writes: usb: fixes for v4.12-rc4 A fix to a really old synchronization bug on mass storage gadget. Support for Meson8 SoCs on dwc2 Synchronization fixes on renesas USB driver.
This commit is contained in:
Коммит
b132e4a25d
|
@ -59,20 +59,28 @@ button driver uses the following 3 modes in order not to trigger issues.
|
|||
If the userspace hasn't been prepared to ignore the unreliable "opened"
|
||||
events and the unreliable initial state notification, Linux users can use
|
||||
the following kernel parameters to handle the possible issues:
|
||||
A. button.lid_init_state=open:
|
||||
A. button.lid_init_state=method:
|
||||
When this option is specified, the ACPI button driver reports the
|
||||
initial lid state using the returning value of the _LID control method
|
||||
and whether the "opened"/"closed" events are paired fully relies on the
|
||||
firmware implementation.
|
||||
This option can be used to fix some platforms where the returning value
|
||||
of the _LID control method is reliable but the initial lid state
|
||||
notification is missing.
|
||||
This option is the default behavior during the period the userspace
|
||||
isn't ready to handle the buggy AML tables.
|
||||
B. button.lid_init_state=open:
|
||||
When this option is specified, the ACPI button driver always reports the
|
||||
initial lid state as "opened" and whether the "opened"/"closed" events
|
||||
are paired fully relies on the firmware implementation.
|
||||
This may fix some platforms where the returning value of the _LID
|
||||
control method is not reliable and the initial lid state notification is
|
||||
missing.
|
||||
This option is the default behavior during the period the userspace
|
||||
isn't ready to handle the buggy AML tables.
|
||||
|
||||
If the userspace has been prepared to ignore the unreliable "opened" events
|
||||
and the unreliable initial state notification, Linux users should always
|
||||
use the following kernel parameter:
|
||||
B. button.lid_init_state=ignore:
|
||||
C. button.lid_init_state=ignore:
|
||||
When this option is specified, the ACPI button driver never reports the
|
||||
initial lid state and there is a compensation mechanism implemented to
|
||||
ensure that the reliable "closed" notifications can always be delievered
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
.. |struct cpufreq_policy| replace:: :c:type:`struct cpufreq_policy <cpufreq_policy>`
|
||||
.. |intel_pstate| replace:: :doc:`intel_pstate <intel_pstate>`
|
||||
|
||||
=======================
|
||||
CPU Performance Scaling
|
||||
|
@ -75,7 +76,7 @@ feedback registers, as that information is typically specific to the hardware
|
|||
interface it comes from and may not be easily represented in an abstract,
|
||||
platform-independent way. For this reason, ``CPUFreq`` allows scaling drivers
|
||||
to bypass the governor layer and implement their own performance scaling
|
||||
algorithms. That is done by the ``intel_pstate`` scaling driver.
|
||||
algorithms. That is done by the |intel_pstate| scaling driver.
|
||||
|
||||
|
||||
``CPUFreq`` Policy Objects
|
||||
|
@ -174,13 +175,13 @@ necessary to restart the scaling governor so that it can take the new online CPU
|
|||
into account. That is achieved by invoking the governor's ``->stop`` and
|
||||
``->start()`` callbacks, in this order, for the entire policy.
|
||||
|
||||
As mentioned before, the ``intel_pstate`` scaling driver bypasses the scaling
|
||||
As mentioned before, the |intel_pstate| scaling driver bypasses the scaling
|
||||
governor layer of ``CPUFreq`` and provides its own P-state selection algorithms.
|
||||
Consequently, if ``intel_pstate`` is used, scaling governors are not attached to
|
||||
Consequently, if |intel_pstate| is used, scaling governors are not attached to
|
||||
new policy objects. Instead, the driver's ``->setpolicy()`` callback is invoked
|
||||
to register per-CPU utilization update callbacks for each policy. These
|
||||
callbacks are invoked by the CPU scheduler in the same way as for scaling
|
||||
governors, but in the ``intel_pstate`` case they both determine the P-state to
|
||||
governors, but in the |intel_pstate| case they both determine the P-state to
|
||||
use and change the hardware configuration accordingly in one go from scheduler
|
||||
context.
|
||||
|
||||
|
@ -257,7 +258,7 @@ are the following:
|
|||
|
||||
``scaling_available_governors``
|
||||
List of ``CPUFreq`` scaling governors present in the kernel that can
|
||||
be attached to this policy or (if the ``intel_pstate`` scaling driver is
|
||||
be attached to this policy or (if the |intel_pstate| scaling driver is
|
||||
in use) list of scaling algorithms provided by the driver that can be
|
||||
applied to this policy.
|
||||
|
||||
|
@ -274,7 +275,7 @@ are the following:
|
|||
the CPU is actually running at (due to hardware design and other
|
||||
limitations).
|
||||
|
||||
Some scaling drivers (e.g. ``intel_pstate``) attempt to provide
|
||||
Some scaling drivers (e.g. |intel_pstate|) attempt to provide
|
||||
information more precisely reflecting the current CPU frequency through
|
||||
this attribute, but that still may not be the exact current CPU
|
||||
frequency as seen by the hardware at the moment.
|
||||
|
@ -284,13 +285,13 @@ are the following:
|
|||
|
||||
``scaling_governor``
|
||||
The scaling governor currently attached to this policy or (if the
|
||||
``intel_pstate`` scaling driver is in use) the scaling algorithm
|
||||
|intel_pstate| scaling driver is in use) the scaling algorithm
|
||||
provided by the driver that is currently applied to this policy.
|
||||
|
||||
This attribute is read-write and writing to it will cause a new scaling
|
||||
governor to be attached to this policy or a new scaling algorithm
|
||||
provided by the scaling driver to be applied to it (in the
|
||||
``intel_pstate`` case), as indicated by the string written to this
|
||||
|intel_pstate| case), as indicated by the string written to this
|
||||
attribute (which must be one of the names listed by the
|
||||
``scaling_available_governors`` attribute described above).
|
||||
|
||||
|
@ -619,7 +620,7 @@ This file is located under :file:`/sys/devices/system/cpu/cpufreq/` and controls
|
|||
the "boost" setting for the whole system. It is not present if the underlying
|
||||
scaling driver does not support the frequency boost mechanism (or supports it,
|
||||
but provides a driver-specific interface for controlling it, like
|
||||
``intel_pstate``).
|
||||
|intel_pstate|).
|
||||
|
||||
If the value in this file is 1, the frequency boost mechanism is enabled. This
|
||||
means that either the hardware can be put into states in which it is able to
|
||||
|
|
|
@ -6,6 +6,7 @@ Power Management
|
|||
:maxdepth: 2
|
||||
|
||||
cpufreq
|
||||
intel_pstate
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
|
|
@ -0,0 +1,755 @@
|
|||
===============================================
|
||||
``intel_pstate`` CPU Performance Scaling Driver
|
||||
===============================================
|
||||
|
||||
::
|
||||
|
||||
Copyright (c) 2017 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
|
||||
|
||||
General Information
|
||||
===================
|
||||
|
||||
``intel_pstate`` is a part of the
|
||||
:doc:`CPU performance scaling subsystem <cpufreq>` in the Linux kernel
|
||||
(``CPUFreq``). It is a scaling driver for the Sandy Bridge and later
|
||||
generations of Intel processors. Note, however, that some of those processors
|
||||
may not be supported. [To understand ``intel_pstate`` it is necessary to know
|
||||
how ``CPUFreq`` works in general, so this is the time to read :doc:`cpufreq` if
|
||||
you have not done that yet.]
|
||||
|
||||
For the processors supported by ``intel_pstate``, the P-state concept is broader
|
||||
than just an operating frequency or an operating performance point (see the
|
||||
`LinuxCon Europe 2015 presentation by Kristen Accardi <LCEU2015_>`_ for more
|
||||
information about that). For this reason, the representation of P-states used
|
||||
by ``intel_pstate`` internally follows the hardware specification (for details
|
||||
refer to `Intel® 64 and IA-32 Architectures Software Developer’s Manual
|
||||
Volume 3: System Programming Guide <SDM_>`_). However, the ``CPUFreq`` core
|
||||
uses frequencies for identifying operating performance points of CPUs and
|
||||
frequencies are involved in the user space interface exposed by it, so
|
||||
``intel_pstate`` maps its internal representation of P-states to frequencies too
|
||||
(fortunately, that mapping is unambiguous). At the same time, it would not be
|
||||
practical for ``intel_pstate`` to supply the ``CPUFreq`` core with a table of
|
||||
available frequencies due to the possible size of it, so the driver does not do
|
||||
that. Some functionality of the core is limited by that.
|
||||
|
||||
Since the hardware P-state selection interface used by ``intel_pstate`` is
|
||||
available at the logical CPU level, the driver always works with individual
|
||||
CPUs. Consequently, if ``intel_pstate`` is in use, every ``CPUFreq`` policy
|
||||
object corresponds to one logical CPU and ``CPUFreq`` policies are effectively
|
||||
equivalent to CPUs. In particular, this means that they become "inactive" every
|
||||
time the corresponding CPU is taken offline and need to be re-initialized when
|
||||
it goes back online.
|
||||
|
||||
``intel_pstate`` is not modular, so it cannot be unloaded, which means that the
|
||||
only way to pass early-configuration-time parameters to it is via the kernel
|
||||
command line. However, its configuration can be adjusted via ``sysfs`` to a
|
||||
great extent. In some configurations it even is possible to unregister it via
|
||||
``sysfs`` which allows another ``CPUFreq`` scaling driver to be loaded and
|
||||
registered (see `below <status_attr_>`_).
|
||||
|
||||
|
||||
Operation Modes
|
||||
===============
|
||||
|
||||
``intel_pstate`` can operate in three different modes: in the active mode with
|
||||
or without hardware-managed P-states support and in the passive mode. Which of
|
||||
them will be in effect depends on what kernel command line options are used and
|
||||
on the capabilities of the processor.
|
||||
|
||||
Active Mode
|
||||
-----------
|
||||
|
||||
This is the default operation mode of ``intel_pstate``. If it works in this
|
||||
mode, the ``scaling_driver`` policy attribute in ``sysfs`` for all ``CPUFreq``
|
||||
policies contains the string "intel_pstate".
|
||||
|
||||
In this mode the driver bypasses the scaling governors layer of ``CPUFreq`` and
|
||||
provides its own scaling algorithms for P-state selection. Those algorithms
|
||||
can be applied to ``CPUFreq`` policies in the same way as generic scaling
|
||||
governors (that is, through the ``scaling_governor`` policy attribute in
|
||||
``sysfs``). [Note that different P-state selection algorithms may be chosen for
|
||||
different policies, but that is not recommended.]
|
||||
|
||||
They are not generic scaling governors, but their names are the same as the
|
||||
names of some of those governors. Moreover, confusingly enough, they generally
|
||||
do not work in the same way as the generic governors they share the names with.
|
||||
For example, the ``powersave`` P-state selection algorithm provided by
|
||||
``intel_pstate`` is not a counterpart of the generic ``powersave`` governor
|
||||
(roughly, it corresponds to the ``schedutil`` and ``ondemand`` governors).
|
||||
|
||||
There are two P-state selection algorithms provided by ``intel_pstate`` in the
|
||||
active mode: ``powersave`` and ``performance``. The way they both operate
|
||||
depends on whether or not the hardware-managed P-states (HWP) feature has been
|
||||
enabled in the processor and possibly on the processor model.
|
||||
|
||||
Which of the P-state selection algorithms is used by default depends on the
|
||||
:c:macro:`CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE` kernel configuration option.
|
||||
Namely, if that option is set, the ``performance`` algorithm will be used by
|
||||
default, and the other one will be used by default if it is not set.
|
||||
|
||||
Active Mode With HWP
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the processor supports the HWP feature, it will be enabled during the
|
||||
processor initialization and cannot be disabled after that. It is possible
|
||||
to avoid enabling it by passing the ``intel_pstate=no_hwp`` argument to the
|
||||
kernel in the command line.
|
||||
|
||||
If the HWP feature has been enabled, ``intel_pstate`` relies on the processor to
|
||||
select P-states by itself, but still it can give hints to the processor's
|
||||
internal P-state selection logic. What those hints are depends on which P-state
|
||||
selection algorithm has been applied to the given policy (or to the CPU it
|
||||
corresponds to).
|
||||
|
||||
Even though the P-state selection is carried out by the processor automatically,
|
||||
``intel_pstate`` registers utilization update callbacks with the CPU scheduler
|
||||
in this mode. However, they are not used for running a P-state selection
|
||||
algorithm, but for periodic updates of the current CPU frequency information to
|
||||
be made available from the ``scaling_cur_freq`` policy attribute in ``sysfs``.
|
||||
|
||||
HWP + ``performance``
|
||||
.....................
|
||||
|
||||
In this configuration ``intel_pstate`` will write 0 to the processor's
|
||||
Energy-Performance Preference (EPP) knob (if supported) or its
|
||||
Energy-Performance Bias (EPB) knob (otherwise), which means that the processor's
|
||||
internal P-state selection logic is expected to focus entirely on performance.
|
||||
|
||||
This will override the EPP/EPB setting coming from the ``sysfs`` interface
|
||||
(see `Energy vs Performance Hints`_ below).
|
||||
|
||||
Also, in this configuration the range of P-states available to the processor's
|
||||
internal P-state selection logic is always restricted to the upper boundary
|
||||
(that is, the maximum P-state that the driver is allowed to use).
|
||||
|
||||
HWP + ``powersave``
|
||||
...................
|
||||
|
||||
In this configuration ``intel_pstate`` will set the processor's
|
||||
Energy-Performance Preference (EPP) knob (if supported) or its
|
||||
Energy-Performance Bias (EPB) knob (otherwise) to whatever value it was
|
||||
previously set to via ``sysfs`` (or whatever default value it was
|
||||
set to by the platform firmware). This usually causes the processor's
|
||||
internal P-state selection logic to be less performance-focused.
|
||||
|
||||
Active Mode Without HWP
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is the default operation mode for processors that do not support the HWP
|
||||
feature. It also is used by default with the ``intel_pstate=no_hwp`` argument
|
||||
in the kernel command line. However, in this mode ``intel_pstate`` may refuse
|
||||
to work with the given processor if it does not recognize it. [Note that
|
||||
``intel_pstate`` will never refuse to work with any processor with the HWP
|
||||
feature enabled.]
|
||||
|
||||
In this mode ``intel_pstate`` registers utilization update callbacks with the
|
||||
CPU scheduler in order to run a P-state selection algorithm, either
|
||||
``powersave`` or ``performance``, depending on the ``scaling_cur_freq`` policy
|
||||
setting in ``sysfs``. The current CPU frequency information to be made
|
||||
available from the ``scaling_cur_freq`` policy attribute in ``sysfs`` is
|
||||
periodically updated by those utilization update callbacks too.
|
||||
|
||||
``performance``
|
||||
...............
|
||||
|
||||
Without HWP, this P-state selection algorithm is always the same regardless of
|
||||
the processor model and platform configuration.
|
||||
|
||||
It selects the maximum P-state it is allowed to use, subject to limits set via
|
||||
``sysfs``, every time the P-state selection computations are carried out by the
|
||||
driver's utilization update callback for the given CPU (that does not happen
|
||||
more often than every 10 ms), but the hardware configuration will not be changed
|
||||
if the new P-state is the same as the current one.
|
||||
|
||||
This is the default P-state selection algorithm if the
|
||||
:c:macro:`CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE` kernel configuration option
|
||||
is set.
|
||||
|
||||
``powersave``
|
||||
.............
|
||||
|
||||
Without HWP, this P-state selection algorithm generally depends on the
|
||||
processor model and/or the system profile setting in the ACPI tables and there
|
||||
are two variants of it.
|
||||
|
||||
One of them is used with processors from the Atom line and (regardless of the
|
||||
processor model) on platforms with the system profile in the ACPI tables set to
|
||||
"mobile" (laptops mostly), "tablet", "appliance PC", "desktop", or
|
||||
"workstation". It is also used with processors supporting the HWP feature if
|
||||
that feature has not been enabled (that is, with the ``intel_pstate=no_hwp``
|
||||
argument in the kernel command line). It is similar to the algorithm
|
||||
implemented by the generic ``schedutil`` scaling governor except that the
|
||||
utilization metric used by it is based on numbers coming from feedback
|
||||
registers of the CPU. It generally selects P-states proportional to the
|
||||
current CPU utilization, so it is referred to as the "proportional" algorithm.
|
||||
|
||||
The second variant of the ``powersave`` P-state selection algorithm, used in all
|
||||
of the other cases (generally, on processors from the Core line, so it is
|
||||
referred to as the "Core" algorithm), is based on the values read from the APERF
|
||||
and MPERF feedback registers and the previously requested target P-state.
|
||||
It does not really take CPU utilization into account explicitly, but as a rule
|
||||
it causes the CPU P-state to ramp up very quickly in response to increased
|
||||
utilization which is generally desirable in server environments.
|
||||
|
||||
Regardless of the variant, this algorithm is run by the driver's utilization
|
||||
update callback for the given CPU when it is invoked by the CPU scheduler, but
|
||||
not more often than every 10 ms (that can be tweaked via ``debugfs`` in `this
|
||||
particular case <Tuning Interface in debugfs_>`_). Like in the ``performance``
|
||||
case, the hardware configuration is not touched if the new P-state turns out to
|
||||
be the same as the current one.
|
||||
|
||||
This is the default P-state selection algorithm if the
|
||||
:c:macro:`CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE` kernel configuration option
|
||||
is not set.
|
||||
|
||||
Passive Mode
|
||||
------------
|
||||
|
||||
This mode is used if the ``intel_pstate=passive`` argument is passed to the
|
||||
kernel in the command line (it implies the ``intel_pstate=no_hwp`` setting too).
|
||||
Like in the active mode without HWP support, in this mode ``intel_pstate`` may
|
||||
refuse to work with the given processor if it does not recognize it.
|
||||
|
||||
If the driver works in this mode, the ``scaling_driver`` policy attribute in
|
||||
``sysfs`` for all ``CPUFreq`` policies contains the string "intel_cpufreq".
|
||||
Then, the driver behaves like a regular ``CPUFreq`` scaling driver. That is,
|
||||
it is invoked by generic scaling governors when necessary to talk to the
|
||||
hardware in order to change the P-state of a CPU (in particular, the
|
||||
``schedutil`` governor can invoke it directly from scheduler context).
|
||||
|
||||
While in this mode, ``intel_pstate`` can be used with all of the (generic)
|
||||
scaling governors listed by the ``scaling_available_governors`` policy attribute
|
||||
in ``sysfs`` (and the P-state selection algorithms described above are not
|
||||
used). Then, it is responsible for the configuration of policy objects
|
||||
corresponding to CPUs and provides the ``CPUFreq`` core (and the scaling
|
||||
governors attached to the policy objects) with accurate information on the
|
||||
maximum and minimum operating frequencies supported by the hardware (including
|
||||
the so-called "turbo" frequency ranges). In other words, in the passive mode
|
||||
the entire range of available P-states is exposed by ``intel_pstate`` to the
|
||||
``CPUFreq`` core. However, in this mode the driver does not register
|
||||
utilization update callbacks with the CPU scheduler and the ``scaling_cur_freq``
|
||||
information comes from the ``CPUFreq`` core (and is the last frequency selected
|
||||
by the current scaling governor for the given policy).
|
||||
|
||||
|
||||
.. _turbo:
|
||||
|
||||
Turbo P-states Support
|
||||
======================
|
||||
|
||||
In the majority of cases, the entire range of P-states available to
|
||||
``intel_pstate`` can be divided into two sub-ranges that correspond to
|
||||
different types of processor behavior, above and below a boundary that
|
||||
will be referred to as the "turbo threshold" in what follows.
|
||||
|
||||
The P-states above the turbo threshold are referred to as "turbo P-states" and
|
||||
the whole sub-range of P-states they belong to is referred to as the "turbo
|
||||
range". These names are related to the Turbo Boost technology allowing a
|
||||
multicore processor to opportunistically increase the P-state of one or more
|
||||
cores if there is enough power to do that and if that is not going to cause the
|
||||
thermal envelope of the processor package to be exceeded.
|
||||
|
||||
Specifically, if software sets the P-state of a CPU core within the turbo range
|
||||
(that is, above the turbo threshold), the processor is permitted to take over
|
||||
performance scaling control for that core and put it into turbo P-states of its
|
||||
choice going forward. However, that permission is interpreted differently by
|
||||
different processor generations. Namely, the Sandy Bridge generation of
|
||||
processors will never use any P-states above the last one set by software for
|
||||
the given core, even if it is within the turbo range, whereas all of the later
|
||||
processor generations will take it as a license to use any P-states from the
|
||||
turbo range, even above the one set by software. In other words, on those
|
||||
processors setting any P-state from the turbo range will enable the processor
|
||||
to put the given core into all turbo P-states up to and including the maximum
|
||||
supported one as it sees fit.
|
||||
|
||||
One important property of turbo P-states is that they are not sustainable. More
|
||||
precisely, there is no guarantee that any CPUs will be able to stay in any of
|
||||
those states indefinitely, because the power distribution within the processor
|
||||
package may change over time or the thermal envelope it was designed for might
|
||||
be exceeded if a turbo P-state was used for too long.
|
||||
|
||||
In turn, the P-states below the turbo threshold generally are sustainable. In
|
||||
fact, if one of them is set by software, the processor is not expected to change
|
||||
it to a lower one unless in a thermal stress or a power limit violation
|
||||
situation (a higher P-state may still be used if it is set for another CPU in
|
||||
the same package at the same time, for example).
|
||||
|
||||
Some processors allow multiple cores to be in turbo P-states at the same time,
|
||||
but the maximum P-state that can be set for them generally depends on the number
|
||||
of cores running concurrently. The maximum turbo P-state that can be set for 3
|
||||
cores at the same time usually is lower than the analogous maximum P-state for
|
||||
2 cores, which in turn usually is lower than the maximum turbo P-state that can
|
||||
be set for 1 core. The one-core maximum turbo P-state is thus the maximum
|
||||
supported one overall.
|
||||
|
||||
The maximum supported turbo P-state, the turbo threshold (the maximum supported
|
||||
non-turbo P-state) and the minimum supported P-state are specific to the
|
||||
processor model and can be determined by reading the processor's model-specific
|
||||
registers (MSRs). Moreover, some processors support the Configurable TDP
|
||||
(Thermal Design Power) feature and, when that feature is enabled, the turbo
|
||||
threshold effectively becomes a configurable value that can be set by the
|
||||
platform firmware.
|
||||
|
||||
Unlike ``_PSS`` objects in the ACPI tables, ``intel_pstate`` always exposes
|
||||
the entire range of available P-states, including the whole turbo range, to the
|
||||
``CPUFreq`` core and (in the passive mode) to generic scaling governors. This
|
||||
generally causes turbo P-states to be set more often when ``intel_pstate`` is
|
||||
used relative to ACPI-based CPU performance scaling (see `below <acpi-cpufreq_>`_
|
||||
for more information).
|
||||
|
||||
Moreover, since ``intel_pstate`` always knows what the real turbo threshold is
|
||||
(even if the Configurable TDP feature is enabled in the processor), its
|
||||
``no_turbo`` attribute in ``sysfs`` (described `below <no_turbo_attr_>`_) should
|
||||
work as expected in all cases (that is, if set to disable turbo P-states, it
|
||||
always should prevent ``intel_pstate`` from using them).
|
||||
|
||||
|
||||
Processor Support
|
||||
=================
|
||||
|
||||
To handle a given processor ``intel_pstate`` requires a number of different
|
||||
pieces of information on it to be known, including:
|
||||
|
||||
* The minimum supported P-state.
|
||||
|
||||
* The maximum supported `non-turbo P-state <turbo_>`_.
|
||||
|
||||
* Whether or not turbo P-states are supported at all.
|
||||
|
||||
* The maximum supported `one-core turbo P-state <turbo_>`_ (if turbo P-states
|
||||
are supported).
|
||||
|
||||
* The scaling formula to translate the driver's internal representation
|
||||
of P-states into frequencies and the other way around.
|
||||
|
||||
Generally, ways to obtain that information are specific to the processor model
|
||||
or family. Although it often is possible to obtain all of it from the processor
|
||||
itself (using model-specific registers), there are cases in which hardware
|
||||
manuals need to be consulted to get to it too.
|
||||
|
||||
For this reason, there is a list of supported processors in ``intel_pstate`` and
|
||||
the driver initialization will fail if the detected processor is not in that
|
||||
list, unless it supports the `HWP feature <Active Mode_>`_. [The interface to
|
||||
obtain all of the information listed above is the same for all of the processors
|
||||
supporting the HWP feature, which is why they all are supported by
|
||||
``intel_pstate``.]
|
||||
|
||||
|
||||
User Space Interface in ``sysfs``
|
||||
=================================
|
||||
|
||||
Global Attributes
|
||||
-----------------
|
||||
|
||||
``intel_pstate`` exposes several global attributes (files) in ``sysfs`` to
|
||||
control its functionality at the system level. They are located in the
|
||||
``/sys/devices/system/cpu/cpufreq/intel_pstate/`` directory and affect all
|
||||
CPUs.
|
||||
|
||||
Some of them are not present if the ``intel_pstate=per_cpu_perf_limits``
|
||||
argument is passed to the kernel in the command line.
|
||||
|
||||
``max_perf_pct``
|
||||
Maximum P-state the driver is allowed to set in percent of the
|
||||
maximum supported performance level (the highest supported `turbo
|
||||
P-state <turbo_>`_).
|
||||
|
||||
This attribute will not be exposed if the
|
||||
``intel_pstate=per_cpu_perf_limits`` argument is present in the kernel
|
||||
command line.
|
||||
|
||||
``min_perf_pct``
|
||||
Minimum P-state the driver is allowed to set in percent of the
|
||||
maximum supported performance level (the highest supported `turbo
|
||||
P-state <turbo_>`_).
|
||||
|
||||
This attribute will not be exposed if the
|
||||
``intel_pstate=per_cpu_perf_limits`` argument is present in the kernel
|
||||
command line.
|
||||
|
||||
``num_pstates``
|
||||
Number of P-states supported by the processor (between 0 and 255
|
||||
inclusive) including both turbo and non-turbo P-states (see
|
||||
`Turbo P-states Support`_).
|
||||
|
||||
The value of this attribute is not affected by the ``no_turbo``
|
||||
setting described `below <no_turbo_attr_>`_.
|
||||
|
||||
This attribute is read-only.
|
||||
|
||||
``turbo_pct``
|
||||
Ratio of the `turbo range <turbo_>`_ size to the size of the entire
|
||||
range of supported P-states, in percent.
|
||||
|
||||
This attribute is read-only.
|
||||
|
||||
.. _no_turbo_attr:
|
||||
|
||||
``no_turbo``
|
||||
If set (equal to 1), the driver is not allowed to set any turbo P-states
|
||||
(see `Turbo P-states Support`_). If unset (equalt to 0, which is the
|
||||
default), turbo P-states can be set by the driver.
|
||||
[Note that ``intel_pstate`` does not support the general ``boost``
|
||||
attribute (supported by some other scaling drivers) which is replaced
|
||||
by this one.]
|
||||
|
||||
This attrubute does not affect the maximum supported frequency value
|
||||
supplied to the ``CPUFreq`` core and exposed via the policy interface,
|
||||
but it affects the maximum possible value of per-policy P-state limits
|
||||
(see `Interpretation of Policy Attributes`_ below for details).
|
||||
|
||||
.. _status_attr:
|
||||
|
||||
``status``
|
||||
Operation mode of the driver: "active", "passive" or "off".
|
||||
|
||||
"active"
|
||||
The driver is functional and in the `active mode
|
||||
<Active Mode_>`_.
|
||||
|
||||
"passive"
|
||||
The driver is functional and in the `passive mode
|
||||
<Passive Mode_>`_.
|
||||
|
||||
"off"
|
||||
The driver is not functional (it is not registered as a scaling
|
||||
driver with the ``CPUFreq`` core).
|
||||
|
||||
This attribute can be written to in order to change the driver's
|
||||
operation mode or to unregister it. The string written to it must be
|
||||
one of the possible values of it and, if successful, the write will
|
||||
cause the driver to switch over to the operation mode represented by
|
||||
that string - or to be unregistered in the "off" case. [Actually,
|
||||
switching over from the active mode to the passive mode or the other
|
||||
way around causes the driver to be unregistered and registered again
|
||||
with a different set of callbacks, so all of its settings (the global
|
||||
as well as the per-policy ones) are then reset to their default
|
||||
values, possibly depending on the target operation mode.]
|
||||
|
||||
That only is supported in some configurations, though (for example, if
|
||||
the `HWP feature is enabled in the processor <Active Mode With HWP_>`_,
|
||||
the operation mode of the driver cannot be changed), and if it is not
|
||||
supported in the current configuration, writes to this attribute with
|
||||
fail with an appropriate error.
|
||||
|
||||
Interpretation of Policy Attributes
|
||||
-----------------------------------
|
||||
|
||||
The interpretation of some ``CPUFreq`` policy attributes described in
|
||||
:doc:`cpufreq` is special with ``intel_pstate`` as the current scaling driver
|
||||
and it generally depends on the driver's `operation mode <Operation Modes_>`_.
|
||||
|
||||
First of all, the values of the ``cpuinfo_max_freq``, ``cpuinfo_min_freq`` and
|
||||
``scaling_cur_freq`` attributes are produced by applying a processor-specific
|
||||
multiplier to the internal P-state representation used by ``intel_pstate``.
|
||||
Also, the values of the ``scaling_max_freq`` and ``scaling_min_freq``
|
||||
attributes are capped by the frequency corresponding to the maximum P-state that
|
||||
the driver is allowed to set.
|
||||
|
||||
If the ``no_turbo`` `global attribute <no_turbo_attr_>`_ is set, the driver is
|
||||
not allowed to use turbo P-states, so the maximum value of ``scaling_max_freq``
|
||||
and ``scaling_min_freq`` is limited to the maximum non-turbo P-state frequency.
|
||||
Accordingly, setting ``no_turbo`` causes ``scaling_max_freq`` and
|
||||
``scaling_min_freq`` to go down to that value if they were above it before.
|
||||
However, the old values of ``scaling_max_freq`` and ``scaling_min_freq`` will be
|
||||
restored after unsetting ``no_turbo``, unless these attributes have been written
|
||||
to after ``no_turbo`` was set.
|
||||
|
||||
If ``no_turbo`` is not set, the maximum possible value of ``scaling_max_freq``
|
||||
and ``scaling_min_freq`` corresponds to the maximum supported turbo P-state,
|
||||
which also is the value of ``cpuinfo_max_freq`` in either case.
|
||||
|
||||
Next, the following policy attributes have special meaning if
|
||||
``intel_pstate`` works in the `active mode <Active Mode_>`_:
|
||||
|
||||
``scaling_available_governors``
|
||||
List of P-state selection algorithms provided by ``intel_pstate``.
|
||||
|
||||
``scaling_governor``
|
||||
P-state selection algorithm provided by ``intel_pstate`` currently in
|
||||
use with the given policy.
|
||||
|
||||
``scaling_cur_freq``
|
||||
Frequency of the average P-state of the CPU represented by the given
|
||||
policy for the time interval between the last two invocations of the
|
||||
driver's utilization update callback by the CPU scheduler for that CPU.
|
||||
|
||||
The meaning of these attributes in the `passive mode <Passive Mode_>`_ is the
|
||||
same as for other scaling drivers.
|
||||
|
||||
Additionally, the value of the ``scaling_driver`` attribute for ``intel_pstate``
|
||||
depends on the operation mode of the driver. Namely, it is either
|
||||
"intel_pstate" (in the `active mode <Active Mode_>`_) or "intel_cpufreq" (in the
|
||||
`passive mode <Passive Mode_>`_).
|
||||
|
||||
Coordination of P-State Limits
|
||||
------------------------------
|
||||
|
||||
``intel_pstate`` allows P-state limits to be set in two ways: with the help of
|
||||
the ``max_perf_pct`` and ``min_perf_pct`` `global attributes
|
||||
<Global Attributes_>`_ or via the ``scaling_max_freq`` and ``scaling_min_freq``
|
||||
``CPUFreq`` policy attributes. The coordination between those limits is based
|
||||
on the following rules, regardless of the current operation mode of the driver:
|
||||
|
||||
1. All CPUs are affected by the global limits (that is, none of them can be
|
||||
requested to run faster than the global maximum and none of them can be
|
||||
requested to run slower than the global minimum).
|
||||
|
||||
2. Each individual CPU is affected by its own per-policy limits (that is, it
|
||||
cannot be requested to run faster than its own per-policy maximum and it
|
||||
cannot be requested to run slower than its own per-policy minimum).
|
||||
|
||||
3. The global and per-policy limits can be set independently.
|
||||
|
||||
If the `HWP feature is enabled in the processor <Active Mode With HWP_>`_, the
|
||||
resulting effective values are written into its registers whenever the limits
|
||||
change in order to request its internal P-state selection logic to always set
|
||||
P-states within these limits. Otherwise, the limits are taken into account by
|
||||
scaling governors (in the `passive mode <Passive Mode_>`_) and by the driver
|
||||
every time before setting a new P-state for a CPU.
|
||||
|
||||
Additionally, if the ``intel_pstate=per_cpu_perf_limits`` command line argument
|
||||
is passed to the kernel, ``max_perf_pct`` and ``min_perf_pct`` are not exposed
|
||||
at all and the only way to set the limits is by using the policy attributes.
|
||||
|
||||
|
||||
Energy vs Performance Hints
|
||||
---------------------------
|
||||
|
||||
If ``intel_pstate`` works in the `active mode with the HWP feature enabled
|
||||
<Active Mode With HWP_>`_ in the processor, additional attributes are present
|
||||
in every ``CPUFreq`` policy directory in ``sysfs``. They are intended to allow
|
||||
user space to help ``intel_pstate`` to adjust the processor's internal P-state
|
||||
selection logic by focusing it on performance or on energy-efficiency, or
|
||||
somewhere between the two extremes:
|
||||
|
||||
``energy_performance_preference``
|
||||
Current value of the energy vs performance hint for the given policy
|
||||
(or the CPU represented by it).
|
||||
|
||||
The hint can be changed by writing to this attribute.
|
||||
|
||||
``energy_performance_available_preferences``
|
||||
List of strings that can be written to the
|
||||
``energy_performance_preference`` attribute.
|
||||
|
||||
They represent different energy vs performance hints and should be
|
||||
self-explanatory, except that ``default`` represents whatever hint
|
||||
value was set by the platform firmware.
|
||||
|
||||
Strings written to the ``energy_performance_preference`` attribute are
|
||||
internally translated to integer values written to the processor's
|
||||
Energy-Performance Preference (EPP) knob (if supported) or its
|
||||
Energy-Performance Bias (EPB) knob.
|
||||
|
||||
[Note that tasks may by migrated from one CPU to another by the scheduler's
|
||||
load-balancing algorithm and if different energy vs performance hints are
|
||||
set for those CPUs, that may lead to undesirable outcomes. To avoid such
|
||||
issues it is better to set the same energy vs performance hint for all CPUs
|
||||
or to pin every task potentially sensitive to them to a specific CPU.]
|
||||
|
||||
.. _acpi-cpufreq:
|
||||
|
||||
``intel_pstate`` vs ``acpi-cpufreq``
|
||||
====================================
|
||||
|
||||
On the majority of systems supported by ``intel_pstate``, the ACPI tables
|
||||
provided by the platform firmware contain ``_PSS`` objects returning information
|
||||
that can be used for CPU performance scaling (refer to the `ACPI specification`_
|
||||
for details on the ``_PSS`` objects and the format of the information returned
|
||||
by them).
|
||||
|
||||
The information returned by the ACPI ``_PSS`` objects is used by the
|
||||
``acpi-cpufreq`` scaling driver. On systems supported by ``intel_pstate``
|
||||
the ``acpi-cpufreq`` driver uses the same hardware CPU performance scaling
|
||||
interface, but the set of P-states it can use is limited by the ``_PSS``
|
||||
output.
|
||||
|
||||
On those systems each ``_PSS`` object returns a list of P-states supported by
|
||||
the corresponding CPU which basically is a subset of the P-states range that can
|
||||
be used by ``intel_pstate`` on the same system, with one exception: the whole
|
||||
`turbo range <turbo_>`_ is represented by one item in it (the topmost one). By
|
||||
convention, the frequency returned by ``_PSS`` for that item is greater by 1 MHz
|
||||
than the frequency of the highest non-turbo P-state listed by it, but the
|
||||
corresponding P-state representation (following the hardware specification)
|
||||
returned for it matches the maximum supported turbo P-state (or is the
|
||||
special value 255 meaning essentially "go as high as you can get").
|
||||
|
||||
The list of P-states returned by ``_PSS`` is reflected by the table of
|
||||
available frequencies supplied by ``acpi-cpufreq`` to the ``CPUFreq`` core and
|
||||
scaling governors and the minimum and maximum supported frequencies reported by
|
||||
it come from that list as well. In particular, given the special representation
|
||||
of the turbo range described above, this means that the maximum supported
|
||||
frequency reported by ``acpi-cpufreq`` is higher by 1 MHz than the frequency
|
||||
of the highest supported non-turbo P-state listed by ``_PSS`` which, of course,
|
||||
affects decisions made by the scaling governors, except for ``powersave`` and
|
||||
``performance``.
|
||||
|
||||
For example, if a given governor attempts to select a frequency proportional to
|
||||
estimated CPU load and maps the load of 100% to the maximum supported frequency
|
||||
(possibly multiplied by a constant), then it will tend to choose P-states below
|
||||
the turbo threshold if ``acpi-cpufreq`` is used as the scaling driver, because
|
||||
in that case the turbo range corresponds to a small fraction of the frequency
|
||||
band it can use (1 MHz vs 1 GHz or more). In consequence, it will only go to
|
||||
the turbo range for the highest loads and the other loads above 50% that might
|
||||
benefit from running at turbo frequencies will be given non-turbo P-states
|
||||
instead.
|
||||
|
||||
One more issue related to that may appear on systems supporting the
|
||||
`Configurable TDP feature <turbo_>`_ allowing the platform firmware to set the
|
||||
turbo threshold. Namely, if that is not coordinated with the lists of P-states
|
||||
returned by ``_PSS`` properly, there may be more than one item corresponding to
|
||||
a turbo P-state in those lists and there may be a problem with avoiding the
|
||||
turbo range (if desirable or necessary). Usually, to avoid using turbo
|
||||
P-states overall, ``acpi-cpufreq`` simply avoids using the topmost state listed
|
||||
by ``_PSS``, but that is not sufficient when there are other turbo P-states in
|
||||
the list returned by it.
|
||||
|
||||
Apart from the above, ``acpi-cpufreq`` works like ``intel_pstate`` in the
|
||||
`passive mode <Passive Mode_>`_, except that the number of P-states it can set
|
||||
is limited to the ones listed by the ACPI ``_PSS`` objects.
|
||||
|
||||
|
||||
Kernel Command Line Options for ``intel_pstate``
|
||||
================================================
|
||||
|
||||
Several kernel command line options can be used to pass early-configuration-time
|
||||
parameters to ``intel_pstate`` in order to enforce specific behavior of it. All
|
||||
of them have to be prepended with the ``intel_pstate=`` prefix.
|
||||
|
||||
``disable``
|
||||
Do not register ``intel_pstate`` as the scaling driver even if the
|
||||
processor is supported by it.
|
||||
|
||||
``passive``
|
||||
Register ``intel_pstate`` in the `passive mode <Passive Mode_>`_ to
|
||||
start with.
|
||||
|
||||
This option implies the ``no_hwp`` one described below.
|
||||
|
||||
``force``
|
||||
Register ``intel_pstate`` as the scaling driver instead of
|
||||
``acpi-cpufreq`` even if the latter is preferred on the given system.
|
||||
|
||||
This may prevent some platform features (such as thermal controls and
|
||||
power capping) that rely on the availability of ACPI P-states
|
||||
information from functioning as expected, so it should be used with
|
||||
caution.
|
||||
|
||||
This option does not work with processors that are not supported by
|
||||
``intel_pstate`` and on platforms where the ``pcc-cpufreq`` scaling
|
||||
driver is used instead of ``acpi-cpufreq``.
|
||||
|
||||
``no_hwp``
|
||||
Do not enable the `hardware-managed P-states (HWP) feature
|
||||
<Active Mode With HWP_>`_ even if it is supported by the processor.
|
||||
|
||||
``hwp_only``
|
||||
Register ``intel_pstate`` as the scaling driver only if the
|
||||
`hardware-managed P-states (HWP) feature <Active Mode With HWP_>`_ is
|
||||
supported by the processor.
|
||||
|
||||
``support_acpi_ppc``
|
||||
Take ACPI ``_PPC`` performance limits into account.
|
||||
|
||||
If the preferred power management profile in the FADT (Fixed ACPI
|
||||
Description Table) is set to "Enterprise Server" or "Performance
|
||||
Server", the ACPI ``_PPC`` limits are taken into account by default
|
||||
and this option has no effect.
|
||||
|
||||
``per_cpu_perf_limits``
|
||||
Use per-logical-CPU P-State limits (see `Coordination of P-state
|
||||
Limits`_ for details).
|
||||
|
||||
|
||||
Diagnostics and Tuning
|
||||
======================
|
||||
|
||||
Trace Events
|
||||
------------
|
||||
|
||||
There are two static trace events that can be used for ``intel_pstate``
|
||||
diagnostics. One of them is the ``cpu_frequency`` trace event generally used
|
||||
by ``CPUFreq``, and the other one is the ``pstate_sample`` trace event specific
|
||||
to ``intel_pstate``. Both of them are triggered by ``intel_pstate`` only if
|
||||
it works in the `active mode <Active Mode_>`_.
|
||||
|
||||
The following sequence of shell commands can be used to enable them and see
|
||||
their output (if the kernel is generally configured to support event tracing)::
|
||||
|
||||
# cd /sys/kernel/debug/tracing/
|
||||
# echo 1 > events/power/pstate_sample/enable
|
||||
# echo 1 > events/power/cpu_frequency/enable
|
||||
# cat trace
|
||||
gnome-terminal--4510 [001] ..s. 1177.680733: pstate_sample: core_busy=107 scaled=94 from=26 to=26 mperf=1143818 aperf=1230607 tsc=29838618 freq=2474476
|
||||
cat-5235 [002] ..s. 1177.681723: cpu_frequency: state=2900000 cpu_id=2
|
||||
|
||||
If ``intel_pstate`` works in the `passive mode <Passive Mode_>`_, the
|
||||
``cpu_frequency`` trace event will be triggered either by the ``schedutil``
|
||||
scaling governor (for the policies it is attached to), or by the ``CPUFreq``
|
||||
core (for the policies with other scaling governors).
|
||||
|
||||
``ftrace``
|
||||
----------
|
||||
|
||||
The ``ftrace`` interface can be used for low-level diagnostics of
|
||||
``intel_pstate``. For example, to check how often the function to set a
|
||||
P-state is called, the ``ftrace`` filter can be set to to
|
||||
:c:func:`intel_pstate_set_pstate`::
|
||||
|
||||
# cd /sys/kernel/debug/tracing/
|
||||
# cat available_filter_functions | grep -i pstate
|
||||
intel_pstate_set_pstate
|
||||
intel_pstate_cpu_init
|
||||
...
|
||||
# echo intel_pstate_set_pstate > set_ftrace_filter
|
||||
# echo function > current_tracer
|
||||
# cat trace | head -15
|
||||
# tracer: function
|
||||
#
|
||||
# entries-in-buffer/entries-written: 80/80 #P:4
|
||||
#
|
||||
# _-----=> irqs-off
|
||||
# / _----=> need-resched
|
||||
# | / _---=> hardirq/softirq
|
||||
# || / _--=> preempt-depth
|
||||
# ||| / delay
|
||||
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
|
||||
# | | | |||| | |
|
||||
Xorg-3129 [000] ..s. 2537.644844: intel_pstate_set_pstate <-intel_pstate_timer_func
|
||||
gnome-terminal--4510 [002] ..s. 2537.649844: intel_pstate_set_pstate <-intel_pstate_timer_func
|
||||
gnome-shell-3409 [001] ..s. 2537.650850: intel_pstate_set_pstate <-intel_pstate_timer_func
|
||||
<idle>-0 [000] ..s. 2537.654843: intel_pstate_set_pstate <-intel_pstate_timer_func
|
||||
|
||||
Tuning Interface in ``debugfs``
|
||||
-------------------------------
|
||||
|
||||
The ``powersave`` algorithm provided by ``intel_pstate`` for `the Core line of
|
||||
processors in the active mode <powersave_>`_ is based on a `PID controller`_
|
||||
whose parameters were chosen to address a number of different use cases at the
|
||||
same time. However, it still is possible to fine-tune it to a specific workload
|
||||
and the ``debugfs`` interface under ``/sys/kernel/debug/pstate_snb/`` is
|
||||
provided for this purpose. [Note that the ``pstate_snb`` directory will be
|
||||
present only if the specific P-state selection algorithm matching the interface
|
||||
in it actually is in use.]
|
||||
|
||||
The following files present in that directory can be used to modify the PID
|
||||
controller parameters at run time:
|
||||
|
||||
| ``deadband``
|
||||
| ``d_gain_pct``
|
||||
| ``i_gain_pct``
|
||||
| ``p_gain_pct``
|
||||
| ``sample_rate_ms``
|
||||
| ``setpoint``
|
||||
|
||||
Note, however, that achieving desirable results this way generally requires
|
||||
expert-level understanding of the power vs performance tradeoff, so extra care
|
||||
is recommended when attempting to do that.
|
||||
|
||||
|
||||
.. _LCEU2015: http://events.linuxfoundation.org/sites/events/files/slides/LinuxConEurope_2015.pdf
|
||||
.. _SDM: http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-system-programming-manual-325384.html
|
||||
.. _ACPI specification: http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf
|
||||
.. _PID controller: https://en.wikipedia.org/wiki/PID_controller
|
|
@ -1,281 +0,0 @@
|
|||
Intel P-State driver
|
||||
--------------------
|
||||
|
||||
This driver provides an interface to control the P-State selection for the
|
||||
SandyBridge+ Intel processors.
|
||||
|
||||
The following document explains P-States:
|
||||
http://events.linuxfoundation.org/sites/events/files/slides/LinuxConEurope_2015.pdf
|
||||
As stated in the document, P-State doesn’t exactly mean a frequency. However, for
|
||||
the sake of the relationship with cpufreq, P-State and frequency are used
|
||||
interchangeably.
|
||||
|
||||
Understanding the cpufreq core governors and policies are important before
|
||||
discussing more details about the Intel P-State driver. Based on what callbacks
|
||||
a cpufreq driver provides to the cpufreq core, it can support two types of
|
||||
drivers:
|
||||
- with target_index() callback: In this mode, the drivers using cpufreq core
|
||||
simply provide the minimum and maximum frequency limits and an additional
|
||||
interface target_index() to set the current frequency. The cpufreq subsystem
|
||||
has a number of scaling governors ("performance", "powersave", "ondemand",
|
||||
etc.). Depending on which governor is in use, cpufreq core will call for
|
||||
transitions to a specific frequency using target_index() callback.
|
||||
- setpolicy() callback: In this mode, drivers do not provide target_index()
|
||||
callback, so cpufreq core can't request a transition to a specific frequency.
|
||||
The driver provides minimum and maximum frequency limits and callbacks to set a
|
||||
policy. The policy in cpufreq sysfs is referred to as the "scaling governor".
|
||||
The cpufreq core can request the driver to operate in any of the two policies:
|
||||
"performance" and "powersave". The driver decides which frequency to use based
|
||||
on the above policy selection considering minimum and maximum frequency limits.
|
||||
|
||||
The Intel P-State driver falls under the latter category, which implements the
|
||||
setpolicy() callback. This driver decides what P-State to use based on the
|
||||
requested policy from the cpufreq core. If the processor is capable of
|
||||
selecting its next P-State internally, then the driver will offload this
|
||||
responsibility to the processor (aka HWP: Hardware P-States). If not, the
|
||||
driver implements algorithms to select the next P-State.
|
||||
|
||||
Since these policies are implemented in the driver, they are not same as the
|
||||
cpufreq scaling governors implementation, even if they have the same name in
|
||||
the cpufreq sysfs (scaling_governors). For example the "performance" policy is
|
||||
similar to cpufreq’s "performance" governor, but "powersave" is completely
|
||||
different than the cpufreq "powersave" governor. The strategy here is similar
|
||||
to cpufreq "ondemand", where the requested P-State is related to the system load.
|
||||
|
||||
Sysfs Interface
|
||||
|
||||
In addition to the frequency-controlling interfaces provided by the cpufreq
|
||||
core, the driver provides its own sysfs files to control the P-State selection.
|
||||
These files have been added to /sys/devices/system/cpu/intel_pstate/.
|
||||
Any changes made to these files are applicable to all CPUs (even in a
|
||||
multi-package system, Refer to later section on placing "Per-CPU limits").
|
||||
|
||||
max_perf_pct: Limits the maximum P-State that will be requested by
|
||||
the driver. It states it as a percentage of the available performance. The
|
||||
available (P-State) performance may be reduced by the no_turbo
|
||||
setting described below.
|
||||
|
||||
min_perf_pct: Limits the minimum P-State that will be requested by
|
||||
the driver. It states it as a percentage of the max (non-turbo)
|
||||
performance level.
|
||||
|
||||
no_turbo: Limits the driver to selecting P-State below the turbo
|
||||
frequency range.
|
||||
|
||||
turbo_pct: Displays the percentage of the total performance that
|
||||
is supported by hardware that is in the turbo range. This number
|
||||
is independent of whether turbo has been disabled or not.
|
||||
|
||||
num_pstates: Displays the number of P-States that are supported
|
||||
by hardware. This number is independent of whether turbo has
|
||||
been disabled or not.
|
||||
|
||||
For example, if a system has these parameters:
|
||||
Max 1 core turbo ratio: 0x21 (Max 1 core ratio is the maximum P-State)
|
||||
Max non turbo ratio: 0x17
|
||||
Minimum ratio : 0x08 (Here the ratio is called max efficiency ratio)
|
||||
|
||||
Sysfs will show :
|
||||
max_perf_pct:100, which corresponds to 1 core ratio
|
||||
min_perf_pct:24, max_efficiency_ratio / max 1 Core ratio
|
||||
no_turbo:0, turbo is not disabled
|
||||
num_pstates:26 = (max 1 Core ratio - Max Efficiency Ratio + 1)
|
||||
turbo_pct:39 = (max 1 core ratio - max non turbo ratio) / num_pstates
|
||||
|
||||
Refer to "Intel® 64 and IA-32 Architectures Software Developer’s Manual
|
||||
Volume 3: System Programming Guide" to understand ratios.
|
||||
|
||||
There is one more sysfs attribute in /sys/devices/system/cpu/intel_pstate/
|
||||
that can be used for controlling the operation mode of the driver:
|
||||
|
||||
status: Three settings are possible:
|
||||
"off" - The driver is not in use at this time.
|
||||
"active" - The driver works as a P-state governor (default).
|
||||
"passive" - The driver works as a regular cpufreq one and collaborates
|
||||
with the generic cpufreq governors (it sets P-states as
|
||||
requested by those governors).
|
||||
The current setting is returned by reads from this attribute. Writing one
|
||||
of the above strings to it changes the operation mode as indicated by that
|
||||
string, if possible. If HW-managed P-states (HWP) are enabled, it is not
|
||||
possible to change the driver's operation mode and attempts to write to
|
||||
this attribute will fail.
|
||||
|
||||
cpufreq sysfs for Intel P-State
|
||||
|
||||
Since this driver registers with cpufreq, cpufreq sysfs is also presented.
|
||||
There are some important differences, which need to be considered.
|
||||
|
||||
scaling_cur_freq: This displays the real frequency which was used during
|
||||
the last sample period instead of what is requested. Some other cpufreq driver,
|
||||
like acpi-cpufreq, displays what is requested (Some changes are on the
|
||||
way to fix this for acpi-cpufreq driver). The same is true for frequencies
|
||||
displayed at /proc/cpuinfo.
|
||||
|
||||
scaling_governor: This displays current active policy. Since each CPU has a
|
||||
cpufreq sysfs, it is possible to set a scaling governor to each CPU. But this
|
||||
is not possible with Intel P-States, as there is one common policy for all
|
||||
CPUs. Here, the last requested policy will be applicable to all CPUs. It is
|
||||
suggested that one use the cpupower utility to change policy to all CPUs at the
|
||||
same time.
|
||||
|
||||
scaling_setspeed: This attribute can never be used with Intel P-State.
|
||||
|
||||
scaling_max_freq/scaling_min_freq: This interface can be used similarly to
|
||||
the max_perf_pct/min_perf_pct of Intel P-State sysfs. However since frequencies
|
||||
are converted to nearest possible P-State, this is prone to rounding errors.
|
||||
This method is not preferred to limit performance.
|
||||
|
||||
affected_cpus: Not used
|
||||
related_cpus: Not used
|
||||
|
||||
For contemporary Intel processors, the frequency is controlled by the
|
||||
processor itself and the P-State exposed to software is related to
|
||||
performance levels. The idea that frequency can be set to a single
|
||||
frequency is fictional for Intel Core processors. Even if the scaling
|
||||
driver selects a single P-State, the actual frequency the processor
|
||||
will run at is selected by the processor itself.
|
||||
|
||||
Per-CPU limits
|
||||
|
||||
The kernel command line option "intel_pstate=per_cpu_perf_limits" forces
|
||||
the intel_pstate driver to use per-CPU performance limits. When it is set,
|
||||
the sysfs control interface described above is subject to limitations.
|
||||
- The following controls are not available for both read and write
|
||||
/sys/devices/system/cpu/intel_pstate/max_perf_pct
|
||||
/sys/devices/system/cpu/intel_pstate/min_perf_pct
|
||||
- The following controls can be used to set performance limits, as far as the
|
||||
architecture of the processor permits:
|
||||
/sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
|
||||
/sys/devices/system/cpu/cpu*/cpufreq/scaling_min_freq
|
||||
/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
|
||||
- User can still observe turbo percent and number of P-States from
|
||||
/sys/devices/system/cpu/intel_pstate/turbo_pct
|
||||
/sys/devices/system/cpu/intel_pstate/num_pstates
|
||||
- User can read write system wide turbo status
|
||||
/sys/devices/system/cpu/no_turbo
|
||||
|
||||
Support of energy performance hints
|
||||
It is possible to provide hints to the HWP algorithms in the processor
|
||||
to be more performance centric to more energy centric. When the driver
|
||||
is using HWP, two additional cpufreq sysfs attributes are presented for
|
||||
each logical CPU.
|
||||
These attributes are:
|
||||
- energy_performance_available_preferences
|
||||
- energy_performance_preference
|
||||
|
||||
To get list of supported hints:
|
||||
$ cat energy_performance_available_preferences
|
||||
default performance balance_performance balance_power power
|
||||
|
||||
The current preference can be read or changed via cpufreq sysfs
|
||||
attribute "energy_performance_preference". Reading from this attribute
|
||||
will display current effective setting. User can write any of the valid
|
||||
preference string to this attribute. User can always restore to power-on
|
||||
default by writing "default".
|
||||
|
||||
Since threads can migrate to different CPUs, this is possible that the
|
||||
new CPU may have different energy performance preference than the previous
|
||||
one. To avoid such issues, either threads can be pinned to specific CPUs
|
||||
or set the same energy performance preference value to all CPUs.
|
||||
|
||||
Tuning Intel P-State driver
|
||||
|
||||
When the performance can be tuned using PID (Proportional Integral
|
||||
Derivative) controller, debugfs files are provided for adjusting performance.
|
||||
They are presented under:
|
||||
/sys/kernel/debug/pstate_snb/
|
||||
|
||||
The PID tunable parameters are:
|
||||
deadband
|
||||
d_gain_pct
|
||||
i_gain_pct
|
||||
p_gain_pct
|
||||
sample_rate_ms
|
||||
setpoint
|
||||
|
||||
To adjust these parameters, some understanding of driver implementation is
|
||||
necessary. There are some tweeks described here, but be very careful. Adjusting
|
||||
them requires expert level understanding of power and performance relationship.
|
||||
These limits are only useful when the "powersave" policy is active.
|
||||
|
||||
-To make the system more responsive to load changes, sample_rate_ms can
|
||||
be adjusted (current default is 10ms).
|
||||
-To make the system use higher performance, even if the load is lower, setpoint
|
||||
can be adjusted to a lower number. This will also lead to faster ramp up time
|
||||
to reach the maximum P-State.
|
||||
If there are no derivative and integral coefficients, The next P-State will be
|
||||
equal to:
|
||||
current P-State - ((setpoint - current cpu load) * p_gain_pct)
|
||||
|
||||
For example, if the current PID parameters are (Which are defaults for the core
|
||||
processors like SandyBridge):
|
||||
deadband = 0
|
||||
d_gain_pct = 0
|
||||
i_gain_pct = 0
|
||||
p_gain_pct = 20
|
||||
sample_rate_ms = 10
|
||||
setpoint = 97
|
||||
|
||||
If the current P-State = 0x08 and current load = 100, this will result in the
|
||||
next P-State = 0x08 - ((97 - 100) * 0.2) = 8.6 (rounded to 9). Here the P-State
|
||||
goes up by only 1. If during next sample interval the current load doesn't
|
||||
change and still 100, then P-State goes up by one again. This process will
|
||||
continue as long as the load is more than the setpoint until the maximum P-State
|
||||
is reached.
|
||||
|
||||
For the same load at setpoint = 60, this will result in the next P-State
|
||||
= 0x08 - ((60 - 100) * 0.2) = 16
|
||||
So by changing the setpoint from 97 to 60, there is an increase of the
|
||||
next P-State from 9 to 16. So this will make processor execute at higher
|
||||
P-State for the same CPU load. If the load continues to be more than the
|
||||
setpoint during next sample intervals, then P-State will go up again till the
|
||||
maximum P-State is reached. But the ramp up time to reach the maximum P-State
|
||||
will be much faster when the setpoint is 60 compared to 97.
|
||||
|
||||
Debugging Intel P-State driver
|
||||
|
||||
Event tracing
|
||||
To debug P-State transition, the Linux event tracing interface can be used.
|
||||
There are two specific events, which can be enabled (Provided the kernel
|
||||
configs related to event tracing are enabled).
|
||||
|
||||
# cd /sys/kernel/debug/tracing/
|
||||
# echo 1 > events/power/pstate_sample/enable
|
||||
# echo 1 > events/power/cpu_frequency/enable
|
||||
# cat trace
|
||||
gnome-terminal--4510 [001] ..s. 1177.680733: pstate_sample: core_busy=107
|
||||
scaled=94 from=26 to=26 mperf=1143818 aperf=1230607 tsc=29838618
|
||||
freq=2474476
|
||||
cat-5235 [002] ..s. 1177.681723: cpu_frequency: state=2900000 cpu_id=2
|
||||
|
||||
|
||||
Using ftrace
|
||||
|
||||
If function level tracing is required, the Linux ftrace interface can be used.
|
||||
For example if we want to check how often a function to set a P-State is
|
||||
called, we can set ftrace filter to intel_pstate_set_pstate.
|
||||
|
||||
# cd /sys/kernel/debug/tracing/
|
||||
# cat available_filter_functions | grep -i pstate
|
||||
intel_pstate_set_pstate
|
||||
intel_pstate_cpu_init
|
||||
...
|
||||
|
||||
# echo intel_pstate_set_pstate > set_ftrace_filter
|
||||
# echo function > current_tracer
|
||||
# cat trace | head -15
|
||||
# tracer: function
|
||||
#
|
||||
# entries-in-buffer/entries-written: 80/80 #P:4
|
||||
#
|
||||
# _-----=> irqs-off
|
||||
# / _----=> need-resched
|
||||
# | / _---=> hardirq/softirq
|
||||
# || / _--=> preempt-depth
|
||||
# ||| / delay
|
||||
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
|
||||
# | | | |||| | |
|
||||
Xorg-3129 [000] ..s. 2537.644844: intel_pstate_set_pstate <-intel_pstate_timer_func
|
||||
gnome-terminal--4510 [002] ..s. 2537.649844: intel_pstate_set_pstate <-intel_pstate_timer_func
|
||||
gnome-shell-3409 [001] ..s. 2537.650850: intel_pstate_set_pstate <-intel_pstate_timer_func
|
||||
<idle>-0 [000] ..s. 2537.654843: intel_pstate_set_pstate <-intel_pstate_timer_func
|
|
@ -36,7 +36,7 @@ Optional properties:
|
|||
control gpios
|
||||
|
||||
- threshold: allows setting the "click"-threshold in the range
|
||||
from 20 to 80.
|
||||
from 0 to 80.
|
||||
|
||||
- gain: allows setting the sensitivity in the range from 0 to
|
||||
31. Note that lower values indicate higher
|
||||
|
|
|
@ -16,6 +16,11 @@ Required properties:
|
|||
- reg: Base address of PMIC on Hi6220 SoC.
|
||||
- interrupt-controller: Hi655x has internal IRQs (has own IRQ domain).
|
||||
- pmic-gpios: The GPIO used by PMIC IRQ.
|
||||
- #clock-cells: From common clock binding; shall be set to 0
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names: From common clock binding to override the
|
||||
default output clock name
|
||||
|
||||
Example:
|
||||
pmic: pmic@f8000000 {
|
||||
|
@ -24,4 +29,5 @@ Example:
|
|||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
pmic-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
|
||||
#clock-cells = <0>;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ Optional properties:
|
|||
"ext_clock" (External clock provided to the card).
|
||||
- post-power-on-delay-ms : Delay in ms after powering the card and
|
||||
de-asserting the reset-gpios (if any)
|
||||
- power-off-delay-us : Delay in us after asserting the reset-gpios (if any)
|
||||
during power off of the card.
|
||||
|
||||
Example:
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@ Optional properties:
|
|||
- phy-reset-active-high : If present then the reset sequence using the GPIO
|
||||
specified in the "phy-reset-gpios" property is reversed (H=reset state,
|
||||
L=operation state).
|
||||
- phy-reset-post-delay : Post reset delay in milliseconds. If present then
|
||||
a delay of phy-reset-post-delay milliseconds will be observed after the
|
||||
phy-reset-gpios has been toggled. Can be omitted thus no delay is
|
||||
observed. Delay is in range of 1ms to 1000ms. Other delays are invalid.
|
||||
- phy-supply : regulator that powers the Ethernet PHY.
|
||||
- phy-handle : phandle to the PHY device connected to this device.
|
||||
- fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
|
||||
|
|
|
@ -10,6 +10,7 @@ Required properties:
|
|||
- "rockchip,rk3288-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3288 Soc;
|
||||
- "lantiq,arx100-usb": The DWC2 USB controller instance in Lantiq ARX SoCs;
|
||||
- "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq XRX SoCs;
|
||||
- "amlogic,meson8-usb": The DWC2 USB controller instance in Amlogic Meson8 SoCs;
|
||||
- "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs;
|
||||
- "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs;
|
||||
- "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs;
|
||||
|
|
|
@ -15,7 +15,7 @@ It has been tested with the following devices:
|
|||
The driver allows configuration of the touch screen via a set of sysfs files:
|
||||
|
||||
/sys/class/input/eventX/device/device/threshold:
|
||||
allows setting the "click"-threshold in the range from 20 to 80.
|
||||
allows setting the "click"-threshold in the range from 0 to 80.
|
||||
|
||||
/sys/class/input/eventX/device/device/gain:
|
||||
allows setting the sensitivity in the range from 0 to 31. Note that
|
||||
|
|
|
@ -16,6 +16,8 @@ ALC880
|
|||
6-jack in back, 2-jack in front
|
||||
6stack-digout
|
||||
6-jack with a SPDIF out
|
||||
6stack-automute
|
||||
6-jack with headphone jack detection
|
||||
|
||||
ALC260
|
||||
======
|
||||
|
@ -62,6 +64,8 @@ lenovo-dock
|
|||
Enables docking station I/O for some Lenovos
|
||||
hp-gpio-led
|
||||
GPIO LED support on HP laptops
|
||||
hp-dock-gpio-mic1-led
|
||||
HP dock with mic LED support
|
||||
dell-headset-multi
|
||||
Headset jack, which can also be used as mic-in
|
||||
dell-headset-dock
|
||||
|
@ -72,6 +76,12 @@ alc283-sense-combo
|
|||
Combo jack sensing on ALC283
|
||||
tpt440-dock
|
||||
Pin configs for Lenovo Thinkpad Dock support
|
||||
tpt440
|
||||
Lenovo Thinkpad T440s setup
|
||||
tpt460
|
||||
Lenovo Thinkpad T460/560 setup
|
||||
dual-codecs
|
||||
Lenovo laptops with dual codecs
|
||||
|
||||
ALC66x/67x/892
|
||||
==============
|
||||
|
@ -97,6 +107,8 @@ inv-dmic
|
|||
Inverted internal mic workaround
|
||||
dell-headset-multi
|
||||
Headset jack, which can also be used as mic-in
|
||||
dual-codecs
|
||||
Lenovo laptops with dual codecs
|
||||
|
||||
ALC680
|
||||
======
|
||||
|
@ -114,6 +126,8 @@ inv-dmic
|
|||
Inverted internal mic workaround
|
||||
no-primary-hp
|
||||
VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC)
|
||||
dual-codecs
|
||||
ALC1220 dual codecs for Gaming mobos
|
||||
|
||||
ALC861/660
|
||||
==========
|
||||
|
@ -206,65 +220,47 @@ auto
|
|||
|
||||
Conexant 5045
|
||||
=============
|
||||
laptop-hpsense
|
||||
Laptop with HP sense (old model laptop)
|
||||
laptop-micsense
|
||||
Laptop with Mic sense (old model fujitsu)
|
||||
laptop-hpmicsense
|
||||
Laptop with HP and Mic senses
|
||||
benq
|
||||
Benq R55E
|
||||
laptop-hp530
|
||||
HP 530 laptop
|
||||
test
|
||||
for testing/debugging purpose, almost all controls can be
|
||||
adjusted. Appearing only when compiled with $CONFIG_SND_DEBUG=y
|
||||
cap-mix-amp
|
||||
Fix max input level on mixer widget
|
||||
toshiba-p105
|
||||
Toshiba P105 quirk
|
||||
hp-530
|
||||
HP 530 quirk
|
||||
|
||||
Conexant 5047
|
||||
=============
|
||||
laptop
|
||||
Basic Laptop config
|
||||
laptop-hp
|
||||
Laptop config for some HP models (subdevice 30A5)
|
||||
laptop-eapd
|
||||
Laptop config with EAPD support
|
||||
test
|
||||
for testing/debugging purpose, almost all controls can be
|
||||
adjusted. Appearing only when compiled with $CONFIG_SND_DEBUG=y
|
||||
cap-mix-amp
|
||||
Fix max input level on mixer widget
|
||||
|
||||
Conexant 5051
|
||||
=============
|
||||
laptop
|
||||
Basic Laptop config (default)
|
||||
hp
|
||||
HP Spartan laptop
|
||||
hp-dv6736
|
||||
HP dv6736
|
||||
hp-f700
|
||||
HP Compaq Presario F700
|
||||
ideapad
|
||||
Lenovo IdeaPad laptop
|
||||
toshiba
|
||||
Toshiba Satellite M300
|
||||
lenovo-x200
|
||||
Lenovo X200 quirk
|
||||
|
||||
Conexant 5066
|
||||
=============
|
||||
laptop
|
||||
Basic Laptop config (default)
|
||||
hp-laptop
|
||||
HP laptops, e g G60
|
||||
asus
|
||||
Asus K52JU, Lenovo G560
|
||||
dell-laptop
|
||||
Dell laptops
|
||||
dell-vostro
|
||||
Dell Vostro
|
||||
olpc-xo-1_5
|
||||
OLPC XO 1.5
|
||||
ideapad
|
||||
Lenovo IdeaPad U150
|
||||
stereo-dmic
|
||||
Workaround for inverted stereo digital mic
|
||||
gpio1
|
||||
Enable GPIO1 pin
|
||||
headphone-mic-pin
|
||||
Enable headphone mic NID 0x18 without detection
|
||||
tp410
|
||||
Thinkpad T400 & co quirks
|
||||
thinkpad
|
||||
Lenovo Thinkpad
|
||||
Thinkpad mute/mic LED quirk
|
||||
lemote-a1004
|
||||
Lemote A1004 quirk
|
||||
lemote-a1205
|
||||
Lemote A1205 quirk
|
||||
olpc-xo
|
||||
OLPC XO quirk
|
||||
mute-led-eapd
|
||||
Mute LED control via EAPD
|
||||
hp-dock
|
||||
HP dock support
|
||||
mute-led-gpio
|
||||
Mute LED control via GPIO
|
||||
|
||||
STAC9200
|
||||
========
|
||||
|
@ -444,6 +440,8 @@ dell-eq
|
|||
Dell desktops/laptops
|
||||
alienware
|
||||
Alienware M17x
|
||||
asus-mobo
|
||||
Pin configs for ASUS mobo with 5.1/SPDIF out
|
||||
auto
|
||||
BIOS setup (default)
|
||||
|
||||
|
@ -477,6 +475,8 @@ hp-envy-ts-bass
|
|||
Pin fixup for HP Envy TS bass speaker (NID 0x10)
|
||||
hp-bnb13-eq
|
||||
Hardware equalizer setup for HP laptops
|
||||
hp-envy-ts-bass
|
||||
HP Envy TS bass support
|
||||
auto
|
||||
BIOS setup (default)
|
||||
|
||||
|
@ -496,10 +496,22 @@ auto
|
|||
|
||||
Cirrus Logic CS4206/4207
|
||||
========================
|
||||
mbp53
|
||||
MacBook Pro 5,3
|
||||
mbp55
|
||||
MacBook Pro 5,5
|
||||
imac27
|
||||
IMac 27 Inch
|
||||
imac27_122
|
||||
iMac 12,2
|
||||
apple
|
||||
Generic Apple quirk
|
||||
mbp101
|
||||
MacBookPro 10,1
|
||||
mbp81
|
||||
MacBookPro 8,1
|
||||
mba42
|
||||
MacBookAir 4,2
|
||||
auto
|
||||
BIOS setup (default)
|
||||
|
||||
|
@ -509,6 +521,10 @@ mba6
|
|||
MacBook Air 6,1 and 6,2
|
||||
gpio0
|
||||
Enable GPIO 0 amp
|
||||
mbp11
|
||||
MacBookPro 11,2
|
||||
macmini
|
||||
MacMini 7,1
|
||||
auto
|
||||
BIOS setup (default)
|
||||
|
||||
|
|
|
@ -7143,7 +7143,7 @@ S: Maintained
|
|||
F: drivers/media/platform/rcar_jpu.c
|
||||
|
||||
JSM Neo PCI based serial card
|
||||
M: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com>
|
||||
M: Guilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com>
|
||||
L: linux-serial@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/tty/serial/jsm/
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
|||
VERSION = 4
|
||||
PATCHLEVEL = 12
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc2
|
||||
EXTRAVERSION = -rc3
|
||||
NAME = Fearless Coyote
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
@ -81,6 +81,45 @@
|
|||
};
|
||||
};
|
||||
|
||||
reg_sys_5v: regulator@0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "SYS_5V";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
reg_vdd_3v3: regulator@1 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "VDD_3V3";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
vin-supply = <®_sys_5v>;
|
||||
};
|
||||
|
||||
reg_5v_hub: regulator@2 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "5V_HUB";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-boot-on;
|
||||
gpio = <&gpio0 7 0>;
|
||||
regulator-always-on;
|
||||
vin-supply = <®_sys_5v>;
|
||||
};
|
||||
|
||||
wl1835_pwrseq: wl1835-pwrseq {
|
||||
compatible = "mmc-pwrseq-simple";
|
||||
/* WLAN_EN GPIO */
|
||||
reset-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
|
||||
clocks = <&pmic>;
|
||||
clock-names = "ext_clock";
|
||||
power-off-delay-us = <10>;
|
||||
};
|
||||
|
||||
soc {
|
||||
spi0: spi@f7106000 {
|
||||
status = "ok";
|
||||
|
@ -256,11 +295,31 @@
|
|||
|
||||
/* GPIO blocks 16 thru 19 do not appear to be routed to pins */
|
||||
|
||||
dwmmc_2: dwmmc2@f723f000 {
|
||||
ti,non-removable;
|
||||
dwmmc_0: dwmmc0@f723d000 {
|
||||
cap-mmc-highspeed;
|
||||
non-removable;
|
||||
/* WL_EN */
|
||||
vmmc-supply = <&wlan_en_reg>;
|
||||
bus-width = <0x8>;
|
||||
vmmc-supply = <&ldo19>;
|
||||
};
|
||||
|
||||
dwmmc_1: dwmmc1@f723e000 {
|
||||
card-detect-delay = <200>;
|
||||
cap-sd-highspeed;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr25;
|
||||
sd-uhs-sdr50;
|
||||
vqmmc-supply = <&ldo7>;
|
||||
vmmc-supply = <&ldo10>;
|
||||
bus-width = <0x4>;
|
||||
disable-wp;
|
||||
cd-gpios = <&gpio1 0 1>;
|
||||
};
|
||||
|
||||
dwmmc_2: dwmmc2@f723f000 {
|
||||
bus-width = <0x4>;
|
||||
non-removable;
|
||||
vmmc-supply = <®_vdd_3v3>;
|
||||
mmc-pwrseq = <&wl1835_pwrseq>;
|
||||
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x0>;
|
||||
|
@ -272,18 +331,6 @@
|
|||
interrupts = <3 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
};
|
||||
|
||||
wlan_en_reg: regulator@1 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "wlan-en-regulator";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
/* WLAN_EN GPIO */
|
||||
gpio = <&gpio0 5 0>;
|
||||
/* WLAN card specific delay */
|
||||
startup-delay-us = <70000>;
|
||||
enable-active-high;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
|
@ -330,6 +377,7 @@
|
|||
pmic: pmic@f8000000 {
|
||||
compatible = "hisilicon,hi655x-pmic";
|
||||
reg = <0x0 0xf8000000 0x0 0x1000>;
|
||||
#clock-cells = <0>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
pmic-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
|
||||
|
|
|
@ -725,20 +725,10 @@
|
|||
status = "disabled";
|
||||
};
|
||||
|
||||
fixed_5v_hub: regulator@0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "fixed_5v_hub";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-boot-on;
|
||||
gpio = <&gpio0 7 0>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
usb_phy: usbphy {
|
||||
compatible = "hisilicon,hi6220-usb-phy";
|
||||
#phy-cells = <0>;
|
||||
phy-supply = <&fixed_5v_hub>;
|
||||
phy-supply = <®_5v_hub>;
|
||||
hisilicon,peripheral-syscon = <&sys_ctrl>;
|
||||
};
|
||||
|
||||
|
@ -766,17 +756,12 @@
|
|||
|
||||
dwmmc_0: dwmmc0@f723d000 {
|
||||
compatible = "hisilicon,hi6220-dw-mshc";
|
||||
num-slots = <0x1>;
|
||||
cap-mmc-highspeed;
|
||||
non-removable;
|
||||
reg = <0x0 0xf723d000 0x0 0x1000>;
|
||||
interrupts = <0x0 0x48 0x4>;
|
||||
clocks = <&sys_ctrl 2>, <&sys_ctrl 1>;
|
||||
clock-names = "ciu", "biu";
|
||||
resets = <&sys_ctrl PERIPH_RSTDIS0_MMC0>;
|
||||
reset-names = "reset";
|
||||
bus-width = <0x8>;
|
||||
vmmc-supply = <&ldo19>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&emmc_pmx_func &emmc_clk_cfg_func
|
||||
&emmc_cfg_func &emmc_rst_cfg_func>;
|
||||
|
@ -784,13 +769,7 @@
|
|||
|
||||
dwmmc_1: dwmmc1@f723e000 {
|
||||
compatible = "hisilicon,hi6220-dw-mshc";
|
||||
num-slots = <0x1>;
|
||||
card-detect-delay = <200>;
|
||||
hisilicon,peripheral-syscon = <&ao_ctrl>;
|
||||
cap-sd-highspeed;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr25;
|
||||
sd-uhs-sdr50;
|
||||
reg = <0x0 0xf723e000 0x0 0x1000>;
|
||||
interrupts = <0x0 0x49 0x4>;
|
||||
#address-cells = <0x1>;
|
||||
|
@ -799,11 +778,6 @@
|
|||
clock-names = "ciu", "biu";
|
||||
resets = <&sys_ctrl PERIPH_RSTDIS0_MMC1>;
|
||||
reset-names = "reset";
|
||||
vqmmc-supply = <&ldo7>;
|
||||
vmmc-supply = <&ldo10>;
|
||||
bus-width = <0x4>;
|
||||
disable-wp;
|
||||
cd-gpios = <&gpio1 0 1>;
|
||||
pinctrl-names = "default", "idle";
|
||||
pinctrl-0 = <&sd_pmx_func &sd_clk_cfg_func &sd_cfg_func>;
|
||||
pinctrl-1 = <&sd_pmx_idle &sd_clk_cfg_idle &sd_cfg_idle>;
|
||||
|
@ -811,15 +785,12 @@
|
|||
|
||||
dwmmc_2: dwmmc2@f723f000 {
|
||||
compatible = "hisilicon,hi6220-dw-mshc";
|
||||
num-slots = <0x1>;
|
||||
reg = <0x0 0xf723f000 0x0 0x1000>;
|
||||
interrupts = <0x0 0x4a 0x4>;
|
||||
clocks = <&sys_ctrl HI6220_MMC2_CIUCLK>, <&sys_ctrl HI6220_MMC2_CLK>;
|
||||
clock-names = "ciu", "biu";
|
||||
resets = <&sys_ctrl PERIPH_RSTDIS0_MMC2>;
|
||||
reset-names = "reset";
|
||||
bus-width = <0x4>;
|
||||
broken-cd;
|
||||
pinctrl-names = "default", "idle";
|
||||
pinctrl-0 = <&sdio_pmx_func &sdio_clk_cfg_func &sdio_cfg_func>;
|
||||
pinctrl-1 = <&sdio_pmx_idle &sdio_clk_cfg_idle &sdio_cfg_idle>;
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#define PPC_FEATURE2_HTM_NOSC 0x01000000
|
||||
#define PPC_FEATURE2_ARCH_3_00 0x00800000 /* ISA 3.00 */
|
||||
#define PPC_FEATURE2_HAS_IEEE128 0x00400000 /* VSX IEEE Binary Float 128-bit */
|
||||
#define PPC_FEATURE2_DARN 0x00200000 /* darn random number insn */
|
||||
#define PPC_FEATURE2_SCV 0x00100000 /* scv syscall */
|
||||
|
||||
/*
|
||||
* IMPORTANT!
|
||||
|
|
|
@ -124,7 +124,8 @@ extern void __restore_cpu_e6500(void);
|
|||
#define COMMON_USER_POWER9 COMMON_USER_POWER8
|
||||
#define COMMON_USER2_POWER9 (COMMON_USER2_POWER8 | \
|
||||
PPC_FEATURE2_ARCH_3_00 | \
|
||||
PPC_FEATURE2_HAS_IEEE128)
|
||||
PPC_FEATURE2_HAS_IEEE128 | \
|
||||
PPC_FEATURE2_DARN )
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3E_64
|
||||
#define COMMON_USER_BOOKE (COMMON_USER_PPC64 | PPC_FEATURE_BOOKE)
|
||||
|
|
|
@ -161,7 +161,9 @@ static struct ibm_pa_feature {
|
|||
{ .pabyte = 0, .pabit = 3, .cpu_features = CPU_FTR_CTRL },
|
||||
{ .pabyte = 0, .pabit = 6, .cpu_features = CPU_FTR_NOEXECUTE },
|
||||
{ .pabyte = 1, .pabit = 2, .mmu_features = MMU_FTR_CI_LARGE_PAGE },
|
||||
#ifdef CONFIG_PPC_RADIX_MMU
|
||||
{ .pabyte = 40, .pabit = 0, .mmu_features = MMU_FTR_TYPE_RADIX },
|
||||
#endif
|
||||
{ .pabyte = 1, .pabit = 1, .invert = 1, .cpu_features = CPU_FTR_NODSISRALIGN },
|
||||
{ .pabyte = 5, .pabit = 0, .cpu_features = CPU_FTR_REAL_LE,
|
||||
.cpu_user_ftrs = PPC_FEATURE_TRUE_LE },
|
||||
|
|
|
@ -197,7 +197,9 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
|
|||
(REGION_ID(ea) != USER_REGION_ID)) {
|
||||
|
||||
spin_unlock(&spu->register_lock);
|
||||
ret = hash_page(ea, _PAGE_PRESENT | _PAGE_READ, 0x300, dsisr);
|
||||
ret = hash_page(ea,
|
||||
_PAGE_PRESENT | _PAGE_READ | _PAGE_PRIVILEGED,
|
||||
0x300, dsisr);
|
||||
spin_lock(&spu->register_lock);
|
||||
|
||||
if (!ret) {
|
||||
|
|
|
@ -714,7 +714,7 @@ static void pnv_npu2_release_context(struct kref *kref)
|
|||
void pnv_npu2_destroy_context(struct npu_context *npu_context,
|
||||
struct pci_dev *gpdev)
|
||||
{
|
||||
struct pnv_phb *nphb, *phb;
|
||||
struct pnv_phb *nphb;
|
||||
struct npu *npu;
|
||||
struct pci_dev *npdev = pnv_pci_get_npu_dev(gpdev, 0);
|
||||
struct device_node *nvlink_dn;
|
||||
|
@ -728,13 +728,12 @@ void pnv_npu2_destroy_context(struct npu_context *npu_context,
|
|||
|
||||
nphb = pci_bus_to_host(npdev->bus)->private_data;
|
||||
npu = &nphb->npu;
|
||||
phb = pci_bus_to_host(gpdev->bus)->private_data;
|
||||
nvlink_dn = of_parse_phandle(npdev->dev.of_node, "ibm,nvlink", 0);
|
||||
if (WARN_ON(of_property_read_u32(nvlink_dn, "ibm,npu-link-index",
|
||||
&nvlink_index)))
|
||||
return;
|
||||
npu_context->npdev[npu->index][nvlink_index] = NULL;
|
||||
opal_npu_destroy_context(phb->opal_id, npu_context->mm->context.id,
|
||||
opal_npu_destroy_context(nphb->opal_id, npu_context->mm->context.id,
|
||||
PCI_DEVID(gpdev->bus->number, gpdev->devfn));
|
||||
kref_put(&npu_context->kref, pnv_npu2_release_context);
|
||||
}
|
||||
|
|
|
@ -360,7 +360,7 @@ config SMP
|
|||
Management" code will be disabled if you say Y here.
|
||||
|
||||
See also <file:Documentation/x86/i386/IO-APIC.txt>,
|
||||
<file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
|
||||
<file:Documentation/lockup-watchdogs.txt> and the SMP-HOWTO available at
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
|
|
@ -159,7 +159,7 @@ ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
|||
# If '-Os' is enabled, disable it and print a warning.
|
||||
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
undefine CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
$(warning Disabling CONFIG_CC_OPTIMIZE_FOR_SIZE. Your compiler does not have -mfentry so you cannot optimize for size with CONFIG_FUNCTION_GRAPH_TRACER.)
|
||||
$(warning Disabling CONFIG_CC_OPTIMIZE_FOR_SIZE. Your compiler does not have -mfentry so you cannot optimize for size with CONFIG_FUNCTION_GRAPH_TRACER.)
|
||||
endif
|
||||
|
||||
endif
|
||||
|
|
|
@ -94,7 +94,7 @@ vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
|
|||
quiet_cmd_check_data_rel = DATAREL $@
|
||||
define cmd_check_data_rel
|
||||
for obj in $(filter %.o,$^); do \
|
||||
readelf -S $$obj | grep -qF .rel.local && { \
|
||||
${CROSS_COMPILE}readelf -S $$obj | grep -qF .rel.local && { \
|
||||
echo "error: $$obj has data relocations!" >&2; \
|
||||
exit 1; \
|
||||
} || true; \
|
||||
|
|
|
@ -251,6 +251,23 @@ ENTRY(__switch_to_asm)
|
|||
jmp __switch_to
|
||||
END(__switch_to_asm)
|
||||
|
||||
/*
|
||||
* The unwinder expects the last frame on the stack to always be at the same
|
||||
* offset from the end of the page, which allows it to validate the stack.
|
||||
* Calling schedule_tail() directly would break that convention because its an
|
||||
* asmlinkage function so its argument has to be pushed on the stack. This
|
||||
* wrapper creates a proper "end of stack" frame header before the call.
|
||||
*/
|
||||
ENTRY(schedule_tail_wrapper)
|
||||
FRAME_BEGIN
|
||||
|
||||
pushl %eax
|
||||
call schedule_tail
|
||||
popl %eax
|
||||
|
||||
FRAME_END
|
||||
ret
|
||||
ENDPROC(schedule_tail_wrapper)
|
||||
/*
|
||||
* A newly forked process directly context switches into this address.
|
||||
*
|
||||
|
@ -259,24 +276,15 @@ END(__switch_to_asm)
|
|||
* edi: kernel thread arg
|
||||
*/
|
||||
ENTRY(ret_from_fork)
|
||||
FRAME_BEGIN /* help unwinder find end of stack */
|
||||
|
||||
/*
|
||||
* schedule_tail() is asmlinkage so we have to put its 'prev' argument
|
||||
* on the stack.
|
||||
*/
|
||||
pushl %eax
|
||||
call schedule_tail
|
||||
popl %eax
|
||||
call schedule_tail_wrapper
|
||||
|
||||
testl %ebx, %ebx
|
||||
jnz 1f /* kernel threads are uncommon */
|
||||
|
||||
2:
|
||||
/* When we fork, we trace the syscall return in the child, too. */
|
||||
leal FRAME_OFFSET(%esp), %eax
|
||||
movl %esp, %eax
|
||||
call syscall_return_slowpath
|
||||
FRAME_END
|
||||
jmp restore_all
|
||||
|
||||
/* kernel thread */
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include <asm/smap.h>
|
||||
#include <asm/pgtable_types.h>
|
||||
#include <asm/export.h>
|
||||
#include <asm/frame.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
.code64
|
||||
|
@ -406,19 +405,17 @@ END(__switch_to_asm)
|
|||
* r12: kernel thread arg
|
||||
*/
|
||||
ENTRY(ret_from_fork)
|
||||
FRAME_BEGIN /* help unwinder find end of stack */
|
||||
movq %rax, %rdi
|
||||
call schedule_tail /* rdi: 'prev' task parameter */
|
||||
call schedule_tail /* rdi: 'prev' task parameter */
|
||||
|
||||
testq %rbx, %rbx /* from kernel_thread? */
|
||||
jnz 1f /* kernel threads are uncommon */
|
||||
testq %rbx, %rbx /* from kernel_thread? */
|
||||
jnz 1f /* kernel threads are uncommon */
|
||||
|
||||
2:
|
||||
leaq FRAME_OFFSET(%rsp),%rdi /* pt_regs pointer */
|
||||
movq %rsp, %rdi
|
||||
call syscall_return_slowpath /* returns with IRQs disabled */
|
||||
TRACE_IRQS_ON /* user mode is traced as IRQS on */
|
||||
SWAPGS
|
||||
FRAME_END
|
||||
jmp restore_regs_and_iret
|
||||
|
||||
1:
|
||||
|
|
|
@ -266,6 +266,7 @@ static inline int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *s
|
|||
#endif
|
||||
|
||||
int mce_available(struct cpuinfo_x86 *c);
|
||||
bool mce_is_memory_error(struct mce *m);
|
||||
|
||||
DECLARE_PER_CPU(unsigned, mce_exception_count);
|
||||
DECLARE_PER_CPU(unsigned, mce_poll_count);
|
||||
|
|
|
@ -409,8 +409,13 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
|
|||
memcpy(insnbuf, replacement, a->replacementlen);
|
||||
insnbuf_sz = a->replacementlen;
|
||||
|
||||
/* 0xe8 is a relative jump; fix the offset. */
|
||||
if (*insnbuf == 0xe8 && a->replacementlen == 5) {
|
||||
/*
|
||||
* 0xe8 is a relative jump; fix the offset.
|
||||
*
|
||||
* Instruction length is checked before the opcode to avoid
|
||||
* accessing uninitialized bytes for zero-length replacements.
|
||||
*/
|
||||
if (a->replacementlen == 5 && *insnbuf == 0xe8) {
|
||||
*(s32 *)(insnbuf + 1) += replacement - instr;
|
||||
DPRINTK("Fix CALL offset: 0x%x, CALL 0x%lx",
|
||||
*(s32 *)(insnbuf + 1),
|
||||
|
|
|
@ -499,16 +499,14 @@ static int mce_usable_address(struct mce *m)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static bool memory_error(struct mce *m)
|
||||
bool mce_is_memory_error(struct mce *m)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
if (c->x86_vendor == X86_VENDOR_AMD) {
|
||||
if (m->cpuvendor == X86_VENDOR_AMD) {
|
||||
/* ErrCodeExt[20:16] */
|
||||
u8 xec = (m->status >> 16) & 0x1f;
|
||||
|
||||
return (xec == 0x0 || xec == 0x8);
|
||||
} else if (c->x86_vendor == X86_VENDOR_INTEL) {
|
||||
} else if (m->cpuvendor == X86_VENDOR_INTEL) {
|
||||
/*
|
||||
* Intel SDM Volume 3B - 15.9.2 Compound Error Codes
|
||||
*
|
||||
|
@ -529,6 +527,7 @@ static bool memory_error(struct mce *m)
|
|||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mce_is_memory_error);
|
||||
|
||||
static bool cec_add_mce(struct mce *m)
|
||||
{
|
||||
|
@ -536,7 +535,7 @@ static bool cec_add_mce(struct mce *m)
|
|||
return false;
|
||||
|
||||
/* We eat only correctable DRAM errors with usable addresses. */
|
||||
if (memory_error(m) &&
|
||||
if (mce_is_memory_error(m) &&
|
||||
!(m->status & MCI_STATUS_UC) &&
|
||||
mce_usable_address(m))
|
||||
if (!cec_add_elem(m->addr >> PAGE_SHIFT))
|
||||
|
@ -713,7 +712,7 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
|
|||
|
||||
severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
|
||||
|
||||
if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m))
|
||||
if (severity == MCE_DEFERRED_SEVERITY && mce_is_memory_error(&m))
|
||||
if (m.status & MCI_STATUS_ADDRV)
|
||||
m.severity = severity;
|
||||
|
||||
|
|
|
@ -689,8 +689,12 @@ static inline void *alloc_tramp(unsigned long size)
|
|||
{
|
||||
return module_alloc(size);
|
||||
}
|
||||
static inline void tramp_free(void *tramp)
|
||||
static inline void tramp_free(void *tramp, int size)
|
||||
{
|
||||
int npages = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
|
||||
set_memory_nx((unsigned long)tramp, npages);
|
||||
set_memory_rw((unsigned long)tramp, npages);
|
||||
module_memfree(tramp);
|
||||
}
|
||||
#else
|
||||
|
@ -699,7 +703,7 @@ static inline void *alloc_tramp(unsigned long size)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void tramp_free(void *tramp) { }
|
||||
static inline void tramp_free(void *tramp, int size) { }
|
||||
#endif
|
||||
|
||||
/* Defined as markers to the end of the ftrace default trampolines */
|
||||
|
@ -771,7 +775,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|||
/* Copy ftrace_caller onto the trampoline memory */
|
||||
ret = probe_kernel_read(trampoline, (void *)start_offset, size);
|
||||
if (WARN_ON(ret < 0)) {
|
||||
tramp_free(trampoline);
|
||||
tramp_free(trampoline, *tramp_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -797,7 +801,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|||
|
||||
/* Are we pointing to the reference? */
|
||||
if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0)) {
|
||||
tramp_free(trampoline);
|
||||
tramp_free(trampoline, *tramp_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -839,7 +843,7 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
|
|||
unsigned long offset;
|
||||
unsigned long ip;
|
||||
unsigned int size;
|
||||
int ret;
|
||||
int ret, npages;
|
||||
|
||||
if (ops->trampoline) {
|
||||
/*
|
||||
|
@ -848,11 +852,14 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
|
|||
*/
|
||||
if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
|
||||
return;
|
||||
npages = PAGE_ALIGN(ops->trampoline_size) >> PAGE_SHIFT;
|
||||
set_memory_rw(ops->trampoline, npages);
|
||||
} else {
|
||||
ops->trampoline = create_trampoline(ops, &size);
|
||||
if (!ops->trampoline)
|
||||
return;
|
||||
ops->trampoline_size = size;
|
||||
npages = PAGE_ALIGN(size) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS);
|
||||
|
@ -863,6 +870,7 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
|
|||
/* Do a safe modify in case the trampoline is executing */
|
||||
new = ftrace_call_replace(ip, (unsigned long)func);
|
||||
ret = update_ftrace_func(ip, new);
|
||||
set_memory_ro(ops->trampoline, npages);
|
||||
|
||||
/* The update should never fail */
|
||||
WARN_ON(ret);
|
||||
|
@ -939,7 +947,7 @@ void arch_ftrace_trampoline_free(struct ftrace_ops *ops)
|
|||
if (!ops || !(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
|
||||
return;
|
||||
|
||||
tramp_free((void *)ops->trampoline);
|
||||
tramp_free((void *)ops->trampoline, ops->trampoline_size);
|
||||
ops->trampoline = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include <linux/ftrace.h>
|
||||
#include <linux/frame.h>
|
||||
#include <linux/kasan.h>
|
||||
#include <linux/moduleloader.h>
|
||||
|
||||
#include <asm/text-patching.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
@ -417,6 +418,14 @@ static void prepare_boost(struct kprobe *p, struct insn *insn)
|
|||
}
|
||||
}
|
||||
|
||||
/* Recover page to RW mode before releasing it */
|
||||
void free_insn_page(void *page)
|
||||
{
|
||||
set_memory_nx((unsigned long)page & PAGE_MASK, 1);
|
||||
set_memory_rw((unsigned long)page & PAGE_MASK, 1);
|
||||
module_memfree(page);
|
||||
}
|
||||
|
||||
static int arch_copy_kprobe(struct kprobe *p)
|
||||
{
|
||||
struct insn insn;
|
||||
|
|
|
@ -980,8 +980,6 @@ void __init setup_arch(char **cmdline_p)
|
|||
*/
|
||||
x86_configure_nx();
|
||||
|
||||
simple_udelay_calibration();
|
||||
|
||||
parse_early_param();
|
||||
|
||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||
|
@ -1041,6 +1039,8 @@ void __init setup_arch(char **cmdline_p)
|
|||
*/
|
||||
init_hypervisor_platform();
|
||||
|
||||
simple_udelay_calibration();
|
||||
|
||||
x86_init.resources.probe_roms();
|
||||
|
||||
/* after parse_early_param, so could debug it */
|
||||
|
|
|
@ -104,6 +104,11 @@ static inline unsigned long *last_frame(struct unwind_state *state)
|
|||
return (unsigned long *)task_pt_regs(state->task) - 2;
|
||||
}
|
||||
|
||||
static bool is_last_frame(struct unwind_state *state)
|
||||
{
|
||||
return state->bp == last_frame(state);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define GCC_REALIGN_WORDS 3
|
||||
#else
|
||||
|
@ -115,16 +120,15 @@ static inline unsigned long *last_aligned_frame(struct unwind_state *state)
|
|||
return last_frame(state) - GCC_REALIGN_WORDS;
|
||||
}
|
||||
|
||||
static bool is_last_task_frame(struct unwind_state *state)
|
||||
static bool is_last_aligned_frame(struct unwind_state *state)
|
||||
{
|
||||
unsigned long *last_bp = last_frame(state);
|
||||
unsigned long *aligned_bp = last_aligned_frame(state);
|
||||
|
||||
/*
|
||||
* We have to check for the last task frame at two different locations
|
||||
* because gcc can occasionally decide to realign the stack pointer and
|
||||
* change the offset of the stack frame in the prologue of a function
|
||||
* called by head/entry code. Examples:
|
||||
* GCC can occasionally decide to realign the stack pointer and change
|
||||
* the offset of the stack frame in the prologue of a function called
|
||||
* by head/entry code. Examples:
|
||||
*
|
||||
* <start_secondary>:
|
||||
* push %edi
|
||||
|
@ -141,11 +145,38 @@ static bool is_last_task_frame(struct unwind_state *state)
|
|||
* push %rbp
|
||||
* mov %rsp,%rbp
|
||||
*
|
||||
* Note that after aligning the stack, it pushes a duplicate copy of
|
||||
* the return address before pushing the frame pointer.
|
||||
* After aligning the stack, it pushes a duplicate copy of the return
|
||||
* address before pushing the frame pointer.
|
||||
*/
|
||||
return (state->bp == last_bp ||
|
||||
(state->bp == aligned_bp && *(aligned_bp+1) == *(last_bp+1)));
|
||||
return (state->bp == aligned_bp && *(aligned_bp + 1) == *(last_bp + 1));
|
||||
}
|
||||
|
||||
static bool is_last_ftrace_frame(struct unwind_state *state)
|
||||
{
|
||||
unsigned long *last_bp = last_frame(state);
|
||||
unsigned long *last_ftrace_bp = last_bp - 3;
|
||||
|
||||
/*
|
||||
* When unwinding from an ftrace handler of a function called by entry
|
||||
* code, the stack layout of the last frame is:
|
||||
*
|
||||
* bp
|
||||
* parent ret addr
|
||||
* bp
|
||||
* function ret addr
|
||||
* parent ret addr
|
||||
* pt_regs
|
||||
* -----------------
|
||||
*/
|
||||
return (state->bp == last_ftrace_bp &&
|
||||
*state->bp == *(state->bp + 2) &&
|
||||
*(state->bp + 1) == *(state->bp + 4));
|
||||
}
|
||||
|
||||
static bool is_last_task_frame(struct unwind_state *state)
|
||||
{
|
||||
return is_last_frame(state) || is_last_aligned_frame(state) ||
|
||||
is_last_ftrace_frame(state);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -186,7 +186,7 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache)
|
|||
unsigned int i, level;
|
||||
unsigned long addr;
|
||||
|
||||
BUG_ON(irqs_disabled());
|
||||
BUG_ON(irqs_disabled() && !early_boot_irqs_disabled);
|
||||
WARN_ON(PAGE_ALIGN(start) != start);
|
||||
|
||||
on_each_cpu(__cpa_flush_range, NULL, 1);
|
||||
|
|
|
@ -65,9 +65,11 @@ static int __init nopat(char *str)
|
|||
}
|
||||
early_param("nopat", nopat);
|
||||
|
||||
static bool __read_mostly __pat_initialized = false;
|
||||
|
||||
bool pat_enabled(void)
|
||||
{
|
||||
return !!__pat_enabled;
|
||||
return __pat_initialized;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pat_enabled);
|
||||
|
||||
|
@ -225,13 +227,14 @@ static void pat_bsp_init(u64 pat)
|
|||
}
|
||||
|
||||
wrmsrl(MSR_IA32_CR_PAT, pat);
|
||||
__pat_initialized = true;
|
||||
|
||||
__init_cache_modes(pat);
|
||||
}
|
||||
|
||||
static void pat_ap_init(u64 pat)
|
||||
{
|
||||
if (!boot_cpu_has(X86_FEATURE_PAT)) {
|
||||
if (!this_cpu_has(X86_FEATURE_PAT)) {
|
||||
/*
|
||||
* If this happens we are on a secondary CPU, but switched to
|
||||
* PAT on the boot CPU. We have no way to undo PAT.
|
||||
|
@ -306,7 +309,7 @@ void pat_init(void)
|
|||
u64 pat;
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
if (!pat_enabled()) {
|
||||
if (!__pat_enabled) {
|
||||
init_cache_modes();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -628,25 +628,6 @@ void blk_mq_delay_kick_requeue_list(struct request_queue *q,
|
|||
}
|
||||
EXPORT_SYMBOL(blk_mq_delay_kick_requeue_list);
|
||||
|
||||
void blk_mq_abort_requeue_list(struct request_queue *q)
|
||||
{
|
||||
unsigned long flags;
|
||||
LIST_HEAD(rq_list);
|
||||
|
||||
spin_lock_irqsave(&q->requeue_lock, flags);
|
||||
list_splice_init(&q->requeue_list, &rq_list);
|
||||
spin_unlock_irqrestore(&q->requeue_lock, flags);
|
||||
|
||||
while (!list_empty(&rq_list)) {
|
||||
struct request *rq;
|
||||
|
||||
rq = list_first_entry(&rq_list, struct request, queuelist);
|
||||
list_del_init(&rq->queuelist);
|
||||
blk_mq_end_request(rq, -EIO);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(blk_mq_abort_requeue_list);
|
||||
|
||||
struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag)
|
||||
{
|
||||
if (tag < tags->nr_tags) {
|
||||
|
|
|
@ -887,10 +887,10 @@ int blk_register_queue(struct gendisk *disk)
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
if (q->mq_ops)
|
||||
if (q->mq_ops) {
|
||||
__blk_mq_register_dev(dev, q);
|
||||
|
||||
blk_mq_debugfs_register(q);
|
||||
blk_mq_debugfs_register(q);
|
||||
}
|
||||
|
||||
kobject_uevent(&q->kobj, KOBJ_ADD);
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ static int throtl_quantum = 32;
|
|||
#define DFL_THROTL_SLICE_HD (HZ / 10)
|
||||
#define DFL_THROTL_SLICE_SSD (HZ / 50)
|
||||
#define MAX_THROTL_SLICE (HZ)
|
||||
#define DFL_IDLE_THRESHOLD_SSD (1000L) /* 1 ms */
|
||||
#define DFL_IDLE_THRESHOLD_HD (100L * 1000) /* 100 ms */
|
||||
#define MAX_IDLE_TIME (5L * 1000 * 1000) /* 5 s */
|
||||
/* default latency target is 0, eg, guarantee IO latency by default */
|
||||
#define DFL_LATENCY_TARGET (0)
|
||||
#define MIN_THROTL_BPS (320 * 1024)
|
||||
#define MIN_THROTL_IOPS (10)
|
||||
#define DFL_LATENCY_TARGET (-1L)
|
||||
#define DFL_IDLE_THRESHOLD (0)
|
||||
|
||||
#define SKIP_LATENCY (((u64)1) << BLK_STAT_RES_SHIFT)
|
||||
|
||||
|
@ -157,6 +157,7 @@ struct throtl_grp {
|
|||
unsigned long last_check_time;
|
||||
|
||||
unsigned long latency_target; /* us */
|
||||
unsigned long latency_target_conf; /* us */
|
||||
/* When did we start a new slice */
|
||||
unsigned long slice_start[2];
|
||||
unsigned long slice_end[2];
|
||||
|
@ -165,6 +166,7 @@ struct throtl_grp {
|
|||
unsigned long checked_last_finish_time; /* ns / 1024 */
|
||||
unsigned long avg_idletime; /* ns / 1024 */
|
||||
unsigned long idletime_threshold; /* us */
|
||||
unsigned long idletime_threshold_conf; /* us */
|
||||
|
||||
unsigned int bio_cnt; /* total bios */
|
||||
unsigned int bad_bio_cnt; /* bios exceeding latency threshold */
|
||||
|
@ -201,8 +203,6 @@ struct throtl_data
|
|||
unsigned int limit_index;
|
||||
bool limit_valid[LIMIT_CNT];
|
||||
|
||||
unsigned long dft_idletime_threshold; /* us */
|
||||
|
||||
unsigned long low_upgrade_time;
|
||||
unsigned long low_downgrade_time;
|
||||
|
||||
|
@ -294,8 +294,14 @@ static uint64_t tg_bps_limit(struct throtl_grp *tg, int rw)
|
|||
|
||||
td = tg->td;
|
||||
ret = tg->bps[rw][td->limit_index];
|
||||
if (ret == 0 && td->limit_index == LIMIT_LOW)
|
||||
return tg->bps[rw][LIMIT_MAX];
|
||||
if (ret == 0 && td->limit_index == LIMIT_LOW) {
|
||||
/* intermediate node or iops isn't 0 */
|
||||
if (!list_empty(&blkg->blkcg->css.children) ||
|
||||
tg->iops[rw][td->limit_index])
|
||||
return U64_MAX;
|
||||
else
|
||||
return MIN_THROTL_BPS;
|
||||
}
|
||||
|
||||
if (td->limit_index == LIMIT_MAX && tg->bps[rw][LIMIT_LOW] &&
|
||||
tg->bps[rw][LIMIT_LOW] != tg->bps[rw][LIMIT_MAX]) {
|
||||
|
@ -315,10 +321,17 @@ static unsigned int tg_iops_limit(struct throtl_grp *tg, int rw)
|
|||
|
||||
if (cgroup_subsys_on_dfl(io_cgrp_subsys) && !blkg->parent)
|
||||
return UINT_MAX;
|
||||
|
||||
td = tg->td;
|
||||
ret = tg->iops[rw][td->limit_index];
|
||||
if (ret == 0 && tg->td->limit_index == LIMIT_LOW)
|
||||
return tg->iops[rw][LIMIT_MAX];
|
||||
if (ret == 0 && tg->td->limit_index == LIMIT_LOW) {
|
||||
/* intermediate node or bps isn't 0 */
|
||||
if (!list_empty(&blkg->blkcg->css.children) ||
|
||||
tg->bps[rw][td->limit_index])
|
||||
return UINT_MAX;
|
||||
else
|
||||
return MIN_THROTL_IOPS;
|
||||
}
|
||||
|
||||
if (td->limit_index == LIMIT_MAX && tg->iops[rw][LIMIT_LOW] &&
|
||||
tg->iops[rw][LIMIT_LOW] != tg->iops[rw][LIMIT_MAX]) {
|
||||
|
@ -482,6 +495,9 @@ static struct blkg_policy_data *throtl_pd_alloc(gfp_t gfp, int node)
|
|||
/* LIMIT_LOW will have default value 0 */
|
||||
|
||||
tg->latency_target = DFL_LATENCY_TARGET;
|
||||
tg->latency_target_conf = DFL_LATENCY_TARGET;
|
||||
tg->idletime_threshold = DFL_IDLE_THRESHOLD;
|
||||
tg->idletime_threshold_conf = DFL_IDLE_THRESHOLD;
|
||||
|
||||
return &tg->pd;
|
||||
}
|
||||
|
@ -510,8 +526,6 @@ static void throtl_pd_init(struct blkg_policy_data *pd)
|
|||
if (cgroup_subsys_on_dfl(io_cgrp_subsys) && blkg->parent)
|
||||
sq->parent_sq = &blkg_to_tg(blkg->parent)->service_queue;
|
||||
tg->td = td;
|
||||
|
||||
tg->idletime_threshold = td->dft_idletime_threshold;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1349,7 +1363,7 @@ static int tg_print_conf_uint(struct seq_file *sf, void *v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tg_conf_updated(struct throtl_grp *tg)
|
||||
static void tg_conf_updated(struct throtl_grp *tg, bool global)
|
||||
{
|
||||
struct throtl_service_queue *sq = &tg->service_queue;
|
||||
struct cgroup_subsys_state *pos_css;
|
||||
|
@ -1367,8 +1381,26 @@ static void tg_conf_updated(struct throtl_grp *tg)
|
|||
* restrictions in the whole hierarchy and allows them to bypass
|
||||
* blk-throttle.
|
||||
*/
|
||||
blkg_for_each_descendant_pre(blkg, pos_css, tg_to_blkg(tg))
|
||||
tg_update_has_rules(blkg_to_tg(blkg));
|
||||
blkg_for_each_descendant_pre(blkg, pos_css,
|
||||
global ? tg->td->queue->root_blkg : tg_to_blkg(tg)) {
|
||||
struct throtl_grp *this_tg = blkg_to_tg(blkg);
|
||||
struct throtl_grp *parent_tg;
|
||||
|
||||
tg_update_has_rules(this_tg);
|
||||
/* ignore root/second level */
|
||||
if (!cgroup_subsys_on_dfl(io_cgrp_subsys) || !blkg->parent ||
|
||||
!blkg->parent->parent)
|
||||
continue;
|
||||
parent_tg = blkg_to_tg(blkg->parent);
|
||||
/*
|
||||
* make sure all children has lower idle time threshold and
|
||||
* higher latency target
|
||||
*/
|
||||
this_tg->idletime_threshold = min(this_tg->idletime_threshold,
|
||||
parent_tg->idletime_threshold);
|
||||
this_tg->latency_target = max(this_tg->latency_target,
|
||||
parent_tg->latency_target);
|
||||
}
|
||||
|
||||
/*
|
||||
* We're already holding queue_lock and know @tg is valid. Let's
|
||||
|
@ -1413,7 +1445,7 @@ static ssize_t tg_set_conf(struct kernfs_open_file *of,
|
|||
else
|
||||
*(unsigned int *)((void *)tg + of_cft(of)->private) = v;
|
||||
|
||||
tg_conf_updated(tg);
|
||||
tg_conf_updated(tg, false);
|
||||
ret = 0;
|
||||
out_finish:
|
||||
blkg_conf_finish(&ctx);
|
||||
|
@ -1497,34 +1529,34 @@ static u64 tg_prfill_limit(struct seq_file *sf, struct blkg_policy_data *pd,
|
|||
tg->iops_conf[READ][off] == iops_dft &&
|
||||
tg->iops_conf[WRITE][off] == iops_dft &&
|
||||
(off != LIMIT_LOW ||
|
||||
(tg->idletime_threshold == tg->td->dft_idletime_threshold &&
|
||||
tg->latency_target == DFL_LATENCY_TARGET)))
|
||||
(tg->idletime_threshold_conf == DFL_IDLE_THRESHOLD &&
|
||||
tg->latency_target_conf == DFL_LATENCY_TARGET)))
|
||||
return 0;
|
||||
|
||||
if (tg->bps_conf[READ][off] != bps_dft)
|
||||
if (tg->bps_conf[READ][off] != U64_MAX)
|
||||
snprintf(bufs[0], sizeof(bufs[0]), "%llu",
|
||||
tg->bps_conf[READ][off]);
|
||||
if (tg->bps_conf[WRITE][off] != bps_dft)
|
||||
if (tg->bps_conf[WRITE][off] != U64_MAX)
|
||||
snprintf(bufs[1], sizeof(bufs[1]), "%llu",
|
||||
tg->bps_conf[WRITE][off]);
|
||||
if (tg->iops_conf[READ][off] != iops_dft)
|
||||
if (tg->iops_conf[READ][off] != UINT_MAX)
|
||||
snprintf(bufs[2], sizeof(bufs[2]), "%u",
|
||||
tg->iops_conf[READ][off]);
|
||||
if (tg->iops_conf[WRITE][off] != iops_dft)
|
||||
if (tg->iops_conf[WRITE][off] != UINT_MAX)
|
||||
snprintf(bufs[3], sizeof(bufs[3]), "%u",
|
||||
tg->iops_conf[WRITE][off]);
|
||||
if (off == LIMIT_LOW) {
|
||||
if (tg->idletime_threshold == ULONG_MAX)
|
||||
if (tg->idletime_threshold_conf == ULONG_MAX)
|
||||
strcpy(idle_time, " idle=max");
|
||||
else
|
||||
snprintf(idle_time, sizeof(idle_time), " idle=%lu",
|
||||
tg->idletime_threshold);
|
||||
tg->idletime_threshold_conf);
|
||||
|
||||
if (tg->latency_target == ULONG_MAX)
|
||||
if (tg->latency_target_conf == ULONG_MAX)
|
||||
strcpy(latency_time, " latency=max");
|
||||
else
|
||||
snprintf(latency_time, sizeof(latency_time),
|
||||
" latency=%lu", tg->latency_target);
|
||||
" latency=%lu", tg->latency_target_conf);
|
||||
}
|
||||
|
||||
seq_printf(sf, "%s rbps=%s wbps=%s riops=%s wiops=%s%s%s\n",
|
||||
|
@ -1563,8 +1595,8 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
|
|||
v[2] = tg->iops_conf[READ][index];
|
||||
v[3] = tg->iops_conf[WRITE][index];
|
||||
|
||||
idle_time = tg->idletime_threshold;
|
||||
latency_time = tg->latency_target;
|
||||
idle_time = tg->idletime_threshold_conf;
|
||||
latency_time = tg->latency_target_conf;
|
||||
while (true) {
|
||||
char tok[27]; /* wiops=18446744073709551616 */
|
||||
char *p;
|
||||
|
@ -1623,17 +1655,33 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
|
|||
tg->iops_conf[READ][LIMIT_MAX]);
|
||||
tg->iops[WRITE][LIMIT_LOW] = min(tg->iops_conf[WRITE][LIMIT_LOW],
|
||||
tg->iops_conf[WRITE][LIMIT_MAX]);
|
||||
tg->idletime_threshold_conf = idle_time;
|
||||
tg->latency_target_conf = latency_time;
|
||||
|
||||
if (index == LIMIT_LOW) {
|
||||
blk_throtl_update_limit_valid(tg->td);
|
||||
if (tg->td->limit_valid[LIMIT_LOW])
|
||||
tg->td->limit_index = LIMIT_LOW;
|
||||
tg->idletime_threshold = (idle_time == ULONG_MAX) ?
|
||||
ULONG_MAX : idle_time;
|
||||
tg->latency_target = (latency_time == ULONG_MAX) ?
|
||||
ULONG_MAX : latency_time;
|
||||
/* force user to configure all settings for low limit */
|
||||
if (!(tg->bps[READ][LIMIT_LOW] || tg->iops[READ][LIMIT_LOW] ||
|
||||
tg->bps[WRITE][LIMIT_LOW] || tg->iops[WRITE][LIMIT_LOW]) ||
|
||||
tg->idletime_threshold_conf == DFL_IDLE_THRESHOLD ||
|
||||
tg->latency_target_conf == DFL_LATENCY_TARGET) {
|
||||
tg->bps[READ][LIMIT_LOW] = 0;
|
||||
tg->bps[WRITE][LIMIT_LOW] = 0;
|
||||
tg->iops[READ][LIMIT_LOW] = 0;
|
||||
tg->iops[WRITE][LIMIT_LOW] = 0;
|
||||
tg->idletime_threshold = DFL_IDLE_THRESHOLD;
|
||||
tg->latency_target = DFL_LATENCY_TARGET;
|
||||
} else if (index == LIMIT_LOW) {
|
||||
tg->idletime_threshold = tg->idletime_threshold_conf;
|
||||
tg->latency_target = tg->latency_target_conf;
|
||||
}
|
||||
tg_conf_updated(tg);
|
||||
|
||||
blk_throtl_update_limit_valid(tg->td);
|
||||
if (tg->td->limit_valid[LIMIT_LOW]) {
|
||||
if (index == LIMIT_LOW)
|
||||
tg->td->limit_index = LIMIT_LOW;
|
||||
} else
|
||||
tg->td->limit_index = LIMIT_MAX;
|
||||
tg_conf_updated(tg, index == LIMIT_LOW &&
|
||||
tg->td->limit_valid[LIMIT_LOW]);
|
||||
ret = 0;
|
||||
out_finish:
|
||||
blkg_conf_finish(&ctx);
|
||||
|
@ -1722,17 +1770,25 @@ static bool throtl_tg_is_idle(struct throtl_grp *tg)
|
|||
/*
|
||||
* cgroup is idle if:
|
||||
* - single idle is too long, longer than a fixed value (in case user
|
||||
* configure a too big threshold) or 4 times of slice
|
||||
* configure a too big threshold) or 4 times of idletime threshold
|
||||
* - average think time is more than threshold
|
||||
* - IO latency is largely below threshold
|
||||
*/
|
||||
unsigned long time = jiffies_to_usecs(4 * tg->td->throtl_slice);
|
||||
unsigned long time;
|
||||
bool ret;
|
||||
|
||||
time = min_t(unsigned long, MAX_IDLE_TIME, time);
|
||||
return (ktime_get_ns() >> 10) - tg->last_finish_time > time ||
|
||||
tg->avg_idletime > tg->idletime_threshold ||
|
||||
(tg->latency_target && tg->bio_cnt &&
|
||||
time = min_t(unsigned long, MAX_IDLE_TIME, 4 * tg->idletime_threshold);
|
||||
ret = tg->latency_target == DFL_LATENCY_TARGET ||
|
||||
tg->idletime_threshold == DFL_IDLE_THRESHOLD ||
|
||||
(ktime_get_ns() >> 10) - tg->last_finish_time > time ||
|
||||
tg->avg_idletime > tg->idletime_threshold ||
|
||||
(tg->latency_target && tg->bio_cnt &&
|
||||
tg->bad_bio_cnt * 5 < tg->bio_cnt);
|
||||
throtl_log(&tg->service_queue,
|
||||
"avg_idle=%ld, idle_threshold=%ld, bad_bio=%d, total_bio=%d, is_idle=%d, scale=%d",
|
||||
tg->avg_idletime, tg->idletime_threshold, tg->bad_bio_cnt,
|
||||
tg->bio_cnt, ret, tg->td->scale);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool throtl_tg_can_upgrade(struct throtl_grp *tg)
|
||||
|
@ -1828,6 +1884,7 @@ static void throtl_upgrade_state(struct throtl_data *td)
|
|||
struct cgroup_subsys_state *pos_css;
|
||||
struct blkcg_gq *blkg;
|
||||
|
||||
throtl_log(&td->service_queue, "upgrade to max");
|
||||
td->limit_index = LIMIT_MAX;
|
||||
td->low_upgrade_time = jiffies;
|
||||
td->scale = 0;
|
||||
|
@ -1850,6 +1907,7 @@ static void throtl_downgrade_state(struct throtl_data *td, int new)
|
|||
{
|
||||
td->scale /= 2;
|
||||
|
||||
throtl_log(&td->service_queue, "downgrade, scale %d", td->scale);
|
||||
if (td->scale) {
|
||||
td->low_upgrade_time = jiffies - td->scale * td->throtl_slice;
|
||||
return;
|
||||
|
@ -2023,6 +2081,11 @@ static void throtl_update_latency_buckets(struct throtl_data *td)
|
|||
td->avg_buckets[i].valid = true;
|
||||
last_latency = td->avg_buckets[i].latency;
|
||||
}
|
||||
|
||||
for (i = 0; i < LATENCY_BUCKET_SIZE; i++)
|
||||
throtl_log(&td->service_queue,
|
||||
"Latency bucket %d: latency=%ld, valid=%d", i,
|
||||
td->avg_buckets[i].latency, td->avg_buckets[i].valid);
|
||||
}
|
||||
#else
|
||||
static inline void throtl_update_latency_buckets(struct throtl_data *td)
|
||||
|
@ -2354,19 +2417,14 @@ void blk_throtl_exit(struct request_queue *q)
|
|||
void blk_throtl_register_queue(struct request_queue *q)
|
||||
{
|
||||
struct throtl_data *td;
|
||||
struct cgroup_subsys_state *pos_css;
|
||||
struct blkcg_gq *blkg;
|
||||
|
||||
td = q->td;
|
||||
BUG_ON(!td);
|
||||
|
||||
if (blk_queue_nonrot(q)) {
|
||||
if (blk_queue_nonrot(q))
|
||||
td->throtl_slice = DFL_THROTL_SLICE_SSD;
|
||||
td->dft_idletime_threshold = DFL_IDLE_THRESHOLD_SSD;
|
||||
} else {
|
||||
else
|
||||
td->throtl_slice = DFL_THROTL_SLICE_HD;
|
||||
td->dft_idletime_threshold = DFL_IDLE_THRESHOLD_HD;
|
||||
}
|
||||
#ifndef CONFIG_BLK_DEV_THROTTLING_LOW
|
||||
/* if no low limit, use previous default */
|
||||
td->throtl_slice = DFL_THROTL_SLICE_HD;
|
||||
|
@ -2375,18 +2433,6 @@ void blk_throtl_register_queue(struct request_queue *q)
|
|||
td->track_bio_latency = !q->mq_ops && !q->request_fn;
|
||||
if (!td->track_bio_latency)
|
||||
blk_stat_enable_accounting(q);
|
||||
|
||||
/*
|
||||
* some tg are created before queue is fully initialized, eg, nonrot
|
||||
* isn't initialized yet
|
||||
*/
|
||||
rcu_read_lock();
|
||||
blkg_for_each_descendant_post(blkg, pos_css, q->root_blkg) {
|
||||
struct throtl_grp *tg = blkg_to_tg(blkg);
|
||||
|
||||
tg->idletime_threshold = td->dft_idletime_threshold;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_THROTTLING_LOW
|
||||
|
|
|
@ -320,8 +320,10 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
|||
|
||||
if (info) {
|
||||
struct partition_meta_info *pinfo = alloc_part_info(disk);
|
||||
if (!pinfo)
|
||||
if (!pinfo) {
|
||||
err = -ENOMEM;
|
||||
goto out_free_stats;
|
||||
}
|
||||
memcpy(pinfo, info, sizeof(*info));
|
||||
p->info = pinfo;
|
||||
}
|
||||
|
|
|
@ -300,6 +300,8 @@ static void parse_bsd(struct parsed_partitions *state,
|
|||
continue;
|
||||
bsd_start = le32_to_cpu(p->p_offset);
|
||||
bsd_size = le32_to_cpu(p->p_size);
|
||||
if (memcmp(flavour, "bsd\0", 4) == 0)
|
||||
bsd_start += offset;
|
||||
if (offset == bsd_start && size == bsd_size)
|
||||
/* full parent partition, we have it already */
|
||||
continue;
|
||||
|
|
|
@ -764,6 +764,44 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skcipher_setkey_unaligned(struct crypto_skcipher *tfm,
|
||||
const u8 *key, unsigned int keylen)
|
||||
{
|
||||
unsigned long alignmask = crypto_skcipher_alignmask(tfm);
|
||||
struct skcipher_alg *cipher = crypto_skcipher_alg(tfm);
|
||||
u8 *buffer, *alignbuffer;
|
||||
unsigned long absize;
|
||||
int ret;
|
||||
|
||||
absize = keylen + alignmask;
|
||||
buffer = kmalloc(absize, GFP_ATOMIC);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
|
||||
memcpy(alignbuffer, key, keylen);
|
||||
ret = cipher->setkey(tfm, alignbuffer, keylen);
|
||||
kzfree(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
struct skcipher_alg *cipher = crypto_skcipher_alg(tfm);
|
||||
unsigned long alignmask = crypto_skcipher_alignmask(tfm);
|
||||
|
||||
if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
|
||||
crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((unsigned long)key & alignmask)
|
||||
return skcipher_setkey_unaligned(tfm, key, keylen);
|
||||
|
||||
return cipher->setkey(tfm, key, keylen);
|
||||
}
|
||||
|
||||
static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm)
|
||||
{
|
||||
struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm);
|
||||
|
@ -784,7 +822,7 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm)
|
|||
tfm->__crt_alg->cra_type == &crypto_givcipher_type)
|
||||
return crypto_init_skcipher_ops_ablkcipher(tfm);
|
||||
|
||||
skcipher->setkey = alg->setkey;
|
||||
skcipher->setkey = skcipher_setkey;
|
||||
skcipher->encrypt = alg->encrypt;
|
||||
skcipher->decrypt = alg->decrypt;
|
||||
skcipher->ivsize = alg->ivsize;
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
|
||||
#define ACPI_BUTTON_LID_INIT_IGNORE 0x00
|
||||
#define ACPI_BUTTON_LID_INIT_OPEN 0x01
|
||||
#define ACPI_BUTTON_LID_INIT_METHOD 0x02
|
||||
|
||||
#define _COMPONENT ACPI_BUTTON_COMPONENT
|
||||
ACPI_MODULE_NAME("button");
|
||||
|
@ -376,6 +377,9 @@ static void acpi_lid_initialize_state(struct acpi_device *device)
|
|||
case ACPI_BUTTON_LID_INIT_OPEN:
|
||||
(void)acpi_lid_notify_state(device, 1);
|
||||
break;
|
||||
case ACPI_BUTTON_LID_INIT_METHOD:
|
||||
(void)acpi_lid_update_state(device);
|
||||
break;
|
||||
case ACPI_BUTTON_LID_INIT_IGNORE:
|
||||
default:
|
||||
break;
|
||||
|
@ -560,6 +564,9 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp)
|
|||
if (!strncmp(val, "open", sizeof("open") - 1)) {
|
||||
lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
|
||||
pr_info("Notify initial lid state as open\n");
|
||||
} else if (!strncmp(val, "method", sizeof("method") - 1)) {
|
||||
lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
|
||||
pr_info("Notify initial lid state with _LID return value\n");
|
||||
} else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
|
||||
lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
|
||||
pr_info("Do not notify initial lid state\n");
|
||||
|
@ -573,6 +580,8 @@ static int param_get_lid_init_state(char *buffer, struct kernel_param *kp)
|
|||
switch (lid_init_state) {
|
||||
case ACPI_BUTTON_LID_INIT_OPEN:
|
||||
return sprintf(buffer, "open");
|
||||
case ACPI_BUTTON_LID_INIT_METHOD:
|
||||
return sprintf(buffer, "method");
|
||||
case ACPI_BUTTON_LID_INIT_IGNORE:
|
||||
return sprintf(buffer, "ignore");
|
||||
default:
|
||||
|
|
|
@ -26,7 +26,7 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val,
|
|||
struct nfit_spa *nfit_spa;
|
||||
|
||||
/* We only care about memory errors */
|
||||
if (!(mce->status & MCACOD))
|
||||
if (!mce_is_memory_error(mce))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/*
|
||||
|
|
|
@ -512,13 +512,12 @@ static bool wakeup_source_not_registered(struct wakeup_source *ws)
|
|||
/**
|
||||
* wakup_source_activate - Mark given wakeup source as active.
|
||||
* @ws: Wakeup source to handle.
|
||||
* @hard: If set, abort suspends in progress and wake up from suspend-to-idle.
|
||||
*
|
||||
* Update the @ws' statistics and, if @ws has just been activated, notify the PM
|
||||
* core of the event by incrementing the counter of of wakeup events being
|
||||
* processed.
|
||||
*/
|
||||
static void wakeup_source_activate(struct wakeup_source *ws, bool hard)
|
||||
static void wakeup_source_activate(struct wakeup_source *ws)
|
||||
{
|
||||
unsigned int cec;
|
||||
|
||||
|
@ -526,9 +525,6 @@ static void wakeup_source_activate(struct wakeup_source *ws, bool hard)
|
|||
"unregistered wakeup source\n"))
|
||||
return;
|
||||
|
||||
if (hard)
|
||||
pm_system_wakeup();
|
||||
|
||||
ws->active = true;
|
||||
ws->active_count++;
|
||||
ws->last_time = ktime_get();
|
||||
|
@ -554,7 +550,10 @@ static void wakeup_source_report_event(struct wakeup_source *ws, bool hard)
|
|||
ws->wakeup_count++;
|
||||
|
||||
if (!ws->active)
|
||||
wakeup_source_activate(ws, hard);
|
||||
wakeup_source_activate(ws);
|
||||
|
||||
if (hard)
|
||||
pm_system_wakeup();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,6 +71,15 @@ config ARM_HIGHBANK_CPUFREQ
|
|||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_DB8500_CPUFREQ
|
||||
tristate "ST-Ericsson DB8500 cpufreq" if COMPILE_TEST && !ARCH_U8500
|
||||
default ARCH_U8500
|
||||
depends on HAS_IOMEM
|
||||
depends on !CPU_THERMAL || THERMAL
|
||||
help
|
||||
This adds the CPUFreq driver for ST-Ericsson Ux500 (DB8500) SoC
|
||||
series.
|
||||
|
||||
config ARM_IMX6Q_CPUFREQ
|
||||
tristate "Freescale i.MX6 cpufreq support"
|
||||
depends on ARCH_MXC
|
||||
|
|
|
@ -53,7 +53,7 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
|
|||
|
||||
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
|
||||
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
|
||||
obj-$(CONFIG_ARM_DB8500_CPUFREQ) += dbx500-cpufreq.o
|
||||
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
|
||||
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
|
||||
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
|
||||
|
|
|
@ -53,6 +53,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
|
|||
if (sscanf(name, "dump-type%u-%u-%d-%lu-%c",
|
||||
&record->type, &part, &cnt, &time, &data_type) == 5) {
|
||||
record->id = generic_id(time, part, cnt);
|
||||
record->part = part;
|
||||
record->count = cnt;
|
||||
record->time.tv_sec = time;
|
||||
record->time.tv_nsec = 0;
|
||||
|
@ -64,6 +65,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
|
|||
} else if (sscanf(name, "dump-type%u-%u-%d-%lu",
|
||||
&record->type, &part, &cnt, &time) == 4) {
|
||||
record->id = generic_id(time, part, cnt);
|
||||
record->part = part;
|
||||
record->count = cnt;
|
||||
record->time.tv_sec = time;
|
||||
record->time.tv_nsec = 0;
|
||||
|
@ -77,6 +79,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry,
|
|||
* multiple logs, remains.
|
||||
*/
|
||||
record->id = generic_id(time, part, 0);
|
||||
record->part = part;
|
||||
record->count = 0;
|
||||
record->time.tv_sec = time;
|
||||
record->time.tv_nsec = 0;
|
||||
|
@ -241,9 +244,15 @@ static int efi_pstore_write(struct pstore_record *record)
|
|||
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
|
||||
int i, ret = 0;
|
||||
|
||||
record->time.tv_sec = get_seconds();
|
||||
record->time.tv_nsec = 0;
|
||||
|
||||
record->id = generic_id(record->time.tv_sec, record->part,
|
||||
record->count);
|
||||
|
||||
snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lu-%c",
|
||||
record->type, record->part, record->count,
|
||||
get_seconds(), record->compressed ? 'C' : 'D');
|
||||
record->time.tv_sec, record->compressed ? 'C' : 'D');
|
||||
|
||||
for (i = 0; i < DUMP_NAME_LEN; i++)
|
||||
efi_name[i] = name[i];
|
||||
|
@ -255,7 +264,6 @@ static int efi_pstore_write(struct pstore_record *record)
|
|||
if (record->reason == KMSG_DUMP_OOPS)
|
||||
efivar_run_worker();
|
||||
|
||||
record->id = record->part;
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
@ -287,7 +295,7 @@ static int efi_pstore_erase_func(struct efivar_entry *entry, void *data)
|
|||
* holding multiple logs, remains.
|
||||
*/
|
||||
snprintf(name_old, sizeof(name_old), "dump-type%u-%u-%lu",
|
||||
ed->record->type, (unsigned int)ed->record->id,
|
||||
ed->record->type, ed->record->part,
|
||||
ed->record->time.tv_sec);
|
||||
|
||||
for (i = 0; i < DUMP_NAME_LEN; i++)
|
||||
|
@ -320,10 +328,7 @@ static int efi_pstore_erase(struct pstore_record *record)
|
|||
char name[DUMP_NAME_LEN];
|
||||
efi_char16_t efi_name[DUMP_NAME_LEN];
|
||||
int found, i;
|
||||
unsigned int part;
|
||||
|
||||
do_div(record->id, 1000);
|
||||
part = do_div(record->id, 100);
|
||||
snprintf(name, sizeof(name), "dump-type%u-%u-%d-%lu",
|
||||
record->type, record->part, record->count,
|
||||
record->time.tv_sec);
|
||||
|
|
|
@ -425,10 +425,15 @@ bool amdgpu_fbdev_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj)
|
|||
|
||||
void amdgpu_fbdev_restore_mode(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_fbdev *afbdev = adev->mode_info.rfbdev;
|
||||
struct amdgpu_fbdev *afbdev;
|
||||
struct drm_fb_helper *fb_helper;
|
||||
int ret;
|
||||
|
||||
if (!adev)
|
||||
return;
|
||||
|
||||
afbdev = adev->mode_info.rfbdev;
|
||||
|
||||
if (!afbdev)
|
||||
return;
|
||||
|
||||
|
|
|
@ -634,7 +634,7 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job)
|
|||
mutex_unlock(&id_mgr->lock);
|
||||
}
|
||||
|
||||
if (gds_switch_needed) {
|
||||
if (ring->funcs->emit_gds_switch && gds_switch_needed) {
|
||||
id->gds_base = job->gds_base;
|
||||
id->gds_size = job->gds_size;
|
||||
id->gws_base = job->gws_base;
|
||||
|
@ -672,6 +672,7 @@ void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vmhub,
|
|||
struct amdgpu_vm_id_manager *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
||||
struct amdgpu_vm_id *id = &id_mgr->ids[vmid];
|
||||
|
||||
atomic64_set(&id->owner, 0);
|
||||
id->gds_base = 0;
|
||||
id->gds_size = 0;
|
||||
id->gws_base = 0;
|
||||
|
@ -680,6 +681,26 @@ void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vmhub,
|
|||
id->oa_size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_reset_all_id - reset VMID to zero
|
||||
*
|
||||
* @adev: amdgpu device structure
|
||||
*
|
||||
* Reset VMID to force flush on next use
|
||||
*/
|
||||
void amdgpu_vm_reset_all_ids(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
|
||||
struct amdgpu_vm_id_manager *id_mgr =
|
||||
&adev->vm_manager.id_mgr[i];
|
||||
|
||||
for (j = 1; j < id_mgr->num_ids; ++j)
|
||||
amdgpu_vm_reset_id(adev, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_vm_bo_find - find the bo_va for a specific vm & bo
|
||||
*
|
||||
|
@ -2270,7 +2291,6 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev)
|
|||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
|
||||
adev->vm_manager.seqno[i] = 0;
|
||||
|
||||
|
||||
atomic_set(&adev->vm_manager.vm_pte_next_ring, 0);
|
||||
atomic64_set(&adev->vm_manager.client_counter, 0);
|
||||
spin_lock_init(&adev->vm_manager.prt_lock);
|
||||
|
|
|
@ -204,6 +204,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
|||
int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job);
|
||||
void amdgpu_vm_reset_id(struct amdgpu_device *adev, unsigned vmhub,
|
||||
unsigned vmid);
|
||||
void amdgpu_vm_reset_all_ids(struct amdgpu_device *adev);
|
||||
int amdgpu_vm_update_directories(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm);
|
||||
int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
|
||||
|
|
|
@ -906,6 +906,12 @@ static bool ci_dpm_vblank_too_short(struct amdgpu_device *adev)
|
|||
u32 vblank_time = amdgpu_dpm_get_vblank_time(adev);
|
||||
u32 switch_limit = adev->mc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 300;
|
||||
|
||||
/* disable mclk switching if the refresh is >120Hz, even if the
|
||||
* blanking period would allow it
|
||||
*/
|
||||
if (amdgpu_dpm_get_vrefresh(adev) > 120)
|
||||
return true;
|
||||
|
||||
if (vblank_time < switch_limit)
|
||||
return true;
|
||||
else
|
||||
|
|
|
@ -950,10 +950,6 @@ static int gmc_v6_0_suspend(void *handle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->vm_manager.enabled) {
|
||||
gmc_v6_0_vm_fini(adev);
|
||||
adev->vm_manager.enabled = false;
|
||||
}
|
||||
gmc_v6_0_hw_fini(adev);
|
||||
|
||||
return 0;
|
||||
|
@ -968,16 +964,9 @@ static int gmc_v6_0_resume(void *handle)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (!adev->vm_manager.enabled) {
|
||||
r = gmc_v6_0_vm_init(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "vm manager initialization failed (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
adev->vm_manager.enabled = true;
|
||||
}
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool gmc_v6_0_is_idle(void *handle)
|
||||
|
|
|
@ -1117,10 +1117,6 @@ static int gmc_v7_0_suspend(void *handle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->vm_manager.enabled) {
|
||||
gmc_v7_0_vm_fini(adev);
|
||||
adev->vm_manager.enabled = false;
|
||||
}
|
||||
gmc_v7_0_hw_fini(adev);
|
||||
|
||||
return 0;
|
||||
|
@ -1135,16 +1131,9 @@ static int gmc_v7_0_resume(void *handle)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (!adev->vm_manager.enabled) {
|
||||
r = gmc_v7_0_vm_init(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "vm manager initialization failed (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
adev->vm_manager.enabled = true;
|
||||
}
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool gmc_v7_0_is_idle(void *handle)
|
||||
|
|
|
@ -1209,10 +1209,6 @@ static int gmc_v8_0_suspend(void *handle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->vm_manager.enabled) {
|
||||
gmc_v8_0_vm_fini(adev);
|
||||
adev->vm_manager.enabled = false;
|
||||
}
|
||||
gmc_v8_0_hw_fini(adev);
|
||||
|
||||
return 0;
|
||||
|
@ -1227,16 +1223,9 @@ static int gmc_v8_0_resume(void *handle)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (!adev->vm_manager.enabled) {
|
||||
r = gmc_v8_0_vm_init(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "vm manager initialization failed (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
adev->vm_manager.enabled = true;
|
||||
}
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool gmc_v8_0_is_idle(void *handle)
|
||||
|
|
|
@ -791,10 +791,6 @@ static int gmc_v9_0_suspend(void *handle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
|
||||
if (adev->vm_manager.enabled) {
|
||||
gmc_v9_0_vm_fini(adev);
|
||||
adev->vm_manager.enabled = false;
|
||||
}
|
||||
gmc_v9_0_hw_fini(adev);
|
||||
|
||||
return 0;
|
||||
|
@ -809,17 +805,9 @@ static int gmc_v9_0_resume(void *handle)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (!adev->vm_manager.enabled) {
|
||||
r = gmc_v9_0_vm_init(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev,
|
||||
"vm manager initialization failed (%d).\n", r);
|
||||
return r;
|
||||
}
|
||||
adev->vm_manager.enabled = true;
|
||||
}
|
||||
amdgpu_vm_reset_all_ids(adev);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool gmc_v9_0_is_idle(void *handle)
|
||||
|
|
|
@ -2655,6 +2655,28 @@ static int smu7_get_power_state_size(struct pp_hwmgr *hwmgr)
|
|||
return sizeof(struct smu7_power_state);
|
||||
}
|
||||
|
||||
static int smu7_vblank_too_short(struct pp_hwmgr *hwmgr,
|
||||
uint32_t vblank_time_us)
|
||||
{
|
||||
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
|
||||
uint32_t switch_limit_us;
|
||||
|
||||
switch (hwmgr->chip_id) {
|
||||
case CHIP_POLARIS10:
|
||||
case CHIP_POLARIS11:
|
||||
case CHIP_POLARIS12:
|
||||
switch_limit_us = data->is_memory_gddr5 ? 190 : 150;
|
||||
break;
|
||||
default:
|
||||
switch_limit_us = data->is_memory_gddr5 ? 450 : 150;
|
||||
break;
|
||||
}
|
||||
|
||||
if (vblank_time_us < switch_limit_us)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
|
||||
struct pp_power_state *request_ps,
|
||||
|
@ -2669,6 +2691,7 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
|
|||
bool disable_mclk_switching;
|
||||
bool disable_mclk_switching_for_frame_lock;
|
||||
struct cgs_display_info info = {0};
|
||||
struct cgs_mode_info mode_info = {0};
|
||||
const struct phm_clock_and_voltage_limits *max_limits;
|
||||
uint32_t i;
|
||||
struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
|
||||
|
@ -2677,6 +2700,7 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
|
|||
int32_t count;
|
||||
int32_t stable_pstate_sclk = 0, stable_pstate_mclk = 0;
|
||||
|
||||
info.mode_info = &mode_info;
|
||||
data->battery_state = (PP_StateUILabel_Battery ==
|
||||
request_ps->classification.ui_label);
|
||||
|
||||
|
@ -2703,8 +2727,6 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
|
|||
|
||||
cgs_get_active_displays_info(hwmgr->device, &info);
|
||||
|
||||
/*TO DO result = PHM_CheckVBlankTime(hwmgr, &vblankTooShort);*/
|
||||
|
||||
minimum_clocks.engineClock = hwmgr->display_config.min_core_set_clock;
|
||||
minimum_clocks.memoryClock = hwmgr->display_config.min_mem_set_clock;
|
||||
|
||||
|
@ -2769,8 +2791,10 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
|
|||
PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
|
||||
|
||||
|
||||
disable_mclk_switching = (1 < info.display_count) ||
|
||||
disable_mclk_switching_for_frame_lock;
|
||||
disable_mclk_switching = ((1 < info.display_count) ||
|
||||
disable_mclk_switching_for_frame_lock ||
|
||||
smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) ||
|
||||
(mode_info.refresh_rate > 120));
|
||||
|
||||
sclk = smu7_ps->performance_levels[0].engine_clock;
|
||||
mclk = smu7_ps->performance_levels[0].memory_clock;
|
||||
|
|
|
@ -4186,7 +4186,7 @@ static int vega10_force_clock_level(struct pp_hwmgr *hwmgr,
|
|||
enum pp_clock_type type, uint32_t mask)
|
||||
{
|
||||
struct vega10_hwmgr *data = (struct vega10_hwmgr *)(hwmgr->backend);
|
||||
uint32_t i;
|
||||
int i;
|
||||
|
||||
if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -948,8 +948,6 @@ retry:
|
|||
}
|
||||
|
||||
out:
|
||||
if (ret && crtc->funcs->page_flip_target)
|
||||
drm_crtc_vblank_put(crtc);
|
||||
if (fb)
|
||||
drm_framebuffer_put(fb);
|
||||
if (crtc->primary->old_fb)
|
||||
|
@ -964,5 +962,8 @@ out:
|
|||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
if (ret && crtc->funcs->page_flip_target)
|
||||
drm_crtc_vblank_put(crtc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -759,20 +759,23 @@ void psb_intel_lvds_init(struct drm_device *dev,
|
|||
if (scan->type & DRM_MODE_TYPE_PREFERRED) {
|
||||
mode_dev->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, scan);
|
||||
DRM_DEBUG_KMS("Using mode from DDC\n");
|
||||
goto out; /* FIXME: check for quirks */
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed to get EDID, what about VBT? do we need this? */
|
||||
if (mode_dev->vbt_mode)
|
||||
if (dev_priv->lfp_lvds_vbt_mode) {
|
||||
mode_dev->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, mode_dev->vbt_mode);
|
||||
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
||||
|
||||
if (!mode_dev->panel_fixed_mode)
|
||||
if (dev_priv->lfp_lvds_vbt_mode)
|
||||
mode_dev->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev,
|
||||
dev_priv->lfp_lvds_vbt_mode);
|
||||
if (mode_dev->panel_fixed_mode) {
|
||||
mode_dev->panel_fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
DRM_DEBUG_KMS("Using mode from VBT\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't get EDID, try checking if the panel is already turned
|
||||
|
@ -789,6 +792,7 @@ void psb_intel_lvds_init(struct drm_device *dev,
|
|||
if (mode_dev->panel_fixed_mode) {
|
||||
mode_dev->panel_fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
DRM_DEBUG_KMS("Using pre-programmed mode\n");
|
||||
goto out; /* FIXME: check for quirks */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -575,8 +575,6 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
|
|||
if (ret)
|
||||
return;
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release);
|
||||
|
||||
if (fb != old_state->fb) {
|
||||
obj = to_qxl_framebuffer(fb)->obj;
|
||||
user_bo = gem_to_qxl_bo(obj);
|
||||
|
@ -614,6 +612,7 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
|
|||
qxl_bo_kunmap(cursor_bo);
|
||||
qxl_bo_kunmap(user_bo);
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release);
|
||||
cmd->u.set.visible = 1;
|
||||
cmd->u.set.shape = qxl_bo_physical_address(qdev,
|
||||
cursor_bo, 0);
|
||||
|
@ -624,6 +623,7 @@ static void qxl_cursor_atomic_update(struct drm_plane *plane,
|
|||
if (ret)
|
||||
goto out_free_release;
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_MOVE;
|
||||
}
|
||||
|
||||
|
|
|
@ -776,6 +776,12 @@ bool ci_dpm_vblank_too_short(struct radeon_device *rdev)
|
|||
u32 vblank_time = r600_dpm_get_vblank_time(rdev);
|
||||
u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
|
||||
|
||||
/* disable mclk switching if the refresh is >120Hz, even if the
|
||||
* blanking period would allow it
|
||||
*/
|
||||
if (r600_dpm_get_vrefresh(rdev) > 120)
|
||||
return true;
|
||||
|
||||
if (vblank_time < switch_limit)
|
||||
return true;
|
||||
else
|
||||
|
|
|
@ -7401,7 +7401,7 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
|
|||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
@ -7431,7 +7431,7 @@ static inline void cik_irq_ack(struct radeon_device *rdev)
|
|||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_RX_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
|
|
@ -4927,7 +4927,7 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
|
|||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
@ -4958,7 +4958,7 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
|
|||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_RX_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
|
|
@ -3988,7 +3988,7 @@ static void r600_irq_ack(struct radeon_device *rdev)
|
|||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
|
|||
if ((radeon_runtime_pm != 0) &&
|
||||
radeon_has_atpx() &&
|
||||
((flags & RADEON_IS_IGP) == 0) &&
|
||||
!pci_is_thunderbolt_attached(rdev->pdev))
|
||||
!pci_is_thunderbolt_attached(dev->pdev))
|
||||
flags |= RADEON_IS_PX;
|
||||
|
||||
/* radeon_device_init should report only fatal error
|
||||
|
|
|
@ -6317,7 +6317,7 @@ static inline void si_irq_ack(struct radeon_device *rdev)
|
|||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
@ -6348,7 +6348,7 @@ static inline void si_irq_ack(struct radeon_device *rdev)
|
|||
WREG32(DC_HPD5_INT_CONTROL, tmp);
|
||||
}
|
||||
if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) {
|
||||
tmp = RREG32(DC_HPD5_INT_CONTROL);
|
||||
tmp = RREG32(DC_HPD6_INT_CONTROL);
|
||||
tmp |= DC_HPDx_RX_INT_ACK;
|
||||
WREG32(DC_HPD6_INT_CONTROL, tmp);
|
||||
}
|
||||
|
|
|
@ -94,9 +94,9 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
|
|||
static int dw_i2c_acpi_configure(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
|
||||
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
|
||||
const struct acpi_device_id *id;
|
||||
u32 ss_ht, fp_ht, hs_ht, fs_ht;
|
||||
struct acpi_device *adev;
|
||||
const char *uid;
|
||||
|
||||
|
|
|
@ -178,22 +178,39 @@ static int usb_read(struct i2c_adapter *adapter, int cmd,
|
|||
int value, int index, void *data, int len)
|
||||
{
|
||||
struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
|
||||
void *dmadata = kmalloc(len, GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (!dmadata)
|
||||
return -ENOMEM;
|
||||
|
||||
/* do control transfer */
|
||||
return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
|
||||
ret = usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
|
||||
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
|
||||
USB_DIR_IN, value, index, data, len, 2000);
|
||||
USB_DIR_IN, value, index, dmadata, len, 2000);
|
||||
|
||||
memcpy(data, dmadata, len);
|
||||
kfree(dmadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_write(struct i2c_adapter *adapter, int cmd,
|
||||
int value, int index, void *data, int len)
|
||||
{
|
||||
struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
|
||||
void *dmadata = kmemdup(data, len, GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (!dmadata)
|
||||
return -ENOMEM;
|
||||
|
||||
/* do control transfer */
|
||||
return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
|
||||
ret = usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
|
||||
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
value, index, data, len, 2000);
|
||||
value, index, dmadata, len, 2000);
|
||||
|
||||
kfree(dmadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
|
||||
|
|
|
@ -554,32 +554,34 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client,
|
|||
struct completion *completion)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
long ret;
|
||||
int error;
|
||||
int len;
|
||||
u8 buffer[ETP_I2C_INF_LENGTH];
|
||||
u8 buffer[ETP_I2C_REPORT_LEN];
|
||||
|
||||
len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
|
||||
if (len != ETP_I2C_REPORT_LEN) {
|
||||
error = len < 0 ? len : -EIO;
|
||||
dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
|
||||
error, len);
|
||||
}
|
||||
|
||||
reinit_completion(completion);
|
||||
enable_irq(client->irq);
|
||||
|
||||
error = elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD, ETP_I2C_RESET);
|
||||
if (!error)
|
||||
ret = wait_for_completion_interruptible_timeout(completion,
|
||||
msecs_to_jiffies(300));
|
||||
disable_irq(client->irq);
|
||||
|
||||
if (error) {
|
||||
dev_err(dev, "device reset failed: %d\n", error);
|
||||
return error;
|
||||
} else if (ret == 0) {
|
||||
} else if (!wait_for_completion_timeout(completion,
|
||||
msecs_to_jiffies(300))) {
|
||||
dev_err(dev, "timeout waiting for device reset\n");
|
||||
return -ETIMEDOUT;
|
||||
} else if (ret < 0) {
|
||||
error = ret;
|
||||
dev_err(dev, "error waiting for device reset: %d\n", error);
|
||||
return error;
|
||||
error = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
disable_irq(client->irq);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
len = i2c_master_recv(client, buffer, ETP_I2C_INF_LENGTH);
|
||||
if (len != ETP_I2C_INF_LENGTH) {
|
||||
error = len < 0 ? len : -EIO;
|
||||
|
|
|
@ -350,6 +350,7 @@ static bool mxt_object_readable(unsigned int type)
|
|||
case MXT_TOUCH_KEYARRAY_T15:
|
||||
case MXT_TOUCH_PROXIMITY_T23:
|
||||
case MXT_TOUCH_PROXKEY_T52:
|
||||
case MXT_TOUCH_MULTITOUCHSCREEN_T100:
|
||||
case MXT_PROCI_GRIPFACE_T20:
|
||||
case MXT_PROCG_NOISE_T22:
|
||||
case MXT_PROCI_ONETOUCH_T24:
|
||||
|
|
|
@ -471,7 +471,7 @@ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
|
|||
static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
|
||||
M09_REGISTER_OFFSET, 0, 31);
|
||||
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
|
||||
M09_REGISTER_THRESHOLD, 20, 80);
|
||||
M09_REGISTER_THRESHOLD, 0, 80);
|
||||
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
|
||||
NO_REGISTER, 3, 14);
|
||||
|
||||
|
|
|
@ -285,7 +285,7 @@ static int pca955x_probe(struct i2c_client *client,
|
|||
"slave address 0x%02x\n",
|
||||
client->name, chip->bits, client->addr);
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
if (pdata) {
|
||||
|
|
|
@ -27,6 +27,7 @@ struct mmc_pwrseq_simple {
|
|||
struct mmc_pwrseq pwrseq;
|
||||
bool clk_enabled;
|
||||
u32 post_power_on_delay_ms;
|
||||
u32 power_off_delay_us;
|
||||
struct clk *ext_clk;
|
||||
struct gpio_descs *reset_gpios;
|
||||
};
|
||||
|
@ -78,6 +79,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
|||
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
|
||||
|
||||
if (pwrseq->power_off_delay_us)
|
||||
usleep_range(pwrseq->power_off_delay_us,
|
||||
2 * pwrseq->power_off_delay_us);
|
||||
|
||||
if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) {
|
||||
clk_disable_unprepare(pwrseq->ext_clk);
|
||||
pwrseq->clk_enabled = false;
|
||||
|
@ -119,6 +124,8 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
|
|||
|
||||
device_property_read_u32(dev, "post-power-on-delay-ms",
|
||||
&pwrseq->post_power_on_delay_ms);
|
||||
device_property_read_u32(dev, "power-off-delay-us",
|
||||
&pwrseq->power_off_delay_us);
|
||||
|
||||
pwrseq->pwrseq.dev = dev;
|
||||
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
|
||||
|
|
|
@ -108,7 +108,7 @@ static void octeon_mmc_release_bus(struct cvm_mmc_host *host)
|
|||
static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
|
||||
{
|
||||
writeq(val, host->base + MIO_EMM_INT(host));
|
||||
if (!host->dma_active || (host->dma_active && !host->has_ciu3))
|
||||
if (!host->has_ciu3)
|
||||
writeq(val, host->base + MIO_EMM_INT_EN(host));
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ static int octeon_mmc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev,
|
||||
"power-gpios",
|
||||
"power",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(host->global_pwr_gpiod)) {
|
||||
dev_err(&pdev->dev, "Invalid power GPIO\n");
|
||||
|
@ -288,11 +288,20 @@ static int octeon_mmc_probe(struct platform_device *pdev)
|
|||
if (ret) {
|
||||
dev_err(&pdev->dev, "Error populating slots\n");
|
||||
octeon_mmc_set_shared_power(host, 0);
|
||||
return ret;
|
||||
goto error;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
for (i = 0; i < CAVIUM_MAX_MMC; i++) {
|
||||
if (host->slot[i])
|
||||
cvm_mmc_of_slot_remove(host->slot[i]);
|
||||
if (host->slot_pdev[i])
|
||||
of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int octeon_mmc_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -146,6 +146,12 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
|
|||
return 0;
|
||||
|
||||
error:
|
||||
for (i = 0; i < CAVIUM_MAX_MMC; i++) {
|
||||
if (host->slot[i])
|
||||
cvm_mmc_of_slot_remove(host->slot[i]);
|
||||
if (host->slot_pdev[i])
|
||||
of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
|
||||
}
|
||||
clk_disable_unprepare(host->clk);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -839,14 +839,14 @@ static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
cvm_mmc_reset_bus(slot);
|
||||
if (host->global_pwr_gpiod)
|
||||
host->set_shared_power(host, 0);
|
||||
else
|
||||
else if (!IS_ERR(mmc->supply.vmmc))
|
||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
|
||||
break;
|
||||
|
||||
case MMC_POWER_UP:
|
||||
if (host->global_pwr_gpiod)
|
||||
host->set_shared_power(host, 1);
|
||||
else
|
||||
else if (!IS_ERR(mmc->supply.vmmc))
|
||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
|
||||
break;
|
||||
}
|
||||
|
@ -968,20 +968,15 @@ static int cvm_mmc_of_parse(struct device *dev, struct cvm_mmc_slot *slot)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
|
||||
if (IS_ERR(mmc->supply.vmmc)) {
|
||||
if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
/*
|
||||
* Legacy Octeon firmware has no regulator entry, fall-back to
|
||||
* a hard-coded voltage to get a sane OCR.
|
||||
*/
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
/*
|
||||
* Legacy Octeon firmware has no regulator entry, fall-back to
|
||||
* a hard-coded voltage to get a sane OCR.
|
||||
*/
|
||||
if (IS_ERR(mmc->supply.vmmc))
|
||||
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||
} else {
|
||||
ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
|
||||
if (ret > 0)
|
||||
mmc->ocr_avail = ret;
|
||||
}
|
||||
|
||||
/* Common MMC bindings */
|
||||
ret = mmc_of_parse(mmc);
|
||||
|
|
|
@ -187,7 +187,8 @@ static const struct sdhci_iproc_data iproc_cygnus_data = {
|
|||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
|
||||
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
|
||||
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
|
||||
SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
|
||||
.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,
|
||||
.ops = &sdhci_iproc_ops,
|
||||
};
|
||||
|
|
|
@ -787,14 +787,6 @@ int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void xenon_clean_phy(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
kfree(priv->phy_params);
|
||||
}
|
||||
|
||||
static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
|
||||
const char *phy_name)
|
||||
{
|
||||
|
@ -819,11 +811,7 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params);
|
||||
if (ret)
|
||||
xenon_clean_phy(host);
|
||||
|
||||
return ret;
|
||||
return xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params);
|
||||
}
|
||||
|
||||
int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host)
|
||||
|
|
|
@ -486,7 +486,7 @@ static int xenon_probe(struct platform_device *pdev)
|
|||
|
||||
err = xenon_sdhc_prepare(host);
|
||||
if (err)
|
||||
goto clean_phy_param;
|
||||
goto err_clk;
|
||||
|
||||
err = sdhci_add_host(host);
|
||||
if (err)
|
||||
|
@ -496,8 +496,6 @@ static int xenon_probe(struct platform_device *pdev)
|
|||
|
||||
remove_sdhc:
|
||||
xenon_sdhc_unprepare(host);
|
||||
clean_phy_param:
|
||||
xenon_clean_phy(host);
|
||||
err_clk:
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
free_pltfm:
|
||||
|
@ -510,8 +508,6 @@ static int xenon_remove(struct platform_device *pdev)
|
|||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
||||
xenon_clean_phy(host);
|
||||
|
||||
sdhci_remove_host(host, 0);
|
||||
|
||||
xenon_sdhc_unprepare(host);
|
||||
|
|
|
@ -93,7 +93,6 @@ struct xenon_priv {
|
|||
};
|
||||
|
||||
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
|
||||
void xenon_clean_phy(struct sdhci_host *host);
|
||||
int xenon_phy_parse_dt(struct device_node *np,
|
||||
struct sdhci_host *host);
|
||||
void xenon_soc_pad_ctrl(struct sdhci_host *host,
|
||||
|
|
|
@ -2577,7 +2577,7 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
|
|||
return -1;
|
||||
|
||||
ad_info->aggregator_id = aggregator->aggregator_identifier;
|
||||
ad_info->ports = aggregator->num_of_ports;
|
||||
ad_info->ports = __agg_active_ports(aggregator);
|
||||
ad_info->actor_key = aggregator->actor_oper_aggregator_key;
|
||||
ad_info->partner_key = aggregator->partner_oper_aggregator_key;
|
||||
ether_addr_copy(ad_info->partner_system,
|
||||
|
|
|
@ -2612,11 +2612,13 @@ static void bond_loadbalance_arp_mon(struct bonding *bond)
|
|||
bond_for_each_slave_rcu(bond, slave, iter) {
|
||||
unsigned long trans_start = dev_trans_start(slave->dev);
|
||||
|
||||
slave->new_link = BOND_LINK_NOCHANGE;
|
||||
|
||||
if (slave->link != BOND_LINK_UP) {
|
||||
if (bond_time_in_interval(bond, trans_start, 1) &&
|
||||
bond_time_in_interval(bond, slave->last_rx, 1)) {
|
||||
|
||||
slave->link = BOND_LINK_UP;
|
||||
slave->new_link = BOND_LINK_UP;
|
||||
slave_state_changed = 1;
|
||||
|
||||
/* primary_slave has no meaning in round-robin
|
||||
|
@ -2643,7 +2645,7 @@ static void bond_loadbalance_arp_mon(struct bonding *bond)
|
|||
if (!bond_time_in_interval(bond, trans_start, 2) ||
|
||||
!bond_time_in_interval(bond, slave->last_rx, 2)) {
|
||||
|
||||
slave->link = BOND_LINK_DOWN;
|
||||
slave->new_link = BOND_LINK_DOWN;
|
||||
slave_state_changed = 1;
|
||||
|
||||
if (slave->link_failure_count < UINT_MAX)
|
||||
|
@ -2674,6 +2676,11 @@ static void bond_loadbalance_arp_mon(struct bonding *bond)
|
|||
if (!rtnl_trylock())
|
||||
goto re_arm;
|
||||
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (slave->new_link != BOND_LINK_NOCHANGE)
|
||||
slave->link = slave->new_link;
|
||||
}
|
||||
|
||||
if (slave_state_changed) {
|
||||
bond_slave_state_change(bond);
|
||||
if (BOND_MODE(bond) == BOND_MODE_XOR)
|
||||
|
@ -4271,10 +4278,10 @@ static int bond_check_params(struct bond_params *params)
|
|||
int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
|
||||
struct bond_opt_value newval;
|
||||
const struct bond_opt_value *valptr;
|
||||
int arp_all_targets_value;
|
||||
int arp_all_targets_value = 0;
|
||||
u16 ad_actor_sys_prio = 0;
|
||||
u16 ad_user_port_key = 0;
|
||||
__be32 arp_target[BOND_MAX_ARP_TARGETS];
|
||||
__be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0 };
|
||||
int arp_ip_count;
|
||||
int bond_mode = BOND_MODE_ROUNDROBIN;
|
||||
int xmit_hashtype = BOND_XMIT_POLICY_LAYER2;
|
||||
|
@ -4501,7 +4508,6 @@ static int bond_check_params(struct bond_params *params)
|
|||
arp_validate_value = 0;
|
||||
}
|
||||
|
||||
arp_all_targets_value = 0;
|
||||
if (arp_all_targets) {
|
||||
bond_opt_initstr(&newval, arp_all_targets);
|
||||
valptr = bond_opt_parse(bond_opt_get(BOND_OPT_ARP_ALL_TARGETS),
|
||||
|
|
|
@ -748,13 +748,13 @@ static int ax_init_dev(struct net_device *dev)
|
|||
|
||||
ret = ax_mii_init(dev);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
goto err_out;
|
||||
|
||||
ax_NS8390_init(dev, 0);
|
||||
|
||||
ret = register_netdev(dev);
|
||||
if (ret)
|
||||
goto out_irq;
|
||||
goto err_out;
|
||||
|
||||
netdev_info(dev, "%dbit, irq %d, %lx, MAC: %pM\n",
|
||||
ei_local->word16 ? 16 : 8, dev->irq, dev->base_addr,
|
||||
|
@ -762,9 +762,6 @@ static int ax_init_dev(struct net_device *dev)
|
|||
|
||||
return 0;
|
||||
|
||||
out_irq:
|
||||
/* cleanup irq */
|
||||
free_irq(dev->irq, dev);
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1353,6 +1353,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) &&
|
||||
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
|
||||
printk(KERN_ERR "atl2: No usable DMA configuration, aborting\n");
|
||||
err = -EIO;
|
||||
goto err_dma;
|
||||
}
|
||||
|
||||
|
@ -1366,10 +1367,11 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
* pcibios_set_master to do the needed arch specific settings */
|
||||
pci_set_master(pdev);
|
||||
|
||||
err = -ENOMEM;
|
||||
netdev = alloc_etherdev(sizeof(struct atl2_adapter));
|
||||
if (!netdev)
|
||||
if (!netdev) {
|
||||
err = -ENOMEM;
|
||||
goto err_alloc_etherdev;
|
||||
}
|
||||
|
||||
SET_NETDEV_DEV(netdev, &pdev->dev);
|
||||
|
||||
|
@ -1408,8 +1410,6 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
if (err)
|
||||
goto err_sw_init;
|
||||
|
||||
err = -EIO;
|
||||
|
||||
netdev->hw_features = NETIF_F_HW_VLAN_CTAG_RX;
|
||||
netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
|
||||
|
||||
|
|
|
@ -5078,9 +5078,11 @@ static netdev_features_t be_features_check(struct sk_buff *skb,
|
|||
struct be_adapter *adapter = netdev_priv(dev);
|
||||
u8 l4_hdr = 0;
|
||||
|
||||
/* The code below restricts offload features for some tunneled packets.
|
||||
/* The code below restricts offload features for some tunneled and
|
||||
* Q-in-Q packets.
|
||||
* Offload features for normal (non tunnel) packets are unchanged.
|
||||
*/
|
||||
features = vlan_features_check(skb, features);
|
||||
if (!skb->encapsulation ||
|
||||
!(adapter->flags & BE_FLAGS_VXLAN_OFFLOADS))
|
||||
return features;
|
||||
|
|
|
@ -3192,7 +3192,7 @@ static int fec_reset_phy(struct platform_device *pdev)
|
|||
{
|
||||
int err, phy_reset;
|
||||
bool active_high = false;
|
||||
int msec = 1;
|
||||
int msec = 1, phy_post_delay = 0;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
if (!np)
|
||||
|
@ -3209,6 +3209,11 @@ static int fec_reset_phy(struct platform_device *pdev)
|
|||
else if (!gpio_is_valid(phy_reset))
|
||||
return 0;
|
||||
|
||||
err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay);
|
||||
/* valid reset duration should be less than 1s */
|
||||
if (!err && phy_post_delay > 1000)
|
||||
return -EINVAL;
|
||||
|
||||
active_high = of_property_read_bool(np, "phy-reset-active-high");
|
||||
|
||||
err = devm_gpio_request_one(&pdev->dev, phy_reset,
|
||||
|
@ -3226,6 +3231,15 @@ static int fec_reset_phy(struct platform_device *pdev)
|
|||
|
||||
gpio_set_value_cansleep(phy_reset, !active_high);
|
||||
|
||||
if (!phy_post_delay)
|
||||
return 0;
|
||||
|
||||
if (phy_post_delay > 20)
|
||||
msleep(phy_post_delay);
|
||||
else
|
||||
usleep_range(phy_post_delay * 1000,
|
||||
phy_post_delay * 1000 + 1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
|
|
|
@ -774,7 +774,7 @@ static void cb_timeout_handler(struct work_struct *work)
|
|||
mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
|
||||
mlx5_command_str(msg_to_opcode(ent->in)),
|
||||
msg_to_opcode(ent->in));
|
||||
mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
|
||||
mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
|
||||
}
|
||||
|
||||
static void cmd_work_handler(struct work_struct *work)
|
||||
|
@ -804,6 +804,7 @@ static void cmd_work_handler(struct work_struct *work)
|
|||
}
|
||||
|
||||
cmd->ent_arr[ent->idx] = ent;
|
||||
set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state);
|
||||
lay = get_inst(cmd, ent->idx);
|
||||
ent->lay = lay;
|
||||
memset(lay, 0, sizeof(*lay));
|
||||
|
@ -825,6 +826,20 @@ static void cmd_work_handler(struct work_struct *work)
|
|||
if (ent->callback)
|
||||
schedule_delayed_work(&ent->cb_timeout_work, cb_timeout);
|
||||
|
||||
/* Skip sending command to fw if internal error */
|
||||
if (pci_channel_offline(dev->pdev) ||
|
||||
dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
|
||||
u8 status = 0;
|
||||
u32 drv_synd;
|
||||
|
||||
ent->ret = mlx5_internal_err_ret_value(dev, msg_to_opcode(ent->in), &drv_synd, &status);
|
||||
MLX5_SET(mbox_out, ent->out, status, status);
|
||||
MLX5_SET(mbox_out, ent->out, syndrome, drv_synd);
|
||||
|
||||
mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ring doorbell after the descriptor is valid */
|
||||
mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx);
|
||||
wmb();
|
||||
|
@ -835,7 +850,7 @@ static void cmd_work_handler(struct work_struct *work)
|
|||
poll_timeout(ent);
|
||||
/* make sure we read the descriptor after ownership is SW */
|
||||
rmb();
|
||||
mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
|
||||
mlx5_cmd_comp_handler(dev, 1UL << ent->idx, (ent->ret == -ETIMEDOUT));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -879,7 +894,7 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
|
|||
wait_for_completion(&ent->done);
|
||||
} else if (!wait_for_completion_timeout(&ent->done, timeout)) {
|
||||
ent->ret = -ETIMEDOUT;
|
||||
mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
|
||||
mlx5_cmd_comp_handler(dev, 1UL << ent->idx, true);
|
||||
}
|
||||
|
||||
err = ent->ret;
|
||||
|
@ -1375,7 +1390,7 @@ static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
|
|||
}
|
||||
}
|
||||
|
||||
void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec)
|
||||
void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool forced)
|
||||
{
|
||||
struct mlx5_cmd *cmd = &dev->cmd;
|
||||
struct mlx5_cmd_work_ent *ent;
|
||||
|
@ -1395,6 +1410,19 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec)
|
|||
struct semaphore *sem;
|
||||
|
||||
ent = cmd->ent_arr[i];
|
||||
|
||||
/* if we already completed the command, ignore it */
|
||||
if (!test_and_clear_bit(MLX5_CMD_ENT_STATE_PENDING_COMP,
|
||||
&ent->state)) {
|
||||
/* only real completion can free the cmd slot */
|
||||
if (!forced) {
|
||||
mlx5_core_err(dev, "Command completion arrived after timeout (entry idx = %d).\n",
|
||||
ent->idx);
|
||||
free_ent(cmd, ent->idx);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ent->callback)
|
||||
cancel_delayed_work(&ent->cb_timeout_work);
|
||||
if (ent->page_queue)
|
||||
|
@ -1417,7 +1445,10 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec)
|
|||
mlx5_core_dbg(dev, "command completed. ret 0x%x, delivery status %s(0x%x)\n",
|
||||
ent->ret, deliv_status_to_str(ent->status), ent->status);
|
||||
}
|
||||
free_ent(cmd, ent->idx);
|
||||
|
||||
/* only real completion will free the entry slot */
|
||||
if (!forced)
|
||||
free_ent(cmd, ent->idx);
|
||||
|
||||
if (ent->callback) {
|
||||
ds = ent->ts2 - ent->ts1;
|
||||
|
|
|
@ -1041,6 +1041,8 @@ void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq)
|
|||
#define MLX5_IB_GRH_BYTES 40
|
||||
#define MLX5_IPOIB_ENCAP_LEN 4
|
||||
#define MLX5_GID_SIZE 16
|
||||
#define MLX5_IPOIB_PSEUDO_LEN 20
|
||||
#define MLX5_IPOIB_HARD_LEN (MLX5_IPOIB_PSEUDO_LEN + MLX5_IPOIB_ENCAP_LEN)
|
||||
|
||||
static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
|
||||
struct mlx5_cqe64 *cqe,
|
||||
|
@ -1048,6 +1050,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
|
|||
struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *netdev = rq->netdev;
|
||||
char *pseudo_header;
|
||||
u8 *dgid;
|
||||
u8 g;
|
||||
|
||||
|
@ -1076,8 +1079,11 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
|
|||
if (likely(netdev->features & NETIF_F_RXHASH))
|
||||
mlx5e_skb_set_hash(cqe, skb);
|
||||
|
||||
/* 20 bytes of ipoib header and 4 for encap existing */
|
||||
pseudo_header = skb_push(skb, MLX5_IPOIB_PSEUDO_LEN);
|
||||
memset(pseudo_header, 0, MLX5_IPOIB_PSEUDO_LEN);
|
||||
skb_reset_mac_header(skb);
|
||||
skb_pull(skb, MLX5_IPOIB_ENCAP_LEN);
|
||||
skb_pull(skb, MLX5_IPOIB_HARD_LEN);
|
||||
|
||||
skb->dev = netdev;
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <net/tc_act/tc_vlan.h>
|
||||
#include <net/tc_act/tc_tunnel_key.h>
|
||||
#include <net/tc_act/tc_pedit.h>
|
||||
#include <net/tc_act/tc_csum.h>
|
||||
#include <net/vxlan.h>
|
||||
#include <net/arp.h>
|
||||
#include "en.h"
|
||||
|
@ -384,7 +385,7 @@ static void mlx5e_detach_encap(struct mlx5e_priv *priv,
|
|||
if (e->flags & MLX5_ENCAP_ENTRY_VALID)
|
||||
mlx5_encap_dealloc(priv->mdev, e->encap_id);
|
||||
|
||||
hlist_del_rcu(&e->encap_hlist);
|
||||
hash_del_rcu(&e->encap_hlist);
|
||||
kfree(e->encap_header);
|
||||
kfree(e);
|
||||
}
|
||||
|
@ -925,11 +926,11 @@ static int offload_pedit_fields(struct pedit_headers *masks,
|
|||
struct mlx5e_tc_flow_parse_attr *parse_attr)
|
||||
{
|
||||
struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals;
|
||||
int i, action_size, nactions, max_actions, first, last;
|
||||
int i, action_size, nactions, max_actions, first, last, first_z;
|
||||
void *s_masks_p, *a_masks_p, *vals_p;
|
||||
u32 s_mask, a_mask, val;
|
||||
struct mlx5_fields *f;
|
||||
u8 cmd, field_bsize;
|
||||
u32 s_mask, a_mask;
|
||||
unsigned long mask;
|
||||
void *action;
|
||||
|
||||
|
@ -946,7 +947,8 @@ static int offload_pedit_fields(struct pedit_headers *masks,
|
|||
for (i = 0; i < ARRAY_SIZE(fields); i++) {
|
||||
f = &fields[i];
|
||||
/* avoid seeing bits set from previous iterations */
|
||||
s_mask = a_mask = mask = val = 0;
|
||||
s_mask = 0;
|
||||
a_mask = 0;
|
||||
|
||||
s_masks_p = (void *)set_masks + f->offset;
|
||||
a_masks_p = (void *)add_masks + f->offset;
|
||||
|
@ -981,12 +983,12 @@ static int offload_pedit_fields(struct pedit_headers *masks,
|
|||
memset(a_masks_p, 0, f->size);
|
||||
}
|
||||
|
||||
memcpy(&val, vals_p, f->size);
|
||||
|
||||
field_bsize = f->size * BITS_PER_BYTE;
|
||||
|
||||
first_z = find_first_zero_bit(&mask, field_bsize);
|
||||
first = find_first_bit(&mask, field_bsize);
|
||||
last = find_last_bit(&mask, field_bsize);
|
||||
if (first > 0 || last != (field_bsize - 1)) {
|
||||
if (first > 0 || last != (field_bsize - 1) || first_z < last) {
|
||||
printk(KERN_WARNING "mlx5: partial rewrite (mask %lx) is currently not offloaded\n",
|
||||
mask);
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -1002,11 +1004,11 @@ static int offload_pedit_fields(struct pedit_headers *masks,
|
|||
}
|
||||
|
||||
if (field_bsize == 32)
|
||||
MLX5_SET(set_action_in, action, data, ntohl(val));
|
||||
MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p));
|
||||
else if (field_bsize == 16)
|
||||
MLX5_SET(set_action_in, action, data, ntohs(val));
|
||||
MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p));
|
||||
else if (field_bsize == 8)
|
||||
MLX5_SET(set_action_in, action, data, val);
|
||||
MLX5_SET(set_action_in, action, data, *(u8 *)vals_p);
|
||||
|
||||
action += action_size;
|
||||
nactions++;
|
||||
|
@ -1109,6 +1111,28 @@ out_err:
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool csum_offload_supported(struct mlx5e_priv *priv, u32 action, u32 update_flags)
|
||||
{
|
||||
u32 prot_flags = TCA_CSUM_UPDATE_FLAG_IPV4HDR | TCA_CSUM_UPDATE_FLAG_TCP |
|
||||
TCA_CSUM_UPDATE_FLAG_UDP;
|
||||
|
||||
/* The HW recalcs checksums only if re-writing headers */
|
||||
if (!(action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)) {
|
||||
netdev_warn(priv->netdev,
|
||||
"TC csum action is only offloaded with pedit\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (update_flags & ~prot_flags) {
|
||||
netdev_warn(priv->netdev,
|
||||
"can't offload TC csum action for some header/s - flags %#x\n",
|
||||
update_flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
|
||||
struct mlx5e_tc_flow_parse_attr *parse_attr,
|
||||
struct mlx5e_tc_flow *flow)
|
||||
|
@ -1149,6 +1173,14 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (is_tcf_csum(a)) {
|
||||
if (csum_offload_supported(priv, attr->action,
|
||||
tcf_csum_update_flags(a)))
|
||||
continue;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (is_tcf_skbedit_mark(a)) {
|
||||
u32 mark = tcf_skbedit_mark(a);
|
||||
|
||||
|
@ -1651,6 +1683,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (is_tcf_csum(a)) {
|
||||
if (csum_offload_supported(priv, attr->action,
|
||||
tcf_csum_update_flags(a)))
|
||||
continue;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (is_tcf_mirred_egress_redirect(a)) {
|
||||
int ifindex = tcf_mirred_ifindex(a);
|
||||
struct net_device *out_dev, *encap_dev = NULL;
|
||||
|
|
|
@ -422,7 +422,7 @@ static irqreturn_t mlx5_eq_int(int irq, void *eq_ptr)
|
|||
break;
|
||||
|
||||
case MLX5_EVENT_TYPE_CMD:
|
||||
mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector));
|
||||
mlx5_cmd_comp_handler(dev, be32_to_cpu(eqe->data.cmd.vector), false);
|
||||
break;
|
||||
|
||||
case MLX5_EVENT_TYPE_PORT_CHANGE:
|
||||
|
|
|
@ -90,7 +90,7 @@ static void trigger_cmd_completions(struct mlx5_core_dev *dev)
|
|||
spin_unlock_irqrestore(&dev->cmd.alloc_lock, flags);
|
||||
|
||||
mlx5_core_dbg(dev, "vector 0x%llx\n", vector);
|
||||
mlx5_cmd_comp_handler(dev, vector);
|
||||
mlx5_cmd_comp_handler(dev, vector, true);
|
||||
return;
|
||||
|
||||
no_trig:
|
||||
|
|
|
@ -612,7 +612,6 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i)
|
|||
struct mlx5_priv *priv = &mdev->priv;
|
||||
struct msix_entry *msix = priv->msix_arr;
|
||||
int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector;
|
||||
int err;
|
||||
|
||||
if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) {
|
||||
mlx5_core_warn(mdev, "zalloc_cpumask_var failed");
|
||||
|
@ -622,18 +621,12 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i)
|
|||
cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node),
|
||||
priv->irq_info[i].mask);
|
||||
|
||||
err = irq_set_affinity_hint(irq, priv->irq_info[i].mask);
|
||||
if (err) {
|
||||
mlx5_core_warn(mdev, "irq_set_affinity_hint failed,irq 0x%.4x",
|
||||
irq);
|
||||
goto err_clear_mask;
|
||||
}
|
||||
#ifdef CONFIG_SMP
|
||||
if (irq_set_affinity_hint(irq, priv->irq_info[i].mask))
|
||||
mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
err_clear_mask:
|
||||
free_cpumask_var(priv->irq_info[i].mask);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i)
|
||||
|
|
|
@ -1293,7 +1293,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|||
if (nla_put_u32(skb, IFLA_GENEVE_ID, vni))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (ip_tunnel_info_af(info) == AF_INET) {
|
||||
if (rtnl_dereference(geneve->sock4)) {
|
||||
if (nla_put_in_addr(skb, IFLA_GENEVE_REMOTE,
|
||||
info->key.u.ipv4.dst))
|
||||
goto nla_put_failure;
|
||||
|
@ -1302,8 +1302,10 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|||
!!(info->key.tun_flags & TUNNEL_CSUM)))
|
||||
goto nla_put_failure;
|
||||
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else {
|
||||
if (rtnl_dereference(geneve->sock6)) {
|
||||
if (nla_put_in6_addr(skb, IFLA_GENEVE_REMOTE6,
|
||||
&info->key.u.ipv6.dst))
|
||||
goto nla_put_failure;
|
||||
|
@ -1315,8 +1317,8 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|||
if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
|
||||
!geneve->use_udp6_rx_checksums))
|
||||
goto nla_put_failure;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nla_put_u8(skb, IFLA_GENEVE_TTL, info->key.ttl) ||
|
||||
nla_put_u8(skb, IFLA_GENEVE_TOS, info->key.tos) ||
|
||||
|
|
|
@ -873,7 +873,7 @@ static struct gtp_dev *gtp_find_dev(struct net *src_net, struct nlattr *nla[])
|
|||
|
||||
/* Check if there's an existing gtpX device to configure */
|
||||
dev = dev_get_by_index_rcu(net, nla_get_u32(nla[GTPA_LINK]));
|
||||
if (dev->netdev_ops == >p_netdev_ops)
|
||||
if (dev && dev->netdev_ops == >p_netdev_ops)
|
||||
gtp = netdev_priv(dev);
|
||||
|
||||
put_net(net);
|
||||
|
|
|
@ -108,7 +108,7 @@ config MDIO_MOXART
|
|||
config MDIO_OCTEON
|
||||
tristate "Octeon and some ThunderX SOCs MDIO buses"
|
||||
depends on 64BIT
|
||||
depends on HAS_IOMEM
|
||||
depends on HAS_IOMEM && OF_MDIO
|
||||
select MDIO_CAVIUM
|
||||
help
|
||||
This module provides a driver for the Octeon and ThunderX MDIO
|
||||
|
|
|
@ -255,34 +255,6 @@ static int marvell_config_aneg(struct phy_device *phydev)
|
|||
{
|
||||
int err;
|
||||
|
||||
/* The Marvell PHY has an errata which requires
|
||||
* that certain registers get written in order
|
||||
* to restart autonegotiation */
|
||||
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x1f);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x200c);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x5);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -316,6 +288,42 @@ static int marvell_config_aneg(struct phy_device *phydev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int m88e1101_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* This Marvell PHY has an errata which requires
|
||||
* that certain registers get written in order
|
||||
* to restart autonegotiation
|
||||
*/
|
||||
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x1f);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x200c);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1d, 0x5);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = phy_write(phydev, 0x1e, 0x100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return marvell_config_aneg(phydev);
|
||||
}
|
||||
|
||||
static int m88e1111_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int err;
|
||||
|
@ -1892,7 +1900,7 @@ static struct phy_driver marvell_drivers[] = {
|
|||
.flags = PHY_HAS_INTERRUPT,
|
||||
.probe = marvell_probe,
|
||||
.config_init = &marvell_config_init,
|
||||
.config_aneg = &marvell_config_aneg,
|
||||
.config_aneg = &m88e1101_config_aneg,
|
||||
.read_status = &genphy_read_status,
|
||||
.ack_interrupt = &marvell_ack_interrupt,
|
||||
.config_intr = &marvell_config_intr,
|
||||
|
|
|
@ -310,13 +310,6 @@ skip:
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Some devices don't initialise properly. In particular
|
||||
* the packet filter is not reset. There are devices that
|
||||
* don't do reset all the way. So the packet filter should
|
||||
* be set to a sane initial value.
|
||||
*/
|
||||
usbnet_cdc_update_filter(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
bad_desc:
|
||||
|
@ -325,6 +318,30 @@ bad_desc:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
|
||||
|
||||
|
||||
/* like usbnet_generic_cdc_bind() but handles filter initialization
|
||||
* correctly
|
||||
*/
|
||||
int usbnet_ether_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = usbnet_generic_cdc_bind(dev, intf);
|
||||
if (rv < 0)
|
||||
goto bail_out;
|
||||
|
||||
/* Some devices don't initialise properly. In particular
|
||||
* the packet filter is not reset. There are devices that
|
||||
* don't do reset all the way. So the packet filter should
|
||||
* be set to a sane initial value.
|
||||
*/
|
||||
usbnet_cdc_update_filter(dev);
|
||||
|
||||
bail_out:
|
||||
return rv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbnet_ether_cdc_bind);
|
||||
|
||||
void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
|
||||
{
|
||||
struct cdc_state *info = (void *) &dev->data;
|
||||
|
@ -417,7 +434,7 @@ int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
|
|||
BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
|
||||
< sizeof(struct cdc_state)));
|
||||
|
||||
status = usbnet_generic_cdc_bind(dev, intf);
|
||||
status = usbnet_ether_cdc_bind(dev, intf);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
|
|
|
@ -681,7 +681,7 @@ static int smsc95xx_set_features(struct net_device *netdev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (features & NETIF_F_HW_CSUM)
|
||||
if (features & NETIF_F_IP_CSUM)
|
||||
read_buf |= Tx_COE_EN_;
|
||||
else
|
||||
read_buf &= ~Tx_COE_EN_;
|
||||
|
@ -1279,12 +1279,19 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
|
|||
|
||||
spin_lock_init(&pdata->mac_cr_lock);
|
||||
|
||||
/* LAN95xx devices do not alter the computed checksum of 0 to 0xffff.
|
||||
* RFC 2460, ipv6 UDP calculated checksum yields a result of zero must
|
||||
* be changed to 0xffff. RFC 768, ipv4 UDP computed checksum is zero,
|
||||
* it is transmitted as all ones. The zero transmitted checksum means
|
||||
* transmitter generated no checksum. Hence, enable csum offload only
|
||||
* for ipv4 packets.
|
||||
*/
|
||||
if (DEFAULT_TX_CSUM_ENABLE)
|
||||
dev->net->features |= NETIF_F_HW_CSUM;
|
||||
dev->net->features |= NETIF_F_IP_CSUM;
|
||||
if (DEFAULT_RX_CSUM_ENABLE)
|
||||
dev->net->features |= NETIF_F_RXCSUM;
|
||||
|
||||
dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
|
||||
dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
|
||||
|
||||
smsc95xx_init_mac_address(dev);
|
||||
|
||||
|
|
|
@ -1989,6 +1989,7 @@ static const struct net_device_ops virtnet_netdev = {
|
|||
.ndo_poll_controller = virtnet_netpoll,
|
||||
#endif
|
||||
.ndo_xdp = virtnet_xdp,
|
||||
.ndo_features_check = passthru_features_check,
|
||||
};
|
||||
|
||||
static void virtnet_config_changed_work(struct work_struct *work)
|
||||
|
|
|
@ -925,6 +925,29 @@ static int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INTEGRITY
|
||||
static void nvme_prep_integrity(struct gendisk *disk, struct nvme_id_ns *id,
|
||||
u16 bs)
|
||||
{
|
||||
struct nvme_ns *ns = disk->private_data;
|
||||
u16 old_ms = ns->ms;
|
||||
u8 pi_type = 0;
|
||||
|
||||
ns->ms = le16_to_cpu(id->lbaf[id->flbas & NVME_NS_FLBAS_LBA_MASK].ms);
|
||||
ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT);
|
||||
|
||||
/* PI implementation requires metadata equal t10 pi tuple size */
|
||||
if (ns->ms == sizeof(struct t10_pi_tuple))
|
||||
pi_type = id->dps & NVME_NS_DPS_PI_MASK;
|
||||
|
||||
if (blk_get_integrity(disk) &&
|
||||
(ns->pi_type != pi_type || ns->ms != old_ms ||
|
||||
bs != queue_logical_block_size(disk->queue) ||
|
||||
(ns->ms && ns->ext)))
|
||||
blk_integrity_unregister(disk);
|
||||
|
||||
ns->pi_type = pi_type;
|
||||
}
|
||||
|
||||
static void nvme_init_integrity(struct nvme_ns *ns)
|
||||
{
|
||||
struct blk_integrity integrity;
|
||||
|
@ -951,6 +974,10 @@ static void nvme_init_integrity(struct nvme_ns *ns)
|
|||
blk_queue_max_integrity_segments(ns->queue, 1);
|
||||
}
|
||||
#else
|
||||
static void nvme_prep_integrity(struct gendisk *disk, struct nvme_id_ns *id,
|
||||
u16 bs)
|
||||
{
|
||||
}
|
||||
static void nvme_init_integrity(struct nvme_ns *ns)
|
||||
{
|
||||
}
|
||||
|
@ -997,37 +1024,22 @@ static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id)
|
|||
static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
|
||||
{
|
||||
struct nvme_ns *ns = disk->private_data;
|
||||
u8 lbaf, pi_type;
|
||||
u16 old_ms;
|
||||
unsigned short bs;
|
||||
|
||||
old_ms = ns->ms;
|
||||
lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
|
||||
ns->lba_shift = id->lbaf[lbaf].ds;
|
||||
ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
|
||||
ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT);
|
||||
u16 bs;
|
||||
|
||||
/*
|
||||
* If identify namespace failed, use default 512 byte block size so
|
||||
* block layer can use before failing read/write for 0 capacity.
|
||||
*/
|
||||
ns->lba_shift = id->lbaf[id->flbas & NVME_NS_FLBAS_LBA_MASK].ds;
|
||||
if (ns->lba_shift == 0)
|
||||
ns->lba_shift = 9;
|
||||
bs = 1 << ns->lba_shift;
|
||||
/* XXX: PI implementation requires metadata equal t10 pi tuple size */
|
||||
pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
|
||||
id->dps & NVME_NS_DPS_PI_MASK : 0;
|
||||
|
||||
blk_mq_freeze_queue(disk->queue);
|
||||
if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
|
||||
ns->ms != old_ms ||
|
||||
bs != queue_logical_block_size(disk->queue) ||
|
||||
(ns->ms && ns->ext)))
|
||||
blk_integrity_unregister(disk);
|
||||
|
||||
ns->pi_type = pi_type;
|
||||
if (ns->ctrl->ops->flags & NVME_F_METADATA_SUPPORTED)
|
||||
nvme_prep_integrity(disk, id, bs);
|
||||
blk_queue_logical_block_size(ns->queue, bs);
|
||||
|
||||
if (ns->ms && !blk_get_integrity(disk) && !ns->ext)
|
||||
nvme_init_integrity(ns);
|
||||
if (ns->ms && !(ns->ms == 8 && ns->pi_type) && !blk_get_integrity(disk))
|
||||
|
@ -1605,7 +1617,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
|
|||
}
|
||||
memcpy(ctrl->psd, id->psd, sizeof(ctrl->psd));
|
||||
|
||||
if (ctrl->ops->is_fabrics) {
|
||||
if (ctrl->ops->flags & NVME_F_FABRICS) {
|
||||
ctrl->icdoff = le16_to_cpu(id->icdoff);
|
||||
ctrl->ioccsz = le32_to_cpu(id->ioccsz);
|
||||
ctrl->iorcsz = le32_to_cpu(id->iorcsz);
|
||||
|
@ -2098,7 +2110,6 @@ static void nvme_ns_remove(struct nvme_ns *ns)
|
|||
if (ns->ndev)
|
||||
nvme_nvm_unregister_sysfs(ns);
|
||||
del_gendisk(ns->disk);
|
||||
blk_mq_abort_requeue_list(ns->queue);
|
||||
blk_cleanup_queue(ns->queue);
|
||||
}
|
||||
|
||||
|
@ -2436,8 +2447,16 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
|
|||
continue;
|
||||
revalidate_disk(ns->disk);
|
||||
blk_set_queue_dying(ns->queue);
|
||||
blk_mq_abort_requeue_list(ns->queue);
|
||||
blk_mq_start_stopped_hw_queues(ns->queue, true);
|
||||
|
||||
/*
|
||||
* Forcibly start all queues to avoid having stuck requests.
|
||||
* Note that we must ensure the queues are not stopped
|
||||
* when the final removal happens.
|
||||
*/
|
||||
blk_mq_start_hw_queues(ns->queue);
|
||||
|
||||
/* draining requests in requeue list */
|
||||
blk_mq_kick_requeue_list(ns->queue);
|
||||
}
|
||||
mutex_unlock(&ctrl->namespaces_mutex);
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче