Merge 236f453294
("Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs") into android-mainline
Merge right before the filesystem parsing happened to make merges easier. Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I7d2449b3876e6fbd96838f703f13f2c0a7ec0354
This commit is contained in:
commit
32aad4282b
1
.mailmap
1
.mailmap
@ -262,6 +262,7 @@ Sumit Semwal <sumit.semwal@ti.com>
|
||||
Tejun Heo <htejun@gmail.com>
|
||||
Thomas Graf <tgraf@suug.ch>
|
||||
Thomas Pedersen <twp@codeaurora.org>
|
||||
Tiezhu Yang <yangtiezhu@loongson.cn> <kernelpatch@126.com>
|
||||
Todor Tomov <todor.too@gmail.com> <todor.tomov@linaro.org>
|
||||
Tony Luck <tony.luck@intel.com>
|
||||
TripleX Chung <xxx.phy@gmail.com> <zhongyu@18mail.cn>
|
||||
|
190
Documentation/admin-guide/bootconfig.rst
Normal file
190
Documentation/admin-guide/bootconfig.rst
Normal file
@ -0,0 +1,190 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. _bootconfig:
|
||||
|
||||
==================
|
||||
Boot Configuration
|
||||
==================
|
||||
|
||||
:Author: Masami Hiramatsu <mhiramat@kernel.org>
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The boot configuration expands the current kernel command line to support
|
||||
additional key-value data when booting the kernel in an efficient way.
|
||||
This allows administrators to pass a structured-Key config file.
|
||||
|
||||
Config File Syntax
|
||||
==================
|
||||
|
||||
The boot config syntax is a simple structured key-value. Each key consists
|
||||
of dot-connected-words, and key and value are connected by ``=``. The value
|
||||
has to be terminated by semi-colon (``;``) or newline (``\n``).
|
||||
For array value, array entries are separated by comma (``,``). ::
|
||||
|
||||
KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
|
||||
|
||||
Unlike the kernel command line syntax, spaces are OK around the comma and ``=``.
|
||||
|
||||
Each key word must contain only alphabets, numbers, dash (``-``) or underscore
|
||||
(``_``). And each value only contains printable characters or spaces except
|
||||
for delimiters such as semi-colon (``;``), new-line (``\n``), comma (``,``),
|
||||
hash (``#``) and closing brace (``}``).
|
||||
|
||||
If you want to use those delimiters in a value, you can use either double-
|
||||
quotes (``"VALUE"``) or single-quotes (``'VALUE'``) to quote it. Note that
|
||||
you can not escape these quotes.
|
||||
|
||||
There can be a key which doesn't have value or has an empty value. Those keys
|
||||
are used for checking if the key exists or not (like a boolean).
|
||||
|
||||
Key-Value Syntax
|
||||
----------------
|
||||
|
||||
The boot config file syntax allows user to merge partially same word keys
|
||||
by brace. For example::
|
||||
|
||||
foo.bar.baz = value1
|
||||
foo.bar.qux.quux = value2
|
||||
|
||||
These can be written also in::
|
||||
|
||||
foo.bar {
|
||||
baz = value1
|
||||
qux.quux = value2
|
||||
}
|
||||
|
||||
Or more shorter, written as following::
|
||||
|
||||
foo.bar { baz = value1; qux.quux = value2 }
|
||||
|
||||
In both styles, same key words are automatically merged when parsing it
|
||||
at boot time. So you can append similar trees or key-values.
|
||||
|
||||
Comments
|
||||
--------
|
||||
|
||||
The config syntax accepts shell-script style comments. The comments starting
|
||||
with hash ("#") until newline ("\n") will be ignored.
|
||||
|
||||
::
|
||||
|
||||
# comment line
|
||||
foo = value # value is set to foo.
|
||||
bar = 1, # 1st element
|
||||
2, # 2nd element
|
||||
3 # 3rd element
|
||||
|
||||
This is parsed as below::
|
||||
|
||||
foo = value
|
||||
bar = 1, 2, 3
|
||||
|
||||
Note that you can not put a comment between value and delimiter(``,`` or
|
||||
``;``). This means following config has a syntax error ::
|
||||
|
||||
key = 1 # comment
|
||||
,2
|
||||
|
||||
|
||||
/proc/bootconfig
|
||||
================
|
||||
|
||||
/proc/bootconfig is a user-space interface of the boot config.
|
||||
Unlike /proc/cmdline, this file shows the key-value style list.
|
||||
Each key-value pair is shown in each line with following style::
|
||||
|
||||
KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...]
|
||||
|
||||
|
||||
Boot Kernel With a Boot Config
|
||||
==============================
|
||||
|
||||
Since the boot configuration file is loaded with initrd, it will be added
|
||||
to the end of the initrd (initramfs) image file. The Linux kernel decodes
|
||||
the last part of the initrd image in memory to get the boot configuration
|
||||
data.
|
||||
Because of this "piggyback" method, there is no need to change or
|
||||
update the boot loader and the kernel image itself.
|
||||
|
||||
To do this operation, Linux kernel provides "bootconfig" command under
|
||||
tools/bootconfig, which allows admin to apply or delete the config file
|
||||
to/from initrd image. You can build it by the following command::
|
||||
|
||||
# make -C tools/bootconfig
|
||||
|
||||
To add your boot config file to initrd image, run bootconfig as below
|
||||
(Old data is removed automatically if exists)::
|
||||
|
||||
# tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z
|
||||
|
||||
To remove the config from the image, you can use -d option as below::
|
||||
|
||||
# tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z
|
||||
|
||||
Then add "bootconfig" on the normal kernel command line to tell the
|
||||
kernel to look for the bootconfig at the end of the initrd file.
|
||||
|
||||
Config File Limitation
|
||||
======================
|
||||
|
||||
Currently the maximum config size size is 32KB and the total key-words (not
|
||||
key-value entries) must be under 1024 nodes.
|
||||
Note: this is not the number of entries but nodes, an entry must consume
|
||||
more than 2 nodes (a key-word and a value). So theoretically, it will be
|
||||
up to 512 key-value pairs. If keys contains 3 words in average, it can
|
||||
contain 256 key-value pairs. In most cases, the number of config items
|
||||
will be under 100 entries and smaller than 8KB, so it would be enough.
|
||||
If the node number exceeds 1024, parser returns an error even if the file
|
||||
size is smaller than 32KB.
|
||||
Anyway, since bootconfig command verifies it when appending a boot config
|
||||
to initrd image, user can notice it before boot.
|
||||
|
||||
|
||||
Bootconfig APIs
|
||||
===============
|
||||
|
||||
User can query or loop on key-value pairs, also it is possible to find
|
||||
a root (prefix) key node and find key-values under that node.
|
||||
|
||||
If you have a key string, you can query the value directly with the key
|
||||
using xbc_find_value(). If you want to know what keys exist in the boot
|
||||
config, you can use xbc_for_each_key_value() to iterate key-value pairs.
|
||||
Note that you need to use xbc_array_for_each_value() for accessing
|
||||
each array's value, e.g.::
|
||||
|
||||
vnode = NULL;
|
||||
xbc_find_value("key.word", &vnode);
|
||||
if (vnode && xbc_node_is_array(vnode))
|
||||
xbc_array_for_each_value(vnode, value) {
|
||||
printk("%s ", value);
|
||||
}
|
||||
|
||||
If you want to focus on keys which have a prefix string, you can use
|
||||
xbc_find_node() to find a node by the prefix string, and iterate
|
||||
keys under the prefix node with xbc_node_for_each_key_value().
|
||||
|
||||
But the most typical usage is to get the named value under prefix
|
||||
or get the named array under prefix as below::
|
||||
|
||||
root = xbc_find_node("key.prefix");
|
||||
value = xbc_node_find_value(root, "option", &vnode);
|
||||
...
|
||||
xbc_node_for_each_array_value(root, "array-option", value, anode) {
|
||||
...
|
||||
}
|
||||
|
||||
This accesses a value of "key.prefix.option" and an array of
|
||||
"key.prefix.array-option".
|
||||
|
||||
Locking is not needed, since after initialization, the config becomes
|
||||
read-only. All data and keys must be copied if you need to modify it.
|
||||
|
||||
|
||||
Functions and structures
|
||||
========================
|
||||
|
||||
.. kernel-doc:: include/linux/bootconfig.h
|
||||
.. kernel-doc:: lib/bootconfig.c
|
||||
|
@ -64,6 +64,7 @@ configure specific aspects of kernel behavior to your liking.
|
||||
binderfs
|
||||
binfmt-misc
|
||||
blockdev/index
|
||||
bootconfig
|
||||
braille-console
|
||||
btmrvl
|
||||
cgroup-v1/index
|
||||
|
@ -437,6 +437,12 @@
|
||||
no delay (0).
|
||||
Format: integer
|
||||
|
||||
bootconfig [KNL]
|
||||
Extended command line options can be added to an initrd
|
||||
and this will cause the kernel to look for it.
|
||||
|
||||
See Documentation/admin-guide/bootconfig.rst
|
||||
|
||||
bert_disable [ACPI]
|
||||
Disable BERT OS support on buggy BIOSes.
|
||||
|
||||
|
@ -632,16 +632,16 @@ class priority list and destroyed. If that happens, the priority list mechanism
|
||||
will be used, again, to determine the new effective value for the whole list
|
||||
and that value will become the new real constraint.
|
||||
|
||||
In turn, for each CPU there is only one resume latency PM QoS request
|
||||
associated with the :file:`power/pm_qos_resume_latency_us` file under
|
||||
In turn, for each CPU there is one resume latency PM QoS request associated with
|
||||
the :file:`power/pm_qos_resume_latency_us` file under
|
||||
:file:`/sys/devices/system/cpu/cpu<N>/` in ``sysfs`` and writing to it causes
|
||||
this single PM QoS request to be updated regardless of which user space
|
||||
process does that. In other words, this PM QoS request is shared by the entire
|
||||
user space, so access to the file associated with it needs to be arbitrated
|
||||
to avoid confusion. [Arguably, the only legitimate use of this mechanism in
|
||||
practice is to pin a process to the CPU in question and let it use the
|
||||
``sysfs`` interface to control the resume latency constraint for it.] It
|
||||
still only is a request, however. It is a member of a priority list used to
|
||||
``sysfs`` interface to control the resume latency constraint for it.] It is
|
||||
still only a request, however. It is an entry in a priority list used to
|
||||
determine the effective value to be set as the resume latency constraint for the
|
||||
CPU in question every time the list of requests is updated this way or another
|
||||
(there may be other requests coming from kernel code in that list).
|
||||
|
@ -60,6 +60,9 @@ of the system. The former are always used if the processor model at hand is
|
||||
recognized by ``intel_idle`` and the latter are used if that is required for
|
||||
the given processor model (which is the case for all server processor models
|
||||
recognized by ``intel_idle``) or if the processor model is not recognized.
|
||||
[There is a module parameter that can be used to make the driver use the ACPI
|
||||
tables with any processor model recognized by it; see
|
||||
`below <intel-idle-parameters_>`_.]
|
||||
|
||||
If the ACPI tables are going to be used for building the list of available idle
|
||||
states, ``intel_idle`` first looks for a ``_CST`` object under one of the ACPI
|
||||
@ -165,7 +168,7 @@ and ``idle=nomwait``. If any of them is present in the kernel command line, the
|
||||
``MWAIT`` instruction is not allowed to be used, so the initialization of
|
||||
``intel_idle`` will fail.
|
||||
|
||||
Apart from that there are two module parameters recognized by ``intel_idle``
|
||||
Apart from that there are four module parameters recognized by ``intel_idle``
|
||||
itself that can be set via the kernel command line (they cannot be updated via
|
||||
sysfs, so that is the only way to change their values).
|
||||
|
||||
@ -186,9 +189,28 @@ QoS) feature can be used to prevent ``CPUIdle`` from touching those idle states
|
||||
even if they have been enumerated (see :ref:`cpu-pm-qos` in :doc:`cpuidle`).
|
||||
Setting ``max_cstate`` to 0 causes the ``intel_idle`` initialization to fail.
|
||||
|
||||
The ``noacpi`` module parameter (which is recognized by ``intel_idle`` if the
|
||||
kernel has been configured with ACPI support), can be set to make the driver
|
||||
ignore the system's ACPI tables entirely (it is unset by default).
|
||||
The ``no_acpi`` and ``use_acpi`` module parameters (recognized by ``intel_idle``
|
||||
if the kernel has been configured with ACPI support) can be set to make the
|
||||
driver ignore the system's ACPI tables entirely or use them for all of the
|
||||
recognized processor models, respectively (they both are unset by default and
|
||||
``use_acpi`` has no effect if ``no_acpi`` is set).
|
||||
|
||||
The value of the ``states_off`` module parameter (0 by default) represents a
|
||||
list of idle states to be disabled by default in the form of a bitmask.
|
||||
|
||||
Namely, the positions of the bits that are set in the ``states_off`` value are
|
||||
the indices of idle states to be disabled by default (as reflected by the names
|
||||
of the corresponding idle state directories in ``sysfs``, :file:`state0`,
|
||||
:file:`state1` ... :file:`state<i>` ..., where ``<i>`` is the index of the given
|
||||
idle state; see :ref:`idle-states-representation` in :doc:`cpuidle`).
|
||||
|
||||
For example, if ``states_off`` is equal to 3, the driver will disable idle
|
||||
states 0 and 1 by default, and if it is equal to 8, idle state 3 will be
|
||||
disabled by default and so on (bit positions beyond the maximum idle state index
|
||||
are ignored).
|
||||
|
||||
The idle states disabled this way can be enabled (on a per-CPU basis) from user
|
||||
space via ``sysfs``.
|
||||
|
||||
|
||||
.. _intel-idle-core-and-package-idle-states:
|
||||
|
@ -153,8 +153,11 @@ for the given CPU architecture includes the low-level code for system resume.
|
||||
Basic ``sysfs`` Interfaces for System Suspend and Hibernation
|
||||
=============================================================
|
||||
|
||||
The following files located in the :file:`/sys/power/` directory can be used by
|
||||
user space for sleep states control.
|
||||
The power management subsystem provides userspace with a unified ``sysfs``
|
||||
interface for system sleep regardless of the underlying system architecture or
|
||||
platform. That interface is located in the :file:`/sys/power/` directory
|
||||
(assuming that ``sysfs`` is mounted at :file:`/sys`) and it consists of the
|
||||
following attributes (files):
|
||||
|
||||
``state``
|
||||
This file contains a list of strings representing sleep states supported
|
||||
@ -162,9 +165,9 @@ user space for sleep states control.
|
||||
to start a transition of the system into the sleep state represented by
|
||||
that string.
|
||||
|
||||
In particular, the strings "disk", "freeze" and "standby" represent the
|
||||
In particular, the "disk", "freeze" and "standby" strings represent the
|
||||
:ref:`hibernation <hibernation>`, :ref:`suspend-to-idle <s2idle>` and
|
||||
:ref:`standby <standby>` sleep states, respectively. The string "mem"
|
||||
:ref:`standby <standby>` sleep states, respectively. The "mem" string
|
||||
is interpreted in accordance with the contents of the ``mem_sleep`` file
|
||||
described below.
|
||||
|
||||
@ -177,7 +180,7 @@ user space for sleep states control.
|
||||
associated with the "mem" string in the ``state`` file described above.
|
||||
|
||||
The strings that may be present in this file are "s2idle", "shallow"
|
||||
and "deep". The string "s2idle" always represents :ref:`suspend-to-idle
|
||||
and "deep". The "s2idle" string always represents :ref:`suspend-to-idle
|
||||
<s2idle>` and, by convention, "shallow" and "deep" represent
|
||||
:ref:`standby <standby>` and :ref:`suspend-to-RAM <s2ram>`,
|
||||
respectively.
|
||||
@ -185,15 +188,17 @@ user space for sleep states control.
|
||||
Writing one of the listed strings into this file causes the system
|
||||
suspend variant represented by it to be associated with the "mem" string
|
||||
in the ``state`` file. The string representing the suspend variant
|
||||
currently associated with the "mem" string in the ``state`` file
|
||||
is listed in square brackets.
|
||||
currently associated with the "mem" string in the ``state`` file is
|
||||
shown in square brackets.
|
||||
|
||||
If the kernel does not support system suspend, this file is not present.
|
||||
|
||||
``disk``
|
||||
This file contains a list of strings representing different operations
|
||||
that can be carried out after the hibernation image has been saved. The
|
||||
possible options are as follows:
|
||||
This file controls the operating mode of hibernation (Suspend-to-Disk).
|
||||
Specifically, it tells the kernel what to do after creating a
|
||||
hibernation image.
|
||||
|
||||
Reading from it returns a list of supported options encoded as:
|
||||
|
||||
``platform``
|
||||
Put the system into a special low-power state (e.g. ACPI S4) to
|
||||
@ -201,6 +206,11 @@ user space for sleep states control.
|
||||
platform firmware to take a simplified initialization path after
|
||||
wakeup.
|
||||
|
||||
It is only available if the platform provides a special
|
||||
mechanism to put the system to sleep after creating a
|
||||
hibernation image (platforms with ACPI do that as a rule, for
|
||||
example).
|
||||
|
||||
``shutdown``
|
||||
Power off the system.
|
||||
|
||||
@ -214,22 +224,53 @@ user space for sleep states control.
|
||||
the hibernation image and continue. Otherwise, use the image
|
||||
to restore the previous state of the system.
|
||||
|
||||
It is available if system suspend is supported.
|
||||
|
||||
``test_resume``
|
||||
Diagnostic operation. Load the image as though the system had
|
||||
just woken up from hibernation and the currently running kernel
|
||||
instance was a restore kernel and follow up with full system
|
||||
resume.
|
||||
|
||||
Writing one of the listed strings into this file causes the option
|
||||
Writing one of the strings listed above into this file causes the option
|
||||
represented by it to be selected.
|
||||
|
||||
The currently selected option is shown in square brackets which means
|
||||
The currently selected option is shown in square brackets, which means
|
||||
that the operation represented by it will be carried out after creating
|
||||
and saving the image next time hibernation is triggered by writing
|
||||
``disk`` to :file:`/sys/power/state`.
|
||||
and saving the image when hibernation is triggered by writing ``disk``
|
||||
to :file:`/sys/power/state`.
|
||||
|
||||
If the kernel does not support hibernation, this file is not present.
|
||||
|
||||
``image_size``
|
||||
This file controls the size of hibernation images.
|
||||
|
||||
It can be written a string representing a non-negative integer that will
|
||||
be used as a best-effort upper limit of the image size, in bytes. The
|
||||
hibernation core will do its best to ensure that the image size will not
|
||||
exceed that number, but if that turns out to be impossible to achieve, a
|
||||
hibernation image will still be created and its size will be as small as
|
||||
possible. In particular, writing '0' to this file causes the size of
|
||||
hibernation images to be minimum.
|
||||
|
||||
Reading from it returns the current image size limit, which is set to
|
||||
around 2/5 of the available RAM size by default.
|
||||
|
||||
``pm_trace``
|
||||
This file controls the "PM trace" mechanism saving the last suspend
|
||||
or resume event point in the RTC memory across reboots. It helps to
|
||||
debug hard lockups or reboots due to device driver failures that occur
|
||||
during system suspend or resume (which is more common) more effectively.
|
||||
|
||||
If it contains "1", the fingerprint of each suspend/resume event point
|
||||
in turn will be stored in the RTC memory (overwriting the actual RTC
|
||||
information), so it will survive a system crash if one occurs right
|
||||
after storing it and it can be used later to identify the driver that
|
||||
caused the crash to happen.
|
||||
|
||||
It contains "0" by default, which may be changed to "1" by writing a
|
||||
string representing a nonzero integer into it.
|
||||
|
||||
According to the above, there are two ways to make the system go into the
|
||||
:ref:`suspend-to-idle <s2idle>` state. The first one is to write "freeze"
|
||||
directly to :file:`/sys/power/state`. The second one is to write "s2idle" to
|
||||
@ -244,6 +285,7 @@ system go into the :ref:`suspend-to-RAM <s2ram>` state (write "deep" into
|
||||
The default suspend variant (ie. the one to be used without writing anything
|
||||
into :file:`/sys/power/mem_sleep`) is either "deep" (on the majority of systems
|
||||
supporting :ref:`suspend-to-RAM <s2ram>`) or "s2idle", but it can be overridden
|
||||
by the value of the "mem_sleep_default" parameter in the kernel command line.
|
||||
On some ACPI-based systems, depending on the information in the ACPI tables, the
|
||||
default may be "s2idle" even if :ref:`suspend-to-RAM <s2ram>` is supported.
|
||||
by the value of the ``mem_sleep_default`` parameter in the kernel command line.
|
||||
On some systems with ACPI, depending on the information in the ACPI tables, the
|
||||
default may be "s2idle" even if :ref:`suspend-to-RAM <s2ram>` is supported in
|
||||
principle.
|
||||
|
@ -0,0 +1,83 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-apq8064.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for APQ8064
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on APQ8064.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-msm8960.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8960.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-apq8064
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
nvmem-cells:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description:
|
||||
Qualcomm TSENS (thermal sensor device) on some devices can
|
||||
be part of GCC and hence the TSENS properties can also be part
|
||||
of the GCC/clock-controller node.
|
||||
For more details on the TSENS properties please refer
|
||||
Documentation/devicetree/bindings/thermal/qcom-tsens.txt
|
||||
|
||||
nvmem-cell-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: calib
|
||||
- const: calib_backup
|
||||
|
||||
'#thermal-sensor-cells':
|
||||
const: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
- nvmem-cells
|
||||
- nvmem-cell-names
|
||||
- '#thermal-sensor-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@900000 {
|
||||
compatible = "qcom,gcc-apq8064";
|
||||
reg = <0x00900000 0x4000>;
|
||||
nvmem-cells = <&tsens_calib>, <&tsens_backup>;
|
||||
nvmem-cell-names = "calib", "calib_backup";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
...
|
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-ipq8074.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Bindingfor IPQ8074
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on IPQ8074.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-ipq8074.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-ipq8074
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@1800000 {
|
||||
compatible = "qcom,gcc-ipq8074";
|
||||
reg = <0x01800000 0x80000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
...
|
@ -0,0 +1,68 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-msm8996.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for MSM8996
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on MSM8996.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-msm8996.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-msm8996
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XO source
|
||||
- description: Second XO source
|
||||
- description: Sleep clock source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: cxo
|
||||
- const: cxo2
|
||||
- const: sleep_clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@300000 {
|
||||
compatible = "qcom,gcc-msm8996";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
reg = <0x300000 0x90000>;
|
||||
};
|
||||
...
|
@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-msm8998.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for MSM8998
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on MSM8998.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-msm8998.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-msm8998
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Sleep clock source
|
||||
- description: USB 3.0 phy pipe clock
|
||||
- description: UFS phy rx symbol clock for pipe 0
|
||||
- description: UFS phy rx symbol clock for pipe 1
|
||||
- description: UFS phy tx symbol clock
|
||||
- description: PCIE phy pipe clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
- const: sleep_clk
|
||||
- const: usb3_pipe
|
||||
- const: ufs_rx_symbol0
|
||||
- const: ufs_rx_symbol1
|
||||
- const: ufs_tx_symbol0
|
||||
- const: pcie0_pipe
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-msm8998";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
reg = <0x00100000 0xb0000>;
|
||||
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
|
||||
<&sleep>,
|
||||
<0>,
|
||||
<0>,
|
||||
<0>,
|
||||
<0>,
|
||||
<0>;
|
||||
clock-names = "xo",
|
||||
"sleep_clk",
|
||||
"usb3_pipe",
|
||||
"ufs_rx_symbol0",
|
||||
"ufs_rx_symbol1",
|
||||
"ufs_tx_symbol0",
|
||||
"pcie0_pipe";
|
||||
};
|
||||
...
|
51
Documentation/devicetree/bindings/clock/qcom,gcc-qcs404.yaml
Normal file
51
Documentation/devicetree/bindings/clock/qcom,gcc-qcs404.yaml
Normal file
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-qcs404.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Bindingfor QCS404
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on QCS404.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-qcs404.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-qcs404
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@1800000 {
|
||||
compatible = "qcom,gcc-qcs404";
|
||||
reg = <0x01800000 0x80000>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
...
|
75
Documentation/devicetree/bindings/clock/qcom,gcc-sc7180.yaml
Normal file
75
Documentation/devicetree/bindings/clock/qcom,gcc-sc7180.yaml
Normal file
@ -0,0 +1,75 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-sc7180.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for SC7180
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on SC7180.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-sc7180.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-sc7180
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Board active XO source
|
||||
- description: Sleep clock source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: bi_tcxo_ao
|
||||
- const: sleep_clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-sc7180";
|
||||
reg = <0 0x00100000 0 0x1f0000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&rpmhcc RPMH_CXO_CLK_A>,
|
||||
<&sleep_clk>;
|
||||
clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
72
Documentation/devicetree/bindings/clock/qcom,gcc-sm8150.yaml
Normal file
72
Documentation/devicetree/bindings/clock/qcom,gcc-sm8150.yaml
Normal file
@ -0,0 +1,72 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-sm8150.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for SM8150
|
||||
|
||||
maintainers:
|
||||
- Stephen Boyd <sboyd@kernel.org>
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains on SM8150.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-sm8150.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-sm8150
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Sleep clock source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: sleep_clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-sm8150";
|
||||
reg = <0 0x00100000 0 0x1f0000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&sleep_clk>;
|
||||
clock-names = "bi_tcxo", "sleep_clk";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -14,77 +14,42 @@ description: |
|
||||
Qualcomm global clock control module which supports the clocks, resets and
|
||||
power domains.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-apq8084.h
|
||||
- dt-bindings/reset/qcom,gcc-apq8084.h
|
||||
- dt-bindings/clock/qcom,gcc-ipq4019.h
|
||||
- dt-bindings/clock/qcom,gcc-ipq6018.h
|
||||
- dt-bindings/reset/qcom,gcc-ipq6018.h
|
||||
- dt-bindings/clock/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
|
||||
- dt-bindings/reset/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
|
||||
- dt-bindings/clock/qcom,gcc-msm8660.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8660.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8974.h
|
||||
- dt-bindings/reset/qcom,gcc-msm8974.h
|
||||
- dt-bindings/clock/qcom,gcc-msm8994.h
|
||||
- dt-bindings/clock/qcom,gcc-mdm9615.h
|
||||
- dt-bindings/reset/qcom,gcc-mdm9615.h
|
||||
- dt-bindings/clock/qcom,gcc-sdm660.h (qcom,gcc-sdm630 and qcom,gcc-sdm660)
|
||||
- dt-bindings/clock/qcom,gcc-sdm845.h
|
||||
|
||||
properties:
|
||||
compatible :
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,gcc-apq8064
|
||||
- qcom,gcc-apq8084
|
||||
- qcom,gcc-ipq4019
|
||||
- qcom,gcc-ipq6018
|
||||
- qcom,gcc-ipq8064
|
||||
- qcom,gcc-ipq8074
|
||||
- qcom,gcc-msm8660
|
||||
- qcom,gcc-msm8916
|
||||
- qcom,gcc-msm8960
|
||||
- qcom,gcc-msm8974
|
||||
- qcom,gcc-msm8974pro
|
||||
- qcom,gcc-msm8974pro-ac
|
||||
- qcom,gcc-msm8994
|
||||
- qcom,gcc-msm8996
|
||||
- qcom,gcc-msm8998
|
||||
- qcom,gcc-mdm9615
|
||||
- qcom,gcc-qcs404
|
||||
- qcom,gcc-sc7180
|
||||
- qcom,gcc-sdm630
|
||||
- qcom,gcc-sdm660
|
||||
- qcom,gcc-sdm845
|
||||
- qcom,gcc-sm8150
|
||||
|
||||
clocks:
|
||||
oneOf:
|
||||
#qcom,gcc-sm8150
|
||||
#qcom,gcc-sc7180
|
||||
- items:
|
||||
- description: Board XO source
|
||||
- description: Board active XO source
|
||||
- description: Sleep clock source
|
||||
#qcom,gcc-msm8996
|
||||
- items:
|
||||
- description: XO source
|
||||
- description: Second XO source
|
||||
- description: Sleep clock source
|
||||
#qcom,gcc-msm8998
|
||||
- items:
|
||||
- description: Board XO source
|
||||
- description: Sleep clock source
|
||||
- description: USB 3.0 phy pipe clock
|
||||
- description: UFS phy rx symbol clock for pipe 0
|
||||
- description: UFS phy rx symbol clock for pipe 1
|
||||
- description: UFS phy tx symbol clock
|
||||
- description: PCIE phy pipe clock
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
#qcom,gcc-sm8150
|
||||
#qcom,gcc-sc7180
|
||||
- items:
|
||||
- const: bi_tcxo
|
||||
- const: bi_tcxo_ao
|
||||
- const: sleep_clk
|
||||
#qcom,gcc-msm8996
|
||||
- items:
|
||||
- const: cxo
|
||||
- const: cxo2
|
||||
- const: sleep_clk
|
||||
#qcom,gcc-msm8998
|
||||
- items:
|
||||
- const: xo
|
||||
- const: sleep_clk
|
||||
- const: usb3_pipe
|
||||
- const: ufs_rx_symbol0
|
||||
- const: ufs_rx_symbol1
|
||||
- const: ufs_tx_symbol0
|
||||
- const: pcie0_pipe
|
||||
- qcom,gcc-apq8084
|
||||
- qcom,gcc-ipq4019
|
||||
- qcom,gcc-ipq6018
|
||||
- qcom,gcc-ipq8064
|
||||
- qcom,gcc-msm8660
|
||||
- qcom,gcc-msm8916
|
||||
- qcom,gcc-msm8960
|
||||
- qcom,gcc-msm8974
|
||||
- qcom,gcc-msm8974pro
|
||||
- qcom,gcc-msm8974pro-ac
|
||||
- qcom,gcc-msm8994
|
||||
- qcom,gcc-mdm9615
|
||||
- qcom,gcc-sdm630
|
||||
- qcom,gcc-sdm660
|
||||
- qcom,gcc-sdm845
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
@ -98,31 +63,9 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
nvmem-cells:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description:
|
||||
Qualcomm TSENS (thermal sensor device) on some devices can
|
||||
be part of GCC and hence the TSENS properties can also be part
|
||||
of the GCC/clock-controller node.
|
||||
For more details on the TSENS properties please refer
|
||||
Documentation/devicetree/bindings/thermal/qcom-tsens.txt
|
||||
|
||||
nvmem-cell-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description:
|
||||
Names for each nvmem-cells specified.
|
||||
items:
|
||||
- const: calib
|
||||
- const: calib_backup
|
||||
|
||||
'thermal-sensor-cells':
|
||||
const: 1
|
||||
|
||||
protected-clocks:
|
||||
description:
|
||||
Protected clock specifier list as per common clock binding
|
||||
Protected clock specifier list as per common clock binding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -131,33 +74,6 @@ required:
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,gcc-apq8064
|
||||
|
||||
then:
|
||||
required:
|
||||
- nvmem-cells
|
||||
- nvmem-cell-names
|
||||
- '#thermal-sensor-cells'
|
||||
|
||||
else:
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,gcc-msm8998
|
||||
- qcom,gcc-sm8150
|
||||
- qcom,gcc-sc7180
|
||||
then:
|
||||
required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
|
||||
examples:
|
||||
# Example for GCC for MSM8960:
|
||||
- |
|
||||
@ -168,78 +84,4 @@ examples:
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
|
||||
# Example of GCC with TSENS properties:
|
||||
- |
|
||||
clock-controller@900000 {
|
||||
compatible = "qcom,gcc-apq8064";
|
||||
reg = <0x00900000 0x4000>;
|
||||
nvmem-cells = <&tsens_calib>, <&tsens_backup>;
|
||||
nvmem-cell-names = "calib", "calib_backup";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
||||
# Example of GCC with protected-clocks properties:
|
||||
- |
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-sdm845";
|
||||
reg = <0x100000 0x1f0000>;
|
||||
protected-clocks = <187>, <188>, <189>, <190>, <191>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
# Example of GCC with clock node properties for SM8150:
|
||||
- |
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-sm8150";
|
||||
reg = <0x00100000 0x1f0000>;
|
||||
clocks = <&rpmhcc 0>, <&rpmhcc 1>, <&sleep_clk>;
|
||||
clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
# Example of GCC with clock nodes properties for SC7180:
|
||||
- |
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-sc7180";
|
||||
reg = <0x100000 0x1f0000>;
|
||||
clocks = <&rpmhcc 0>, <&rpmhcc 1>, <0>;
|
||||
clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
# Example of MSM8998 GCC:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,gcc-msm8998";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
reg = <0x00100000 0xb0000>;
|
||||
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
|
||||
<&sleep>,
|
||||
<0>,
|
||||
<0>,
|
||||
<0>,
|
||||
<0>,
|
||||
<0>;
|
||||
clock-names = "xo",
|
||||
"sleep_clk",
|
||||
"usb3_pipe",
|
||||
"ufs_rx_symbol0",
|
||||
"ufs_rx_symbol1",
|
||||
"ufs_tx_symbol0",
|
||||
"pcie0_pipe";
|
||||
};
|
||||
...
|
||||
|
@ -1,72 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gpucc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Graphics Clock & Reset Controller Binding
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm grpahics clock control module which supports the clocks, resets and
|
||||
power domains.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,msm8998-gpucc
|
||||
- qcom,sc7180-gpucc
|
||||
- qcom,sdm845-gpucc
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: GPLL0 main branch source from GCC(gcc_gpu_gpll0_clk_src)
|
||||
- description: GPLL0 div branch source from GCC(gcc_gpu_gpll0_div_clk_src)
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
- const: xo
|
||||
- const: gpll0_main
|
||||
- const: gpll0_div
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
# Example of GPUCC with clock node properties for SDM845:
|
||||
- |
|
||||
clock-controller@5090000 {
|
||||
compatible = "qcom,sdm845-gpucc";
|
||||
reg = <0x5090000 0x9000>;
|
||||
clocks = <&rpmhcc 0>, <&gcc 31>, <&gcc 32>;
|
||||
clock-names = "xo", "gpll0_main", "gpll0_div";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -1,30 +1,28 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,dispcc.yaml#
|
||||
$id: http://devicetree.org/schemas/clock/qcom,msm8998-gpucc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Display Clock & Reset Controller Binding
|
||||
title: Qualcomm Graphics Clock & Reset Controller Binding for MSM8998
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module which supports the clocks, resets and
|
||||
power domains.
|
||||
Qualcomm graphics clock control module which supports the clocks, resets and
|
||||
power domains on MSM8998.
|
||||
|
||||
See also dt-bindings/clock/qcom,gpucc-msm8998.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7180-dispcc
|
||||
- qcom,sdm845-dispcc
|
||||
const: qcom,msm8998-gpucc
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: GPLL0 source from GCC
|
||||
- description: GPLL0 main branch source (gcc_gpu_gpll0_clk_src)
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
@ -53,15 +51,16 @@ required:
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
# Example of DISPCC with clock node properties for SDM845:
|
||||
- |
|
||||
clock-controller@af00000 {
|
||||
compatible = "qcom,sdm845-dispcc";
|
||||
reg = <0xaf00000 0x10000>;
|
||||
clocks = <&rpmhcc 0>, <&gcc 24>;
|
||||
clock-names = "xo", "gpll0";
|
||||
#include <dt-bindings/clock/qcom,gcc-msm8998.h>
|
||||
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||
clock-controller@5065000 {
|
||||
compatible = "qcom,msm8998-gpucc";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
reg = <0x05065000 0x9000>;
|
||||
clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, <&gcc GPLL0_OUT_MAIN>;
|
||||
clock-names = "xo", "gpll0";
|
||||
};
|
||||
...
|
@ -0,0 +1,84 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sc7180-dispcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Display Clock & Reset Controller Binding for SC7180
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module which supports the clocks, resets and
|
||||
power domains on SC7180.
|
||||
|
||||
See also dt-bindings/clock/qcom,dispcc-sc7180.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sc7180-dispcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: GPLL0 source from GCC
|
||||
- description: Byte clock from DSI PHY
|
||||
- description: Pixel clock from DSI PHY
|
||||
- description: Link clock from DP PHY
|
||||
- description: VCO DIV clock from DP PHY
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: gcc_disp_gpll0_clk_src
|
||||
- const: dsi0_phy_pll_out_byteclk
|
||||
- const: dsi0_phy_pll_out_dsiclk
|
||||
- const: dp_phy_pll_link_clk
|
||||
- const: dp_phy_pll_vco_div_clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@af00000 {
|
||||
compatible = "qcom,sc7180-dispcc";
|
||||
reg = <0 0x0af00000 0 0x200000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_DISP_GPLL0_CLK_SRC>,
|
||||
<&dsi_phy 0>,
|
||||
<&dsi_phy 1>,
|
||||
<&dp_phy 0>,
|
||||
<&dp_phy 1>;
|
||||
clock-names = "bi_tcxo",
|
||||
"gcc_disp_gpll0_clk_src",
|
||||
"dsi0_phy_pll_out_byteclk",
|
||||
"dsi0_phy_pll_out_dsiclk",
|
||||
"dp_phy_pll_link_clk",
|
||||
"dp_phy_pll_vco_div_clk";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -0,0 +1,72 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sc7180-gpucc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Graphics Clock & Reset Controller Binding for SC7180
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm graphics clock control module which supports the clocks, resets and
|
||||
power domains on SC7180.
|
||||
|
||||
See also dt-bindings/clock/qcom,gpucc-sc7180.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sc7180-gpucc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: GPLL0 main branch source
|
||||
- description: GPLL0 div branch source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: gcc_gpu_gpll0_clk_src
|
||||
- const: gcc_gpu_gpll0_div_clk_src
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@5090000 {
|
||||
compatible = "qcom,sc7180-gpucc";
|
||||
reg = <0 0x05090000 0 0x9000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_GPU_GPLL0_CLK_SRC>,
|
||||
<&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
|
||||
clock-names = "bi_tcxo",
|
||||
"gcc_gpu_gpll0_clk_src",
|
||||
"gcc_gpu_gpll0_div_clk_src";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sc7180-videocc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Video Clock & Reset Controller Binding for SC7180
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm video clock control module which supports the clocks, resets and
|
||||
power domains on SC7180.
|
||||
|
||||
See also dt-bindings/clock/qcom,videocc-sc7180.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sc7180-videocc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@ab00000 {
|
||||
compatible = "qcom,sc7180-videocc";
|
||||
reg = <0 0x0ab00000 0 0x10000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>;
|
||||
clock-names = "bi_tcxo";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -0,0 +1,99 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sdm845-dispcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Display Clock & Reset Controller Binding for SDM845
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module which supports the clocks, resets and
|
||||
power domains on SDM845.
|
||||
|
||||
See also dt-bindings/clock/qcom,dispcc-sdm845.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sdm845-dispcc
|
||||
|
||||
# NOTE: sdm845.dtsi existed for quite some time and specified no clocks.
|
||||
# The code had to use hardcoded mechanisms to find the input clocks.
|
||||
# New dts files should have these clocks.
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: GPLL0 source from GCC
|
||||
- description: GPLL0 div source from GCC
|
||||
- description: Byte clock from DSI PHY0
|
||||
- description: Pixel clock from DSI PHY0
|
||||
- description: Byte clock from DSI PHY1
|
||||
- description: Pixel clock from DSI PHY1
|
||||
- description: Link clock from DP PHY
|
||||
- description: VCO DIV clock from DP PHY
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: gcc_disp_gpll0_clk_src
|
||||
- const: gcc_disp_gpll0_div_clk_src
|
||||
- const: dsi0_phy_pll_out_byteclk
|
||||
- const: dsi0_phy_pll_out_dsiclk
|
||||
- const: dsi1_phy_pll_out_byteclk
|
||||
- const: dsi1_phy_pll_out_dsiclk
|
||||
- const: dp_link_clk_divsel_ten
|
||||
- const: dp_vco_divided_clk_src_mux
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sdm845.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@af00000 {
|
||||
compatible = "qcom,sdm845-dispcc";
|
||||
reg = <0 0x0af00000 0 0x10000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_DISP_GPLL0_CLK_SRC>,
|
||||
<&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>,
|
||||
<&dsi0_phy 0>,
|
||||
<&dsi0_phy 1>,
|
||||
<&dsi1_phy 0>,
|
||||
<&dsi1_phy 1>,
|
||||
<&dp_phy 0>,
|
||||
<&dp_phy 1>;
|
||||
clock-names = "bi_tcxo",
|
||||
"gcc_disp_gpll0_clk_src",
|
||||
"gcc_disp_gpll0_div_clk_src",
|
||||
"dsi0_phy_pll_out_byteclk",
|
||||
"dsi0_phy_pll_out_dsiclk",
|
||||
"dsi1_phy_pll_out_byteclk",
|
||||
"dsi1_phy_pll_out_dsiclk",
|
||||
"dp_link_clk_divsel_ten",
|
||||
"dp_vco_divided_clk_src_mux";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -0,0 +1,72 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sdm845-gpucc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Graphics Clock & Reset Controller Binding for SDM845
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm graphics clock control module which supports the clocks, resets and
|
||||
power domains on SDM845.
|
||||
|
||||
See also dt-bindings/clock/qcom,gpucc-sdm845.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sdm845-gpucc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: GPLL0 main branch source
|
||||
- description: GPLL0 div branch source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bi_tcxo
|
||||
- const: gcc_gpu_gpll0_clk_src
|
||||
- const: gcc_gpu_gpll0_div_clk_src
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sdm845.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@5090000 {
|
||||
compatible = "qcom,sdm845-gpucc";
|
||||
reg = <0 0x05090000 0 0x9000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&gcc GCC_GPU_GPLL0_CLK_SRC>,
|
||||
<&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
|
||||
clock-names = "bi_tcxo",
|
||||
"gcc_gpu_gpll0_clk_src",
|
||||
"gcc_gpu_gpll0_div_clk_src";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -1,30 +1,31 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,videocc.yaml#
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sdm845-videocc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Video Clock & Reset Controller Binding
|
||||
title: Qualcomm Video Clock & Reset Controller Binding for SDM845
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <tdas@codeaurora.org>
|
||||
|
||||
description: |
|
||||
Qualcomm video clock control module which supports the clocks, resets and
|
||||
power domains.
|
||||
power domains on SDM845.
|
||||
|
||||
See also dt-bindings/clock/qcom,videocc-sdm845.h.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7180-videocc
|
||||
- qcom,sdm845-videocc
|
||||
const: qcom,sdm845-videocc
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
items:
|
||||
- description: Board XO source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
- const: bi_tcxo
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
@ -48,15 +49,15 @@ required:
|
||||
- '#power-domain-cells'
|
||||
|
||||
examples:
|
||||
# Example of VIDEOCC with clock node properties for SDM845:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@ab00000 {
|
||||
compatible = "qcom,sdm845-videocc";
|
||||
reg = <0xab00000 0x10000>;
|
||||
clocks = <&rpmhcc 0>;
|
||||
clock-names = "xo";
|
||||
reg = <0 0x0ab00000 0 0x10000>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>;
|
||||
clock-names = "bi_tcxo";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
};
|
||||
...
|
@ -145,10 +145,7 @@ properties:
|
||||
over reads to the next slave address. Please consult the manual of
|
||||
your device.
|
||||
|
||||
wp-gpios:
|
||||
description:
|
||||
GPIO to which the write-protect pin of the chip is connected.
|
||||
maxItems: 1
|
||||
wp-gpios: true
|
||||
|
||||
address-width:
|
||||
allOf:
|
||||
@ -167,6 +164,10 @@ properties:
|
||||
minimum: 1
|
||||
maximum: 8
|
||||
|
||||
vcc-supply:
|
||||
description:
|
||||
phandle of the regulator that provides the supply voltage.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -20,6 +20,7 @@ Optional properties:
|
||||
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
|
||||
- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings.
|
||||
- read-only : this parameter-less property disables writes to the eeprom
|
||||
- wp-gpios : GPIO to which the write-protect pin of the chip is connected
|
||||
|
||||
Obsolete legacy properties can be used in place of "size", "pagesize",
|
||||
"address-width", and "read-only":
|
||||
@ -36,6 +37,7 @@ Example:
|
||||
spi-max-frequency = <5000000>;
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
wp-gpios = <&gpio1 3 0>;
|
||||
|
||||
pagesize = <64>;
|
||||
size = <32768>;
|
||||
|
@ -1,10 +1,16 @@
|
||||
I2C for Atmel platforms
|
||||
|
||||
Required properties :
|
||||
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
|
||||
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
|
||||
"atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c", "atmel,sama5d2-i2c" or
|
||||
"microchip,sam9x60-i2c"
|
||||
- compatible : Must be one of:
|
||||
"atmel,at91rm9200-i2c",
|
||||
"atmel,at91sam9261-i2c",
|
||||
"atmel,at91sam9260-i2c",
|
||||
"atmel,at91sam9g20-i2c",
|
||||
"atmel,at91sam9g10-i2c",
|
||||
"atmel,at91sam9x5-i2c",
|
||||
"atmel,sama5d4-i2c",
|
||||
"atmel,sama5d2-i2c",
|
||||
"microchip,sam9x60-i2c".
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
|
@ -1,7 +1,9 @@
|
||||
* Ingenic JZ4780 I2C Bus controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ingenic,jz4780-i2c"
|
||||
- compatible: should be one of the following:
|
||||
- "ingenic,jz4780-i2c" for the JZ4780
|
||||
- "ingenic,x1000-i2c" for the X1000
|
||||
- reg: Should contain the address & size of the I2C controller registers.
|
||||
- interrupts: Should specify the interrupt provided by parent.
|
||||
- clocks: Should contain a single clock specifier for the JZ4780 I2C clock.
|
||||
|
@ -25,6 +25,8 @@ Required Properties:
|
||||
Optional Properties:
|
||||
|
||||
- reset-gpios: Reference to the GPIO connected to the reset input.
|
||||
- idle-state: if present, overrides i2c-mux-idle-disconnect,
|
||||
Please refer to Documentation/devicetree/bindings/mux/mux-controller.txt
|
||||
- i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
|
||||
children in idle state. This is necessary for example, if there are several
|
||||
multiplexers on the bus and the devices behind them use same I2C addresses.
|
||||
|
@ -17,7 +17,8 @@ Required properties:
|
||||
"renesas,i2c-r8a7793" if the device is a part of a R8A7793 SoC.
|
||||
"renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC.
|
||||
"renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC.
|
||||
"renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC.
|
||||
"renesas,i2c-r8a7796" if the device is a part of a R8A77960 SoC.
|
||||
"renesas,i2c-r8a77961" if the device is a part of a R8A77961 SoC.
|
||||
"renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC.
|
||||
"renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC.
|
||||
"renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC.
|
||||
|
@ -17,6 +17,7 @@ Required properties:
|
||||
- "renesas,iic-r8a7794" (R-Car E2)
|
||||
- "renesas,iic-r8a7795" (R-Car H3)
|
||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||
- "renesas,iic-r8a77961" (R-Car M3-W+)
|
||||
- "renesas,iic-r8a77965" (R-Car M3-N)
|
||||
- "renesas,iic-r8a77990" (R-Car E3)
|
||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||
|
@ -34,6 +34,14 @@ properties:
|
||||
description:
|
||||
Mark the provider as read only.
|
||||
|
||||
wp-gpios:
|
||||
description:
|
||||
GPIO to which the write-protect pin of the chip is connected.
|
||||
The write-protect GPIO is asserted, when it's driven high
|
||||
(logical '1') to block the write operation. It's deasserted,
|
||||
when it's driven low (logical '0') to allow writing.
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^.*@[0-9a-f]+$":
|
||||
type: object
|
||||
@ -63,9 +71,12 @@ patternProperties:
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
qfprom: eeprom@700000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
wp-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
/* ... */
|
||||
|
||||
|
@ -6,6 +6,11 @@ Required properties:
|
||||
"dlg,da9061-watchdog", "dlg,da9062-watchdog"
|
||||
"dlg,da9062-watchdog"
|
||||
|
||||
Optional properties:
|
||||
- dlg,use-sw-pm: Add this property to disable the watchdog during suspend.
|
||||
Only use this option if you can't use the watchdog automatic suspend
|
||||
function during a suspend (see register CONTROL_B).
|
||||
|
||||
Example: DA9062
|
||||
|
||||
pmic0: da9062@58 {
|
||||
|
@ -4,22 +4,27 @@ Required properties:
|
||||
|
||||
- compatible should contain:
|
||||
"mediatek,mt2701-wdt", "mediatek,mt6589-wdt": for MT2701
|
||||
"mediatek,mt2712-wdt", "mediatek,mt6589-wdt": for MT2712
|
||||
"mediatek,mt6589-wdt": for MT6589
|
||||
"mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797
|
||||
"mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622
|
||||
"mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623
|
||||
"mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
|
||||
"mediatek,mt8183-wdt", "mediatek,mt6589-wdt": for MT8183
|
||||
"mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516
|
||||
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
|
||||
Optional properties:
|
||||
- timeout-sec: contains the watchdog timeout in seconds.
|
||||
- #reset-cells: Should be 1.
|
||||
|
||||
Example:
|
||||
|
||||
wdt: watchdog@10000000 {
|
||||
compatible = "mediatek,mt6589-wdt";
|
||||
reg = <0x10000000 0x18>;
|
||||
watchdog: watchdog@10007000 {
|
||||
compatible = "mediatek,mt8183-wdt",
|
||||
"mediatek,mt6589-wdt";
|
||||
reg = <0 0x10007000 0 0x100>;
|
||||
timeout-sec = <10>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
How to help improve kernel documentation
|
||||
========================================
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Documentation subsystem maintainer entry profile
|
||||
================================================
|
||||
|
||||
|
@ -1,41 +1,40 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
==============
|
||||
FUSE
|
||||
==============
|
||||
|
||||
Definitions
|
||||
~~~~~~~~~~~
|
||||
===========
|
||||
|
||||
Userspace filesystem:
|
||||
|
||||
A filesystem in which data and metadata are provided by an ordinary
|
||||
userspace process. The filesystem can be accessed normally through
|
||||
the kernel interface.
|
||||
|
||||
Filesystem daemon:
|
||||
|
||||
The process(es) providing the data and metadata of the filesystem.
|
||||
|
||||
Non-privileged mount (or user mount):
|
||||
|
||||
A userspace filesystem mounted by a non-privileged (non-root) user.
|
||||
The filesystem daemon is running with the privileges of the mounting
|
||||
user. NOTE: this is not the same as mounts allowed with the "user"
|
||||
option in /etc/fstab, which is not discussed here.
|
||||
|
||||
Filesystem connection:
|
||||
|
||||
A connection between the filesystem daemon and the kernel. The
|
||||
connection exists until either the daemon dies, or the filesystem is
|
||||
umounted. Note that detaching (or lazy umounting) the filesystem
|
||||
does _not_ break the connection, in this case it will exist until
|
||||
does *not* break the connection, in this case it will exist until
|
||||
the last reference to the filesystem is released.
|
||||
|
||||
Mount owner:
|
||||
|
||||
The user who does the mounting.
|
||||
|
||||
User:
|
||||
|
||||
The user who is performing filesystem operations.
|
||||
|
||||
What is FUSE?
|
||||
~~~~~~~~~~~~~
|
||||
=============
|
||||
|
||||
FUSE is a userspace filesystem framework. It consists of a kernel
|
||||
module (fuse.ko), a userspace library (libfuse.*) and a mount utility
|
||||
@ -46,50 +45,41 @@ non-privileged mounts. This opens up new possibilities for the use of
|
||||
filesystems. A good example is sshfs: a secure network filesystem
|
||||
using the sftp protocol.
|
||||
|
||||
The userspace library and utilities are available from the FUSE
|
||||
homepage:
|
||||
|
||||
http://fuse.sourceforge.net/
|
||||
The userspace library and utilities are available from the
|
||||
`FUSE homepage: <http://fuse.sourceforge.net/>`_
|
||||
|
||||
Filesystem type
|
||||
~~~~~~~~~~~~~~~
|
||||
===============
|
||||
|
||||
The filesystem type given to mount(2) can be one of the following:
|
||||
|
||||
'fuse'
|
||||
fuse
|
||||
This is the usual way to mount a FUSE filesystem. The first
|
||||
argument of the mount system call may contain an arbitrary string,
|
||||
which is not interpreted by the kernel.
|
||||
|
||||
This is the usual way to mount a FUSE filesystem. The first
|
||||
argument of the mount system call may contain an arbitrary string,
|
||||
which is not interpreted by the kernel.
|
||||
|
||||
'fuseblk'
|
||||
|
||||
The filesystem is block device based. The first argument of the
|
||||
mount system call is interpreted as the name of the device.
|
||||
fuseblk
|
||||
The filesystem is block device based. The first argument of the
|
||||
mount system call is interpreted as the name of the device.
|
||||
|
||||
Mount options
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
'fd=N'
|
||||
=============
|
||||
|
||||
fd=N
|
||||
The file descriptor to use for communication between the userspace
|
||||
filesystem and the kernel. The file descriptor must have been
|
||||
obtained by opening the FUSE device ('/dev/fuse').
|
||||
|
||||
'rootmode=M'
|
||||
|
||||
rootmode=M
|
||||
The file mode of the filesystem's root in octal representation.
|
||||
|
||||
'user_id=N'
|
||||
|
||||
user_id=N
|
||||
The numeric user id of the mount owner.
|
||||
|
||||
'group_id=N'
|
||||
|
||||
group_id=N
|
||||
The numeric group id of the mount owner.
|
||||
|
||||
'default_permissions'
|
||||
|
||||
default_permissions
|
||||
By default FUSE doesn't check file access permissions, the
|
||||
filesystem is free to implement its access policy or leave it to
|
||||
the underlying file access mechanism (e.g. in case of network
|
||||
@ -97,28 +87,25 @@ Mount options
|
||||
access based on file mode. It is usually useful together with the
|
||||
'allow_other' mount option.
|
||||
|
||||
'allow_other'
|
||||
|
||||
allow_other
|
||||
This option overrides the security measure restricting file access
|
||||
to the user mounting the filesystem. This option is by default only
|
||||
allowed to root, but this restriction can be removed with a
|
||||
(userspace) configuration option.
|
||||
|
||||
'max_read=N'
|
||||
|
||||
max_read=N
|
||||
With this option the maximum size of read operations can be set.
|
||||
The default is infinite. Note that the size of read requests is
|
||||
limited anyway to 32 pages (which is 128kbyte on i386).
|
||||
|
||||
'blksize=N'
|
||||
|
||||
blksize=N
|
||||
Set the block size for the filesystem. The default is 512. This
|
||||
option is only valid for 'fuseblk' type mounts.
|
||||
|
||||
Control filesystem
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
==================
|
||||
|
||||
There's a control filesystem for FUSE, which can be mounted by:
|
||||
There's a control filesystem for FUSE, which can be mounted by::
|
||||
|
||||
mount -t fusectl none /sys/fs/fuse/connections
|
||||
|
||||
@ -130,53 +117,51 @@ named by a unique number.
|
||||
|
||||
For each connection the following files exist within this directory:
|
||||
|
||||
'waiting'
|
||||
waiting
|
||||
The number of requests which are waiting to be transferred to
|
||||
userspace or being processed by the filesystem daemon. If there is
|
||||
no filesystem activity and 'waiting' is non-zero, then the
|
||||
filesystem is hung or deadlocked.
|
||||
|
||||
The number of requests which are waiting to be transferred to
|
||||
userspace or being processed by the filesystem daemon. If there is
|
||||
no filesystem activity and 'waiting' is non-zero, then the
|
||||
filesystem is hung or deadlocked.
|
||||
|
||||
'abort'
|
||||
|
||||
Writing anything into this file will abort the filesystem
|
||||
connection. This means that all waiting requests will be aborted an
|
||||
error returned for all aborted and new requests.
|
||||
abort
|
||||
Writing anything into this file will abort the filesystem
|
||||
connection. This means that all waiting requests will be aborted an
|
||||
error returned for all aborted and new requests.
|
||||
|
||||
Only the owner of the mount may read or write these files.
|
||||
|
||||
Interrupting filesystem operations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
##################################
|
||||
|
||||
If a process issuing a FUSE filesystem request is interrupted, the
|
||||
following will happen:
|
||||
|
||||
1) If the request is not yet sent to userspace AND the signal is
|
||||
- If the request is not yet sent to userspace AND the signal is
|
||||
fatal (SIGKILL or unhandled fatal signal), then the request is
|
||||
dequeued and returns immediately.
|
||||
|
||||
2) If the request is not yet sent to userspace AND the signal is not
|
||||
fatal, then an 'interrupted' flag is set for the request. When
|
||||
- If the request is not yet sent to userspace AND the signal is not
|
||||
fatal, then an interrupted flag is set for the request. When
|
||||
the request has been successfully transferred to userspace and
|
||||
this flag is set, an INTERRUPT request is queued.
|
||||
|
||||
3) If the request is already sent to userspace, then an INTERRUPT
|
||||
- If the request is already sent to userspace, then an INTERRUPT
|
||||
request is queued.
|
||||
|
||||
INTERRUPT requests take precedence over other requests, so the
|
||||
userspace filesystem will receive queued INTERRUPTs before any others.
|
||||
|
||||
The userspace filesystem may ignore the INTERRUPT requests entirely,
|
||||
or may honor them by sending a reply to the _original_ request, with
|
||||
or may honor them by sending a reply to the *original* request, with
|
||||
the error set to EINTR.
|
||||
|
||||
It is also possible that there's a race between processing the
|
||||
original request and its INTERRUPT request. There are two possibilities:
|
||||
|
||||
1) The INTERRUPT request is processed before the original request is
|
||||
1. The INTERRUPT request is processed before the original request is
|
||||
processed
|
||||
|
||||
2) The INTERRUPT request is processed after the original request has
|
||||
2. The INTERRUPT request is processed after the original request has
|
||||
been answered
|
||||
|
||||
If the filesystem cannot find the original request, it should wait for
|
||||
@ -186,7 +171,7 @@ should reply to the INTERRUPT request with an EAGAIN error. In case
|
||||
reply will be ignored.
|
||||
|
||||
Aborting a filesystem connection
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
================================
|
||||
|
||||
It is possible to get into certain situations where the filesystem is
|
||||
not responding. Reasons for this may be:
|
||||
@ -216,7 +201,7 @@ the filesystem. There are several ways to do this:
|
||||
powerful method, always works.
|
||||
|
||||
How do non-privileged mounts work?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
==================================
|
||||
|
||||
Since the mount() system call is a privileged operation, a helper
|
||||
program (fusermount) is needed, which is installed setuid root.
|
||||
@ -235,15 +220,13 @@ system. Obvious requirements arising from this are:
|
||||
other users' or the super user's processes
|
||||
|
||||
How are requirements fulfilled?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
===============================
|
||||
|
||||
A) The mount owner could gain elevated privileges by either:
|
||||
|
||||
1) creating a filesystem containing a device file, then opening
|
||||
this device
|
||||
1. creating a filesystem containing a device file, then opening this device
|
||||
|
||||
2) creating a filesystem containing a suid or sgid application,
|
||||
then executing this application
|
||||
2. creating a filesystem containing a suid or sgid application, then executing this application
|
||||
|
||||
The solution is not to allow opening device files and ignore
|
||||
setuid and setgid bits when executing programs. To ensure this
|
||||
@ -275,16 +258,16 @@ How are requirements fulfilled?
|
||||
of other users' processes.
|
||||
|
||||
i) It can slow down or indefinitely delay the execution of a
|
||||
filesystem operation creating a DoS against the user or the
|
||||
whole system. For example a suid application locking a
|
||||
system file, and then accessing a file on the mount owner's
|
||||
filesystem could be stopped, and thus causing the system
|
||||
file to be locked forever.
|
||||
filesystem operation creating a DoS against the user or the
|
||||
whole system. For example a suid application locking a
|
||||
system file, and then accessing a file on the mount owner's
|
||||
filesystem could be stopped, and thus causing the system
|
||||
file to be locked forever.
|
||||
|
||||
ii) It can present files or directories of unlimited length, or
|
||||
directory structures of unlimited depth, possibly causing a
|
||||
system process to eat up diskspace, memory or other
|
||||
resources, again causing DoS.
|
||||
directory structures of unlimited depth, possibly causing a
|
||||
system process to eat up diskspace, memory or other
|
||||
resources, again causing *DoS*.
|
||||
|
||||
The solution to this as well as B) is not to allow processes
|
||||
to access the filesystem, which could otherwise not be
|
||||
@ -294,28 +277,27 @@ How are requirements fulfilled?
|
||||
ptrace can be used to check if a process is allowed to access
|
||||
the filesystem or not.
|
||||
|
||||
Note that the ptrace check is not strictly necessary to
|
||||
Note that the *ptrace* check is not strictly necessary to
|
||||
prevent B/2/i, it is enough to check if mount owner has enough
|
||||
privilege to send signal to the process accessing the
|
||||
filesystem, since SIGSTOP can be used to get a similar effect.
|
||||
filesystem, since *SIGSTOP* can be used to get a similar effect.
|
||||
|
||||
I think these limitations are unacceptable?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
===========================================
|
||||
|
||||
If a sysadmin trusts the users enough, or can ensure through other
|
||||
measures, that system processes will never enter non-privileged
|
||||
mounts, it can relax the last limitation with a "user_allow_other"
|
||||
mounts, it can relax the last limitation with a 'user_allow_other'
|
||||
config option. If this config option is set, the mounting user can
|
||||
add the "allow_other" mount option which disables the check for other
|
||||
add the 'allow_other' mount option which disables the check for other
|
||||
users' processes.
|
||||
|
||||
Kernel - userspace interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
============================
|
||||
|
||||
The following diagram shows how a filesystem operation (in this
|
||||
example unlink) is performed in FUSE.
|
||||
example unlink) is performed in FUSE. ::
|
||||
|
||||
NOTE: everything in this description is greatly simplified
|
||||
|
||||
| "rm /mnt/fuse/file" | FUSE filesystem daemon
|
||||
| |
|
||||
@ -357,12 +339,13 @@ NOTE: everything in this description is greatly simplified
|
||||
| <fuse_unlink() |
|
||||
| <sys_unlink() |
|
||||
|
||||
.. note:: Everything in the description above is greatly simplified
|
||||
|
||||
There are a couple of ways in which to deadlock a FUSE filesystem.
|
||||
Since we are talking about unprivileged userspace programs,
|
||||
something must be done about these.
|
||||
|
||||
Scenario 1 - Simple deadlock
|
||||
-----------------------------
|
||||
**Scenario 1 - Simple deadlock**::
|
||||
|
||||
| "rm /mnt/fuse/file" | FUSE filesystem daemon
|
||||
| |
|
||||
@ -379,12 +362,12 @@ Scenario 1 - Simple deadlock
|
||||
|
||||
The solution for this is to allow the filesystem to be aborted.
|
||||
|
||||
Scenario 2 - Tricky deadlock
|
||||
----------------------------
|
||||
**Scenario 2 - Tricky deadlock**
|
||||
|
||||
|
||||
This one needs a carefully crafted filesystem. It's a variation on
|
||||
the above, only the call back to the filesystem is not explicit,
|
||||
but is caused by a pagefault.
|
||||
but is caused by a pagefault. ::
|
||||
|
||||
| Kamikaze filesystem thread 1 | Kamikaze filesystem thread 2
|
||||
| |
|
||||
@ -410,7 +393,7 @@ but is caused by a pagefault.
|
||||
| | [lock page]
|
||||
| | * DEADLOCK *
|
||||
|
||||
Solution is basically the same as above.
|
||||
The solution is basically the same as above.
|
||||
|
||||
An additional problem is that while the write buffer is being copied
|
||||
to the request, the request must not be interrupted/aborted. This is
|
@ -47,6 +47,7 @@ Documentation for filesystem implementations.
|
||||
:maxdepth: 2
|
||||
|
||||
autofs
|
||||
fuse
|
||||
overlayfs
|
||||
virtiofs
|
||||
vfat
|
||||
|
@ -1,24 +0,0 @@
|
||||
===============================
|
||||
Kernel driver i2c-parport-light
|
||||
===============================
|
||||
|
||||
Author: Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
This driver is a light version of i2c-parport. It doesn't depend
|
||||
on the parport driver, and uses direct I/O access instead. This might be
|
||||
preferred on embedded systems where wasting memory for the clean but heavy
|
||||
parport handling is not an option. The drawback is a reduced portability
|
||||
and the impossibility to daisy-chain other parallel port devices.
|
||||
|
||||
Please see i2c-parport for documentation.
|
||||
|
||||
Module parameters:
|
||||
|
||||
* type: type of adapter (see i2c-parport or modinfo)
|
||||
|
||||
* base: base I/O address
|
||||
Default is 0x378 which is fairly common for parallel ports, at least on PC.
|
||||
|
||||
* irq: optional IRQ
|
||||
This must be passed if you want SMBus alert support, assuming your adapter
|
||||
actually supports this.
|
@ -20,7 +20,6 @@ I2C Bus Drivers
|
||||
i2c-nforce2
|
||||
i2c-nvidia-gpu
|
||||
i2c-ocores
|
||||
i2c-parport-light
|
||||
i2c-parport
|
||||
i2c-pca-isa
|
||||
i2c-piix4
|
||||
|
@ -1,27 +1,27 @@
|
||||
====================
|
||||
I2C Device Interface
|
||||
====================
|
||||
============================================
|
||||
Implementing I2C device drivers in userspace
|
||||
============================================
|
||||
|
||||
Usually, i2c devices are controlled by a kernel driver. But it is also
|
||||
Usually, I2C devices are controlled by a kernel driver. But it is also
|
||||
possible to access all devices on an adapter from userspace, through
|
||||
the /dev interface. You need to load module i2c-dev for this.
|
||||
|
||||
Each registered i2c adapter gets a number, counting from 0. You can
|
||||
Each registered I2C adapter gets a number, counting from 0. You can
|
||||
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
|
||||
Alternatively, you can run "i2cdetect -l" to obtain a formatted list of all
|
||||
i2c adapters present on your system at a given time. i2cdetect is part of
|
||||
I2C adapters present on your system at a given time. i2cdetect is part of
|
||||
the i2c-tools package.
|
||||
|
||||
I2C device files are character device files with major device number 89
|
||||
and a minor device number corresponding to the number assigned as
|
||||
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
|
||||
i2c-10, ...). All 256 minor device numbers are reserved for i2c.
|
||||
i2c-10, ...). All 256 minor device numbers are reserved for I2C.
|
||||
|
||||
|
||||
C example
|
||||
=========
|
||||
|
||||
So let's say you want to access an i2c adapter from a C program.
|
||||
So let's say you want to access an I2C adapter from a C program.
|
||||
First, you need to include these two headers::
|
||||
|
||||
#include <linux/i2c-dev.h>
|
||||
@ -66,7 +66,7 @@ the device supports them. Both are illustrated below::
|
||||
/* Using SMBus commands */
|
||||
res = i2c_smbus_read_word_data(file, reg);
|
||||
if (res < 0) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
/* ERROR HANDLING: I2C transaction failed */
|
||||
} else {
|
||||
/* res contains the read word */
|
||||
}
|
||||
@ -79,12 +79,12 @@ the device supports them. Both are illustrated below::
|
||||
buf[1] = 0x43;
|
||||
buf[2] = 0x65;
|
||||
if (write(file, buf, 3) != 3) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
/* ERROR HANDLING: I2C transaction failed */
|
||||
}
|
||||
|
||||
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
|
||||
if (read(file, buf, 1) != 1) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
/* ERROR HANDLING: I2C transaction failed */
|
||||
} else {
|
||||
/* buf[0] contains the read byte */
|
||||
}
|
||||
@ -144,7 +144,7 @@ The following IOCTLs are defined:
|
||||
If possible, use the provided ``i2c_smbus_*`` methods described below instead
|
||||
of issuing direct ioctls.
|
||||
|
||||
You can do plain i2c transactions by using read(2) and write(2) calls.
|
||||
You can do plain I2C transactions by using read(2) and write(2) calls.
|
||||
You do not need to pass the address byte; instead, set it through
|
||||
ioctl I2C_SLAVE before you try to access the device.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
Linux I2C and DMA
|
||||
=================
|
||||
|
||||
Given that i2c is a low-speed bus, over which the majority of messages
|
||||
Given that I2C is a low-speed bus, over which the majority of messages
|
||||
transferred are small, it is not considered a prime user of DMA access. At this
|
||||
time of writing, only 10% of I2C bus master drivers have DMA support
|
||||
implemented. And the vast majority of transactions are so small that setting up
|
||||
|
@ -1,26 +1,26 @@
|
||||
============
|
||||
I2C Protocol
|
||||
============
|
||||
================
|
||||
The I2C Protocol
|
||||
================
|
||||
|
||||
This document describes the i2c protocol. Or will, when it is finished :-)
|
||||
This document describes the I2C protocol. Or will, when it is finished :-)
|
||||
|
||||
Key to symbols
|
||||
==============
|
||||
|
||||
=============== =============================================================
|
||||
S (1 bit) : Start bit
|
||||
P (1 bit) : Stop bit
|
||||
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) : Accept and reverse accept bit.
|
||||
Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to
|
||||
S Start condition
|
||||
P Stop condition
|
||||
Rd/Wr (1 bit) Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) Acknowledge (ACK) and Not Acknowledge (NACK) bit
|
||||
Addr (7 bits) I2C 7 bit address. Note that this can be expanded as usual to
|
||||
get a 10 bit I2C address.
|
||||
Comm (8 bits): Command byte, a data byte which often selects a register on
|
||||
Comm (8 bits) Command byte, a data byte which often selects a register on
|
||||
the device.
|
||||
Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
Data (8 bits) A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
for 16 bit data.
|
||||
Count (8 bits): A data byte containing the length of a block operation.
|
||||
Count (8 bits) A data byte containing the length of a block operation.
|
||||
|
||||
[..]: Data sent by I2C device, as opposed to data sent by the
|
||||
[..] Data sent by I2C device, as opposed to data sent by the
|
||||
host adapter.
|
||||
=============== =============================================================
|
||||
|
||||
@ -28,7 +28,7 @@ Count (8 bits): A data byte containing the length of a block operation.
|
||||
Simple send transaction
|
||||
=======================
|
||||
|
||||
This corresponds to i2c_master_send::
|
||||
Implemented by i2c_master_send()::
|
||||
|
||||
S Addr Wr [A] Data [A] Data [A] ... [A] Data [A] P
|
||||
|
||||
@ -36,7 +36,7 @@ This corresponds to i2c_master_send::
|
||||
Simple receive transaction
|
||||
==========================
|
||||
|
||||
This corresponds to i2c_master_recv::
|
||||
Implemented by i2c_master_recv()::
|
||||
|
||||
S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
|
||||
|
||||
@ -44,11 +44,11 @@ This corresponds to i2c_master_recv::
|
||||
Combined transactions
|
||||
=====================
|
||||
|
||||
This corresponds to i2c_transfer
|
||||
Implemented by i2c_transfer().
|
||||
|
||||
They are just like the above transactions, but instead of a stop bit P
|
||||
a start bit S is sent and the transaction continues. An example of
|
||||
a byte read, followed by a byte write::
|
||||
They are just like the above transactions, but instead of a stop
|
||||
condition P a start condition S is sent and the transaction continues.
|
||||
An example of a byte read, followed by a byte write::
|
||||
|
||||
S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
|
||||
|
||||
@ -57,7 +57,7 @@ Modified transactions
|
||||
=====================
|
||||
|
||||
The following modifications to the I2C protocol can also be generated by
|
||||
setting these flags for i2c messages. With the exception of I2C_M_NOSTART, they
|
||||
setting these flags for I2C messages. With the exception of I2C_M_NOSTART, they
|
||||
are usually only needed to work around device issues:
|
||||
|
||||
I2C_M_IGNORE_NAK:
|
||||
@ -77,8 +77,9 @@ I2C_M_NOSTART:
|
||||
S Addr Rd [A] [Data] NA Data [A] P
|
||||
|
||||
If you set the I2C_M_NOSTART variable for the first partial message,
|
||||
we do not generate Addr, but we do generate the startbit S. This will
|
||||
probably confuse all other clients on your bus, so don't try this.
|
||||
we do not generate Addr, but we do generate the start condition S.
|
||||
This will probably confuse all other clients on your bus, so don't
|
||||
try this.
|
||||
|
||||
This is often used to gather transmits from multiple data buffers in
|
||||
system memory into something that appears as a single transfer to the
|
||||
|
@ -1,9 +1,9 @@
|
||||
============
|
||||
I2C topology
|
||||
============
|
||||
================================
|
||||
I2C muxes and complex topologies
|
||||
================================
|
||||
|
||||
There are a couple of reasons for building more complex i2c topologies
|
||||
than a straight-forward i2c bus with one adapter and one or more devices.
|
||||
There are a couple of reasons for building more complex I2C topologies
|
||||
than a straight-forward I2C bus with one adapter and one or more devices.
|
||||
|
||||
1. A mux may be needed on the bus to prevent address collisions.
|
||||
|
||||
@ -11,20 +11,20 @@ than a straight-forward i2c bus with one adapter and one or more devices.
|
||||
may be needed to determine if it is ok to access the bus.
|
||||
|
||||
3. A device (particularly RF tuners) may want to avoid the digital noise
|
||||
from the i2c bus, at least most of the time, and sits behind a gate
|
||||
from the I2C bus, at least most of the time, and sits behind a gate
|
||||
that has to be operated before the device can be accessed.
|
||||
|
||||
Etc
|
||||
===
|
||||
|
||||
These constructs are represented as i2c adapter trees by Linux, where
|
||||
These constructs are represented as I2C adapter trees by Linux, where
|
||||
each adapter has a parent adapter (except the root adapter) and zero or
|
||||
more child adapters. The root adapter is the actual adapter that issues
|
||||
i2c transfers, and all adapters with a parent are part of an "i2c-mux"
|
||||
I2C transfers, and all adapters with a parent are part of an "i2c-mux"
|
||||
object (quoted, since it can also be an arbitrator or a gate).
|
||||
|
||||
Depending of the particular mux driver, something happens when there is
|
||||
an i2c transfer on one of its child adapters. The mux driver can
|
||||
an I2C transfer on one of its child adapters. The mux driver can
|
||||
obviously operate a mux, but it can also do arbitration with an external
|
||||
bus master or open a gate. The mux driver has two operations for this,
|
||||
select and deselect. select is called before the transfer and (the
|
||||
@ -34,7 +34,7 @@ optional) deselect is called after the transfer.
|
||||
Locking
|
||||
=======
|
||||
|
||||
There are two variants of locking available to i2c muxes, they can be
|
||||
There are two variants of locking available to I2C muxes, they can be
|
||||
mux-locked or parent-locked muxes. As is evident from below, it can be
|
||||
useful to know if a mux is mux-locked or if it is parent-locked. The
|
||||
following list was correct at the time of writing:
|
||||
@ -45,7 +45,7 @@ In drivers/i2c/muxes/:
|
||||
i2c-arb-gpio-challenge Parent-locked
|
||||
i2c-mux-gpio Normally parent-locked, mux-locked iff
|
||||
all involved gpio pins are controlled by the
|
||||
same i2c root adapter that they mux.
|
||||
same I2C root adapter that they mux.
|
||||
i2c-mux-gpmux Normally parent-locked, mux-locked iff
|
||||
specified in device-tree.
|
||||
i2c-mux-ltc4306 Mux-locked
|
||||
@ -54,7 +54,7 @@ i2c-mux-pca9541 Parent-locked
|
||||
i2c-mux-pca954x Parent-locked
|
||||
i2c-mux-pinctrl Normally parent-locked, mux-locked iff
|
||||
all involved pinctrl devices are controlled
|
||||
by the same i2c root adapter that they mux.
|
||||
by the same I2C root adapter that they mux.
|
||||
i2c-mux-reg Parent-locked
|
||||
====================== =============================================
|
||||
|
||||
@ -83,9 +83,9 @@ Mux-locked muxes
|
||||
Mux-locked muxes does not lock the entire parent adapter during the
|
||||
full select-transfer-deselect transaction, only the muxes on the parent
|
||||
adapter are locked. Mux-locked muxes are mostly interesting if the
|
||||
select and/or deselect operations must use i2c transfers to complete
|
||||
select and/or deselect operations must use I2C transfers to complete
|
||||
their tasks. Since the parent adapter is not fully locked during the
|
||||
full transaction, unrelated i2c transfers may interleave the different
|
||||
full transaction, unrelated I2C transfers may interleave the different
|
||||
stages of the transaction. This has the benefit that the mux driver
|
||||
may be easier and cleaner to implement, but it has some caveats.
|
||||
|
||||
@ -109,14 +109,14 @@ ML2. It is not safe to build arbitrary topologies with two (or more)
|
||||
|
||||
ML3. A mux-locked mux cannot be used by a driver for auto-closing
|
||||
gates/muxes, i.e. something that closes automatically after a given
|
||||
number (one, in most cases) of i2c transfers. Unrelated i2c transfers
|
||||
number (one, in most cases) of I2C transfers. Unrelated I2C transfers
|
||||
may creep in and close prematurely.
|
||||
|
||||
ML4. If any non-i2c operation in the mux driver changes the i2c mux state,
|
||||
ML4. If any non-I2C operation in the mux driver changes the I2C mux state,
|
||||
the driver has to lock the root adapter during that operation.
|
||||
Otherwise garbage may appear on the bus as seen from devices
|
||||
behind the mux, when an unrelated i2c transfer is in flight during
|
||||
the non-i2c mux-changing operation.
|
||||
behind the mux, when an unrelated I2C transfer is in flight during
|
||||
the non-I2C mux-changing operation.
|
||||
==== =====================================================================
|
||||
|
||||
|
||||
@ -137,14 +137,14 @@ Mux-locked Example
|
||||
|
||||
When there is an access to D1, this happens:
|
||||
|
||||
1. Someone issues an i2c-transfer to D1.
|
||||
1. Someone issues an I2C transfer to D1.
|
||||
2. M1 locks muxes on its parent (the root adapter in this case).
|
||||
3. M1 calls ->select to ready the mux.
|
||||
4. M1 (presumably) does some i2c-transfers as part of its select.
|
||||
These transfers are normal i2c-transfers that locks the parent
|
||||
4. M1 (presumably) does some I2C transfers as part of its select.
|
||||
These transfers are normal I2C transfers that locks the parent
|
||||
adapter.
|
||||
5. M1 feeds the i2c-transfer from step 1 to its parent adapter as a
|
||||
normal i2c-transfer that locks the parent adapter.
|
||||
5. M1 feeds the I2C transfer from step 1 to its parent adapter as a
|
||||
normal I2C transfer that locks the parent adapter.
|
||||
6. M1 calls ->deselect, if it has one.
|
||||
7. Same rules as in step 4, but for ->deselect.
|
||||
8. M1 unlocks muxes on its parent.
|
||||
@ -159,8 +159,8 @@ Parent-locked muxes
|
||||
|
||||
Parent-locked muxes lock the parent adapter during the full select-
|
||||
transfer-deselect transaction. The implication is that the mux driver
|
||||
has to ensure that any and all i2c transfers through that parent
|
||||
adapter during the transaction are unlocked i2c transfers (using e.g.
|
||||
has to ensure that any and all I2C transfers through that parent
|
||||
adapter during the transaction are unlocked I2C transfers (using e.g.
|
||||
__i2c_transfer), or a deadlock will follow. There are a couple of
|
||||
caveats.
|
||||
|
||||
@ -169,12 +169,12 @@ PL1. If you build a topology with a parent-locked mux being the child
|
||||
of another mux, this might break a possible assumption from the
|
||||
child mux that the root adapter is unused between its select op
|
||||
and the actual transfer (e.g. if the child mux is auto-closing
|
||||
and the parent mux issus i2c-transfers as part of its select).
|
||||
and the parent mux issues I2C transfers as part of its select).
|
||||
This is especially the case if the parent mux is mux-locked, but
|
||||
it may also happen if the parent mux is parent-locked.
|
||||
|
||||
PL2. If select/deselect calls out to other subsystems such as gpio,
|
||||
pinctrl, regmap or iio, it is essential that any i2c transfers
|
||||
pinctrl, regmap or iio, it is essential that any I2C transfers
|
||||
caused by these subsystems are unlocked. This can be convoluted to
|
||||
accomplish, maybe even impossible if an acceptably clean solution
|
||||
is sought.
|
||||
@ -197,15 +197,15 @@ Parent-locked Example
|
||||
|
||||
When there is an access to D1, this happens:
|
||||
|
||||
1. Someone issues an i2c-transfer to D1.
|
||||
1. Someone issues an I2C transfer to D1.
|
||||
2. M1 locks muxes on its parent (the root adapter in this case).
|
||||
3. M1 locks its parent adapter.
|
||||
4. M1 calls ->select to ready the mux.
|
||||
5. If M1 does any i2c-transfers (on this root adapter) as part of
|
||||
its select, those transfers must be unlocked i2c-transfers so
|
||||
5. If M1 does any I2C transfers (on this root adapter) as part of
|
||||
its select, those transfers must be unlocked I2C transfers so
|
||||
that they do not deadlock the root adapter.
|
||||
6. M1 feeds the i2c-transfer from step 1 to the root adapter as an
|
||||
unlocked i2c-transfer, so that it does not deadlock the parent
|
||||
6. M1 feeds the I2C transfer from step 1 to the root adapter as an
|
||||
unlocked I2C transfer, so that it does not deadlock the parent
|
||||
adapter.
|
||||
7. M1 calls ->deselect, if it has one.
|
||||
8. Same rules as in step 5, but for ->deselect.
|
||||
@ -240,7 +240,7 @@ and specifically when M2 requests its parent to lock, M1 passes
|
||||
the buck to the root adapter).
|
||||
|
||||
This topology is bad if M2 is an auto-closing mux and M1->select
|
||||
issues any unlocked i2c transfers on the root adapter that may leak
|
||||
issues any unlocked I2C transfers on the root adapter that may leak
|
||||
through and be seen by the M2 adapter, thus closing M2 prematurely.
|
||||
|
||||
|
||||
@ -286,14 +286,14 @@ point.
|
||||
|
||||
This kind of topology is generally not suitable and should probably
|
||||
be avoided. The reason is that M2 probably assumes that there will
|
||||
be no i2c transfers during its calls to ->select and ->deselect, and
|
||||
be no I2C transfers during its calls to ->select and ->deselect, and
|
||||
if there are, any such transfers might appear on the slave side of M2
|
||||
as partial i2c transfers, i.e. garbage or worse. This might cause
|
||||
as partial I2C transfers, i.e. garbage or worse. This might cause
|
||||
device lockups and/or other problems.
|
||||
|
||||
The topology is especially troublesome if M2 is an auto-closing
|
||||
mux. In that case, any interleaved accesses to D4 might close M2
|
||||
prematurely, as might any i2c-transfers part of M1->select.
|
||||
prematurely, as might any I2C transfers part of M1->select.
|
||||
|
||||
But if M2 is not making the above stated assumption, and if M2 is not
|
||||
auto-closing, the topology is fine.
|
||||
|
1341
Documentation/i2c/i2c.svg
Normal file
1341
Documentation/i2c/i2c.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 55 KiB |
@ -4,30 +4,66 @@
|
||||
I2C/SMBus Subsystem
|
||||
===================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
summary
|
||||
i2c-protocol
|
||||
smbus-protocol
|
||||
instantiating-devices
|
||||
busses/index
|
||||
i2c-topology
|
||||
muxes/i2c-mux-gpio
|
||||
|
||||
Writing device drivers
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
writing-clients
|
||||
dev-interface
|
||||
dma-considerations
|
||||
fault-codes
|
||||
functionality
|
||||
|
||||
Debugging
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
gpio-fault-injection
|
||||
i2c-protocol
|
||||
i2c-stub
|
||||
i2c-topology
|
||||
instantiating-devices
|
||||
old-module-parameters
|
||||
slave-eeprom-backend
|
||||
|
||||
Slave I2C
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
slave-interface
|
||||
smbus-protocol
|
||||
summary
|
||||
slave-eeprom-backend
|
||||
|
||||
Advanced topics
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ten-bit-addresses
|
||||
|
||||
Legacy documentation
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
upgrading-clients
|
||||
writing-clients
|
||||
|
||||
muxes/i2c-mux-gpio
|
||||
|
||||
busses/index
|
||||
old-module-parameters
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
@ -9,14 +9,67 @@ reason, the kernel code must instantiate I2C devices explicitly. There are
|
||||
several ways to achieve this, depending on the context and requirements.
|
||||
|
||||
|
||||
Method 1a: Declare the I2C devices by bus number
|
||||
------------------------------------------------
|
||||
Method 1: Declare the I2C devices statically
|
||||
--------------------------------------------
|
||||
|
||||
This method is appropriate when the I2C bus is a system bus as is the case
|
||||
for many embedded systems. On such systems, each I2C bus has a number
|
||||
which is known in advance. It is thus possible to pre-declare the I2C
|
||||
devices which live on this bus. This is done with an array of struct
|
||||
i2c_board_info which is registered by calling i2c_register_board_info().
|
||||
for many embedded systems. On such systems, each I2C bus has a number which
|
||||
is known in advance. It is thus possible to pre-declare the I2C devices
|
||||
which live on this bus.
|
||||
|
||||
This information is provided to the kernel in a different way on different
|
||||
architectures: device tree, ACPI or board files.
|
||||
|
||||
When the I2C bus in question is registered, the I2C devices will be
|
||||
instantiated automatically by i2c-core. The devices will be automatically
|
||||
unbound and destroyed when the I2C bus they sit on goes away (if ever).
|
||||
|
||||
|
||||
Declare the I2C devices via devicetree
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
On platforms using devicetree, the declaration of I2C devices is done in
|
||||
subnodes of the master controller.
|
||||
|
||||
Example::
|
||||
|
||||
i2c1: i2c@400a0000 {
|
||||
/* ... master properties skipped ... */
|
||||
clock-frequency = <100000>;
|
||||
|
||||
flash@50 {
|
||||
compatible = "atmel,24c256";
|
||||
reg = <0x50>;
|
||||
};
|
||||
|
||||
pca9532: gpio@60 {
|
||||
compatible = "nxp,pca9532";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
reg = <0x60>;
|
||||
};
|
||||
};
|
||||
|
||||
Here, two devices are attached to the bus using a speed of 100kHz. For
|
||||
additional properties which might be needed to set up the device, please refer
|
||||
to its devicetree documentation in Documentation/devicetree/bindings/.
|
||||
|
||||
|
||||
Declare the I2C devices via ACPI
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
ACPI can also describe I2C devices. There is special documentation for this
|
||||
which is currently located at :doc:`../firmware-guide/acpi/enumeration`.
|
||||
|
||||
|
||||
Declare the I2C devices in board files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In many embedded architectures, devicetree has replaced the old hardware
|
||||
description based on board files, but the latter are still used in old
|
||||
code. Instantiating I2C devices via board files is done with an array of
|
||||
struct i2c_board_info which is registered by calling
|
||||
i2c_register_board_info().
|
||||
|
||||
Example (from omap2 h4)::
|
||||
|
||||
@ -44,49 +97,7 @@ Example (from omap2 h4)::
|
||||
}
|
||||
|
||||
The above code declares 3 devices on I2C bus 1, including their respective
|
||||
addresses and custom data needed by their drivers. When the I2C bus in
|
||||
question is registered, the I2C devices will be instantiated automatically
|
||||
by i2c-core.
|
||||
|
||||
The devices will be automatically unbound and destroyed when the I2C bus
|
||||
they sit on goes away (if ever.)
|
||||
|
||||
|
||||
Method 1b: Declare the I2C devices via devicetree
|
||||
-------------------------------------------------
|
||||
|
||||
This method has the same implications as method 1a. The declaration of I2C
|
||||
devices is here done via devicetree as subnodes of the master controller.
|
||||
|
||||
Example::
|
||||
|
||||
i2c1: i2c@400a0000 {
|
||||
/* ... master properties skipped ... */
|
||||
clock-frequency = <100000>;
|
||||
|
||||
flash@50 {
|
||||
compatible = "atmel,24c256";
|
||||
reg = <0x50>;
|
||||
};
|
||||
|
||||
pca9532: gpio@60 {
|
||||
compatible = "nxp,pca9532";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
reg = <0x60>;
|
||||
};
|
||||
};
|
||||
|
||||
Here, two devices are attached to the bus using a speed of 100kHz. For
|
||||
additional properties which might be needed to set up the device, please refer
|
||||
to its devicetree documentation in Documentation/devicetree/bindings/.
|
||||
|
||||
|
||||
Method 1c: Declare the I2C devices via ACPI
|
||||
-------------------------------------------
|
||||
|
||||
ACPI can also describe I2C devices. There is special documentation for this
|
||||
which is currently located at Documentation/firmware-guide/acpi/enumeration.rst.
|
||||
addresses and custom data needed by their drivers.
|
||||
|
||||
|
||||
Method 2: Instantiate the devices explicitly
|
||||
@ -98,7 +109,7 @@ tuner, a video decoder, an audio decoder, etc. usually connected to the
|
||||
main chip by the means of an I2C bus. You won't know the number of the I2C
|
||||
bus in advance, so the method 1 described above can't be used. Instead,
|
||||
you can instantiate your I2C devices explicitly. This is done by filling
|
||||
a struct i2c_board_info and calling i2c_new_device().
|
||||
a struct i2c_board_info and calling i2c_new_client_device().
|
||||
|
||||
Example (from the sfe4001 network driver)::
|
||||
|
||||
@ -110,7 +121,7 @@ Example (from the sfe4001 network driver)::
|
||||
{
|
||||
(...)
|
||||
efx->board_info.hwmon_client =
|
||||
i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
|
||||
i2c_new_client_device(&efx->i2c_adap, &sfe4001_hwmon_info);
|
||||
|
||||
(...)
|
||||
}
|
||||
@ -123,7 +134,7 @@ present or not (for example for an optional feature which is not present
|
||||
on cheap variants of a board but you have no way to tell them apart), or
|
||||
it may have different addresses from one board to the next (manufacturer
|
||||
changing its design without notice). In this case, you can call
|
||||
i2c_new_scanned_device() instead of i2c_new_device().
|
||||
i2c_new_scanned_device() instead of i2c_new_client_device().
|
||||
|
||||
Example (from the nxp OHCI driver)::
|
||||
|
||||
@ -152,7 +163,7 @@ simply gives up.
|
||||
|
||||
The driver which instantiated the I2C device is responsible for destroying
|
||||
it on cleanup. This is done by calling i2c_unregister_device() on the
|
||||
pointer that was earlier returned by i2c_new_device() or
|
||||
pointer that was earlier returned by i2c_new_client_device() or
|
||||
i2c_new_scanned_device().
|
||||
|
||||
|
||||
@ -188,7 +199,7 @@ destroyed automatically when the driver which detected them is removed,
|
||||
or when the underlying I2C bus is itself destroyed, whichever happens
|
||||
first.
|
||||
|
||||
Those of you familiar with the i2c subsystem of 2.4 kernels and early 2.6
|
||||
Those of you familiar with the I2C subsystem of 2.4 kernels and early 2.6
|
||||
kernels will find out that this method 3 is essentially similar to what
|
||||
was done there. Two significant differences are:
|
||||
|
||||
@ -214,15 +225,15 @@ In general, the kernel should know which I2C devices are connected and
|
||||
what addresses they live at. However, in certain cases, it does not, so a
|
||||
sysfs interface was added to let the user provide the information. This
|
||||
interface is made of 2 attribute files which are created in every I2C bus
|
||||
directory: new_device and delete_device. Both files are write only and you
|
||||
must write the right parameters to them in order to properly instantiate,
|
||||
respectively delete, an I2C device.
|
||||
directory: ``new_device`` and ``delete_device``. Both files are write
|
||||
only and you must write the right parameters to them in order to properly
|
||||
instantiate, respectively delete, an I2C device.
|
||||
|
||||
File new_device takes 2 parameters: the name of the I2C device (a string)
|
||||
and the address of the I2C device (a number, typically expressed in
|
||||
hexadecimal starting with 0x, but can also be expressed in decimal.)
|
||||
File ``new_device`` takes 2 parameters: the name of the I2C device (a
|
||||
string) and the address of the I2C device (a number, typically expressed
|
||||
in hexadecimal starting with 0x, but can also be expressed in decimal.)
|
||||
|
||||
File delete_device takes a single parameter: the address of the I2C
|
||||
File ``delete_device`` takes a single parameter: the address of the I2C
|
||||
device. As no two devices can live at the same address on a given I2C
|
||||
segment, the address is sufficient to uniquely identify the device to be
|
||||
deleted.
|
||||
|
@ -1,19 +1,24 @@
|
||||
=================================================
|
||||
I2C device driver binding control from user-space
|
||||
=================================================
|
||||
================================================================
|
||||
I2C device driver binding control from user-space in old kernels
|
||||
================================================================
|
||||
|
||||
Up to kernel 2.6.32, many i2c drivers used helper macros provided by
|
||||
.. NOTE::
|
||||
Note: this section is only relevant if you are handling some old code
|
||||
found in kernel 2.6. If you work with more recent kernels, you can
|
||||
safely skip this section.
|
||||
|
||||
Up to kernel 2.6.32, many I2C drivers used helper macros provided by
|
||||
<linux/i2c.h> which created standard module parameters to let the user
|
||||
control how the driver would probe i2c buses and attach to devices. These
|
||||
parameters were known as "probe" (to let the driver probe for an extra
|
||||
address), "force" (to forcibly attach the driver to a given device) and
|
||||
"ignore" (to prevent a driver from probing a given address).
|
||||
control how the driver would probe I2C buses and attach to devices. These
|
||||
parameters were known as ``probe`` (to let the driver probe for an extra
|
||||
address), ``force`` (to forcibly attach the driver to a given device) and
|
||||
``ignore`` (to prevent a driver from probing a given address).
|
||||
|
||||
With the conversion of the i2c subsystem to the standard device driver
|
||||
With the conversion of the I2C subsystem to the standard device driver
|
||||
binding model, it became clear that these per-module parameters were no
|
||||
longer needed, and that a centralized implementation was possible. The new,
|
||||
sysfs-based interface is described in the documentation file
|
||||
"instantiating-devices", section "Method 4: Instantiate from user-space".
|
||||
sysfs-based interface is described in :doc:`instantiating-devices`, section
|
||||
"Method 4: Instantiate from user-space".
|
||||
|
||||
Below is a mapping from the old module parameters to the new interface.
|
||||
|
||||
@ -42,8 +47,8 @@ New method (sysfs interface)::
|
||||
# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device
|
||||
# modprobe <driver>
|
||||
|
||||
Of course, it is important to instantiate the "dummy" device before loading
|
||||
Of course, it is important to instantiate the ``dummy`` device before loading
|
||||
the driver. The dummy device will be handled by i2c-core itself, preventing
|
||||
other drivers from binding to it later on. If there is a real device at the
|
||||
problematic address, and you want another driver to bind to it, then simply
|
||||
pass the name of the device in question instead of "dummy".
|
||||
pass the name of the device in question instead of ``dummy``.
|
||||
|
@ -59,7 +59,7 @@ The bus driver sends an event to the backend using the following function::
|
||||
|
||||
ret = i2c_slave_event(client, event, &val)
|
||||
|
||||
'client' describes the i2c slave device. 'event' is one of the special event
|
||||
'client' describes the I2C slave device. 'event' is one of the special event
|
||||
types described hereafter. 'val' holds an u8 value for the data byte to be
|
||||
read/written and is thus bidirectional. The pointer to val must always be
|
||||
provided even if val is not used for an event, i.e. don't use NULL here. 'ret'
|
||||
@ -143,7 +143,7 @@ Bus driver support
|
||||
If you want to add slave support to the bus driver:
|
||||
|
||||
* implement calls to register/unregister the slave and add those to the
|
||||
struct i2c_algorithm. When registering, you probably need to set the i2c
|
||||
struct i2c_algorithm. When registering, you probably need to set the I2C
|
||||
slave address and enable slave specific interrupts. If you use runtime pm, you
|
||||
should use pm_runtime_get_sync() because your device usually needs to be
|
||||
powered on always to be able to detect its slave address. When unregistering,
|
||||
|
@ -1,6 +1,6 @@
|
||||
======================
|
||||
SMBus Protocol Summary
|
||||
======================
|
||||
==================
|
||||
The SMBus Protocol
|
||||
==================
|
||||
|
||||
The following is a summary of the SMBus protocol. It applies to
|
||||
all revisions of the protocol (1.0, 1.1, and 2.0).
|
||||
@ -27,27 +27,27 @@ a different protocol operation entirely.
|
||||
Each transaction type corresponds to a functionality flag. Before calling a
|
||||
transaction function, a device driver should always check (just once) for
|
||||
the corresponding functionality flag to ensure that the underlying I2C
|
||||
adapter supports the transaction in question. See
|
||||
<file:Documentation/i2c/functionality.rst> for the details.
|
||||
adapter supports the transaction in question. See :doc:`functionality` for
|
||||
the details.
|
||||
|
||||
|
||||
Key to symbols
|
||||
==============
|
||||
|
||||
=============== =============================================================
|
||||
S (1 bit) : Start bit
|
||||
P (1 bit) : Stop bit
|
||||
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) : Accept and reverse accept bit.
|
||||
Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to
|
||||
S Start condition
|
||||
P Stop condition
|
||||
Rd/Wr (1 bit) Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) Acknowledge (ACK) and Not Acknowledge (NACK) bit
|
||||
Addr (7 bits) I2C 7 bit address. Note that this can be expanded as usual to
|
||||
get a 10 bit I2C address.
|
||||
Comm (8 bits): Command byte, a data byte which often selects a register on
|
||||
Comm (8 bits) Command byte, a data byte which often selects a register on
|
||||
the device.
|
||||
Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
Data (8 bits) A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
for 16 bit data.
|
||||
Count (8 bits): A data byte containing the length of a block operation.
|
||||
Count (8 bits) A data byte containing the length of a block operation.
|
||||
|
||||
[..]: Data sent by I2C device, as opposed to data sent by the host
|
||||
[..] Data sent by I2C device, as opposed to data sent by the host
|
||||
adapter.
|
||||
=============== =============================================================
|
||||
|
||||
@ -62,8 +62,10 @@ This sends a single bit to the device, at the place of the Rd/Wr bit::
|
||||
Functionality flag: I2C_FUNC_SMBUS_QUICK
|
||||
|
||||
|
||||
SMBus Receive Byte: i2c_smbus_read_byte()
|
||||
==========================================
|
||||
SMBus Receive Byte
|
||||
==================
|
||||
|
||||
Implemented by i2c_smbus_read_byte()
|
||||
|
||||
This reads a single byte from a device, without specifying a device
|
||||
register. Some devices are so simple that this interface is enough; for
|
||||
@ -75,8 +77,10 @@ the previous SMBus command::
|
||||
Functionality flag: I2C_FUNC_SMBUS_READ_BYTE
|
||||
|
||||
|
||||
SMBus Send Byte: i2c_smbus_write_byte()
|
||||
========================================
|
||||
SMBus Send Byte
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_write_byte()
|
||||
|
||||
This operation is the reverse of Receive Byte: it sends a single byte
|
||||
to a device. See Receive Byte for more information.
|
||||
@ -88,8 +92,10 @@ to a device. See Receive Byte for more information.
|
||||
Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE
|
||||
|
||||
|
||||
SMBus Read Byte: i2c_smbus_read_byte_data()
|
||||
============================================
|
||||
SMBus Read Byte
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_read_byte_data()
|
||||
|
||||
This reads a single byte from a device, from a designated register.
|
||||
The register is specified through the Comm byte::
|
||||
@ -99,8 +105,10 @@ The register is specified through the Comm byte::
|
||||
Functionality flag: I2C_FUNC_SMBUS_READ_BYTE_DATA
|
||||
|
||||
|
||||
SMBus Read Word: i2c_smbus_read_word_data()
|
||||
============================================
|
||||
SMBus Read Word
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_read_word_data()
|
||||
|
||||
This operation is very like Read Byte; again, data is read from a
|
||||
device, from a designated register that is specified through the Comm
|
||||
@ -110,13 +118,15 @@ byte. But this time, the data is a complete word (16 bits)::
|
||||
|
||||
Functionality flag: I2C_FUNC_SMBUS_READ_WORD_DATA
|
||||
|
||||
Note the convenience function i2c_smbus_read_word_swapped is
|
||||
Note the convenience function i2c_smbus_read_word_swapped() is
|
||||
available for reads where the two data bytes are the other way
|
||||
around (not SMBus compliant, but very popular.)
|
||||
|
||||
|
||||
SMBus Write Byte: i2c_smbus_write_byte_data()
|
||||
==============================================
|
||||
SMBus Write Byte
|
||||
================
|
||||
|
||||
Implemented by i2c_smbus_write_byte_data()
|
||||
|
||||
This writes a single byte to a device, to a designated register. The
|
||||
register is specified through the Comm byte. This is the opposite of
|
||||
@ -129,24 +139,26 @@ the Read Byte operation.
|
||||
Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE_DATA
|
||||
|
||||
|
||||
SMBus Write Word: i2c_smbus_write_word_data()
|
||||
==============================================
|
||||
SMBus Write Word
|
||||
================
|
||||
|
||||
Implemented by i2c_smbus_write_word_data()
|
||||
|
||||
This is the opposite of the Read Word operation. 16 bits
|
||||
of data is written to a device, to the designated register that is
|
||||
specified through the Comm byte.::
|
||||
of data are written to a device, to the designated register that is
|
||||
specified through the Comm byte::
|
||||
|
||||
S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
|
||||
|
||||
Functionality flag: I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
||||
|
||||
Note the convenience function i2c_smbus_write_word_swapped is
|
||||
Note the convenience function i2c_smbus_write_word_swapped() is
|
||||
available for writes where the two data bytes are the other way
|
||||
around (not SMBus compliant, but very popular.)
|
||||
|
||||
|
||||
SMBus Process Call:
|
||||
===================
|
||||
SMBus Process Call
|
||||
==================
|
||||
|
||||
This command selects a device register (through the Comm byte), sends
|
||||
16 bits of data to it, and reads 16 bits of data in return::
|
||||
@ -157,8 +169,10 @@ This command selects a device register (through the Comm byte), sends
|
||||
Functionality flag: I2C_FUNC_SMBUS_PROC_CALL
|
||||
|
||||
|
||||
SMBus Block Read: i2c_smbus_read_block_data()
|
||||
==============================================
|
||||
SMBus Block Read
|
||||
================
|
||||
|
||||
Implemented by i2c_smbus_read_block_data()
|
||||
|
||||
This command reads a block of up to 32 bytes from a device, from a
|
||||
designated register that is specified through the Comm byte. The amount
|
||||
@ -172,8 +186,10 @@ of data is specified by the device in the Count byte.
|
||||
Functionality flag: I2C_FUNC_SMBUS_READ_BLOCK_DATA
|
||||
|
||||
|
||||
SMBus Block Write: i2c_smbus_write_block_data()
|
||||
================================================
|
||||
SMBus Block Write
|
||||
=================
|
||||
|
||||
Implemented by i2c_smbus_write_block_data()
|
||||
|
||||
The opposite of the Block Read command, this writes up to 32 bytes to
|
||||
a device, to a designated register that is specified through the
|
||||
@ -266,16 +282,19 @@ This is implemented the following way in the Linux kernel:
|
||||
I2C Block Transactions
|
||||
======================
|
||||
|
||||
The following I2C block transactions are supported by the
|
||||
SMBus layer and are described here for completeness.
|
||||
They are *NOT* defined by the SMBus specification.
|
||||
The following I2C block transactions are similar to the SMBus Block Read
|
||||
and Write operations, except these do not have a Count byte. They are
|
||||
supported by the SMBus layer and are described here for completeness, but
|
||||
they are *NOT* defined by the SMBus specification.
|
||||
|
||||
I2C block transactions do not limit the number of bytes transferred
|
||||
but the SMBus layer places a limit of 32 bytes.
|
||||
|
||||
|
||||
I2C Block Read: i2c_smbus_read_i2c_block_data()
|
||||
================================================
|
||||
I2C Block Read
|
||||
==============
|
||||
|
||||
Implemented by i2c_smbus_read_i2c_block_data()
|
||||
|
||||
This command reads a block of bytes from a device, from a
|
||||
designated register that is specified through the Comm byte::
|
||||
@ -286,8 +305,10 @@ designated register that is specified through the Comm byte::
|
||||
Functionality flag: I2C_FUNC_SMBUS_READ_I2C_BLOCK
|
||||
|
||||
|
||||
I2C Block Write: i2c_smbus_write_i2c_block_data()
|
||||
==================================================
|
||||
I2C Block Write
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_write_i2c_block_data()
|
||||
|
||||
The opposite of the Block Read command, this writes bytes to
|
||||
a device, to a designated register that is specified through the
|
||||
|
@ -1,13 +1,19 @@
|
||||
=============
|
||||
I2C and SMBus
|
||||
=============
|
||||
=============================
|
||||
Introduction to I2C and SMBus
|
||||
=============================
|
||||
|
||||
I2C (pronounce: I squared C) is a protocol developed by Philips. It is a
|
||||
slow two-wire protocol (variable speed, up to 400 kHz), with a high speed
|
||||
extension (3.4 MHz). It provides an inexpensive bus for connecting many
|
||||
types of devices with infrequent or low bandwidth communications needs.
|
||||
I2C is widely used with embedded systems. Some systems use variants that
|
||||
don't meet branding requirements, and so are not advertised as being I2C.
|
||||
I²C (pronounce: I squared C and written I2C in the kernel documentation) is
|
||||
a protocol developed by Philips. It is a slow two-wire protocol (variable
|
||||
speed, up to 400 kHz), with a high speed extension (3.4 MHz). It provides
|
||||
an inexpensive bus for connecting many types of devices with infrequent or
|
||||
low bandwidth communications needs. I2C is widely used with embedded
|
||||
systems. Some systems use variants that don't meet branding requirements,
|
||||
and so are not advertised as being I2C but come under different names,
|
||||
e.g. TWI (Two Wire Interface), IIC.
|
||||
|
||||
The official I2C specification is the `"I2C-bus specification and user
|
||||
manual" (UM10204) <https://www.nxp.com/docs/en/user-guide/UM10204.pdf>`_
|
||||
published by NXP Semiconductors.
|
||||
|
||||
SMBus (System Management Bus) is based on the I2C protocol, and is mostly
|
||||
a subset of I2C protocols and signaling. Many I2C devices will work on an
|
||||
@ -25,21 +31,29 @@ implement all the common SMBus protocol semantics or messages.
|
||||
Terminology
|
||||
===========
|
||||
|
||||
When we talk about I2C, we use the following terms::
|
||||
Using the terminology from the official documentation, the I2C bus connects
|
||||
one or more *master* chips and one or more *slave* chips.
|
||||
|
||||
Bus -> Algorithm
|
||||
Adapter
|
||||
Device -> Driver
|
||||
Client
|
||||
.. kernel-figure:: i2c.svg
|
||||
:alt: Simple I2C bus with one master and 3 slaves
|
||||
|
||||
An Algorithm driver contains general code that can be used for a whole class
|
||||
of I2C adapters. Each specific adapter driver either depends on one algorithm
|
||||
driver, or includes its own implementation.
|
||||
Simple I2C bus
|
||||
|
||||
A Driver driver (yes, this sounds ridiculous, sorry) contains the general
|
||||
code to access some type of device. Each detected device gets its own
|
||||
data in the Client structure. Usually, Driver and Client are more closely
|
||||
integrated than Algorithm and Adapter.
|
||||
A **master** chip is a node that starts communications with slaves. In the
|
||||
Linux kernel implementation it is called an **adapter** or bus. Adapter
|
||||
drivers are in the ``drivers/i2c/busses/`` subdirectory.
|
||||
|
||||
For a given configuration, you will need a driver for your I2C bus, and
|
||||
drivers for your I2C devices (usually one driver for each device).
|
||||
An **algorithm** contains general code that can be used to implement a
|
||||
whole class of I2C adapters. Each specific adapter driver either depends on
|
||||
an algorithm driver in the ``drivers/i2c/algos/`` subdirectory, or includes
|
||||
its own implementation.
|
||||
|
||||
A **slave** chip is a node that responds to communications when addressed
|
||||
by the master. In Linux it is called a **client**. Client drivers are kept
|
||||
in a directory specific to the feature they provide, for example
|
||||
``drivers/media/gpio/`` for GPIO expanders and ``drivers/media/i2c/`` for
|
||||
video-related chips.
|
||||
|
||||
For the example configuration in figure, you will need a driver for your
|
||||
I2C adapter, and drivers for your I2C devices (usually one driver for each
|
||||
device).
|
||||
|
@ -1,6 +1,6 @@
|
||||
===================
|
||||
Writing I2C Clients
|
||||
===================
|
||||
===============================
|
||||
Implementing I2C device drivers
|
||||
===============================
|
||||
|
||||
This is a small guide for those who want to write kernel drivers for I2C
|
||||
or SMBus devices, using Linux as the protocol host/master (not slave).
|
||||
@ -95,7 +95,7 @@ to gather information from the client, or write new information to the
|
||||
client.
|
||||
|
||||
I have found it useful to define foo_read and foo_write functions for this.
|
||||
For some cases, it will be easier to call the i2c functions directly,
|
||||
For some cases, it will be easier to call the I2C functions directly,
|
||||
but many chips have some kind of register-value idea that can easily
|
||||
be encapsulated.
|
||||
|
||||
@ -175,8 +175,8 @@ Device Creation
|
||||
If you know for a fact that an I2C device is connected to a given I2C bus,
|
||||
you can instantiate that device by simply filling an i2c_board_info
|
||||
structure with the device address and driver name, and calling
|
||||
i2c_new_device(). This will create the device, then the driver core will
|
||||
take care of finding the right driver and will call its probe() method.
|
||||
i2c_new_client_device(). This will create the device, then the driver core
|
||||
will take care of finding the right driver and will call its probe() method.
|
||||
If a driver supports different device types, you can specify the type you
|
||||
want using the type field. You can also specify an IRQ and platform data
|
||||
if needed.
|
||||
@ -186,14 +186,14 @@ don't know the exact address it uses. This happens on TV adapters for
|
||||
example, where the same driver supports dozens of slightly different
|
||||
models, and I2C device addresses change from one model to the next. In
|
||||
that case, you can use the i2c_new_scanned_device() variant, which is
|
||||
similar to i2c_new_device(), except that it takes an additional list of
|
||||
possible I2C addresses to probe. A device is created for the first
|
||||
similar to i2c_new_client_device(), except that it takes an additional list
|
||||
of possible I2C addresses to probe. A device is created for the first
|
||||
responsive address in the list. If you expect more than one device to be
|
||||
present in the address range, simply call i2c_new_scanned_device() that
|
||||
many times.
|
||||
|
||||
The call to i2c_new_device() or i2c_new_scanned_device() typically happens
|
||||
in the I2C bus driver. You may want to save the returned i2c_client
|
||||
The call to i2c_new_client_device() or i2c_new_scanned_device() typically
|
||||
happens in the I2C bus driver. You may want to save the returned i2c_client
|
||||
reference for later use.
|
||||
|
||||
|
||||
@ -236,11 +236,11 @@ possible.
|
||||
Device Deletion
|
||||
---------------
|
||||
|
||||
Each I2C device which has been created using i2c_new_device() or
|
||||
i2c_new_scanned_device() can be unregistered by calling
|
||||
Each I2C device which has been created using i2c_new_client_device()
|
||||
or i2c_new_scanned_device() can be unregistered by calling
|
||||
i2c_unregister_device(). If you don't call it explicitly, it will be
|
||||
called automatically before the underlying I2C bus itself is removed, as a
|
||||
device can't survive its parent in the device driver model.
|
||||
called automatically before the underlying I2C bus itself is removed,
|
||||
as a device can't survive its parent in the device driver model.
|
||||
|
||||
|
||||
Initializing the driver
|
||||
@ -344,7 +344,7 @@ Plain I2C communication
|
||||
int i2c_master_recv(struct i2c_client *client, char *buf, int count);
|
||||
|
||||
These routines read and write some bytes from/to a client. The client
|
||||
contains the i2c address, so you do not have to include it. The second
|
||||
contains the I2C address, so you do not have to include it. The second
|
||||
parameter contains the bytes to read/write, the third the number of bytes
|
||||
to read/write (must be less than the length of the buffer, also should be
|
||||
less than 64k since msg.len is u16.) Returned is the actual number of bytes
|
||||
@ -357,9 +357,9 @@ read/written.
|
||||
|
||||
This sends a series of messages. Each message can be a read or write,
|
||||
and they can be mixed in any way. The transactions are combined: no
|
||||
stop bit is sent between transaction. The i2c_msg structure contains
|
||||
for each message the client address, the number of bytes of the message
|
||||
and the message data itself.
|
||||
stop condition is issued between transaction. The i2c_msg structure
|
||||
contains for each message the client address, the number of bytes of the
|
||||
message and the message data itself.
|
||||
|
||||
You can read the file ``i2c-protocol`` for more information about the
|
||||
actual I2C protocol.
|
||||
|
@ -25,9 +25,9 @@ worry about UP vs SMP issues: the spinlocks work correctly under both.
|
||||
|
||||
Documentation/memory-barriers.txt
|
||||
|
||||
(5) LOCK operations.
|
||||
(5) ACQUIRE operations.
|
||||
|
||||
(6) UNLOCK operations.
|
||||
(6) RELEASE operations.
|
||||
|
||||
The above is usually pretty simple (you usually need and want only one
|
||||
spinlock for most things - using more than one spinlock can make things a
|
||||
|
@ -1,79 +0,0 @@
|
||||
===========================================
|
||||
Power Management Interface for System Sleep
|
||||
===========================================
|
||||
|
||||
Copyright (c) 2016 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
|
||||
The power management subsystem provides userspace with a unified sysfs interface
|
||||
for system sleep regardless of the underlying system architecture or platform.
|
||||
The interface is located in the /sys/power/ directory (assuming that sysfs is
|
||||
mounted at /sys).
|
||||
|
||||
/sys/power/state is the system sleep state control file.
|
||||
|
||||
Reading from it returns a list of supported sleep states, encoded as:
|
||||
|
||||
- 'freeze' (Suspend-to-Idle)
|
||||
- 'standby' (Power-On Suspend)
|
||||
- 'mem' (Suspend-to-RAM)
|
||||
- 'disk' (Suspend-to-Disk)
|
||||
|
||||
Suspend-to-Idle is always supported. Suspend-to-Disk is always supported
|
||||
too as long the kernel has been configured to support hibernation at all
|
||||
(ie. CONFIG_HIBERNATION is set in the kernel configuration file). Support
|
||||
for Suspend-to-RAM and Power-On Suspend depends on the capabilities of the
|
||||
platform.
|
||||
|
||||
If one of the strings listed in /sys/power/state is written to it, the system
|
||||
will attempt to transition into the corresponding sleep state. Refer to
|
||||
Documentation/admin-guide/pm/sleep-states.rst for a description of each of
|
||||
those states.
|
||||
|
||||
/sys/power/disk controls the operating mode of hibernation (Suspend-to-Disk).
|
||||
Specifically, it tells the kernel what to do after creating a hibernation image.
|
||||
|
||||
Reading from it returns a list of supported options encoded as:
|
||||
|
||||
- 'platform' (put the system into sleep using a platform-provided method)
|
||||
- 'shutdown' (shut the system down)
|
||||
- 'reboot' (reboot the system)
|
||||
- 'suspend' (trigger a Suspend-to-RAM transition)
|
||||
- 'test_resume' (resume-after-hibernation test mode)
|
||||
|
||||
The currently selected option is printed in square brackets.
|
||||
|
||||
The 'platform' option is only available if the platform provides a special
|
||||
mechanism to put the system to sleep after creating a hibernation image (ACPI
|
||||
does that, for example). The 'suspend' option is available if Suspend-to-RAM
|
||||
is supported. Refer to Documentation/power/basic-pm-debugging.rst for the
|
||||
description of the 'test_resume' option.
|
||||
|
||||
To select an option, write the string representing it to /sys/power/disk.
|
||||
|
||||
/sys/power/image_size controls the size of hibernation images.
|
||||
|
||||
It can be written a string representing a non-negative integer that will be
|
||||
used as a best-effort upper limit of the image size, in bytes. The hibernation
|
||||
core will do its best to ensure that the image size will not exceed that number.
|
||||
However, if that turns out to be impossible to achieve, a hibernation image will
|
||||
still be created and its size will be as small as possible. In particular,
|
||||
writing '0' to this file will enforce hibernation images to be as small as
|
||||
possible.
|
||||
|
||||
Reading from this file returns the current image size limit, which is set to
|
||||
around 2/5 of available RAM by default.
|
||||
|
||||
/sys/power/pm_trace controls the PM trace mechanism saving the last suspend
|
||||
or resume event point in the RTC across reboots.
|
||||
|
||||
It helps to debug hard lockups or reboots due to device driver failures that
|
||||
occur during system suspend or resume (which is more common) more effectively.
|
||||
|
||||
If /sys/power/pm_trace contains '1', the fingerprint of each suspend/resume
|
||||
event point in turn will be stored in the RTC memory (overwriting the actual
|
||||
RTC information), so it will survive a system crash if one occurs right after
|
||||
storing it and it can be used later to identify the driver that caused the crash
|
||||
to happen (see Documentation/power/s2ram.rst for more information).
|
||||
|
||||
Initially it contains '0' which may be changed to '1' by writing a string
|
||||
representing a nonzero integer into it.
|
@ -383,7 +383,8 @@ Mkinitrd
|
||||
E2fsprogs
|
||||
---------
|
||||
|
||||
- <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.29.tar.gz>
|
||||
- <https://www.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/>
|
||||
- <https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/>
|
||||
|
||||
JFSutils
|
||||
--------
|
||||
@ -393,12 +394,13 @@ JFSutils
|
||||
Reiserfsprogs
|
||||
-------------
|
||||
|
||||
- <http://www.kernel.org/pub/linux/utils/fs/reiserfs/>
|
||||
- <https://git.kernel.org/pub/scm/linux/kernel/git/jeffm/reiserfsprogs.git/>
|
||||
|
||||
Xfsprogs
|
||||
--------
|
||||
|
||||
- <ftp://oss.sgi.com/projects/xfs/>
|
||||
- <https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git>
|
||||
- <https://www.kernel.org/pub/linux/utils/fs/xfs/xfsprogs/>
|
||||
|
||||
Pcmciautils
|
||||
-----------
|
||||
@ -437,7 +439,9 @@ Networking
|
||||
PPP
|
||||
---
|
||||
|
||||
- <ftp://ftp.samba.org/pub/ppp/>
|
||||
- <https://download.samba.org/pub/ppp/>
|
||||
- <https://git.ozlabs.org/?p=ppp.git>
|
||||
- <https://github.com/paulusmack/ppp/>
|
||||
|
||||
NFS-utils
|
||||
---------
|
||||
@ -447,7 +451,7 @@ NFS-utils
|
||||
Iptables
|
||||
--------
|
||||
|
||||
- <http://www.iptables.org/downloads.html>
|
||||
- <https://netfilter.org/projects/iptables/index.html>
|
||||
|
||||
Ip-route2
|
||||
---------
|
||||
|
184
Documentation/trace/boottime-trace.rst
Normal file
184
Documentation/trace/boottime-trace.rst
Normal file
@ -0,0 +1,184 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=================
|
||||
Boot-time tracing
|
||||
=================
|
||||
|
||||
:Author: Masami Hiramatsu <mhiramat@kernel.org>
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
Boot-time tracing allows users to trace boot-time process including
|
||||
device initialization with full features of ftrace including per-event
|
||||
filter and actions, histograms, kprobe-events and synthetic-events,
|
||||
and trace instances.
|
||||
Since kernel command line is not enough to control these complex features,
|
||||
this uses bootconfig file to describe tracing feature programming.
|
||||
|
||||
Options in the Boot Config
|
||||
==========================
|
||||
|
||||
Here is the list of available options list for boot time tracing in
|
||||
boot config file [1]_. All options are under "ftrace." or "kernel."
|
||||
prefix. See kernel parameters for the options which starts
|
||||
with "kernel." prefix [2]_.
|
||||
|
||||
.. [1] See :ref:`Documentation/admin-guide/bootconfig.rst <bootconfig>`
|
||||
.. [2] See :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>`
|
||||
|
||||
Ftrace Global Options
|
||||
---------------------
|
||||
|
||||
Ftrace global options have "kernel." prefix in boot config, which means
|
||||
these options are passed as a part of kernel legacy command line.
|
||||
|
||||
kernel.tp_printk
|
||||
Output trace-event data on printk buffer too.
|
||||
|
||||
kernel.dump_on_oops [= MODE]
|
||||
Dump ftrace on Oops. If MODE = 1 or omitted, dump trace buffer
|
||||
on all CPUs. If MODE = 2, dump a buffer on a CPU which kicks Oops.
|
||||
|
||||
kernel.traceoff_on_warning
|
||||
Stop tracing if WARN_ON() occurs.
|
||||
|
||||
kernel.fgraph_max_depth = MAX_DEPTH
|
||||
Set MAX_DEPTH to maximum depth of fgraph tracer.
|
||||
|
||||
kernel.fgraph_filters = FILTER[, FILTER2...]
|
||||
Add fgraph tracing function filters.
|
||||
|
||||
kernel.fgraph_notraces = FILTER[, FILTER2...]
|
||||
Add fgraph non-tracing function filters.
|
||||
|
||||
|
||||
Ftrace Per-instance Options
|
||||
---------------------------
|
||||
|
||||
These options can be used for each instance including global ftrace node.
|
||||
|
||||
ftrace.[instance.INSTANCE.]options = OPT1[, OPT2[...]]
|
||||
Enable given ftrace options.
|
||||
|
||||
ftrace.[instance.INSTANCE.]trace_clock = CLOCK
|
||||
Set given CLOCK to ftrace's trace_clock.
|
||||
|
||||
ftrace.[instance.INSTANCE.]buffer_size = SIZE
|
||||
Configure ftrace buffer size to SIZE. You can use "KB" or "MB"
|
||||
for that SIZE.
|
||||
|
||||
ftrace.[instance.INSTANCE.]alloc_snapshot
|
||||
Allocate snapshot buffer.
|
||||
|
||||
ftrace.[instance.INSTANCE.]cpumask = CPUMASK
|
||||
Set CPUMASK as trace cpu-mask.
|
||||
|
||||
ftrace.[instance.INSTANCE.]events = EVENT[, EVENT2[...]]
|
||||
Enable given events on boot. You can use a wild card in EVENT.
|
||||
|
||||
ftrace.[instance.INSTANCE.]tracer = TRACER
|
||||
Set TRACER to current tracer on boot. (e.g. function)
|
||||
|
||||
ftrace.[instance.INSTANCE.]ftrace.filters
|
||||
This will take an array of tracing function filter rules.
|
||||
|
||||
ftrace.[instance.INSTANCE.]ftrace.notraces
|
||||
This will take an array of NON-tracing function filter rules.
|
||||
|
||||
|
||||
Ftrace Per-Event Options
|
||||
------------------------
|
||||
|
||||
These options are setting per-event options.
|
||||
|
||||
ftrace.[instance.INSTANCE.]event.GROUP.EVENT.enable
|
||||
Enable GROUP:EVENT tracing.
|
||||
|
||||
ftrace.[instance.INSTANCE.]event.GROUP.EVENT.filter = FILTER
|
||||
Set FILTER rule to the GROUP:EVENT.
|
||||
|
||||
ftrace.[instance.INSTANCE.]event.GROUP.EVENT.actions = ACTION[, ACTION2[...]]
|
||||
Set ACTIONs to the GROUP:EVENT.
|
||||
|
||||
ftrace.[instance.INSTANCE.]event.kprobes.EVENT.probes = PROBE[, PROBE2[...]]
|
||||
Defines new kprobe event based on PROBEs. It is able to define
|
||||
multiple probes on one event, but those must have same type of
|
||||
arguments. This option is available only for the event which
|
||||
group name is "kprobes".
|
||||
|
||||
ftrace.[instance.INSTANCE.]event.synthetic.EVENT.fields = FIELD[, FIELD2[...]]
|
||||
Defines new synthetic event with FIELDs. Each field should be
|
||||
"type varname".
|
||||
|
||||
Note that kprobe and synthetic event definitions can be written under
|
||||
instance node, but those are also visible from other instances. So please
|
||||
take care for event name conflict.
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
For example, to add filter and actions for each event, define kprobe
|
||||
events, and synthetic events with histogram, write a boot config like
|
||||
below::
|
||||
|
||||
ftrace.event {
|
||||
task.task_newtask {
|
||||
filter = "pid < 128"
|
||||
enable
|
||||
}
|
||||
kprobes.vfs_read {
|
||||
probes = "vfs_read $arg1 $arg2"
|
||||
filter = "common_pid < 200"
|
||||
enable
|
||||
}
|
||||
synthetic.initcall_latency {
|
||||
fields = "unsigned long func", "u64 lat"
|
||||
actions = "hist:keys=func.sym,lat:vals=lat:sort=lat"
|
||||
}
|
||||
initcall.initcall_start {
|
||||
actions = "hist:keys=func:ts0=common_timestamp.usecs"
|
||||
}
|
||||
initcall.initcall_finish {
|
||||
actions = "hist:keys=func:lat=common_timestamp.usecs-$ts0:onmatch(initcall.initcall_start).initcall_latency(func,$lat)"
|
||||
}
|
||||
}
|
||||
|
||||
Also, boot-time tracing supports "instance" node, which allows us to run
|
||||
several tracers for different purpose at once. For example, one tracer
|
||||
is for tracing functions starting with "user\_", and others tracing
|
||||
"kernel\_" functions, you can write boot config as below::
|
||||
|
||||
ftrace.instance {
|
||||
foo {
|
||||
tracer = "function"
|
||||
ftrace.filters = "user_*"
|
||||
}
|
||||
bar {
|
||||
tracer = "function"
|
||||
ftrace.filters = "kernel_*"
|
||||
}
|
||||
}
|
||||
|
||||
The instance node also accepts event nodes so that each instance
|
||||
can customize its event tracing.
|
||||
|
||||
This boot-time tracing also supports ftrace kernel parameters via boot
|
||||
config.
|
||||
For example, following kernel parameters::
|
||||
|
||||
trace_options=sym-addr trace_event=initcall:* tp_printk trace_buf_size=1M ftrace=function ftrace_filter="vfs*"
|
||||
|
||||
This can be written in boot config like below::
|
||||
|
||||
kernel {
|
||||
trace_options = sym-addr
|
||||
trace_event = "initcall:*"
|
||||
tp_printk
|
||||
trace_buf_size = 1M
|
||||
ftrace = function
|
||||
ftrace_filter = "vfs*"
|
||||
}
|
||||
|
||||
Note that parameters start with "kernel" prefix instead of "ftrace".
|
@ -525,3 +525,518 @@ The following commands are supported:
|
||||
event counts (hitcount).
|
||||
|
||||
See Documentation/trace/histogram.rst for details and examples.
|
||||
|
||||
6.3 In-kernel trace event API
|
||||
-----------------------------
|
||||
|
||||
In most cases, the command-line interface to trace events is more than
|
||||
sufficient. Sometimes, however, applications might find the need for
|
||||
more complex relationships than can be expressed through a simple
|
||||
series of linked command-line expressions, or putting together sets of
|
||||
commands may be simply too cumbersome. An example might be an
|
||||
application that needs to 'listen' to the trace stream in order to
|
||||
maintain an in-kernel state machine detecting, for instance, when an
|
||||
illegal kernel state occurs in the scheduler.
|
||||
|
||||
The trace event subsystem provides an in-kernel API allowing modules
|
||||
or other kernel code to generate user-defined 'synthetic' events at
|
||||
will, which can be used to either augment the existing trace stream
|
||||
and/or signal that a particular important state has occurred.
|
||||
|
||||
A similar in-kernel API is also available for creating kprobe and
|
||||
kretprobe events.
|
||||
|
||||
Both the synthetic event and k/ret/probe event APIs are built on top
|
||||
of a lower-level "dynevent_cmd" event command API, which is also
|
||||
available for more specialized applications, or as the basis of other
|
||||
higher-level trace event APIs.
|
||||
|
||||
The API provided for these purposes is describe below and allows the
|
||||
following:
|
||||
|
||||
- dynamically creating synthetic event definitions
|
||||
- dynamically creating kprobe and kretprobe event definitions
|
||||
- tracing synthetic events from in-kernel code
|
||||
- the low-level "dynevent_cmd" API
|
||||
|
||||
6.3.1 Dyamically creating synthetic event definitions
|
||||
-----------------------------------------------------
|
||||
|
||||
There are a couple ways to create a new synthetic event from a kernel
|
||||
module or other kernel code.
|
||||
|
||||
The first creates the event in one step, using synth_event_create().
|
||||
In this method, the name of the event to create and an array defining
|
||||
the fields is supplied to synth_event_create(). If successful, a
|
||||
synthetic event with that name and fields will exist following that
|
||||
call. For example, to create a new "schedtest" synthetic event:
|
||||
|
||||
ret = synth_event_create("schedtest", sched_fields,
|
||||
ARRAY_SIZE(sched_fields), THIS_MODULE);
|
||||
|
||||
The sched_fields param in this example points to an array of struct
|
||||
synth_field_desc, each of which describes an event field by type and
|
||||
name:
|
||||
|
||||
static struct synth_field_desc sched_fields[] = {
|
||||
{ .type = "pid_t", .name = "next_pid_field" },
|
||||
{ .type = "char[16]", .name = "next_comm_field" },
|
||||
{ .type = "u64", .name = "ts_ns" },
|
||||
{ .type = "u64", .name = "ts_ms" },
|
||||
{ .type = "unsigned int", .name = "cpu" },
|
||||
{ .type = "char[64]", .name = "my_string_field" },
|
||||
{ .type = "int", .name = "my_int_field" },
|
||||
};
|
||||
|
||||
See synth_field_size() for available types. If field_name contains [n]
|
||||
the field is considered to be an array.
|
||||
|
||||
If the event is created from within a module, a pointer to the module
|
||||
must be passed to synth_event_create(). This will ensure that the
|
||||
trace buffer won't contain unreadable events when the module is
|
||||
removed.
|
||||
|
||||
At this point, the event object is ready to be used for generating new
|
||||
events.
|
||||
|
||||
In the second method, the event is created in several steps. This
|
||||
allows events to be created dynamically and without the need to create
|
||||
and populate an array of fields beforehand.
|
||||
|
||||
To use this method, an empty or partially empty synthetic event should
|
||||
first be created using synth_event_gen_cmd_start() or
|
||||
synth_event_gen_cmd_array_start(). For synth_event_gen_cmd_start(),
|
||||
the name of the event along with one or more pairs of args each pair
|
||||
representing a 'type field_name;' field specification should be
|
||||
supplied. For synth_event_gen_cmd_array_start(), the name of the
|
||||
event along with an array of struct synth_field_desc should be
|
||||
supplied. Before calling synth_event_gen_cmd_start() or
|
||||
synth_event_gen_cmd_array_start(), the user should create and
|
||||
initialize a dynevent_cmd object using synth_event_cmd_init().
|
||||
|
||||
For example, to create a new "schedtest" synthetic event with two
|
||||
fields:
|
||||
|
||||
struct dynevent_cmd cmd;
|
||||
char *buf;
|
||||
|
||||
/* Create a buffer to hold the generated command */
|
||||
buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
|
||||
|
||||
/* Before generating the command, initialize the cmd object */
|
||||
synth_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
|
||||
|
||||
ret = synth_event_gen_cmd_start(&cmd, "schedtest", THIS_MODULE,
|
||||
"pid_t", "next_pid_field",
|
||||
"u64", "ts_ns");
|
||||
|
||||
Alternatively, using an array of struct synth_field_desc fields
|
||||
containing the same information:
|
||||
|
||||
ret = synth_event_gen_cmd_array_start(&cmd, "schedtest", THIS_MODULE,
|
||||
fields, n_fields);
|
||||
|
||||
Once the synthetic event object has been created, it can then be
|
||||
populated with more fields. Fields are added one by one using
|
||||
synth_event_add_field(), supplying the dynevent_cmd object, a field
|
||||
type, and a field name. For example, to add a new int field named
|
||||
"intfield", the following call should be made:
|
||||
|
||||
ret = synth_event_add_field(&cmd, "int", "intfield");
|
||||
|
||||
See synth_field_size() for available types. If field_name contains [n]
|
||||
the field is considered to be an array.
|
||||
|
||||
A group of fields can also be added all at once using an array of
|
||||
synth_field_desc with add_synth_fields(). For example, this would add
|
||||
just the first four sched_fields:
|
||||
|
||||
ret = synth_event_add_fields(&cmd, sched_fields, 4);
|
||||
|
||||
If you already have a string of the form 'type field_name',
|
||||
synth_event_add_field_str() can be used to add it as-is; it will
|
||||
also automatically append a ';' to the string.
|
||||
|
||||
Once all the fields have been added, the event should be finalized and
|
||||
registered by calling the synth_event_gen_cmd_end() function:
|
||||
|
||||
ret = synth_event_gen_cmd_end(&cmd);
|
||||
|
||||
At this point, the event object is ready to be used for tracing new
|
||||
events.
|
||||
|
||||
6.3.3 Tracing synthetic events from in-kernel code
|
||||
--------------------------------------------------
|
||||
|
||||
To trace a synthetic event, there are several options. The first
|
||||
option is to trace the event in one call, using synth_event_trace()
|
||||
with a variable number of values, or synth_event_trace_array() with an
|
||||
array of values to be set. A second option can be used to avoid the
|
||||
need for a pre-formed array of values or list of arguments, via
|
||||
synth_event_trace_start() and synth_event_trace_end() along with
|
||||
synth_event_add_next_val() or synth_event_add_val() to add the values
|
||||
piecewise.
|
||||
|
||||
6.3.3.1 Tracing a synthetic event all at once
|
||||
---------------------------------------------
|
||||
|
||||
To trace a synthetic event all at once, the synth_event_trace() or
|
||||
synth_event_trace_array() functions can be used.
|
||||
|
||||
The synth_event_trace() function is passed the trace_event_file
|
||||
representing the synthetic event (which can be retrieved using
|
||||
trace_get_event_file() using the synthetic event name, "synthetic" as
|
||||
the system name, and the trace instance name (NULL if using the global
|
||||
trace array)), along with an variable number of u64 args, one for each
|
||||
synthetic event field, and the number of values being passed.
|
||||
|
||||
So, to trace an event corresponding to the synthetic event definition
|
||||
above, code like the following could be used:
|
||||
|
||||
ret = synth_event_trace(create_synth_test, 7, /* number of values */
|
||||
444, /* next_pid_field */
|
||||
(u64)"clackers", /* next_comm_field */
|
||||
1000000, /* ts_ns */
|
||||
1000, /* ts_ms */
|
||||
smp_processor_id(),/* cpu */
|
||||
(u64)"Thneed", /* my_string_field */
|
||||
999); /* my_int_field */
|
||||
|
||||
All vals should be cast to u64, and string vals are just pointers to
|
||||
strings, cast to u64. Strings will be copied into space reserved in
|
||||
the event for the string, using these pointers.
|
||||
|
||||
Alternatively, the synth_event_trace_array() function can be used to
|
||||
accomplish the same thing. It is passed the trace_event_file
|
||||
representing the synthetic event (which can be retrieved using
|
||||
trace_get_event_file() using the synthetic event name, "synthetic" as
|
||||
the system name, and the trace instance name (NULL if using the global
|
||||
trace array)), along with an array of u64, one for each synthetic
|
||||
event field.
|
||||
|
||||
To trace an event corresponding to the synthetic event definition
|
||||
above, code like the following could be used:
|
||||
|
||||
u64 vals[7];
|
||||
|
||||
vals[0] = 777; /* next_pid_field */
|
||||
vals[1] = (u64)"tiddlywinks"; /* next_comm_field */
|
||||
vals[2] = 1000000; /* ts_ns */
|
||||
vals[3] = 1000; /* ts_ms */
|
||||
vals[4] = smp_processor_id(); /* cpu */
|
||||
vals[5] = (u64)"thneed"; /* my_string_field */
|
||||
vals[6] = 398; /* my_int_field */
|
||||
|
||||
The 'vals' array is just an array of u64, the number of which must
|
||||
match the number of field in the synthetic event, and which must be in
|
||||
the same order as the synthetic event fields.
|
||||
|
||||
All vals should be cast to u64, and string vals are just pointers to
|
||||
strings, cast to u64. Strings will be copied into space reserved in
|
||||
the event for the string, using these pointers.
|
||||
|
||||
In order to trace a synthetic event, a pointer to the trace event file
|
||||
is needed. The trace_get_event_file() function can be used to get
|
||||
it - it will find the file in the given trace instance (in this case
|
||||
NULL since the top trace array is being used) while at the same time
|
||||
preventing the instance containing it from going away:
|
||||
|
||||
schedtest_event_file = trace_get_event_file(NULL, "synthetic",
|
||||
"schedtest");
|
||||
|
||||
Before tracing the event, it should be enabled in some way, otherwise
|
||||
the synthetic event won't actually show up in the trace buffer.
|
||||
|
||||
To enable a synthetic event from the kernel, trace_array_set_clr_event()
|
||||
can be used (which is not specific to synthetic events, so does need
|
||||
the "synthetic" system name to be specified explicitly).
|
||||
|
||||
To enable the event, pass 'true' to it:
|
||||
|
||||
trace_array_set_clr_event(schedtest_event_file->tr,
|
||||
"synthetic", "schedtest", true);
|
||||
|
||||
To disable it pass false:
|
||||
|
||||
trace_array_set_clr_event(schedtest_event_file->tr,
|
||||
"synthetic", "schedtest", false);
|
||||
|
||||
Finally, synth_event_trace_array() can be used to actually trace the
|
||||
event, which should be visible in the trace buffer afterwards:
|
||||
|
||||
ret = synth_event_trace_array(schedtest_event_file, vals,
|
||||
ARRAY_SIZE(vals));
|
||||
|
||||
To remove the synthetic event, the event should be disabled, and the
|
||||
trace instance should be 'put' back using trace_put_event_file():
|
||||
|
||||
trace_array_set_clr_event(schedtest_event_file->tr,
|
||||
"synthetic", "schedtest", false);
|
||||
trace_put_event_file(schedtest_event_file);
|
||||
|
||||
If those have been successful, synth_event_delete() can be called to
|
||||
remove the event:
|
||||
|
||||
ret = synth_event_delete("schedtest");
|
||||
|
||||
6.3.3.1 Tracing a synthetic event piecewise
|
||||
-------------------------------------------
|
||||
|
||||
To trace a synthetic using the piecewise method described above, the
|
||||
synth_event_trace_start() function is used to 'open' the synthetic
|
||||
event trace:
|
||||
|
||||
struct synth_trace_state trace_state;
|
||||
|
||||
ret = synth_event_trace_start(schedtest_event_file, &trace_state);
|
||||
|
||||
It's passed the trace_event_file representing the synthetic event
|
||||
using the same methods as described above, along with a pointer to a
|
||||
struct synth_trace_state object, which will be zeroed before use and
|
||||
used to maintain state between this and following calls.
|
||||
|
||||
Once the event has been opened, which means space for it has been
|
||||
reserved in the trace buffer, the individual fields can be set. There
|
||||
are two ways to do that, either one after another for each field in
|
||||
the event, which requires no lookups, or by name, which does. The
|
||||
tradeoff is flexibility in doing the assignments vs the cost of a
|
||||
lookup per field.
|
||||
|
||||
To assign the values one after the other without lookups,
|
||||
synth_event_add_next_val() should be used. Each call is passed the
|
||||
same synth_trace_state object used in the synth_event_trace_start(),
|
||||
along with the value to set the next field in the event. After each
|
||||
field is set, the 'cursor' points to the next field, which will be set
|
||||
by the subsequent call, continuing until all the fields have been set
|
||||
in order. The same sequence of calls as in the above examples using
|
||||
this method would be (without error-handling code):
|
||||
|
||||
/* next_pid_field */
|
||||
ret = synth_event_add_next_val(777, &trace_state);
|
||||
|
||||
/* next_comm_field */
|
||||
ret = synth_event_add_next_val((u64)"slinky", &trace_state);
|
||||
|
||||
/* ts_ns */
|
||||
ret = synth_event_add_next_val(1000000, &trace_state);
|
||||
|
||||
/* ts_ms */
|
||||
ret = synth_event_add_next_val(1000, &trace_state);
|
||||
|
||||
/* cpu */
|
||||
ret = synth_event_add_next_val(smp_processor_id(), &trace_state);
|
||||
|
||||
/* my_string_field */
|
||||
ret = synth_event_add_next_val((u64)"thneed_2.01", &trace_state);
|
||||
|
||||
/* my_int_field */
|
||||
ret = synth_event_add_next_val(395, &trace_state);
|
||||
|
||||
To assign the values in any order, synth_event_add_val() should be
|
||||
used. Each call is passed the same synth_trace_state object used in
|
||||
the synth_event_trace_start(), along with the field name of the field
|
||||
to set and the value to set it to. The same sequence of calls as in
|
||||
the above examples using this method would be (without error-handling
|
||||
code):
|
||||
|
||||
ret = synth_event_add_val("next_pid_field", 777, &trace_state);
|
||||
ret = synth_event_add_val("next_comm_field", (u64)"silly putty",
|
||||
&trace_state);
|
||||
ret = synth_event_add_val("ts_ns", 1000000, &trace_state);
|
||||
ret = synth_event_add_val("ts_ms", 1000, &trace_state);
|
||||
ret = synth_event_add_val("cpu", smp_processor_id(), &trace_state);
|
||||
ret = synth_event_add_val("my_string_field", (u64)"thneed_9",
|
||||
&trace_state);
|
||||
ret = synth_event_add_val("my_int_field", 3999, &trace_state);
|
||||
|
||||
Note that synth_event_add_next_val() and synth_event_add_val() are
|
||||
incompatible if used within the same trace of an event - either one
|
||||
can be used but not both at the same time.
|
||||
|
||||
Finally, the event won't be actually traced until it's 'closed',
|
||||
which is done using synth_event_trace_end(), which takes only the
|
||||
struct synth_trace_state object used in the previous calls:
|
||||
|
||||
ret = synth_event_trace_end(&trace_state);
|
||||
|
||||
Note that synth_event_trace_end() must be called at the end regardless
|
||||
of whether any of the add calls failed (say due to a bad field name
|
||||
being passed in).
|
||||
|
||||
6.3.4 Dyamically creating kprobe and kretprobe event definitions
|
||||
----------------------------------------------------------------
|
||||
|
||||
To create a kprobe or kretprobe trace event from kernel code, the
|
||||
kprobe_event_gen_cmd_start() or kretprobe_event_gen_cmd_start()
|
||||
functions can be used.
|
||||
|
||||
To create a kprobe event, an empty or partially empty kprobe event
|
||||
should first be created using kprobe_event_gen_cmd_start(). The name
|
||||
of the event and the probe location should be specfied along with one
|
||||
or args each representing a probe field should be supplied to this
|
||||
function. Before calling kprobe_event_gen_cmd_start(), the user
|
||||
should create and initialize a dynevent_cmd object using
|
||||
kprobe_event_cmd_init().
|
||||
|
||||
For example, to create a new "schedtest" kprobe event with two fields:
|
||||
|
||||
struct dynevent_cmd cmd;
|
||||
char *buf;
|
||||
|
||||
/* Create a buffer to hold the generated command */
|
||||
buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
|
||||
|
||||
/* Before generating the command, initialize the cmd object */
|
||||
kprobe_event_cmd_init(&cmd, buf, MAX_DYNEVENT_CMD_LEN);
|
||||
|
||||
/*
|
||||
* Define the gen_kprobe_test event with the first 2 kprobe
|
||||
* fields.
|
||||
*/
|
||||
ret = kprobe_event_gen_cmd_start(&cmd, "gen_kprobe_test", "do_sys_open",
|
||||
"dfd=%ax", "filename=%dx");
|
||||
|
||||
Once the kprobe event object has been created, it can then be
|
||||
populated with more fields. Fields can be added using
|
||||
kprobe_event_add_fields(), supplying the dynevent_cmd object along
|
||||
with a variable arg list of probe fields. For example, to add a
|
||||
couple additional fields, the following call could be made:
|
||||
|
||||
ret = kprobe_event_add_fields(&cmd, "flags=%cx", "mode=+4($stack)");
|
||||
|
||||
Once all the fields have been added, the event should be finalized and
|
||||
registered by calling the kprobe_event_gen_cmd_end() or
|
||||
kretprobe_event_gen_cmd_end() functions, depending on whether a kprobe
|
||||
or kretprobe command was started:
|
||||
|
||||
ret = kprobe_event_gen_cmd_end(&cmd);
|
||||
|
||||
or
|
||||
|
||||
ret = kretprobe_event_gen_cmd_end(&cmd);
|
||||
|
||||
At this point, the event object is ready to be used for tracing new
|
||||
events.
|
||||
|
||||
Similarly, a kretprobe event can be created using
|
||||
kretprobe_event_gen_cmd_start() with a probe name and location and
|
||||
additional params such as $retval:
|
||||
|
||||
ret = kretprobe_event_gen_cmd_start(&cmd, "gen_kretprobe_test",
|
||||
"do_sys_open", "$retval");
|
||||
|
||||
Similar to the synthetic event case, code like the following can be
|
||||
used to enable the newly created kprobe event:
|
||||
|
||||
gen_kprobe_test = trace_get_event_file(NULL, "kprobes", "gen_kprobe_test");
|
||||
|
||||
ret = trace_array_set_clr_event(gen_kprobe_test->tr,
|
||||
"kprobes", "gen_kprobe_test", true);
|
||||
|
||||
Finally, also similar to synthetic events, the following code can be
|
||||
used to give the kprobe event file back and delete the event:
|
||||
|
||||
trace_put_event_file(gen_kprobe_test);
|
||||
|
||||
ret = kprobe_event_delete("gen_kprobe_test");
|
||||
|
||||
6.3.4 The "dynevent_cmd" low-level API
|
||||
--------------------------------------
|
||||
|
||||
Both the in-kernel synthetic event and kprobe interfaces are built on
|
||||
top of a lower-level "dynevent_cmd" interface. This interface is
|
||||
meant to provide the basis for higher-level interfaces such as the
|
||||
synthetic and kprobe interfaces, which can be used as examples.
|
||||
|
||||
The basic idea is simple and amounts to providing a general-purpose
|
||||
layer that can be used to generate trace event commands. The
|
||||
generated command strings can then be passed to the command-parsing
|
||||
and event creation code that already exists in the trace event
|
||||
subystem for creating the corresponding trace events.
|
||||
|
||||
In a nutshell, the way it works is that the higher-level interface
|
||||
code creates a struct dynevent_cmd object, then uses a couple
|
||||
functions, dynevent_arg_add() and dynevent_arg_pair_add() to build up
|
||||
a command string, which finally causes the command to be executed
|
||||
using the dynevent_create() function. The details of the interface
|
||||
are described below.
|
||||
|
||||
The first step in building a new command string is to create and
|
||||
initialize an instance of a dynevent_cmd. Here, for instance, we
|
||||
create a dynevent_cmd on the stack and initialize it:
|
||||
|
||||
struct dynevent_cmd cmd;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
buf = kzalloc(MAX_DYNEVENT_CMD_LEN, GFP_KERNEL);
|
||||
|
||||
dynevent_cmd_init(cmd, buf, maxlen, DYNEVENT_TYPE_FOO,
|
||||
foo_event_run_command);
|
||||
|
||||
The dynevent_cmd initialization needs to be given a user-specified
|
||||
buffer and the length of the buffer (MAX_DYNEVENT_CMD_LEN can be used
|
||||
for this purpose - at 2k it's generally too big to be comfortably put
|
||||
on the stack, so is dynamically allocated), a dynevent type id, which
|
||||
is meant to be used to check that further API calls are for the
|
||||
correct command type, and a pointer to an event-specific run_command()
|
||||
callback that will be called to actually execute the event-specific
|
||||
command function.
|
||||
|
||||
Once that's done, the command string can by built up by successive
|
||||
calls to argument-adding functions.
|
||||
|
||||
To add a single argument, define and initialize a struct dynevent_arg
|
||||
or struct dynevent_arg_pair object. Here's an example of the simplest
|
||||
possible arg addition, which is simply to append the given string as
|
||||
a whitespace-separated argument to the command:
|
||||
|
||||
struct dynevent_arg arg;
|
||||
|
||||
dynevent_arg_init(&arg, NULL, 0);
|
||||
|
||||
arg.str = name;
|
||||
|
||||
ret = dynevent_arg_add(cmd, &arg);
|
||||
|
||||
The arg object is first initialized using dynevent_arg_init() and in
|
||||
this case the parameters are NULL or 0, which means there's no
|
||||
optional sanity-checking function or separator appended to the end of
|
||||
the arg.
|
||||
|
||||
Here's another more complicated example using an 'arg pair', which is
|
||||
used to create an argument that consists of a couple components added
|
||||
together as a unit, for example, a 'type field_name;' arg or a simple
|
||||
expression arg e.g. 'flags=%cx':
|
||||
|
||||
struct dynevent_arg_pair arg_pair;
|
||||
|
||||
dynevent_arg_pair_init(&arg_pair, dynevent_foo_check_arg_fn, 0, ';');
|
||||
|
||||
arg_pair.lhs = type;
|
||||
arg_pair.rhs = name;
|
||||
|
||||
ret = dynevent_arg_pair_add(cmd, &arg_pair);
|
||||
|
||||
Again, the arg_pair is first initialized, in this case with a callback
|
||||
function used to check the sanity of the args (for example, that
|
||||
neither part of the pair is NULL), along with a character to be used
|
||||
to add an operator between the pair (here none) and a separator to be
|
||||
appended onto the end of the arg pair (here ';').
|
||||
|
||||
There's also a dynevent_str_add() function that can be used to simply
|
||||
add a string as-is, with no spaces, delimeters, or arg check.
|
||||
|
||||
Any number of dynevent_*_add() calls can be made to build up the string
|
||||
(until its length surpasses cmd->maxlen). When all the arguments have
|
||||
been added and the command string is complete, the only thing left to
|
||||
do is run the command, which happens by simply calling
|
||||
dynevent_create():
|
||||
|
||||
ret = dynevent_create(&cmd);
|
||||
|
||||
At that point, if the return value is 0, the dynamic event has been
|
||||
created and is ready to use.
|
||||
|
||||
See the dynevent_cmd function definitions themselves for the details
|
||||
of the API.
|
||||
|
@ -19,6 +19,7 @@ Linux Tracing Technologies
|
||||
events-msr
|
||||
mmiotrace
|
||||
histogram
|
||||
boottime-trace
|
||||
hwlat_detector
|
||||
intel_th
|
||||
stm
|
||||
|
@ -97,6 +97,7 @@ which shows given pointer in "symbol+offset" style.
|
||||
For $comm, the default type is "string"; any other type is invalid.
|
||||
|
||||
.. _user_mem_access:
|
||||
|
||||
User Memory Access
|
||||
------------------
|
||||
Kprobe events supports user-space memory access. For that purpose, you can use
|
||||
@ -252,4 +253,3 @@ And you can see the traced information via /sys/kernel/debug/tracing/trace.
|
||||
Each line shows when the kernel hits an event, and <- SYMBOL means kernel
|
||||
returns from SYMBOL(e.g. "sys_open+0x1b/0x1d <- do_sys_open" means kernel
|
||||
returns from do_sys_open to sys_open+0x1b).
|
||||
|
||||
|
@ -390,7 +390,8 @@ Mkinitrd
|
||||
E2fsprogs
|
||||
---------
|
||||
|
||||
- <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.29.tar.gz>
|
||||
- <https://www.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/>
|
||||
- <https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/>
|
||||
|
||||
JFSutils
|
||||
--------
|
||||
@ -400,12 +401,13 @@ JFSutils
|
||||
Reiserfsprogs
|
||||
-------------
|
||||
|
||||
- <http://www.kernel.org/pub/linux/utils/fs/reiserfs/>
|
||||
- <https://git.kernel.org/pub/scm/linux/kernel/git/jeffm/reiserfsprogs.git/>
|
||||
|
||||
Xfsprogs
|
||||
--------
|
||||
|
||||
- <ftp://oss.sgi.com/projects/xfs/>
|
||||
- <https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git>
|
||||
- <https://www.kernel.org/pub/linux/utils/fs/xfs/xfsprogs/>
|
||||
|
||||
Pcmciautils
|
||||
-----------
|
||||
@ -444,7 +446,9 @@ Rete
|
||||
PPP
|
||||
---
|
||||
|
||||
- <ftp://ftp.samba.org/pub/ppp/>
|
||||
- <https://download.samba.org/pub/ppp/>
|
||||
- <https://git.ozlabs.org/?p=ppp.git>
|
||||
- <https://github.com/paulusmack/ppp/>
|
||||
|
||||
|
||||
NFS-utils
|
||||
@ -455,7 +459,7 @@ NFS-utils
|
||||
Iptables
|
||||
--------
|
||||
|
||||
- <http://www.iptables.org/downloads.html>
|
||||
- <https://netfilter.org/projects/iptables/index.html>
|
||||
|
||||
Ip-route2
|
||||
---------
|
||||
|
@ -318,8 +318,8 @@ Andrew Morton의 글이 있다.
|
||||
리뷰 프로세스는 patchwork라는 도구를 통해 추적된다. patchwork은 등록된 패치와
|
||||
패치에 대한 코멘트, 패치의 버전을 볼 수 있는 웹 인터페이스를 제공하고,
|
||||
메인테이너는 패치를 리뷰 중, 리뷰 통과, 또는 반려됨으로 표시할 수 있다.
|
||||
대부분의 이러한 patchwork 사이트는 https://patchwork.kernel.org/ 또는
|
||||
http://patchwork.ozlabs.org/ 에 나열되어 있다.
|
||||
대부분의 이러한 patchwork 사이트는 https://patchwork.kernel.org/ 에 나열되어
|
||||
있다.
|
||||
|
||||
통합 테스트를 위한 linux-next 커널 트리
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -328,7 +328,7 @@ http://patchwork.ozlabs.org/ 에 나열되어 있다.
|
||||
거쳐야 한다. 이런 목적으로, 모든 서브시스템 트리의 변경사항을 거의 매일
|
||||
받아가는 특수한 테스트 저장소가 존재한다:
|
||||
|
||||
https://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
|
||||
https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
|
||||
|
||||
이런 식으로, linux-next 커널을 통해 다음 머지 기간에 메인라인 커널에 어떤
|
||||
변경이 가해질 것인지 간략히 알 수 있다. 모험심 강한 테스터라면 linux-next
|
||||
|
@ -4177,6 +4177,42 @@ This ioctl issues an ultravisor call to terminate the secure guest,
|
||||
unpins the VPA pages and releases all the device pages that are used to
|
||||
track the secure pages by hypervisor.
|
||||
|
||||
4.122 KVM_S390_NORMAL_RESET
|
||||
|
||||
Capability: KVM_CAP_S390_VCPU_RESETS
|
||||
Architectures: s390
|
||||
Type: vcpu ioctl
|
||||
Parameters: none
|
||||
Returns: 0
|
||||
|
||||
This ioctl resets VCPU registers and control structures according to
|
||||
the cpu reset definition in the POP (Principles Of Operation).
|
||||
|
||||
4.123 KVM_S390_INITIAL_RESET
|
||||
|
||||
Capability: none
|
||||
Architectures: s390
|
||||
Type: vcpu ioctl
|
||||
Parameters: none
|
||||
Returns: 0
|
||||
|
||||
This ioctl resets VCPU registers and control structures according to
|
||||
the initial cpu reset definition in the POP. However, the cpu is not
|
||||
put into ESA mode. This reset is a superset of the normal reset.
|
||||
|
||||
4.124 KVM_S390_CLEAR_RESET
|
||||
|
||||
Capability: KVM_CAP_S390_VCPU_RESETS
|
||||
Architectures: s390
|
||||
Type: vcpu ioctl
|
||||
Parameters: none
|
||||
Returns: 0
|
||||
|
||||
This ioctl resets VCPU registers and control structures according to
|
||||
the clear cpu reset definition in the POP. However, the cpu is not put
|
||||
into ESA mode. This reset is a superset of the initial reset.
|
||||
|
||||
|
||||
5. The kvm_run structure
|
||||
------------------------
|
||||
|
||||
@ -5405,3 +5441,10 @@ handling by KVM (as some KVM hypercall may be mistakenly treated as TLB
|
||||
flush hypercalls by Hyper-V) so userspace should disable KVM identification
|
||||
in CPUID and only exposes Hyper-V identification. In this case, guest
|
||||
thinks it's running on Hyper-V and only use Hyper-V hypercalls.
|
||||
|
||||
8.22 KVM_CAP_S390_VCPU_RESETS
|
||||
|
||||
Architectures: s390
|
||||
|
||||
This capability indicates that the KVM_S390_NORMAL_RESET and
|
||||
KVM_S390_CLEAR_RESET ioctls are available.
|
||||
|
16
MAINTAINERS
16
MAINTAINERS
@ -6903,7 +6903,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git
|
||||
S: Maintained
|
||||
F: fs/fuse/
|
||||
F: include/uapi/linux/fuse.h
|
||||
F: Documentation/filesystems/fuse.txt
|
||||
F: Documentation/filesystems/fuse.rst
|
||||
|
||||
FUTEX SUBSYSTEM
|
||||
M: Thomas Gleixner <tglx@linutronix.de>
|
||||
@ -7814,9 +7814,7 @@ M: Jean Delvare <jdelvare@suse.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/i2c/busses/i2c-parport.rst
|
||||
F: Documentation/i2c/busses/i2c-parport-light.rst
|
||||
F: drivers/i2c/busses/i2c-parport.c
|
||||
F: drivers/i2c/busses/i2c-parport-light.c
|
||||
|
||||
I2C SUBSYSTEM
|
||||
M: Wolfram Sang <wsa@the-dreams.de>
|
||||
@ -14106,7 +14104,6 @@ F: include/linux/platform_data/rtc-*
|
||||
F: tools/testing/selftests/rtc/
|
||||
|
||||
REALTEK AUDIO CODECS
|
||||
M: Bard Liao <bardliao@realtek.com>
|
||||
M: Oder Chiou <oder_chiou@realtek.com>
|
||||
S: Maintained
|
||||
F: sound/soc/codecs/rt*
|
||||
@ -14947,8 +14944,8 @@ S: Maintained
|
||||
F: drivers/mmc/host/sdhci-omap.c
|
||||
|
||||
SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER
|
||||
M: Scott Bauer <scott.bauer@intel.com>
|
||||
M: Jonathan Derrick <jonathan.derrick@intel.com>
|
||||
M: Revanth Rajashekar <revanth.rajashekar@intel.com>
|
||||
L: linux-block@vger.kernel.org
|
||||
S: Supported
|
||||
F: block/sed*
|
||||
@ -15934,6 +15931,15 @@ S: Supported
|
||||
F: Documentation/networking/device_drivers/stmicro/
|
||||
F: drivers/net/ethernet/stmicro/stmmac/
|
||||
|
||||
EXTRA BOOT CONFIG
|
||||
M: Masami Hiramatsu <mhiramat@kernel.org>
|
||||
S: Maintained
|
||||
F: lib/bootconfig.c
|
||||
F: fs/proc/bootconfig.c
|
||||
F: include/linux/bootconfig.h
|
||||
F: tools/bootconfig/*
|
||||
F: Documentation/admin-guide/bootconfig.rst
|
||||
|
||||
SUN3/3X
|
||||
M: Sam Creasey <sammy@sammy.net>
|
||||
W: http://sammy.net/sun3/
|
||||
|
@ -13,7 +13,6 @@ CONFIG_EMBEDDED=y
|
||||
# CONFIG_SLUB_DEBUG is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_M5307=y
|
||||
CONFIG_AMCORE=y
|
||||
|
@ -10,8 +10,6 @@ CONFIG_EXPERT=y
|
||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
# CONFIG_MMU is not set
|
||||
# CONFIG_4KSTACKS is not set
|
||||
CONFIG_RAMBASE=0x40000000
|
||||
|
@ -10,8 +10,6 @@ CONFIG_EXPERT=y
|
||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_SLUB_DEBUG is not set
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_M5249=y
|
||||
CONFIG_M5249C3=y
|
||||
|
@ -10,8 +10,6 @@ CONFIG_EXPERT=y
|
||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_SLUB_DEBUG is not set
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_M5272=y
|
||||
CONFIG_M5272C3=y
|
||||
|
@ -10,8 +10,6 @@ CONFIG_EXPERT=y
|
||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_SLUB_DEBUG is not set
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_M5275=y
|
||||
# CONFIG_4KSTACKS is not set
|
||||
|
@ -10,8 +10,6 @@ CONFIG_EXPERT=y
|
||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_SLUB_DEBUG is not set
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_M5307=y
|
||||
CONFIG_M5307C3=y
|
||||
|
@ -11,8 +11,6 @@ CONFIG_EXPERT=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
# CONFIG_MMU is not set
|
||||
CONFIG_M5407=y
|
||||
CONFIG_M5407C3=y
|
||||
|
@ -11,8 +11,6 @@ CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_EMBEDDED=y
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
CONFIG_COLDFIRE=y
|
||||
# CONFIG_4KSTACKS is not set
|
||||
CONFIG_RAMBASE=0x0
|
||||
|
@ -71,26 +71,29 @@ extern int __put_user_bad(void);
|
||||
#define get_user(x, ptr) \
|
||||
({ \
|
||||
int __gu_err = 0; \
|
||||
typeof(x) __gu_val = 0; \
|
||||
switch (sizeof(*(ptr))) { \
|
||||
case 1: \
|
||||
__get_user_asm(__gu_err, __gu_val, ptr, b, "=d"); \
|
||||
__get_user_asm(__gu_err, x, ptr, b, "=d"); \
|
||||
break; \
|
||||
case 2: \
|
||||
__get_user_asm(__gu_err, __gu_val, ptr, w, "=r"); \
|
||||
__get_user_asm(__gu_err, x, ptr, w, "=r"); \
|
||||
break; \
|
||||
case 4: \
|
||||
__get_user_asm(__gu_err, __gu_val, ptr, l, "=r"); \
|
||||
__get_user_asm(__gu_err, x, ptr, l, "=r"); \
|
||||
break; \
|
||||
case 8: \
|
||||
memcpy((void *) &__gu_val, ptr, sizeof (*(ptr))); \
|
||||
case 8: { \
|
||||
union { \
|
||||
u64 l; \
|
||||
__typeof__(*(ptr)) t; \
|
||||
} __gu_val; \
|
||||
memcpy(&__gu_val.l, ptr, sizeof(__gu_val.l)); \
|
||||
(x) = __gu_val.t; \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
__gu_val = 0; \
|
||||
__gu_err = __get_user_bad(); \
|
||||
break; \
|
||||
} \
|
||||
(x) = (typeof(*(ptr))) __gu_val; \
|
||||
__gu_err; \
|
||||
})
|
||||
#define __get_user(x, ptr) get_user(x, ptr)
|
||||
|
@ -280,6 +280,22 @@ static inline void dump_handler(const char *symbol, void *start, void *end)
|
||||
pr_debug("\tEND(%s)\n", symbol);
|
||||
}
|
||||
|
||||
/* low level hrtimer wake routine */
|
||||
static enum hrtimer_restart kvm_mips_comparecount_wakeup(struct hrtimer *timer)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
vcpu = container_of(timer, struct kvm_vcpu, arch.comparecount_timer);
|
||||
|
||||
kvm_mips_callbacks->queue_timer_int(vcpu);
|
||||
|
||||
vcpu->arch.wait = 0;
|
||||
if (swq_has_sleeper(&vcpu->wq))
|
||||
swake_up_one(&vcpu->wq);
|
||||
|
||||
return kvm_mips_count_timeout(vcpu);
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
|
||||
{
|
||||
return 0;
|
||||
@ -1209,27 +1225,6 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_mips_comparecount_func(unsigned long data)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
|
||||
|
||||
kvm_mips_callbacks->queue_timer_int(vcpu);
|
||||
|
||||
vcpu->arch.wait = 0;
|
||||
if (swq_has_sleeper(&vcpu->wq))
|
||||
swake_up_one(&vcpu->wq);
|
||||
}
|
||||
|
||||
/* low level hrtimer wake routine */
|
||||
static enum hrtimer_restart kvm_mips_comparecount_wakeup(struct hrtimer *timer)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
vcpu = container_of(timer, struct kvm_vcpu, arch.comparecount_timer);
|
||||
kvm_mips_comparecount_func((unsigned long) vcpu);
|
||||
return kvm_mips_count_timeout(vcpu);
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
|
||||
struct kvm_translation *tr)
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_VIRTIO_BLK_SCSI=y
|
||||
CONFIG_SCSI_VIRTIO=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_NET_FAILOVER=y
|
||||
|
@ -122,6 +122,11 @@ struct mcck_volatile_info {
|
||||
__u32 reserved;
|
||||
};
|
||||
|
||||
#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \
|
||||
CR0_MEASUREMENT_ALERT_SUBMASK)
|
||||
#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \
|
||||
CR14_EXTERNAL_DAMAGE_SUBMASK)
|
||||
|
||||
#define CPUSTAT_STOPPED 0x80000000
|
||||
#define CPUSTAT_WAIT 0x10000000
|
||||
#define CPUSTAT_ECALL_PEND 0x08000000
|
||||
|
@ -2190,7 +2190,7 @@ static int flic_ais_mode_get_all(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||
return -EINVAL;
|
||||
|
||||
if (!test_kvm_facility(kvm, 72))
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&fi->ais_lock);
|
||||
ais.simm = fi->simm;
|
||||
@ -2499,7 +2499,7 @@ static int modify_ais_mode(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||
int ret = 0;
|
||||
|
||||
if (!test_kvm_facility(kvm, 72))
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req)))
|
||||
return -EFAULT;
|
||||
@ -2579,7 +2579,7 @@ static int flic_ais_mode_set_all(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||
struct kvm_s390_ais_all ais;
|
||||
|
||||
if (!test_kvm_facility(kvm, 72))
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais)))
|
||||
return -EFAULT;
|
||||
|
@ -529,6 +529,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
case KVM_CAP_S390_CMMA_MIGRATION:
|
||||
case KVM_CAP_S390_AIS:
|
||||
case KVM_CAP_S390_AIS_MIGRATION:
|
||||
case KVM_CAP_S390_VCPU_RESETS:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_S390_HPAGE_1M:
|
||||
@ -2808,35 +2809,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
||||
|
||||
}
|
||||
|
||||
static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/* this equals initial cpu reset in pop, but we don't switch to ESA */
|
||||
vcpu->arch.sie_block->gpsw.mask = 0UL;
|
||||
vcpu->arch.sie_block->gpsw.addr = 0UL;
|
||||
kvm_s390_set_prefix(vcpu, 0);
|
||||
kvm_s390_set_cpu_timer(vcpu, 0);
|
||||
vcpu->arch.sie_block->ckc = 0UL;
|
||||
vcpu->arch.sie_block->todpr = 0;
|
||||
memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
|
||||
vcpu->arch.sie_block->gcr[0] = CR0_UNUSED_56 |
|
||||
CR0_INTERRUPT_KEY_SUBMASK |
|
||||
CR0_MEASUREMENT_ALERT_SUBMASK;
|
||||
vcpu->arch.sie_block->gcr[14] = CR14_UNUSED_32 |
|
||||
CR14_UNUSED_33 |
|
||||
CR14_EXTERNAL_DAMAGE_SUBMASK;
|
||||
/* make sure the new fpc will be lazily loaded */
|
||||
save_fpu_regs();
|
||||
current->thread.fpu.fpc = 0;
|
||||
vcpu->arch.sie_block->gbea = 1;
|
||||
vcpu->arch.sie_block->pp = 0;
|
||||
vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
|
||||
vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
|
||||
kvm_clear_async_pf_completion_queue(vcpu);
|
||||
if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
|
||||
kvm_s390_vcpu_stop(vcpu);
|
||||
kvm_s390_clear_local_irqs(vcpu);
|
||||
}
|
||||
|
||||
void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
mutex_lock(&vcpu->kvm->lock);
|
||||
@ -3279,10 +3251,53 @@ static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
|
||||
static void kvm_arch_vcpu_ioctl_normal_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvm_s390_vcpu_initial_reset(vcpu);
|
||||
return 0;
|
||||
vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_RI;
|
||||
vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
|
||||
memset(vcpu->run->s.regs.riccb, 0, sizeof(vcpu->run->s.regs.riccb));
|
||||
|
||||
kvm_clear_async_pf_completion_queue(vcpu);
|
||||
if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
|
||||
kvm_s390_vcpu_stop(vcpu);
|
||||
kvm_s390_clear_local_irqs(vcpu);
|
||||
}
|
||||
|
||||
static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/* Initial reset is a superset of the normal reset */
|
||||
kvm_arch_vcpu_ioctl_normal_reset(vcpu);
|
||||
|
||||
/* this equals initial cpu reset in pop, but we don't switch to ESA */
|
||||
vcpu->arch.sie_block->gpsw.mask = 0;
|
||||
vcpu->arch.sie_block->gpsw.addr = 0;
|
||||
kvm_s390_set_prefix(vcpu, 0);
|
||||
kvm_s390_set_cpu_timer(vcpu, 0);
|
||||
vcpu->arch.sie_block->ckc = 0;
|
||||
vcpu->arch.sie_block->todpr = 0;
|
||||
memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr));
|
||||
vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK;
|
||||
vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK;
|
||||
vcpu->run->s.regs.fpc = 0;
|
||||
vcpu->arch.sie_block->gbea = 1;
|
||||
vcpu->arch.sie_block->pp = 0;
|
||||
vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
|
||||
}
|
||||
|
||||
static void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_sync_regs *regs = &vcpu->run->s.regs;
|
||||
|
||||
/* Clear reset is a superset of the initial reset */
|
||||
kvm_arch_vcpu_ioctl_initial_reset(vcpu);
|
||||
|
||||
memset(®s->gprs, 0, sizeof(regs->gprs));
|
||||
memset(®s->vrs, 0, sizeof(regs->vrs));
|
||||
memset(®s->acrs, 0, sizeof(regs->acrs));
|
||||
memset(®s->gscb, 0, sizeof(regs->gscb));
|
||||
|
||||
regs->etoken = 0;
|
||||
regs->etoken_extension = 0;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
||||
@ -4343,7 +4358,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
switch (ioctl) {
|
||||
case KVM_S390_STORE_STATUS:
|
||||
idx = srcu_read_lock(&vcpu->kvm->srcu);
|
||||
r = kvm_s390_vcpu_store_status(vcpu, arg);
|
||||
r = kvm_s390_store_status_unloaded(vcpu, arg);
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||||
break;
|
||||
case KVM_S390_SET_INITIAL_PSW: {
|
||||
@ -4355,8 +4370,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
|
||||
break;
|
||||
}
|
||||
case KVM_S390_CLEAR_RESET:
|
||||
r = 0;
|
||||
kvm_arch_vcpu_ioctl_clear_reset(vcpu);
|
||||
break;
|
||||
case KVM_S390_INITIAL_RESET:
|
||||
r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
|
||||
r = 0;
|
||||
kvm_arch_vcpu_ioctl_initial_reset(vcpu);
|
||||
break;
|
||||
case KVM_S390_NORMAL_RESET:
|
||||
r = 0;
|
||||
kvm_arch_vcpu_ioctl_normal_reset(vcpu);
|
||||
break;
|
||||
case KVM_SET_ONE_REG:
|
||||
case KVM_GET_ONE_REG: {
|
||||
|
@ -78,6 +78,8 @@
|
||||
#define KVM_REQ_HV_STIMER KVM_ARCH_REQ(22)
|
||||
#define KVM_REQ_LOAD_EOI_EXITMAP KVM_ARCH_REQ(23)
|
||||
#define KVM_REQ_GET_VMCS12_PAGES KVM_ARCH_REQ(24)
|
||||
#define KVM_REQ_APICV_UPDATE \
|
||||
KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
|
||||
|
||||
#define CR0_RESERVED_BITS \
|
||||
(~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
|
||||
@ -873,6 +875,12 @@ enum kvm_irqchip_mode {
|
||||
KVM_IRQCHIP_SPLIT, /* created with KVM_CAP_SPLIT_IRQCHIP */
|
||||
};
|
||||
|
||||
#define APICV_INHIBIT_REASON_DISABLE 0
|
||||
#define APICV_INHIBIT_REASON_HYPERV 1
|
||||
#define APICV_INHIBIT_REASON_NESTED 2
|
||||
#define APICV_INHIBIT_REASON_IRQWIN 3
|
||||
#define APICV_INHIBIT_REASON_PIT_REINJ 4
|
||||
|
||||
struct kvm_arch {
|
||||
unsigned long n_used_mmu_pages;
|
||||
unsigned long n_requested_mmu_pages;
|
||||
@ -904,6 +912,7 @@ struct kvm_arch {
|
||||
struct kvm_apic_map *apic_map;
|
||||
|
||||
bool apic_access_page_done;
|
||||
unsigned long apicv_inhibit_reasons;
|
||||
|
||||
gpa_t wall_clock;
|
||||
|
||||
@ -1118,7 +1127,8 @@ struct kvm_x86_ops {
|
||||
void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
|
||||
void (*enable_irq_window)(struct kvm_vcpu *vcpu);
|
||||
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
|
||||
bool (*get_enable_apicv)(struct kvm *kvm);
|
||||
bool (*check_apicv_inhibit_reasons)(ulong bit);
|
||||
void (*pre_update_apicv_exec_ctrl)(struct kvm *kvm, bool activate);
|
||||
void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
|
||||
void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
|
||||
void (*hwapic_isr_update)(struct kvm_vcpu *vcpu, int isr);
|
||||
@ -1477,7 +1487,11 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva,
|
||||
gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
|
||||
struct x86_exception *exception);
|
||||
|
||||
void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu);
|
||||
bool kvm_apicv_activated(struct kvm *kvm);
|
||||
void kvm_apicv_init(struct kvm *kvm, bool enable);
|
||||
void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu);
|
||||
void kvm_request_apicv_update(struct kvm *kvm, bool activate,
|
||||
unsigned long bit);
|
||||
|
||||
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
@ -33,13 +33,13 @@ extern int pci_routeirq;
|
||||
extern int noioapicquirk;
|
||||
extern int noioapicreroute;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
static inline struct pci_sysdata *to_pci_sysdata(const struct pci_bus *bus)
|
||||
{
|
||||
return bus->sysdata;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
#ifdef CONFIG_PCI_DOMAINS
|
||||
static inline int pci_domain_nr(struct pci_bus *bus)
|
||||
{
|
||||
|
@ -22,8 +22,8 @@
|
||||
/*
|
||||
* Definitions of Primary Processor-Based VM-Execution Controls.
|
||||
*/
|
||||
#define CPU_BASED_INTR_WINDOW_EXITING VMCS_CONTROL_BIT(VIRTUAL_INTR_PENDING)
|
||||
#define CPU_BASED_USE_TSC_OFFSETTING VMCS_CONTROL_BIT(TSC_OFFSETTING)
|
||||
#define CPU_BASED_INTR_WINDOW_EXITING VMCS_CONTROL_BIT(INTR_WINDOW_EXITING)
|
||||
#define CPU_BASED_USE_TSC_OFFSETTING VMCS_CONTROL_BIT(USE_TSC_OFFSETTING)
|
||||
#define CPU_BASED_HLT_EXITING VMCS_CONTROL_BIT(HLT_EXITING)
|
||||
#define CPU_BASED_INVLPG_EXITING VMCS_CONTROL_BIT(INVLPG_EXITING)
|
||||
#define CPU_BASED_MWAIT_EXITING VMCS_CONTROL_BIT(MWAIT_EXITING)
|
||||
@ -34,7 +34,7 @@
|
||||
#define CPU_BASED_CR8_LOAD_EXITING VMCS_CONTROL_BIT(CR8_LOAD_EXITING)
|
||||
#define CPU_BASED_CR8_STORE_EXITING VMCS_CONTROL_BIT(CR8_STORE_EXITING)
|
||||
#define CPU_BASED_TPR_SHADOW VMCS_CONTROL_BIT(VIRTUAL_TPR)
|
||||
#define CPU_BASED_NMI_WINDOW_EXITING VMCS_CONTROL_BIT(VIRTUAL_NMI_PENDING)
|
||||
#define CPU_BASED_NMI_WINDOW_EXITING VMCS_CONTROL_BIT(NMI_WINDOW_EXITING)
|
||||
#define CPU_BASED_MOV_DR_EXITING VMCS_CONTROL_BIT(MOV_DR_EXITING)
|
||||
#define CPU_BASED_UNCOND_IO_EXITING VMCS_CONTROL_BIT(UNCOND_IO_EXITING)
|
||||
#define CPU_BASED_USE_IO_BITMAPS VMCS_CONTROL_BIT(USE_IO_BITMAPS)
|
||||
|
@ -34,8 +34,8 @@
|
||||
#define VMX_FEATURE_EPTP_SWITCHING ( 0*32+ 28) /* EPTP switching (in guest) */
|
||||
|
||||
/* Primary Processor-Based VM-Execution Controls, word 1 */
|
||||
#define VMX_FEATURE_VIRTUAL_INTR_PENDING ( 1*32+ 2) /* "" VM-Exit if INTRs are unblocked in guest */
|
||||
#define VMX_FEATURE_TSC_OFFSETTING ( 1*32+ 3) /* "tsc_offset" Offset hardware TSC when read in guest */
|
||||
#define VMX_FEATURE_INTR_WINDOW_EXITING ( 1*32+ 2) /* "" VM-Exit if INTRs are unblocked in guest */
|
||||
#define VMX_FEATURE_USE_TSC_OFFSETTING ( 1*32+ 3) /* "tsc_offset" Offset hardware TSC when read in guest */
|
||||
#define VMX_FEATURE_HLT_EXITING ( 1*32+ 7) /* "" VM-Exit on HLT */
|
||||
#define VMX_FEATURE_INVLPG_EXITING ( 1*32+ 9) /* "" VM-Exit on INVLPG */
|
||||
#define VMX_FEATURE_MWAIT_EXITING ( 1*32+ 10) /* "" VM-Exit on MWAIT */
|
||||
@ -46,7 +46,7 @@
|
||||
#define VMX_FEATURE_CR8_LOAD_EXITING ( 1*32+ 19) /* "" VM-Exit on writes to CR8 */
|
||||
#define VMX_FEATURE_CR8_STORE_EXITING ( 1*32+ 20) /* "" VM-Exit on reads from CR8 */
|
||||
#define VMX_FEATURE_VIRTUAL_TPR ( 1*32+ 21) /* "vtpr" TPR virtualization, a.k.a. TPR shadow */
|
||||
#define VMX_FEATURE_VIRTUAL_NMI_PENDING ( 1*32+ 22) /* "" VM-Exit if NMIs are unblocked in guest */
|
||||
#define VMX_FEATURE_NMI_WINDOW_EXITING ( 1*32+ 22) /* "" VM-Exit if NMIs are unblocked in guest */
|
||||
#define VMX_FEATURE_MOV_DR_EXITING ( 1*32+ 23) /* "" VM-Exit on accesses to debug registers */
|
||||
#define VMX_FEATURE_UNCOND_IO_EXITING ( 1*32+ 24) /* "" VM-Exit on *all* IN{S} and OUT{S}*/
|
||||
#define VMX_FEATURE_USE_IO_BITMAPS ( 1*32+ 25) /* "" VM-Exit based on I/O port */
|
||||
|
@ -736,6 +736,9 @@ static __init int kvm_setup_pv_tlb_flush(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (!kvm_para_available() || nopv)
|
||||
return 0;
|
||||
|
||||
if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
|
||||
!kvm_para_has_hint(KVM_HINTS_REALTIME) &&
|
||||
kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
|
||||
|
@ -776,9 +776,10 @@ int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)
|
||||
|
||||
/*
|
||||
* Hyper-V SynIC auto EOI SINT's are
|
||||
* not compatible with APICV, so deactivate APICV
|
||||
* not compatible with APICV, so request
|
||||
* to deactivate APICV permanently.
|
||||
*/
|
||||
kvm_vcpu_deactivate_apicv(vcpu);
|
||||
kvm_request_apicv_update(vcpu->kvm, false, APICV_INHIBIT_REASON_HYPERV);
|
||||
synic->active = true;
|
||||
synic->dont_zero_synic_pages = dont_zero_synic_pages;
|
||||
return 0;
|
||||
|
@ -295,12 +295,24 @@ void kvm_pit_set_reinject(struct kvm_pit *pit, bool reinject)
|
||||
if (atomic_read(&ps->reinject) == reinject)
|
||||
return;
|
||||
|
||||
/*
|
||||
* AMD SVM AVIC accelerates EOI write and does not trap.
|
||||
* This cause in-kernel PIT re-inject mode to fail
|
||||
* since it checks ps->irq_ack before kvm_set_irq()
|
||||
* and relies on the ack notifier to timely queue
|
||||
* the pt->worker work iterm and reinject the missed tick.
|
||||
* So, deactivate APICv when PIT is in reinject mode.
|
||||
*/
|
||||
if (reinject) {
|
||||
kvm_request_apicv_update(kvm, false,
|
||||
APICV_INHIBIT_REASON_PIT_REINJ);
|
||||
/* The initial state is preserved while ps->reinject == 0. */
|
||||
kvm_pit_reset_reinject(pit);
|
||||
kvm_register_irq_ack_notifier(kvm, &ps->irq_ack_notifier);
|
||||
kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
|
||||
} else {
|
||||
kvm_request_apicv_update(kvm, true,
|
||||
APICV_INHIBIT_REASON_PIT_REINJ);
|
||||
kvm_unregister_irq_ack_notifier(kvm, &ps->irq_ack_notifier);
|
||||
kvm_unregister_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
|
||||
}
|
||||
|
@ -49,6 +49,11 @@
|
||||
static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
|
||||
bool line_status);
|
||||
|
||||
static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
|
||||
struct kvm_ioapic *ioapic,
|
||||
int trigger_mode,
|
||||
int pin);
|
||||
|
||||
static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
|
||||
unsigned long addr,
|
||||
unsigned long length)
|
||||
@ -154,10 +159,16 @@ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic)
|
||||
__rtc_irq_eoi_tracking_restore_one(vcpu);
|
||||
}
|
||||
|
||||
static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu)
|
||||
static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu,
|
||||
int vector)
|
||||
{
|
||||
if (test_and_clear_bit(vcpu->vcpu_id,
|
||||
ioapic->rtc_status.dest_map.map)) {
|
||||
struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
|
||||
|
||||
/* RTC special handling */
|
||||
if (test_bit(vcpu->vcpu_id, dest_map->map) &&
|
||||
(vector == dest_map->vectors[vcpu->vcpu_id]) &&
|
||||
(test_and_clear_bit(vcpu->vcpu_id,
|
||||
ioapic->rtc_status.dest_map.map))) {
|
||||
--ioapic->rtc_status.pending_eoi;
|
||||
rtc_status_pending_eoi_check_valid(ioapic);
|
||||
}
|
||||
@ -171,6 +182,31 @@ static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ioapic_lazy_update_eoi(struct kvm_ioapic *ioapic, int irq)
|
||||
{
|
||||
int i;
|
||||
struct kvm_vcpu *vcpu;
|
||||
union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, ioapic->kvm) {
|
||||
if (!kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT,
|
||||
entry->fields.dest_id,
|
||||
entry->fields.dest_mode) ||
|
||||
kvm_apic_pending_eoi(vcpu, entry->fields.vector))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If no longer has pending EOI in LAPICs, update
|
||||
* EOI for this vetor.
|
||||
*/
|
||||
rtc_irq_eoi(ioapic, vcpu, entry->fields.vector);
|
||||
kvm_ioapic_update_eoi_one(vcpu, ioapic,
|
||||
entry->fields.trig_mode,
|
||||
irq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
|
||||
int irq_level, bool line_status)
|
||||
{
|
||||
@ -188,6 +224,15 @@ static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* AMD SVM AVIC accelerate EOI write and do not trap,
|
||||
* in-kernel IOAPIC will not be able to receive the EOI.
|
||||
* In this case, we do lazy update of the pending EOI when
|
||||
* trying to set IOAPIC irq.
|
||||
*/
|
||||
if (kvm_apicv_activated(ioapic->kvm))
|
||||
ioapic_lazy_update_eoi(ioapic, irq);
|
||||
|
||||
/*
|
||||
* Return 0 for coalesced interrupts; for edge-triggered interrupts,
|
||||
* this only happens if a previous edge has not been delivered due
|
||||
@ -454,72 +499,68 @@ static void kvm_ioapic_eoi_inject_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
#define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000
|
||||
|
||||
static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
|
||||
struct kvm_ioapic *ioapic, int vector, int trigger_mode)
|
||||
static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
|
||||
struct kvm_ioapic *ioapic,
|
||||
int trigger_mode,
|
||||
int pin)
|
||||
{
|
||||
struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
|
||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
int i;
|
||||
union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[pin];
|
||||
|
||||
/* RTC special handling */
|
||||
if (test_bit(vcpu->vcpu_id, dest_map->map) &&
|
||||
vector == dest_map->vectors[vcpu->vcpu_id])
|
||||
rtc_irq_eoi(ioapic, vcpu);
|
||||
/*
|
||||
* We are dropping lock while calling ack notifiers because ack
|
||||
* notifier callbacks for assigned devices call into IOAPIC
|
||||
* recursively. Since remote_irr is cleared only after call
|
||||
* to notifiers if the same vector will be delivered while lock
|
||||
* is dropped it will be put into irr and will be delivered
|
||||
* after ack notifier returns.
|
||||
*/
|
||||
spin_unlock(&ioapic->lock);
|
||||
kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin);
|
||||
spin_lock(&ioapic->lock);
|
||||
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
|
||||
if (trigger_mode != IOAPIC_LEVEL_TRIG ||
|
||||
kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
|
||||
return;
|
||||
|
||||
if (ent->fields.vector != vector)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We are dropping lock while calling ack notifiers because ack
|
||||
* notifier callbacks for assigned devices call into IOAPIC
|
||||
* recursively. Since remote_irr is cleared only after call
|
||||
* to notifiers if the same vector will be delivered while lock
|
||||
* is dropped it will be put into irr and will be delivered
|
||||
* after ack notifier returns.
|
||||
*/
|
||||
spin_unlock(&ioapic->lock);
|
||||
kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
|
||||
spin_lock(&ioapic->lock);
|
||||
|
||||
if (trigger_mode != IOAPIC_LEVEL_TRIG ||
|
||||
kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
|
||||
continue;
|
||||
|
||||
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
|
||||
ent->fields.remote_irr = 0;
|
||||
if (!ent->fields.mask && (ioapic->irr & (1 << i))) {
|
||||
++ioapic->irq_eoi[i];
|
||||
if (ioapic->irq_eoi[i] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) {
|
||||
/*
|
||||
* Real hardware does not deliver the interrupt
|
||||
* immediately during eoi broadcast, and this
|
||||
* lets a buggy guest make slow progress
|
||||
* even if it does not correctly handle a
|
||||
* level-triggered interrupt. Emulate this
|
||||
* behavior if we detect an interrupt storm.
|
||||
*/
|
||||
schedule_delayed_work(&ioapic->eoi_inject, HZ / 100);
|
||||
ioapic->irq_eoi[i] = 0;
|
||||
trace_kvm_ioapic_delayed_eoi_inj(ent->bits);
|
||||
} else {
|
||||
ioapic_service(ioapic, i, false);
|
||||
}
|
||||
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
|
||||
ent->fields.remote_irr = 0;
|
||||
if (!ent->fields.mask && (ioapic->irr & (1 << pin))) {
|
||||
++ioapic->irq_eoi[pin];
|
||||
if (ioapic->irq_eoi[pin] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) {
|
||||
/*
|
||||
* Real hardware does not deliver the interrupt
|
||||
* immediately during eoi broadcast, and this
|
||||
* lets a buggy guest make slow progress
|
||||
* even if it does not correctly handle a
|
||||
* level-triggered interrupt. Emulate this
|
||||
* behavior if we detect an interrupt storm.
|
||||
*/
|
||||
schedule_delayed_work(&ioapic->eoi_inject, HZ / 100);
|
||||
ioapic->irq_eoi[pin] = 0;
|
||||
trace_kvm_ioapic_delayed_eoi_inj(ent->bits);
|
||||
} else {
|
||||
ioapic->irq_eoi[i] = 0;
|
||||
ioapic_service(ioapic, pin, false);
|
||||
}
|
||||
} else {
|
||||
ioapic->irq_eoi[pin] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode)
|
||||
{
|
||||
int i;
|
||||
struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
|
||||
|
||||
spin_lock(&ioapic->lock);
|
||||
__kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode);
|
||||
rtc_irq_eoi(ioapic, vcpu, vector);
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
|
||||
|
||||
if (ent->fields.vector != vector)
|
||||
continue;
|
||||
kvm_ioapic_update_eoi_one(vcpu, ioapic, trigger_mode, i);
|
||||
}
|
||||
spin_unlock(&ioapic->lock);
|
||||
}
|
||||
|
||||
|
@ -2187,6 +2187,21 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
|
||||
pr_warn_once("APIC base relocation is unsupported by KVM");
|
||||
}
|
||||
|
||||
void kvm_apic_update_apicv(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
|
||||
if (vcpu->arch.apicv_active) {
|
||||
/* irr_pending is always true when apicv is activated. */
|
||||
apic->irr_pending = true;
|
||||
apic->isr_count = 1;
|
||||
} else {
|
||||
apic->irr_pending = (apic_search_irr(apic) != -1);
|
||||
apic->isr_count = count_vectors(apic->regs + APIC_ISR);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_apic_update_apicv);
|
||||
|
||||
void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
{
|
||||
struct kvm_lapic *apic = vcpu->arch.apic;
|
||||
@ -2229,8 +2244,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
kvm_lapic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
|
||||
kvm_lapic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
|
||||
}
|
||||
apic->irr_pending = vcpu->arch.apicv_active;
|
||||
apic->isr_count = vcpu->arch.apicv_active ? 1 : 0;
|
||||
kvm_apic_update_apicv(vcpu);
|
||||
apic->highest_isr_cache = -1;
|
||||
update_divide_count(apic);
|
||||
atomic_set(&apic->lapic_timer.pending, 0);
|
||||
@ -2487,9 +2501,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
|
||||
apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
|
||||
update_divide_count(apic);
|
||||
start_apic_timer(apic);
|
||||
apic->irr_pending = true;
|
||||
apic->isr_count = vcpu->arch.apicv_active ?
|
||||
1 : count_vectors(apic->regs + APIC_ISR);
|
||||
kvm_apic_update_apicv(vcpu);
|
||||
apic->highest_isr_cache = -1;
|
||||
if (vcpu->arch.apicv_active) {
|
||||
kvm_x86_ops->apicv_post_state_restore(vcpu);
|
||||
|
@ -91,6 +91,7 @@ void kvm_apic_update_ppr(struct kvm_vcpu *vcpu);
|
||||
int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
|
||||
struct dest_map *dest_map);
|
||||
int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
|
||||
void kvm_apic_update_apicv(struct kvm_vcpu *vcpu);
|
||||
|
||||
bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
|
||||
struct kvm_lapic_irq *irq, int *r, struct dest_map *dest_map);
|
||||
|
@ -451,9 +451,9 @@ static u64 get_mmio_spte_generation(u64 spte)
|
||||
return gen;
|
||||
}
|
||||
|
||||
static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn,
|
||||
unsigned access)
|
||||
static u64 make_mmio_spte(struct kvm_vcpu *vcpu, u64 gfn, unsigned int access)
|
||||
{
|
||||
|
||||
u64 gen = kvm_vcpu_memslots(vcpu)->generation & MMIO_SPTE_GEN_MASK;
|
||||
u64 mask = generation_mmio_spte_mask(gen);
|
||||
u64 gpa = gfn << PAGE_SHIFT;
|
||||
@ -464,6 +464,17 @@ static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn,
|
||||
mask |= (gpa & shadow_nonpresent_or_rsvd_mask)
|
||||
<< shadow_nonpresent_or_rsvd_mask_len;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn,
|
||||
unsigned int access)
|
||||
{
|
||||
u64 mask = make_mmio_spte(vcpu, gfn, access);
|
||||
unsigned int gen = get_mmio_spte_generation(mask);
|
||||
|
||||
access = mask & ACC_ALL;
|
||||
|
||||
trace_mark_mmio_spte(sptep, gfn, access, gen);
|
||||
mmu_spte_set(sptep, mask);
|
||||
}
|
||||
@ -484,7 +495,7 @@ static unsigned get_mmio_spte_access(u64 spte)
|
||||
}
|
||||
|
||||
static bool set_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
|
||||
kvm_pfn_t pfn, unsigned access)
|
||||
kvm_pfn_t pfn, unsigned int access)
|
||||
{
|
||||
if (unlikely(is_noslot_pfn(pfn))) {
|
||||
mark_mmio_spte(vcpu, sptep, gfn, access);
|
||||
@ -2475,7 +2486,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
|
||||
gva_t gaddr,
|
||||
unsigned level,
|
||||
int direct,
|
||||
unsigned access)
|
||||
unsigned int access)
|
||||
{
|
||||
union kvm_mmu_page_role role;
|
||||
unsigned quadrant;
|
||||
@ -2990,7 +3001,7 @@ static bool kvm_is_mmio_pfn(kvm_pfn_t pfn)
|
||||
#define SET_SPTE_NEED_REMOTE_TLB_FLUSH BIT(1)
|
||||
|
||||
static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
|
||||
unsigned pte_access, int level,
|
||||
unsigned int pte_access, int level,
|
||||
gfn_t gfn, kvm_pfn_t pfn, bool speculative,
|
||||
bool can_unsync, bool host_writable)
|
||||
{
|
||||
@ -3081,9 +3092,10 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
|
||||
int write_fault, int level, gfn_t gfn, kvm_pfn_t pfn,
|
||||
bool speculative, bool host_writable)
|
||||
static int mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
|
||||
unsigned int pte_access, int write_fault, int level,
|
||||
gfn_t gfn, kvm_pfn_t pfn, bool speculative,
|
||||
bool host_writable)
|
||||
{
|
||||
int was_rmapped = 0;
|
||||
int rmap_count;
|
||||
@ -3165,7 +3177,7 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
|
||||
{
|
||||
struct page *pages[PTE_PREFETCH_NUM];
|
||||
struct kvm_memory_slot *slot;
|
||||
unsigned access = sp->role.access;
|
||||
unsigned int access = sp->role.access;
|
||||
int i, ret;
|
||||
gfn_t gfn;
|
||||
|
||||
@ -3400,7 +3412,8 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)
|
||||
}
|
||||
|
||||
static bool handle_abnormal_pfn(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,
|
||||
kvm_pfn_t pfn, unsigned access, int *ret_val)
|
||||
kvm_pfn_t pfn, unsigned int access,
|
||||
int *ret_val)
|
||||
{
|
||||
/* The pfn is invalid, report the error! */
|
||||
if (unlikely(is_error_pfn(pfn))) {
|
||||
@ -4005,7 +4018,7 @@ static int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct)
|
||||
|
||||
if (is_mmio_spte(spte)) {
|
||||
gfn_t gfn = get_mmio_spte_gfn(spte);
|
||||
unsigned access = get_mmio_spte_access(spte);
|
||||
unsigned int access = get_mmio_spte_access(spte);
|
||||
|
||||
if (!check_mmio_spte(vcpu, spte))
|
||||
return RET_PF_INVALID;
|
||||
@ -4349,7 +4362,7 @@ static void inject_page_fault(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
|
||||
static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
|
||||
unsigned access, int *nr_present)
|
||||
unsigned int access, int *nr_present)
|
||||
{
|
||||
if (unlikely(is_mmio_spte(*sptep))) {
|
||||
if (gfn != get_mmio_spte_gfn(*sptep)) {
|
||||
|
@ -387,6 +387,8 @@ static u8 rsm_ins_bytes[] = "\x0f\xaa";
|
||||
static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
|
||||
static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa);
|
||||
static void svm_complete_interrupts(struct vcpu_svm *svm);
|
||||
static void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate);
|
||||
static inline void avic_post_state_restore(struct kvm_vcpu *vcpu);
|
||||
|
||||
static int nested_svm_exit_handled(struct vcpu_svm *svm);
|
||||
static int nested_svm_intercept(struct vcpu_svm *svm);
|
||||
@ -1545,7 +1547,10 @@ static void avic_init_vmcb(struct vcpu_svm *svm)
|
||||
vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK;
|
||||
vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK;
|
||||
vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT;
|
||||
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
|
||||
if (kvm_apicv_activated(svm->vcpu.kvm))
|
||||
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
|
||||
else
|
||||
vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
|
||||
}
|
||||
|
||||
static void init_vmcb(struct vcpu_svm *svm)
|
||||
@ -1729,23 +1734,28 @@ static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu,
|
||||
* field of the VMCB. Therefore, we set up the
|
||||
* APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here.
|
||||
*/
|
||||
static int avic_init_access_page(struct kvm_vcpu *vcpu)
|
||||
static int avic_update_access_page(struct kvm *kvm, bool activate)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
if (kvm->arch.apic_access_page_done)
|
||||
/*
|
||||
* During kvm_destroy_vm(), kvm_pit_set_reinject() could trigger
|
||||
* APICv mode change, which update APIC_ACCESS_PAGE_PRIVATE_MEMSLOT
|
||||
* memory region. So, we need to ensure that kvm->mm == current->mm.
|
||||
*/
|
||||
if ((kvm->arch.apic_access_page_done == activate) ||
|
||||
(kvm->mm != current->mm))
|
||||
goto out;
|
||||
|
||||
ret = __x86_set_memory_region(kvm,
|
||||
APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
|
||||
APIC_DEFAULT_PHYS_BASE,
|
||||
PAGE_SIZE);
|
||||
activate ? PAGE_SIZE : 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
kvm->arch.apic_access_page_done = true;
|
||||
kvm->arch.apic_access_page_done = activate;
|
||||
out:
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
return ret;
|
||||
@ -1753,21 +1763,24 @@ static int avic_init_access_page(struct kvm_vcpu *vcpu)
|
||||
|
||||
static int avic_init_backing_page(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret;
|
||||
u64 *entry, new_entry;
|
||||
int id = vcpu->vcpu_id;
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
ret = avic_init_access_page(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (id >= AVIC_MAX_PHYSICAL_ID_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
if (!svm->vcpu.arch.apic->regs)
|
||||
return -EINVAL;
|
||||
|
||||
if (kvm_apicv_activated(vcpu->kvm)) {
|
||||
int ret;
|
||||
|
||||
ret = avic_update_access_page(vcpu->kvm, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
svm->avic_backing_page = virt_to_page(svm->vcpu.arch.apic->regs);
|
||||
|
||||
/* Setting AVIC backing page address in the phy APIC ID table */
|
||||
@ -2052,6 +2065,18 @@ static int avic_vm_init(struct kvm *kvm)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int svm_vm_init(struct kvm *kvm)
|
||||
{
|
||||
if (avic) {
|
||||
int ret = avic_vm_init(kvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
kvm_apicv_init(kvm, avic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu, bool r)
|
||||
{
|
||||
@ -2223,7 +2248,8 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
|
||||
/* We initialize this flag to true to make sure that the is_running
|
||||
* bit would be set the first time the vcpu is loaded.
|
||||
*/
|
||||
svm->avic_is_running = true;
|
||||
if (irqchip_in_kernel(vcpu->kvm) && kvm_apicv_activated(vcpu->kvm))
|
||||
svm->avic_is_running = true;
|
||||
|
||||
svm->nested.hsave = page_address(hsave_page);
|
||||
|
||||
@ -2348,6 +2374,8 @@ static void svm_vcpu_blocking(struct kvm_vcpu *vcpu)
|
||||
|
||||
static void svm_vcpu_unblocking(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
|
||||
kvm_vcpu_update_apicv(vcpu);
|
||||
avic_set_running(vcpu, true);
|
||||
}
|
||||
|
||||
@ -4197,6 +4225,8 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
break;
|
||||
case MSR_IA32_SPEC_CTRL:
|
||||
if (!msr_info->host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
|
||||
return 1;
|
||||
@ -4282,6 +4312,8 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
|
||||
break;
|
||||
case MSR_IA32_SPEC_CTRL:
|
||||
if (!msr->host_initiated &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) &&
|
||||
!guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD))
|
||||
return 1;
|
||||
@ -4440,6 +4472,14 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
|
||||
{
|
||||
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
|
||||
svm_clear_vintr(svm);
|
||||
|
||||
/*
|
||||
* For AVIC, the only reason to end up here is ExtINTs.
|
||||
* In this case AVIC was temporarily disabled for
|
||||
* requesting the IRQ window and we have to re-enable it.
|
||||
*/
|
||||
svm_toggle_avic_for_irq_window(&svm->vcpu, true);
|
||||
|
||||
svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
|
||||
mark_dirty(svm->vmcb, VMCB_INTR);
|
||||
++svm->vcpu.stat.irq_window_exits;
|
||||
@ -5135,11 +5175,6 @@ static void svm_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
|
||||
return;
|
||||
}
|
||||
|
||||
static bool svm_get_enable_apicv(struct kvm *kvm)
|
||||
{
|
||||
return avic && irqchip_split(kvm);
|
||||
}
|
||||
|
||||
static void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
|
||||
{
|
||||
}
|
||||
@ -5148,17 +5183,71 @@ static void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr)
|
||||
{
|
||||
}
|
||||
|
||||
/* Note: Currently only used by Hyper-V. */
|
||||
static void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate)
|
||||
{
|
||||
if (!avic || !lapic_in_kernel(vcpu))
|
||||
return;
|
||||
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
|
||||
kvm_request_apicv_update(vcpu->kvm, activate,
|
||||
APICV_INHIBIT_REASON_IRQWIN);
|
||||
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
|
||||
}
|
||||
|
||||
static int svm_set_pi_irte_mode(struct kvm_vcpu *vcpu, bool activate)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
struct amd_svm_iommu_ir *ir;
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
if (!kvm_arch_has_assigned_device(vcpu->kvm))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Here, we go through the per-vcpu ir_list to update all existing
|
||||
* interrupt remapping table entry targeting this vcpu.
|
||||
*/
|
||||
spin_lock_irqsave(&svm->ir_list_lock, flags);
|
||||
|
||||
if (list_empty(&svm->ir_list))
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(ir, &svm->ir_list, node) {
|
||||
if (activate)
|
||||
ret = amd_iommu_activate_guest_mode(ir->data);
|
||||
else
|
||||
ret = amd_iommu_deactivate_guest_mode(ir->data);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
out:
|
||||
spin_unlock_irqrestore(&svm->ir_list_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
struct vmcb *vmcb = svm->vmcb;
|
||||
bool activated = kvm_vcpu_apicv_active(vcpu);
|
||||
|
||||
if (kvm_vcpu_apicv_active(vcpu))
|
||||
if (activated) {
|
||||
/**
|
||||
* During AVIC temporary deactivation, guest could update
|
||||
* APIC ID, DFR and LDR registers, which would not be trapped
|
||||
* by avic_unaccelerated_access_interception(). In this case,
|
||||
* we need to check and update the AVIC logical APIC ID table
|
||||
* accordingly before re-activating.
|
||||
*/
|
||||
avic_post_state_restore(vcpu);
|
||||
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
|
||||
else
|
||||
} else {
|
||||
vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
|
||||
}
|
||||
mark_dirty(vmcb, VMCB_AVIC);
|
||||
|
||||
svm_set_pi_irte_mode(vcpu, activated);
|
||||
}
|
||||
|
||||
static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
|
||||
@ -5445,9 +5534,6 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
|
||||
if (kvm_vcpu_apicv_active(vcpu))
|
||||
return;
|
||||
|
||||
/*
|
||||
* In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
|
||||
* 1, because that's a separate STGI/VMRUN intercept. The next time we
|
||||
@ -5457,6 +5543,13 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
|
||||
* window under the assumption that the hardware will set the GIF.
|
||||
*/
|
||||
if ((vgif_enabled(svm) || gif_set(svm)) && nested_svm_intr(svm)) {
|
||||
/*
|
||||
* IRQ window is not needed when AVIC is enabled,
|
||||
* unless we have pending ExtINT since it cannot be injected
|
||||
* via AVIC. In such case, we need to temporarily disable AVIC,
|
||||
* and fallback to injecting IRQ via V_IRQ.
|
||||
*/
|
||||
svm_toggle_avic_for_irq_window(vcpu, false);
|
||||
svm_set_vintr(svm);
|
||||
svm_inject_irq(svm, 0x0);
|
||||
}
|
||||
@ -5929,6 +6022,14 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu)
|
||||
return;
|
||||
|
||||
guest_cpuid_clear(vcpu, X86_FEATURE_X2APIC);
|
||||
|
||||
/*
|
||||
* Currently, AVIC does not work with nested virtualization.
|
||||
* So, we disable AVIC when cpuid for SVM is set in the L1 guest.
|
||||
*/
|
||||
if (nested && guest_cpuid_has(vcpu, X86_FEATURE_SVM))
|
||||
kvm_request_apicv_update(vcpu->kvm, false,
|
||||
APICV_INHIBIT_REASON_NESTED);
|
||||
}
|
||||
|
||||
#define F feature_bit
|
||||
@ -7257,6 +7358,22 @@ static bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu)
|
||||
(svm->vmcb->control.intercept & (1ULL << INTERCEPT_INIT));
|
||||
}
|
||||
|
||||
static bool svm_check_apicv_inhibit_reasons(ulong bit)
|
||||
{
|
||||
ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
|
||||
BIT(APICV_INHIBIT_REASON_HYPERV) |
|
||||
BIT(APICV_INHIBIT_REASON_NESTED) |
|
||||
BIT(APICV_INHIBIT_REASON_IRQWIN) |
|
||||
BIT(APICV_INHIBIT_REASON_PIT_REINJ);
|
||||
|
||||
return supported & BIT(bit);
|
||||
}
|
||||
|
||||
static void svm_pre_update_apicv_exec_ctrl(struct kvm *kvm, bool activate)
|
||||
{
|
||||
avic_update_access_page(kvm, activate);
|
||||
}
|
||||
|
||||
static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
|
||||
.cpu_has_kvm_support = has_svm,
|
||||
.disabled_by_bios = is_disabled,
|
||||
@ -7274,7 +7391,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
|
||||
|
||||
.vm_alloc = svm_vm_alloc,
|
||||
.vm_free = svm_vm_free,
|
||||
.vm_init = avic_vm_init,
|
||||
.vm_init = svm_vm_init,
|
||||
.vm_destroy = svm_vm_destroy,
|
||||
|
||||
.prepare_guest_switch = svm_prepare_guest_switch,
|
||||
@ -7331,8 +7448,9 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
|
||||
.enable_irq_window = enable_irq_window,
|
||||
.update_cr8_intercept = update_cr8_intercept,
|
||||
.set_virtual_apic_mode = svm_set_virtual_apic_mode,
|
||||
.get_enable_apicv = svm_get_enable_apicv,
|
||||
.refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl,
|
||||
.check_apicv_inhibit_reasons = svm_check_apicv_inhibit_reasons,
|
||||
.pre_update_apicv_exec_ctrl = svm_pre_update_apicv_exec_ctrl,
|
||||
.load_eoi_exitmap = svm_load_eoi_exitmap,
|
||||
.hwapic_irr_update = svm_hwapic_irr_update,
|
||||
.hwapic_isr_update = svm_hwapic_isr_update,
|
||||
|
@ -1291,6 +1291,25 @@ TRACE_EVENT(kvm_hv_stimer_cleanup,
|
||||
__entry->vcpu_id, __entry->timer_index)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_apicv_update_request,
|
||||
TP_PROTO(bool activate, unsigned long bit),
|
||||
TP_ARGS(activate, bit),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(bool, activate)
|
||||
__field(unsigned long, bit)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->activate = activate;
|
||||
__entry->bit = bit;
|
||||
),
|
||||
|
||||
TP_printk("%s bit=%lu",
|
||||
__entry->activate ? "activate" : "deactivate",
|
||||
__entry->bit)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for AMD AVIC
|
||||
*/
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "evmcs.h"
|
||||
#include "vmcs.h"
|
||||
#include "vmx.h"
|
||||
#include "trace.h"
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(enable_evmcs);
|
||||
|
||||
@ -346,6 +347,84 @@ uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
|
||||
{
|
||||
u32 ctl_low = (u32)*pdata;
|
||||
u32 ctl_high = (u32)(*pdata >> 32);
|
||||
|
||||
/*
|
||||
* Hyper-V 2016 and 2019 try using these features even when eVMCS
|
||||
* is enabled but there are no corresponding fields.
|
||||
*/
|
||||
switch (msr_index) {
|
||||
case MSR_IA32_VMX_EXIT_CTLS:
|
||||
case MSR_IA32_VMX_TRUE_EXIT_CTLS:
|
||||
ctl_high &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL;
|
||||
break;
|
||||
case MSR_IA32_VMX_ENTRY_CTLS:
|
||||
case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
|
||||
ctl_high &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
|
||||
break;
|
||||
case MSR_IA32_VMX_PROCBASED_CTLS2:
|
||||
ctl_high &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
|
||||
break;
|
||||
}
|
||||
|
||||
*pdata = ctl_low | ((u64)ctl_high << 32);
|
||||
}
|
||||
|
||||
int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 unsupp_ctl;
|
||||
|
||||
unsupp_ctl = vmcs12->pin_based_vm_exec_control &
|
||||
EVMCS1_UNSUPPORTED_PINCTRL;
|
||||
if (unsupp_ctl) {
|
||||
trace_kvm_nested_vmenter_failed(
|
||||
"eVMCS: unsupported pin-based VM-execution controls",
|
||||
unsupp_ctl);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unsupp_ctl = vmcs12->secondary_vm_exec_control &
|
||||
EVMCS1_UNSUPPORTED_2NDEXEC;
|
||||
if (unsupp_ctl) {
|
||||
trace_kvm_nested_vmenter_failed(
|
||||
"eVMCS: unsupported secondary VM-execution controls",
|
||||
unsupp_ctl);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unsupp_ctl = vmcs12->vm_exit_controls &
|
||||
EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
|
||||
if (unsupp_ctl) {
|
||||
trace_kvm_nested_vmenter_failed(
|
||||
"eVMCS: unsupported VM-exit controls",
|
||||
unsupp_ctl);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unsupp_ctl = vmcs12->vm_entry_controls &
|
||||
EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
|
||||
if (unsupp_ctl) {
|
||||
trace_kvm_nested_vmenter_failed(
|
||||
"eVMCS: unsupported VM-entry controls",
|
||||
unsupp_ctl);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unsupp_ctl = vmcs12->vm_function_control & EVMCS1_UNSUPPORTED_VMFUNC;
|
||||
if (unsupp_ctl) {
|
||||
trace_kvm_nested_vmenter_failed(
|
||||
"eVMCS: unsupported VM-function controls",
|
||||
unsupp_ctl);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
|
||||
uint16_t *vmcs_version)
|
||||
{
|
||||
@ -356,11 +435,5 @@ int nested_enable_evmcs(struct kvm_vcpu *vcpu,
|
||||
if (vmcs_version)
|
||||
*vmcs_version = nested_get_evmcs_version(vcpu);
|
||||
|
||||
vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL;
|
||||
vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
|
||||
vmx->nested.msrs.exit_ctls_high &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
|
||||
vmx->nested.msrs.secondary_ctls_high &= ~EVMCS1_UNSUPPORTED_2NDEXEC;
|
||||
vmx->nested.msrs.vmfunc_controls &= ~EVMCS1_UNSUPPORTED_VMFUNC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "capabilities.h"
|
||||
#include "vmcs.h"
|
||||
#include "vmcs12.h"
|
||||
|
||||
struct vmcs_config;
|
||||
|
||||
@ -201,5 +202,7 @@ bool nested_enlightened_vmentry(struct kvm_vcpu *vcpu, u64 *evmcs_gpa);
|
||||
uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
|
||||
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
|
||||
uint16_t *vmcs_version);
|
||||
void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata);
|
||||
int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
|
||||
|
||||
#endif /* __KVM_X86_VMX_EVMCS_H */
|
||||
|
@ -1074,10 +1074,10 @@ static bool nested_cr3_valid(struct kvm_vcpu *vcpu, unsigned long val)
|
||||
}
|
||||
|
||||
/*
|
||||
* Load guest's/host's cr3 at nested entry/exit. nested_ept is true if we are
|
||||
* emulating VM entry into a guest with EPT enabled.
|
||||
* Returns 0 on success, 1 on failure. Invalid state exit qualification code
|
||||
* is assigned to entry_failure_code on failure.
|
||||
* Load guest's/host's cr3 at nested entry/exit. @nested_ept is true if we are
|
||||
* emulating VM-Entry into a guest with EPT enabled. On failure, the expected
|
||||
* Exit Qualification (for a VM-Entry consistency check VM-Exit) is assigned to
|
||||
* @entry_failure_code.
|
||||
*/
|
||||
static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept,
|
||||
u32 *entry_failure_code)
|
||||
@ -2757,6 +2757,9 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
|
||||
nested_check_vm_entry_controls(vcpu, vmcs12))
|
||||
return -EINVAL;
|
||||
|
||||
if (to_vmx(vcpu)->nested.enlightened_vmcs_enabled)
|
||||
return nested_evmcs_check_controls(vmcs12);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4723,8 +4726,6 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
|
||||
return nested_vmx_succeed(vcpu);
|
||||
}
|
||||
|
||||
static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch);
|
||||
|
||||
/* Emulate the VMLAUNCH instruction */
|
||||
static int handle_vmlaunch(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
|
@ -260,13 +260,12 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
break;
|
||||
default:
|
||||
if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0))) {
|
||||
if (msr_info->host_initiated)
|
||||
pmc->counter = data;
|
||||
else
|
||||
pmc->counter = (s32)data;
|
||||
if (!msr_info->host_initiated)
|
||||
data = (s64)(s32)data;
|
||||
pmc->counter += data - pmc_read_counter(pmc);
|
||||
return 0;
|
||||
} else if ((pmc = get_fixed_pmc(pmu, msr))) {
|
||||
pmc->counter = data;
|
||||
pmc->counter += data - pmc_read_counter(pmc);
|
||||
return 0;
|
||||
} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
|
||||
if (data == pmc->eventsel)
|
||||
|
@ -1428,8 +1428,6 @@ static bool emulation_required(struct kvm_vcpu *vcpu)
|
||||
return emulate_invalid_guest_state && !guest_state_valid(vcpu);
|
||||
}
|
||||
|
||||
static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu);
|
||||
|
||||
unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
@ -1853,8 +1851,20 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
|
||||
if (!nested_vmx_allowed(vcpu))
|
||||
return 1;
|
||||
return vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
|
||||
&msr_info->data);
|
||||
if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
|
||||
&msr_info->data))
|
||||
return 1;
|
||||
/*
|
||||
* Enlightened VMCS v1 doesn't have certain fields, but buggy
|
||||
* Hyper-V versions are still trying to use corresponding
|
||||
* features when they are exposed. Filter out the essential
|
||||
* minimum.
|
||||
*/
|
||||
if (!msr_info->host_initiated &&
|
||||
vmx->nested.enlightened_vmcs_enabled)
|
||||
nested_evmcs_filter_control_msr(msr_info->index,
|
||||
&msr_info->data);
|
||||
break;
|
||||
case MSR_IA32_RTIT_CTL:
|
||||
if (pt_mode != PT_MODE_HOST_GUEST)
|
||||
return 1;
|
||||
@ -3719,11 +3729,6 @@ void pt_update_intercept_for_msr(struct vcpu_vmx *vmx)
|
||||
}
|
||||
}
|
||||
|
||||
static bool vmx_get_enable_apicv(struct kvm *kvm)
|
||||
{
|
||||
return enable_apicv;
|
||||
}
|
||||
|
||||
static bool vmx_guest_apic_has_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
@ -6813,6 +6818,7 @@ static int vmx_vm_init(struct kvm *kvm)
|
||||
break;
|
||||
}
|
||||
}
|
||||
kvm_apicv_init(kvm, enable_apicv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -7714,6 +7720,14 @@ static __exit void hardware_unsetup(void)
|
||||
free_kvm_area();
|
||||
}
|
||||
|
||||
static bool vmx_check_apicv_inhibit_reasons(ulong bit)
|
||||
{
|
||||
ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
|
||||
BIT(APICV_INHIBIT_REASON_HYPERV);
|
||||
|
||||
return supported & BIT(bit);
|
||||
}
|
||||
|
||||
static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
|
||||
.cpu_has_kvm_support = cpu_has_kvm_support,
|
||||
.disabled_by_bios = vmx_disabled_by_bios,
|
||||
@ -7786,10 +7800,10 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
|
||||
.update_cr8_intercept = update_cr8_intercept,
|
||||
.set_virtual_apic_mode = vmx_set_virtual_apic_mode,
|
||||
.set_apic_access_page_addr = vmx_set_apic_access_page_addr,
|
||||
.get_enable_apicv = vmx_get_enable_apicv,
|
||||
.refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
|
||||
.load_eoi_exitmap = vmx_load_eoi_exitmap,
|
||||
.apicv_post_state_restore = vmx_apicv_post_state_restore,
|
||||
.check_apicv_inhibit_reasons = vmx_check_apicv_inhibit_reasons,
|
||||
.hwapic_irr_update = vmx_hwapic_irr_update,
|
||||
.hwapic_isr_update = vmx_hwapic_isr_update,
|
||||
.guest_apic_has_interrupt = vmx_guest_apic_has_interrupt,
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "cpuid.h"
|
||||
#include "pmu.h"
|
||||
#include "hyperv.h"
|
||||
#include "lapic.h"
|
||||
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -897,6 +898,8 @@ EXPORT_SYMBOL_GPL(kvm_set_xcr);
|
||||
__reserved_bits |= X86_CR4_PKE; \
|
||||
if (!__cpu_has(__c, X86_FEATURE_LA57)) \
|
||||
__reserved_bits |= X86_CR4_LA57; \
|
||||
if (!__cpu_has(__c, X86_FEATURE_UMIP)) \
|
||||
__reserved_bits |= X86_CR4_UMIP; \
|
||||
__reserved_bits; \
|
||||
})
|
||||
|
||||
@ -1609,6 +1612,8 @@ struct pvclock_clock {
|
||||
u64 mask;
|
||||
u32 mult;
|
||||
u32 shift;
|
||||
u64 base_cycles;
|
||||
u64 offset;
|
||||
};
|
||||
|
||||
struct pvclock_gtod_data {
|
||||
@ -1617,11 +1622,8 @@ struct pvclock_gtod_data {
|
||||
struct pvclock_clock clock; /* extract of a clocksource struct */
|
||||
struct pvclock_clock raw_clock; /* extract of a clocksource struct */
|
||||
|
||||
u64 boot_ns_raw;
|
||||
u64 boot_ns;
|
||||
u64 nsec_base;
|
||||
ktime_t offs_boot;
|
||||
u64 wall_time_sec;
|
||||
u64 monotonic_raw_nsec;
|
||||
};
|
||||
|
||||
static struct pvclock_gtod_data pvclock_gtod_data;
|
||||
@ -1629,10 +1631,6 @@ static struct pvclock_gtod_data pvclock_gtod_data;
|
||||
static void update_pvclock_gtod(struct timekeeper *tk)
|
||||
{
|
||||
struct pvclock_gtod_data *vdata = &pvclock_gtod_data;
|
||||
u64 boot_ns, boot_ns_raw;
|
||||
|
||||
boot_ns = ktime_to_ns(ktime_add(tk->tkr_mono.base, tk->offs_boot));
|
||||
boot_ns_raw = ktime_to_ns(ktime_add(tk->tkr_raw.base, tk->offs_boot));
|
||||
|
||||
write_seqcount_begin(&vdata->seq);
|
||||
|
||||
@ -1642,23 +1640,35 @@ static void update_pvclock_gtod(struct timekeeper *tk)
|
||||
vdata->clock.mask = tk->tkr_mono.mask;
|
||||
vdata->clock.mult = tk->tkr_mono.mult;
|
||||
vdata->clock.shift = tk->tkr_mono.shift;
|
||||
vdata->clock.base_cycles = tk->tkr_mono.xtime_nsec;
|
||||
vdata->clock.offset = tk->tkr_mono.base;
|
||||
|
||||
vdata->raw_clock.vclock_mode = tk->tkr_raw.clock->archdata.vclock_mode;
|
||||
vdata->raw_clock.cycle_last = tk->tkr_raw.cycle_last;
|
||||
vdata->raw_clock.mask = tk->tkr_raw.mask;
|
||||
vdata->raw_clock.mult = tk->tkr_raw.mult;
|
||||
vdata->raw_clock.shift = tk->tkr_raw.shift;
|
||||
|
||||
vdata->boot_ns = boot_ns;
|
||||
vdata->nsec_base = tk->tkr_mono.xtime_nsec;
|
||||
vdata->raw_clock.base_cycles = tk->tkr_raw.xtime_nsec;
|
||||
vdata->raw_clock.offset = tk->tkr_raw.base;
|
||||
|
||||
vdata->wall_time_sec = tk->xtime_sec;
|
||||
|
||||
vdata->boot_ns_raw = boot_ns_raw;
|
||||
vdata->monotonic_raw_nsec = tk->tkr_raw.xtime_nsec;
|
||||
vdata->offs_boot = tk->offs_boot;
|
||||
|
||||
write_seqcount_end(&vdata->seq);
|
||||
}
|
||||
|
||||
static s64 get_kvmclock_base_ns(void)
|
||||
{
|
||||
/* Count up from boot time, but with the frequency of the raw clock. */
|
||||
return ktime_to_ns(ktime_add(ktime_get_raw(), pvclock_gtod_data.offs_boot));
|
||||
}
|
||||
#else
|
||||
static s64 get_kvmclock_base_ns(void)
|
||||
{
|
||||
/* Master clock not used, so we can just use CLOCK_BOOTTIME. */
|
||||
return ktime_get_boottime_ns();
|
||||
}
|
||||
#endif
|
||||
|
||||
void kvm_set_pending_timer(struct kvm_vcpu *vcpu)
|
||||
@ -1672,7 +1682,7 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
|
||||
int version;
|
||||
int r;
|
||||
struct pvclock_wall_clock wc;
|
||||
struct timespec64 boot;
|
||||
u64 wall_nsec;
|
||||
|
||||
if (!wall_clock)
|
||||
return;
|
||||
@ -1692,17 +1702,12 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
|
||||
/*
|
||||
* The guest calculates current wall clock time by adding
|
||||
* system time (updated by kvm_guest_time_update below) to the
|
||||
* wall clock specified here. guest system time equals host
|
||||
* system time for us, thus we must fill in host boot time here.
|
||||
* wall clock specified here. We do the reverse here.
|
||||
*/
|
||||
getboottime64(&boot);
|
||||
wall_nsec = ktime_get_real_ns() - get_kvmclock_ns(kvm);
|
||||
|
||||
if (kvm->arch.kvmclock_offset) {
|
||||
struct timespec64 ts = ns_to_timespec64(kvm->arch.kvmclock_offset);
|
||||
boot = timespec64_sub(boot, ts);
|
||||
}
|
||||
wc.sec = (u32)boot.tv_sec; /* overflow in 2106 guest time */
|
||||
wc.nsec = boot.tv_nsec;
|
||||
wc.nsec = do_div(wall_nsec, 1000000000);
|
||||
wc.sec = (u32)wall_nsec; /* overflow in 2106 guest time */
|
||||
wc.version = version;
|
||||
|
||||
kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc));
|
||||
@ -1950,7 +1955,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
|
||||
|
||||
raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
|
||||
offset = kvm_compute_tsc_offset(vcpu, data);
|
||||
ns = ktime_get_boottime_ns();
|
||||
ns = get_kvmclock_base_ns();
|
||||
elapsed = ns - kvm->arch.last_tsc_nsec;
|
||||
|
||||
if (vcpu->arch.virtual_tsc_khz) {
|
||||
@ -2125,10 +2130,10 @@ static int do_monotonic_raw(s64 *t, u64 *tsc_timestamp)
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(>od->seq);
|
||||
ns = gtod->monotonic_raw_nsec;
|
||||
ns = gtod->raw_clock.base_cycles;
|
||||
ns += vgettsc(>od->raw_clock, tsc_timestamp, &mode);
|
||||
ns >>= gtod->clock.shift;
|
||||
ns += gtod->boot_ns_raw;
|
||||
ns >>= gtod->raw_clock.shift;
|
||||
ns += ktime_to_ns(ktime_add(gtod->raw_clock.offset, gtod->offs_boot));
|
||||
} while (unlikely(read_seqcount_retry(>od->seq, seq)));
|
||||
*t = ns;
|
||||
|
||||
@ -2145,7 +2150,7 @@ static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp)
|
||||
do {
|
||||
seq = read_seqcount_begin(>od->seq);
|
||||
ts->tv_sec = gtod->wall_time_sec;
|
||||
ns = gtod->nsec_base;
|
||||
ns = gtod->clock.base_cycles;
|
||||
ns += vgettsc(>od->clock, tsc_timestamp, &mode);
|
||||
ns >>= gtod->clock.shift;
|
||||
} while (unlikely(read_seqcount_retry(>od->seq, seq)));
|
||||
@ -2288,7 +2293,7 @@ u64 get_kvmclock_ns(struct kvm *kvm)
|
||||
spin_lock(&ka->pvclock_gtod_sync_lock);
|
||||
if (!ka->use_master_clock) {
|
||||
spin_unlock(&ka->pvclock_gtod_sync_lock);
|
||||
return ktime_get_boottime_ns() + ka->kvmclock_offset;
|
||||
return get_kvmclock_base_ns() + ka->kvmclock_offset;
|
||||
}
|
||||
|
||||
hv_clock.tsc_timestamp = ka->master_cycle_now;
|
||||
@ -2304,7 +2309,7 @@ u64 get_kvmclock_ns(struct kvm *kvm)
|
||||
&hv_clock.tsc_to_system_mul);
|
||||
ret = __pvclock_read_cycles(&hv_clock, rdtsc());
|
||||
} else
|
||||
ret = ktime_get_boottime_ns() + ka->kvmclock_offset;
|
||||
ret = get_kvmclock_base_ns() + ka->kvmclock_offset;
|
||||
|
||||
put_cpu();
|
||||
|
||||
@ -2403,7 +2408,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
|
||||
}
|
||||
if (!use_master_clock) {
|
||||
host_tsc = rdtsc();
|
||||
kernel_ns = ktime_get_boottime_ns();
|
||||
kernel_ns = get_kvmclock_base_ns();
|
||||
}
|
||||
|
||||
tsc_timestamp = kvm_read_l1_tsc(v, host_tsc);
|
||||
@ -2443,6 +2448,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
|
||||
vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
|
||||
vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
|
||||
vcpu->last_guest_tsc = tsc_timestamp;
|
||||
WARN_ON(vcpu->hv_clock.system_time < 0);
|
||||
|
||||
/* If the host uses TSC clocksource, then it is stable */
|
||||
pvclock_flags = 0;
|
||||
@ -7456,18 +7462,22 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
|
||||
kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
|
||||
}
|
||||
|
||||
void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
|
||||
bool kvm_apicv_activated(struct kvm *kvm)
|
||||
{
|
||||
if (!lapic_in_kernel(vcpu)) {
|
||||
WARN_ON_ONCE(vcpu->arch.apicv_active);
|
||||
return;
|
||||
}
|
||||
if (!vcpu->arch.apicv_active)
|
||||
return;
|
||||
|
||||
vcpu->arch.apicv_active = false;
|
||||
kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
|
||||
return (READ_ONCE(kvm->arch.apicv_inhibit_reasons) == 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_apicv_activated);
|
||||
|
||||
void kvm_apicv_init(struct kvm *kvm, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
clear_bit(APICV_INHIBIT_REASON_DISABLE,
|
||||
&kvm->arch.apicv_inhibit_reasons);
|
||||
else
|
||||
set_bit(APICV_INHIBIT_REASON_DISABLE,
|
||||
&kvm->arch.apicv_inhibit_reasons);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_apicv_init);
|
||||
|
||||
static void kvm_sched_yield(struct kvm *kvm, unsigned long dest_id)
|
||||
{
|
||||
@ -7996,6 +8006,47 @@ void kvm_make_scan_ioapic_request(struct kvm *kvm)
|
||||
kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
|
||||
}
|
||||
|
||||
void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!lapic_in_kernel(vcpu))
|
||||
return;
|
||||
|
||||
vcpu->arch.apicv_active = kvm_apicv_activated(vcpu->kvm);
|
||||
kvm_apic_update_apicv(vcpu);
|
||||
kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_vcpu_update_apicv);
|
||||
|
||||
/*
|
||||
* NOTE: Do not hold any lock prior to calling this.
|
||||
*
|
||||
* In particular, kvm_request_apicv_update() expects kvm->srcu not to be
|
||||
* locked, because it calls __x86_set_memory_region() which does
|
||||
* synchronize_srcu(&kvm->srcu).
|
||||
*/
|
||||
void kvm_request_apicv_update(struct kvm *kvm, bool activate, ulong bit)
|
||||
{
|
||||
if (!kvm_x86_ops->check_apicv_inhibit_reasons ||
|
||||
!kvm_x86_ops->check_apicv_inhibit_reasons(bit))
|
||||
return;
|
||||
|
||||
if (activate) {
|
||||
if (!test_and_clear_bit(bit, &kvm->arch.apicv_inhibit_reasons) ||
|
||||
!kvm_apicv_activated(kvm))
|
||||
return;
|
||||
} else {
|
||||
if (test_and_set_bit(bit, &kvm->arch.apicv_inhibit_reasons) ||
|
||||
kvm_apicv_activated(kvm))
|
||||
return;
|
||||
}
|
||||
|
||||
trace_kvm_apicv_update_request(activate, bit);
|
||||
if (kvm_x86_ops->pre_update_apicv_exec_ctrl)
|
||||
kvm_x86_ops->pre_update_apicv_exec_ctrl(kvm, activate);
|
||||
kvm_make_all_cpus_request(kvm, KVM_REQ_APICV_UPDATE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_request_apicv_update);
|
||||
|
||||
static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!kvm_apic_present(vcpu))
|
||||
@ -8186,6 +8237,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
|
||||
kvm_hv_process_stimers(vcpu);
|
||||
if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
|
||||
kvm_vcpu_update_apicv(vcpu);
|
||||
}
|
||||
|
||||
if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
|
||||
@ -9219,10 +9272,11 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
||||
return r;
|
||||
|
||||
if (irqchip_in_kernel(vcpu->kvm)) {
|
||||
vcpu->arch.apicv_active = kvm_x86_ops->get_enable_apicv(vcpu->kvm);
|
||||
r = kvm_create_lapic(vcpu, lapic_timer_advance_ns);
|
||||
if (r < 0)
|
||||
goto fail_mmu_destroy;
|
||||
if (kvm_apicv_activated(vcpu->kvm))
|
||||
vcpu->arch.apicv_active = true;
|
||||
} else
|
||||
static_key_slow_inc(&kvm_no_apic_vcpu);
|
||||
|
||||
@ -9633,7 +9687,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||
mutex_init(&kvm->arch.apic_map_lock);
|
||||
spin_lock_init(&kvm->arch.pvclock_gtod_sync_lock);
|
||||
|
||||
kvm->arch.kvmclock_offset = -ktime_get_boottime_ns();
|
||||
kvm->arch.kvmclock_offset = -get_kvmclock_base_ns();
|
||||
pvclock_update_vm_gtod_copy(kvm);
|
||||
|
||||
kvm->arch.guest_can_read_msr_platform_info = true;
|
||||
@ -10448,3 +10502,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pml_full);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_incomplete_ipi);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_apicv_update_request);
|
||||
|
@ -357,7 +357,7 @@ static inline bool kvm_pat_valid(u64 data)
|
||||
return (data | ((data & 0x0202020202020202ull) << 1)) == data;
|
||||
}
|
||||
|
||||
static inline bool kvm_dr7_valid(unsigned long data)
|
||||
static inline bool kvm_dr7_valid(u64 data)
|
||||
{
|
||||
/* Bits [63:32] are reserved */
|
||||
return !(data >> 32);
|
||||
|
@ -180,11 +180,11 @@ config HAVE_SMP
|
||||
depends on XTENSA_VARIANT_CUSTOM
|
||||
select XTENSA_MX
|
||||
help
|
||||
This option is use to indicate that the system-on-a-chip (SOC)
|
||||
This option is used to indicate that the system-on-a-chip (SOC)
|
||||
supports Multiprocessing. Multiprocessor support implemented above
|
||||
the CPU core definition and currently needs to be selected manually.
|
||||
|
||||
Multiprocessor support in implemented with external cache and
|
||||
Multiprocessor support is implemented with external cache and
|
||||
interrupt controllers.
|
||||
|
||||
The MX interrupt distributer adds Interprocessor Interrupts
|
||||
@ -572,15 +572,41 @@ config KERNEL_LOAD_ADDRESS
|
||||
|
||||
If unsure, leave the default value here.
|
||||
|
||||
config VECTORS_OFFSET
|
||||
hex "Kernel vectors offset"
|
||||
default 0x00003000
|
||||
depends on !XIP_KERNEL
|
||||
choice
|
||||
prompt "Relocatable vectors location"
|
||||
default XTENSA_VECTORS_IN_TEXT
|
||||
help
|
||||
This is the offset of the kernel image from the relocatable vectors
|
||||
base.
|
||||
Choose whether relocatable vectors are merged into the kernel .text
|
||||
or placed separately at runtime. This option does not affect
|
||||
configurations without VECBASE register where vectors are always
|
||||
placed at their hardware-defined locations.
|
||||
|
||||
If unsure, leave the default value here.
|
||||
config XTENSA_VECTORS_IN_TEXT
|
||||
bool "Merge relocatable vectors into kernel text"
|
||||
depends on !MTD_XIP
|
||||
help
|
||||
This option puts relocatable vectors into the kernel .text section
|
||||
with proper alignment.
|
||||
This is a safe choice for most configurations.
|
||||
|
||||
config XTENSA_VECTORS_SEPARATE
|
||||
bool "Put relocatable vectors at fixed address"
|
||||
help
|
||||
This option puts relocatable vectors at specific virtual address.
|
||||
Vectors are merged with the .init data in the kernel image and
|
||||
are copied into their designated location during kernel startup.
|
||||
Use it to put vectors into IRAM or out of FLASH on kernels with
|
||||
XIP-aware MTD support.
|
||||
|
||||
endchoice
|
||||
|
||||
config VECTORS_ADDR
|
||||
hex "Kernel vectors virtual address"
|
||||
default 0x00000000
|
||||
depends on XTENSA_VECTORS_SEPARATE
|
||||
help
|
||||
This is the virtual address of the (relocatable) vectors base.
|
||||
It must be within KSEG if MMU is used.
|
||||
|
||||
config XIP_DATA_ADDR
|
||||
hex "XIP kernel data virtual address"
|
||||
|
@ -21,8 +21,6 @@ CONFIG_PROFILING=y
|
||||
CONFIG_OPROFILE=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
CONFIG_XTENSA_VARIANT_CUSTOM=y
|
||||
CONFIG_XTENSA_VARIANT_CUSTOM_NAME="test_kc705_hifi"
|
||||
CONFIG_XTENSA_UNALIGNED_USER=y
|
||||
|
@ -27,8 +27,6 @@ CONFIG_MODULES=y
|
||||
CONFIG_MODULE_FORCE_LOAD=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
CONFIG_XTENSA_VARIANT_CUSTOM=y
|
||||
CONFIG_XTENSA_VARIANT_CUSTOM_NAME="csp"
|
||||
CONFIG_XTENSA_UNALIGNED_USER=y
|
||||
|
@ -21,8 +21,6 @@ CONFIG_PROFILING=y
|
||||
CONFIG_OPROFILE=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
CONFIG_XTENSA_VARIANT_DC233C=y
|
||||
CONFIG_XTENSA_UNALIGNED_USER=y
|
||||
CONFIG_PREEMPT=y
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user