Merge remote-tracking branch 'torvalds/master' into perf/core
To pick up fixes and get in line with other trees, powerpc kernel mostly this time, but BPF as well. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
9
.mailmap
@ -10,10 +10,12 @@
|
||||
# Please keep this list dictionary sorted.
|
||||
#
|
||||
Aaron Durbin <adurbin@google.com>
|
||||
Abhinav Kumar <quic_abhinavk@quicinc.com> <abhinavk@codeaurora.org>
|
||||
Adam Oldham <oldhamca@gmail.com>
|
||||
Adam Radford <aradford@gmail.com>
|
||||
Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com>
|
||||
Adrian Bunk <bunk@stusta.de>
|
||||
Akhil P Oommen <quic_akhilpo@quicinc.com> <akhilpo@codeaurora.org>
|
||||
Alan Cox <alan@lxorguk.ukuu.org.uk>
|
||||
Alan Cox <root@hraefn.swansea.linux.org.uk>
|
||||
Aleksandar Markovic <aleksandar.markovic@mips.com> <aleksandar.markovic@imgtec.com>
|
||||
@ -42,6 +44,7 @@ Andrew Vasquez <andrew.vasquez@qlogic.com>
|
||||
Andrey Konovalov <andreyknvl@gmail.com> <andreyknvl@google.com>
|
||||
Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
|
||||
Andrey Ryabinin <ryabinin.a.a@gmail.com> <aryabinin@virtuozzo.com>
|
||||
Andrzej Hajda <andrzej.hajda@intel.com> <a.hajda@samsung.com>
|
||||
Andy Adamson <andros@citi.umich.edu>
|
||||
Antoine Tenart <atenart@kernel.org> <antoine.tenart@bootlin.com>
|
||||
Antoine Tenart <atenart@kernel.org> <antoine.tenart@free-electrons.com>
|
||||
@ -172,6 +175,7 @@ Jeff Layton <jlayton@kernel.org> <jlayton@redhat.com>
|
||||
Jens Axboe <axboe@suse.de>
|
||||
Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
|
||||
Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
|
||||
Jessica Zhang <quic_jesszhan@quicinc.com> <jesszhan@codeaurora.org>
|
||||
Jiri Slaby <jirislaby@kernel.org> <jirislaby@gmail.com>
|
||||
Jiri Slaby <jirislaby@kernel.org> <jslaby@novell.com>
|
||||
Jiri Slaby <jirislaby@kernel.org> <jslaby@suse.com>
|
||||
@ -191,6 +195,7 @@ Juha Yrjola <at solidboot.com>
|
||||
Juha Yrjola <juha.yrjola@nokia.com>
|
||||
Juha Yrjola <juha.yrjola@solidboot.com>
|
||||
Julien Thierry <julien.thierry.kdev@gmail.com> <julien.thierry@arm.com>
|
||||
Kalyan Thota <quic_kalyant@quicinc.com> <kalyan_t@codeaurora.org>
|
||||
Kay Sievers <kay.sievers@vrfy.org>
|
||||
Kees Cook <keescook@chromium.org> <kees.cook@canonical.com>
|
||||
Kees Cook <keescook@chromium.org> <keescook@google.com>
|
||||
@ -202,9 +207,11 @@ Kenneth W Chen <kenneth.w.chen@intel.com>
|
||||
Konstantin Khlebnikov <koct9i@gmail.com> <khlebnikov@yandex-team.ru>
|
||||
Konstantin Khlebnikov <koct9i@gmail.com> <k.khlebnikov@samsung.com>
|
||||
Koushik <raghavendra.koushik@neterion.com>
|
||||
Krishna Manikandan <quic_mkrishn@quicinc.com> <mkrishn@codeaurora.org>
|
||||
Krzysztof Kozlowski <krzk@kernel.org> <k.kozlowski.k@gmail.com>
|
||||
Krzysztof Kozlowski <krzk@kernel.org> <k.kozlowski@samsung.com>
|
||||
Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
Kuogee Hsieh <quic_khsieh@quicinc.com> <khsieh@codeaurora.org>
|
||||
Leonardo Bras <leobras.c@gmail.com> <leonardo@linux.ibm.com>
|
||||
Leonid I Ananiev <leonid.i.ananiev@intel.com>
|
||||
Leon Romanovsky <leon@kernel.org> <leon@leon.nu>
|
||||
@ -311,6 +318,7 @@ Qais Yousef <qsyousef@gmail.com> <qais.yousef@imgtec.com>
|
||||
Quentin Monnet <quentin@isovalent.com> <quentin.monnet@netronome.com>
|
||||
Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com>
|
||||
Rafael J. Wysocki <rjw@rjwysocki.net> <rjw@sisk.pl>
|
||||
Rajeev Nandan <quic_rajeevny@quicinc.com> <rajeevny@codeaurora.org>
|
||||
Rajesh Shah <rajesh.shah@intel.com>
|
||||
Ralf Baechle <ralf@linux-mips.org>
|
||||
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
@ -325,6 +333,7 @@ Rui Saraiva <rmps@joel.ist.utl.pt>
|
||||
Sachin P Sant <ssant@in.ibm.com>
|
||||
Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi>
|
||||
Sam Ravnborg <sam@mars.ravnborg.org>
|
||||
Sankeerth Billakanti <quic_sbillaka@quicinc.com> <sbillaka@codeaurora.org>
|
||||
Santosh Shilimkar <santosh.shilimkar@oracle.org>
|
||||
Santosh Shilimkar <ssantosh@kernel.org>
|
||||
Sarangdhar Joshi <spjoshi@codeaurora.org>
|
||||
|
@ -1,22 +0,0 @@
|
||||
What: /sys/class/dax/
|
||||
Date: May, 2016
|
||||
KernelVersion: v4.7
|
||||
Contact: nvdimm@lists.linux.dev
|
||||
Description: Device DAX is the device-centric analogue of Filesystem
|
||||
DAX (CONFIG_FS_DAX). It allows memory ranges to be
|
||||
allocated and mapped without need of an intervening file
|
||||
system. Device DAX is strict, precise and predictable.
|
||||
Specifically this interface:
|
||||
|
||||
1. Guarantees fault granularity with respect to a given
|
||||
page size (pte, pmd, or pud) set at configuration time.
|
||||
|
||||
2. Enforces deterministic behavior by being strict about
|
||||
what fault scenarios are supported.
|
||||
|
||||
The /sys/class/dax/ interface enumerates all the
|
||||
device-dax instances in the system. The ABI is
|
||||
deprecated and will be removed after 2020. It is
|
||||
replaced with the DAX bus interface /sys/bus/dax/ where
|
||||
device-dax instances can be found under
|
||||
/sys/bus/dax/devices/
|
676
Documentation/ABI/stable/sysfs-block
Normal file
@ -0,0 +1,676 @@
|
||||
What: /sys/block/<disk>/alignment_offset
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Storage devices may report a physical block size that is
|
||||
bigger than the logical block size (for instance a drive
|
||||
with 4KB physical sectors exposing 512-byte logical
|
||||
blocks to the operating system). This parameter
|
||||
indicates how many bytes the beginning of the device is
|
||||
offset from the disk's natural alignment.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/discard_alignment
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Devices that support discard functionality may
|
||||
internally allocate space in units that are bigger than
|
||||
the exported logical block size. The discard_alignment
|
||||
parameter indicates how many bytes the beginning of the
|
||||
device is offset from the internal allocation unit's
|
||||
natural alignment.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/diskseq
|
||||
Date: February 2021
|
||||
Contact: Matteo Croce <mcroce@microsoft.com>
|
||||
Description:
|
||||
The /sys/block/<disk>/diskseq files reports the disk
|
||||
sequence number, which is a monotonically increasing
|
||||
number assigned to every drive.
|
||||
Some devices, like the loop device, refresh such number
|
||||
every time the backing file is changed.
|
||||
The value type is 64 bit unsigned.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/inflight
|
||||
Date: October 2009
|
||||
Contact: Jens Axboe <axboe@kernel.dk>, Nikanth Karthikesan <knikanth@suse.de>
|
||||
Description:
|
||||
Reports the number of I/O requests currently in progress
|
||||
(pending / in flight) in a device driver. This can be less
|
||||
than the number of requests queued in the block device queue.
|
||||
The report contains 2 fields: one for read requests
|
||||
and one for write requests.
|
||||
The value type is unsigned int.
|
||||
Cf. Documentation/block/stat.rst which contains a single value for
|
||||
requests in flight.
|
||||
This is related to /sys/block/<disk>/queue/nr_requests
|
||||
and for SCSI device also its queue_depth.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/device_is_integrity_capable
|
||||
Date: July 2014
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Indicates whether a storage device is capable of storing
|
||||
integrity metadata. Set if the device is T10 PI-capable.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/format
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Metadata format for integrity capable block device.
|
||||
E.g. T10-DIF-TYPE1-CRC.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/protection_interval_bytes
|
||||
Date: July 2015
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Describes the number of data bytes which are protected
|
||||
by one integrity tuple. Typically the device's logical
|
||||
block size.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/read_verify
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Indicates whether the block layer should verify the
|
||||
integrity of read requests serviced by devices that
|
||||
support sending integrity metadata.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/tag_size
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Number of bytes of integrity tag space available per
|
||||
512 bytes of data.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/write_generate
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Indicates whether the block layer should automatically
|
||||
generate checksums for write requests bound for
|
||||
devices that support receiving integrity metadata.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/<partition>/alignment_offset
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Storage devices may report a physical block size that is
|
||||
bigger than the logical block size (for instance a drive
|
||||
with 4KB physical sectors exposing 512-byte logical
|
||||
blocks to the operating system). This parameter
|
||||
indicates how many bytes the beginning of the partition
|
||||
is offset from the disk's natural alignment.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/<partition>/discard_alignment
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Devices that support discard functionality may
|
||||
internally allocate space in units that are bigger than
|
||||
the exported logical block size. The discard_alignment
|
||||
parameter indicates how many bytes the beginning of the
|
||||
partition is offset from the internal allocation unit's
|
||||
natural alignment.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/<partition>/stat
|
||||
Date: February 2008
|
||||
Contact: Jerome Marchand <jmarchan@redhat.com>
|
||||
Description:
|
||||
The /sys/block/<disk>/<partition>/stat files display the
|
||||
I/O statistics of partition <partition>. The format is the
|
||||
same as the format of /sys/block/<disk>/stat.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/add_random
|
||||
Date: June 2010
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] This file allows to turn off the disk entropy contribution.
|
||||
Default value of this file is '1'(on).
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/chunk_sectors
|
||||
Date: September 2016
|
||||
Contact: Hannes Reinecke <hare@suse.com>
|
||||
Description:
|
||||
[RO] chunk_sectors has different meaning depending on the type
|
||||
of the disk. For a RAID device (dm-raid), chunk_sectors
|
||||
indicates the size in 512B sectors of the RAID volume stripe
|
||||
segment. For a zoned block device, either host-aware or
|
||||
host-managed, chunk_sectors indicates the size in 512B sectors
|
||||
of the zones of the device, with the eventual exception of the
|
||||
last zone of the device which may be smaller.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/dax
|
||||
Date: June 2016
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] This file indicates whether the device supports Direct
|
||||
Access (DAX), used by CPU-addressable storage to bypass the
|
||||
pagecache. It shows '1' if true, '0' if not.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/discard_granularity
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RO] Devices that support discard functionality may internally
|
||||
allocate space using units that are bigger than the logical
|
||||
block size. The discard_granularity parameter indicates the size
|
||||
of the internal allocation unit in bytes if reported by the
|
||||
device. Otherwise the discard_granularity will be set to match
|
||||
the device's physical block size. A discard_granularity of 0
|
||||
means that the device does not support discard functionality.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/discard_max_bytes
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RW] While discard_max_hw_bytes is the hardware limit for the
|
||||
device, this setting is the software limit. Some devices exhibit
|
||||
large latencies when large discards are issued, setting this
|
||||
value lower will make Linux issue smaller discards and
|
||||
potentially help reduce latencies induced by large discard
|
||||
operations.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/discard_max_hw_bytes
|
||||
Date: July 2015
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] Devices that support discard functionality may have
|
||||
internal limits on the number of bytes that can be trimmed or
|
||||
unmapped in a single operation. The `discard_max_hw_bytes`
|
||||
parameter is set by the device driver to the maximum number of
|
||||
bytes that can be discarded in a single operation. Discard
|
||||
requests issued to the device must not exceed this limit. A
|
||||
`discard_max_hw_bytes` value of 0 means that the device does not
|
||||
support discard functionality.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/discard_zeroes_data
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RO] Will always return 0. Don't rely on any specific behavior
|
||||
for discards, and don't read this file.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/fua
|
||||
Date: May 2018
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] Whether or not the block driver supports the FUA flag for
|
||||
write requests. FUA stands for Force Unit Access. If the FUA
|
||||
flag is set that means that write requests must bypass the
|
||||
volatile cache of the storage device.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/hw_sector_size
|
||||
Date: January 2008
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] This is the hardware sector size of the device, in bytes.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/independent_access_ranges/
|
||||
Date: October 2021
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] The presence of this sub-directory of the
|
||||
/sys/block/xxx/queue/ directory indicates that the device is
|
||||
capable of executing requests targeting different sector ranges
|
||||
in parallel. For instance, single LUN multi-actuator hard-disks
|
||||
will have an independent_access_ranges directory if the device
|
||||
correctly advertizes the sector ranges of its actuators.
|
||||
|
||||
The independent_access_ranges directory contains one directory
|
||||
per access range, with each range described using the sector
|
||||
(RO) attribute file to indicate the first sector of the range
|
||||
and the nr_sectors (RO) attribute file to indicate the total
|
||||
number of sectors in the range starting from the first sector of
|
||||
the range. For example, a dual-actuator hard-disk will have the
|
||||
following independent_access_ranges entries.::
|
||||
|
||||
$ tree /sys/block/<disk>/queue/independent_access_ranges/
|
||||
/sys/block/<disk>/queue/independent_access_ranges/
|
||||
|-- 0
|
||||
| |-- nr_sectors
|
||||
| `-- sector
|
||||
`-- 1
|
||||
|-- nr_sectors
|
||||
`-- sector
|
||||
|
||||
The sector and nr_sectors attributes use 512B sector unit,
|
||||
regardless of the actual block size of the device. Independent
|
||||
access ranges do not overlap and include all sectors within the
|
||||
device capacity. The access ranges are numbered in increasing
|
||||
order of the range start sector, that is, the sector attribute
|
||||
of range 0 always has the value 0.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/io_poll
|
||||
Date: November 2015
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] When read, this file shows whether polling is enabled (1)
|
||||
or disabled (0). Writing '0' to this file will disable polling
|
||||
for this device. Writing any non-zero value will enable this
|
||||
feature.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/io_poll_delay
|
||||
Date: November 2016
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] If polling is enabled, this controls what kind of polling
|
||||
will be performed. It defaults to -1, which is classic polling.
|
||||
In this mode, the CPU will repeatedly ask for completions
|
||||
without giving up any time. If set to 0, a hybrid polling mode
|
||||
is used, where the kernel will attempt to make an educated guess
|
||||
at when the IO will complete. Based on this guess, the kernel
|
||||
will put the process issuing IO to sleep for an amount of time,
|
||||
before entering a classic poll loop. This mode might be a little
|
||||
slower than pure classic polling, but it will be more efficient.
|
||||
If set to a value larger than 0, the kernel will put the process
|
||||
issuing IO to sleep for this amount of microseconds before
|
||||
entering classic polling.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/io_timeout
|
||||
Date: November 2018
|
||||
Contact: Weiping Zhang <zhangweiping@didiglobal.com>
|
||||
Description:
|
||||
[RW] io_timeout is the request timeout in milliseconds. If a
|
||||
request does not complete in this time then the block driver
|
||||
timeout handler is invoked. That timeout handler can decide to
|
||||
retry the request, to fail it or to start a device recovery
|
||||
strategy.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/iostats
|
||||
Date: January 2009
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] This file is used to control (on/off) the iostats
|
||||
accounting of the disk.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/logical_block_size
|
||||
Date: May 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RO] This is the smallest unit the storage device can address.
|
||||
It is typically 512 bytes.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_active_zones
|
||||
Date: July 2020
|
||||
Contact: Niklas Cassel <niklas.cassel@wdc.com>
|
||||
Description:
|
||||
[RO] For zoned block devices (zoned attribute indicating
|
||||
"host-managed" or "host-aware"), the sum of zones belonging to
|
||||
any of the zone states: EXPLICIT OPEN, IMPLICIT OPEN or CLOSED,
|
||||
is limited by this value. If this value is 0, there is no limit.
|
||||
|
||||
If the host attempts to exceed this limit, the driver should
|
||||
report this error with BLK_STS_ZONE_ACTIVE_RESOURCE, which user
|
||||
space may see as the EOVERFLOW errno.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_discard_segments
|
||||
Date: February 2017
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] The maximum number of DMA scatter/gather entries in a
|
||||
discard request.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_hw_sectors_kb
|
||||
Date: September 2004
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] This is the maximum number of kilobytes supported in a
|
||||
single data transfer.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_integrity_segments
|
||||
Date: September 2010
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] Maximum number of elements in a DMA scatter/gather list
|
||||
with integrity data that will be submitted by the block layer
|
||||
core to the associated block driver.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_open_zones
|
||||
Date: July 2020
|
||||
Contact: Niklas Cassel <niklas.cassel@wdc.com>
|
||||
Description:
|
||||
[RO] For zoned block devices (zoned attribute indicating
|
||||
"host-managed" or "host-aware"), the sum of zones belonging to
|
||||
any of the zone states: EXPLICIT OPEN or IMPLICIT OPEN, is
|
||||
limited by this value. If this value is 0, there is no limit.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_sectors_kb
|
||||
Date: September 2004
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] This is the maximum number of kilobytes that the block
|
||||
layer will allow for a filesystem request. Must be smaller than
|
||||
or equal to the maximum size allowed by the hardware.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_segment_size
|
||||
Date: March 2010
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] Maximum size in bytes of a single element in a DMA
|
||||
scatter/gather list.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/max_segments
|
||||
Date: March 2010
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] Maximum number of elements in a DMA scatter/gather list
|
||||
that is submitted to the associated block driver.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/minimum_io_size
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RO] Storage devices may report a granularity or preferred
|
||||
minimum I/O size which is the smallest request the device can
|
||||
perform without incurring a performance penalty. For disk
|
||||
drives this is often the physical block size. For RAID arrays
|
||||
it is often the stripe chunk size. A properly aligned multiple
|
||||
of minimum_io_size is the preferred request size for workloads
|
||||
where a high number of I/O operations is desired.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/nomerges
|
||||
Date: January 2010
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] Standard I/O elevator operations include attempts to merge
|
||||
contiguous I/Os. For known random I/O loads these attempts will
|
||||
always fail and result in extra cycles being spent in the
|
||||
kernel. This allows one to turn off this behavior on one of two
|
||||
ways: When set to 1, complex merge checks are disabled, but the
|
||||
simple one-shot merges with the previous I/O request are
|
||||
enabled. When set to 2, all merge tries are disabled. The
|
||||
default value is 0 - which enables all types of merge tries.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/nr_requests
|
||||
Date: July 2003
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] This controls how many requests may be allocated in the
|
||||
block layer for read or write requests. Note that the total
|
||||
allocated number may be twice this amount, since it applies only
|
||||
to reads or writes (not the accumulated sum).
|
||||
|
||||
To avoid priority inversion through request starvation, a
|
||||
request queue maintains a separate request pool per each cgroup
|
||||
when CONFIG_BLK_CGROUP is enabled, and this parameter applies to
|
||||
each such per-block-cgroup request pool. IOW, if there are N
|
||||
block cgroups, each request queue may have up to N request
|
||||
pools, each independently regulated by nr_requests.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/nr_zones
|
||||
Date: November 2018
|
||||
Contact: Damien Le Moal <damien.lemoal@wdc.com>
|
||||
Description:
|
||||
[RO] nr_zones indicates the total number of zones of a zoned
|
||||
block device ("host-aware" or "host-managed" zone model). For
|
||||
regular block devices, the value is always 0.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/optimal_io_size
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RO] Storage devices may report an optimal I/O size, which is
|
||||
the device's preferred unit for sustained I/O. This is rarely
|
||||
reported for disk drives. For RAID arrays it is usually the
|
||||
stripe width or the internal track size. A properly aligned
|
||||
multiple of optimal_io_size is the preferred request size for
|
||||
workloads where sustained throughput is desired. If no optimal
|
||||
I/O size is reported this file contains 0.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/physical_block_size
|
||||
Date: May 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RO] This is the smallest unit a physical storage device can
|
||||
write atomically. It is usually the same as the logical block
|
||||
size but may be bigger. One example is SATA drives with 4KB
|
||||
sectors that expose a 512-byte logical block size to the
|
||||
operating system. For stacked block devices the
|
||||
physical_block_size variable contains the maximum
|
||||
physical_block_size of the component devices.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/read_ahead_kb
|
||||
Date: May 2004
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] Maximum number of kilobytes to read-ahead for filesystems
|
||||
on this block device.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/rotational
|
||||
Date: January 2009
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] This file is used to stat if the device is of rotational
|
||||
type or non-rotational type.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/rq_affinity
|
||||
Date: September 2008
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] If this option is '1', the block layer will migrate request
|
||||
completions to the cpu "group" that originally submitted the
|
||||
request. For some workloads this provides a significant
|
||||
reduction in CPU cycles due to caching effects.
|
||||
|
||||
For storage configurations that need to maximize distribution of
|
||||
completion processing setting this option to '2' forces the
|
||||
completion to run on the requesting cpu (bypassing the "group"
|
||||
aggregation logic).
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/scheduler
|
||||
Date: October 2004
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] When read, this file will display the current and available
|
||||
IO schedulers for this block device. The currently active IO
|
||||
scheduler will be enclosed in [] brackets. Writing an IO
|
||||
scheduler name to this file will switch control of this block
|
||||
device to that new IO scheduler. Note that writing an IO
|
||||
scheduler name to this file will attempt to load that IO
|
||||
scheduler module, if it isn't already present in the system.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/stable_writes
|
||||
Date: September 2020
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] This file will contain '1' if memory must not be modified
|
||||
while it is being used in a write request to this device. When
|
||||
this is the case and the kernel is performing writeback of a
|
||||
page, the kernel will wait for writeback to complete before
|
||||
allowing the page to be modified again, rather than allowing
|
||||
immediate modification as is normally the case. This
|
||||
restriction arises when the device accesses the memory multiple
|
||||
times where the same data must be seen every time -- for
|
||||
example, once to calculate a checksum and once to actually write
|
||||
the data. If no such restriction exists, this file will contain
|
||||
'0'. This file is writable for testing purposes.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/throttle_sample_time
|
||||
Date: March 2017
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] This is the time window that blk-throttle samples data, in
|
||||
millisecond. blk-throttle makes decision based on the
|
||||
samplings. Lower time means cgroups have more smooth throughput,
|
||||
but higher CPU overhead. This exists only when
|
||||
CONFIG_BLK_DEV_THROTTLING_LOW is enabled.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/virt_boundary_mask
|
||||
Date: April 2021
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] This file shows the I/O segment memory alignment mask for
|
||||
the block device. I/O requests to this device will be split
|
||||
between segments wherever either the memory address of the end
|
||||
of the previous segment or the memory address of the beginning
|
||||
of the current segment is not aligned to virt_boundary_mask + 1
|
||||
bytes.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/wbt_lat_usec
|
||||
Date: November 2016
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] If the device is registered for writeback throttling, then
|
||||
this file shows the target minimum read latency. If this latency
|
||||
is exceeded in a given window of time (see wb_window_usec), then
|
||||
the writeback throttling will start scaling back writes. Writing
|
||||
a value of '0' to this file disables the feature. Writing a
|
||||
value of '-1' to this file resets the value to the default
|
||||
setting.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/write_cache
|
||||
Date: April 2016
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RW] When read, this file will display whether the device has
|
||||
write back caching enabled or not. It will return "write back"
|
||||
for the former case, and "write through" for the latter. Writing
|
||||
to this file can change the kernels view of the device, but it
|
||||
doesn't alter the device state. This means that it might not be
|
||||
safe to toggle the setting from "write back" to "write through",
|
||||
since that will also eliminate cache flushes issued by the
|
||||
kernel.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/write_same_max_bytes
|
||||
Date: January 2012
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
[RO] Some devices support a write same operation in which a
|
||||
single data block can be written to a range of several
|
||||
contiguous blocks on storage. This can be used to wipe areas on
|
||||
disk or to initialize drives in a RAID configuration.
|
||||
write_same_max_bytes indicates how many bytes can be written in
|
||||
a single write same command. If write_same_max_bytes is 0, write
|
||||
same is not supported by the device.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/write_zeroes_max_bytes
|
||||
Date: November 2016
|
||||
Contact: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
|
||||
Description:
|
||||
[RO] Devices that support write zeroes operation in which a
|
||||
single request can be issued to zero out the range of contiguous
|
||||
blocks on storage without having any payload in the request.
|
||||
This can be used to optimize writing zeroes to the devices.
|
||||
write_zeroes_max_bytes indicates how many bytes can be written
|
||||
in a single write zeroes command. If write_zeroes_max_bytes is
|
||||
0, write zeroes is not supported by the device.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/zone_append_max_bytes
|
||||
Date: May 2020
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] This is the maximum number of bytes that can be written to
|
||||
a sequential zone of a zoned block device using a zone append
|
||||
write operation (REQ_OP_ZONE_APPEND). This value is always 0 for
|
||||
regular block devices.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/zone_write_granularity
|
||||
Date: January 2021
|
||||
Contact: linux-block@vger.kernel.org
|
||||
Description:
|
||||
[RO] This indicates the alignment constraint, in bytes, for
|
||||
write operations in sequential zones of zoned block devices
|
||||
(devices with a zoned attributed that reports "host-managed" or
|
||||
"host-aware"). This value is always 0 for regular block devices.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/queue/zoned
|
||||
Date: September 2016
|
||||
Contact: Damien Le Moal <damien.lemoal@wdc.com>
|
||||
Description:
|
||||
[RO] zoned indicates if the device is a zoned block device and
|
||||
the zone model of the device if it is indeed zoned. The
|
||||
possible values indicated by zoned are "none" for regular block
|
||||
devices and "host-aware" or "host-managed" for zoned block
|
||||
devices. The characteristics of host-aware and host-managed
|
||||
zoned block devices are described in the ZBC (Zoned Block
|
||||
Commands) and ZAC (Zoned Device ATA Command Set) standards.
|
||||
These standards also define the "drive-managed" zone model.
|
||||
However, since drive-managed zoned block devices do not support
|
||||
zone commands, they will be treated as regular block devices and
|
||||
zoned will report "none".
|
||||
|
||||
|
||||
What: /sys/block/<disk>/stat
|
||||
Date: February 2008
|
||||
Contact: Jerome Marchand <jmarchan@redhat.com>
|
||||
Description:
|
||||
The /sys/block/<disk>/stat files displays the I/O
|
||||
statistics of disk <disk>. They contain 11 fields:
|
||||
|
||||
== ==============================================
|
||||
1 reads completed successfully
|
||||
2 reads merged
|
||||
3 sectors read
|
||||
4 time spent reading (ms)
|
||||
5 writes completed
|
||||
6 writes merged
|
||||
7 sectors written
|
||||
8 time spent writing (ms)
|
||||
9 I/Os currently in progress
|
||||
10 time spent doing I/Os (ms)
|
||||
11 weighted time spent doing I/Os (ms)
|
||||
12 discards completed
|
||||
13 discards merged
|
||||
14 sectors discarded
|
||||
15 time spent discarding (ms)
|
||||
16 flush requests completed
|
||||
17 time spent flushing (ms)
|
||||
== ==============================================
|
||||
|
||||
For more details refer Documentation/admin-guide/iostats.rst
|
@ -27,6 +27,6 @@ Description:
|
||||
(in 1/256 dB)
|
||||
p_volume_res playback volume control resolution
|
||||
(in 1/256 dB)
|
||||
req_number the number of pre-allocated request
|
||||
req_number the number of pre-allocated requests
|
||||
for both capture and playback
|
||||
===================== =======================================
|
||||
|
@ -30,4 +30,6 @@ Description:
|
||||
(in 1/256 dB)
|
||||
p_volume_res playback volume control resolution
|
||||
(in 1/256 dB)
|
||||
req_number the number of pre-allocated requests
|
||||
for both capture and playback
|
||||
===================== =======================================
|
||||
|
@ -1,346 +0,0 @@
|
||||
What: /sys/block/<disk>/stat
|
||||
Date: February 2008
|
||||
Contact: Jerome Marchand <jmarchan@redhat.com>
|
||||
Description:
|
||||
The /sys/block/<disk>/stat files displays the I/O
|
||||
statistics of disk <disk>. They contain 11 fields:
|
||||
|
||||
== ==============================================
|
||||
1 reads completed successfully
|
||||
2 reads merged
|
||||
3 sectors read
|
||||
4 time spent reading (ms)
|
||||
5 writes completed
|
||||
6 writes merged
|
||||
7 sectors written
|
||||
8 time spent writing (ms)
|
||||
9 I/Os currently in progress
|
||||
10 time spent doing I/Os (ms)
|
||||
11 weighted time spent doing I/Os (ms)
|
||||
12 discards completed
|
||||
13 discards merged
|
||||
14 sectors discarded
|
||||
15 time spent discarding (ms)
|
||||
16 flush requests completed
|
||||
17 time spent flushing (ms)
|
||||
== ==============================================
|
||||
|
||||
For more details refer Documentation/admin-guide/iostats.rst
|
||||
|
||||
|
||||
What: /sys/block/<disk>/inflight
|
||||
Date: October 2009
|
||||
Contact: Jens Axboe <axboe@kernel.dk>, Nikanth Karthikesan <knikanth@suse.de>
|
||||
Description:
|
||||
Reports the number of I/O requests currently in progress
|
||||
(pending / in flight) in a device driver. This can be less
|
||||
than the number of requests queued in the block device queue.
|
||||
The report contains 2 fields: one for read requests
|
||||
and one for write requests.
|
||||
The value type is unsigned int.
|
||||
Cf. Documentation/block/stat.rst which contains a single value for
|
||||
requests in flight.
|
||||
This is related to nr_requests in Documentation/block/queue-sysfs.rst
|
||||
and for SCSI device also its queue_depth.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/diskseq
|
||||
Date: February 2021
|
||||
Contact: Matteo Croce <mcroce@microsoft.com>
|
||||
Description:
|
||||
The /sys/block/<disk>/diskseq files reports the disk
|
||||
sequence number, which is a monotonically increasing
|
||||
number assigned to every drive.
|
||||
Some devices, like the loop device, refresh such number
|
||||
every time the backing file is changed.
|
||||
The value type is 64 bit unsigned.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/<part>/stat
|
||||
Date: February 2008
|
||||
Contact: Jerome Marchand <jmarchan@redhat.com>
|
||||
Description:
|
||||
The /sys/block/<disk>/<part>/stat files display the
|
||||
I/O statistics of partition <part>. The format is the
|
||||
same as the above-written /sys/block/<disk>/stat
|
||||
format.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/format
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Metadata format for integrity capable block device.
|
||||
E.g. T10-DIF-TYPE1-CRC.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/read_verify
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Indicates whether the block layer should verify the
|
||||
integrity of read requests serviced by devices that
|
||||
support sending integrity metadata.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/tag_size
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Number of bytes of integrity tag space available per
|
||||
512 bytes of data.
|
||||
|
||||
|
||||
What: /sys/block/<disk>/integrity/device_is_integrity_capable
|
||||
Date: July 2014
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Indicates whether a storage device is capable of storing
|
||||
integrity metadata. Set if the device is T10 PI-capable.
|
||||
|
||||
What: /sys/block/<disk>/integrity/protection_interval_bytes
|
||||
Date: July 2015
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Describes the number of data bytes which are protected
|
||||
by one integrity tuple. Typically the device's logical
|
||||
block size.
|
||||
|
||||
What: /sys/block/<disk>/integrity/write_generate
|
||||
Date: June 2008
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Indicates whether the block layer should automatically
|
||||
generate checksums for write requests bound for
|
||||
devices that support receiving integrity metadata.
|
||||
|
||||
What: /sys/block/<disk>/alignment_offset
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Storage devices may report a physical block size that is
|
||||
bigger than the logical block size (for instance a drive
|
||||
with 4KB physical sectors exposing 512-byte logical
|
||||
blocks to the operating system). This parameter
|
||||
indicates how many bytes the beginning of the device is
|
||||
offset from the disk's natural alignment.
|
||||
|
||||
What: /sys/block/<disk>/<partition>/alignment_offset
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Storage devices may report a physical block size that is
|
||||
bigger than the logical block size (for instance a drive
|
||||
with 4KB physical sectors exposing 512-byte logical
|
||||
blocks to the operating system). This parameter
|
||||
indicates how many bytes the beginning of the partition
|
||||
is offset from the disk's natural alignment.
|
||||
|
||||
What: /sys/block/<disk>/queue/logical_block_size
|
||||
Date: May 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
This is the smallest unit the storage device can
|
||||
address. It is typically 512 bytes.
|
||||
|
||||
What: /sys/block/<disk>/queue/physical_block_size
|
||||
Date: May 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
This is the smallest unit a physical storage device can
|
||||
write atomically. It is usually the same as the logical
|
||||
block size but may be bigger. One example is SATA
|
||||
drives with 4KB sectors that expose a 512-byte logical
|
||||
block size to the operating system. For stacked block
|
||||
devices the physical_block_size variable contains the
|
||||
maximum physical_block_size of the component devices.
|
||||
|
||||
What: /sys/block/<disk>/queue/minimum_io_size
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Storage devices may report a granularity or preferred
|
||||
minimum I/O size which is the smallest request the
|
||||
device can perform without incurring a performance
|
||||
penalty. For disk drives this is often the physical
|
||||
block size. For RAID arrays it is often the stripe
|
||||
chunk size. A properly aligned multiple of
|
||||
minimum_io_size is the preferred request size for
|
||||
workloads where a high number of I/O operations is
|
||||
desired.
|
||||
|
||||
What: /sys/block/<disk>/queue/optimal_io_size
|
||||
Date: April 2009
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Storage devices may report an optimal I/O size, which is
|
||||
the device's preferred unit for sustained I/O. This is
|
||||
rarely reported for disk drives. For RAID arrays it is
|
||||
usually the stripe width or the internal track size. A
|
||||
properly aligned multiple of optimal_io_size is the
|
||||
preferred request size for workloads where sustained
|
||||
throughput is desired. If no optimal I/O size is
|
||||
reported this file contains 0.
|
||||
|
||||
What: /sys/block/<disk>/queue/nomerges
|
||||
Date: January 2010
|
||||
Contact:
|
||||
Description:
|
||||
Standard I/O elevator operations include attempts to
|
||||
merge contiguous I/Os. For known random I/O loads these
|
||||
attempts will always fail and result in extra cycles
|
||||
being spent in the kernel. This allows one to turn off
|
||||
this behavior on one of two ways: When set to 1, complex
|
||||
merge checks are disabled, but the simple one-shot merges
|
||||
with the previous I/O request are enabled. When set to 2,
|
||||
all merge tries are disabled. The default value is 0 -
|
||||
which enables all types of merge tries.
|
||||
|
||||
What: /sys/block/<disk>/discard_alignment
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Devices that support discard functionality may
|
||||
internally allocate space in units that are bigger than
|
||||
the exported logical block size. The discard_alignment
|
||||
parameter indicates how many bytes the beginning of the
|
||||
device is offset from the internal allocation unit's
|
||||
natural alignment.
|
||||
|
||||
What: /sys/block/<disk>/<partition>/discard_alignment
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Devices that support discard functionality may
|
||||
internally allocate space in units that are bigger than
|
||||
the exported logical block size. The discard_alignment
|
||||
parameter indicates how many bytes the beginning of the
|
||||
partition is offset from the internal allocation unit's
|
||||
natural alignment.
|
||||
|
||||
What: /sys/block/<disk>/queue/discard_granularity
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Devices that support discard functionality may
|
||||
internally allocate space using units that are bigger
|
||||
than the logical block size. The discard_granularity
|
||||
parameter indicates the size of the internal allocation
|
||||
unit in bytes if reported by the device. Otherwise the
|
||||
discard_granularity will be set to match the device's
|
||||
physical block size. A discard_granularity of 0 means
|
||||
that the device does not support discard functionality.
|
||||
|
||||
What: /sys/block/<disk>/queue/discard_max_bytes
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Devices that support discard functionality may have
|
||||
internal limits on the number of bytes that can be
|
||||
trimmed or unmapped in a single operation. Some storage
|
||||
protocols also have inherent limits on the number of
|
||||
blocks that can be described in a single command. The
|
||||
discard_max_bytes parameter is set by the device driver
|
||||
to the maximum number of bytes that can be discarded in
|
||||
a single operation. Discard requests issued to the
|
||||
device must not exceed this limit. A discard_max_bytes
|
||||
value of 0 means that the device does not support
|
||||
discard functionality.
|
||||
|
||||
What: /sys/block/<disk>/queue/discard_zeroes_data
|
||||
Date: May 2011
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Will always return 0. Don't rely on any specific behavior
|
||||
for discards, and don't read this file.
|
||||
|
||||
What: /sys/block/<disk>/queue/write_same_max_bytes
|
||||
Date: January 2012
|
||||
Contact: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Description:
|
||||
Some devices support a write same operation in which a
|
||||
single data block can be written to a range of several
|
||||
contiguous blocks on storage. This can be used to wipe
|
||||
areas on disk or to initialize drives in a RAID
|
||||
configuration. write_same_max_bytes indicates how many
|
||||
bytes can be written in a single write same command. If
|
||||
write_same_max_bytes is 0, write same is not supported
|
||||
by the device.
|
||||
|
||||
What: /sys/block/<disk>/queue/write_zeroes_max_bytes
|
||||
Date: November 2016
|
||||
Contact: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
|
||||
Description:
|
||||
Devices that support write zeroes operation in which a
|
||||
single request can be issued to zero out the range of
|
||||
contiguous blocks on storage without having any payload
|
||||
in the request. This can be used to optimize writing zeroes
|
||||
to the devices. write_zeroes_max_bytes indicates how many
|
||||
bytes can be written in a single write zeroes command. If
|
||||
write_zeroes_max_bytes is 0, write zeroes is not supported
|
||||
by the device.
|
||||
|
||||
What: /sys/block/<disk>/queue/zoned
|
||||
Date: September 2016
|
||||
Contact: Damien Le Moal <damien.lemoal@wdc.com>
|
||||
Description:
|
||||
zoned indicates if the device is a zoned block device
|
||||
and the zone model of the device if it is indeed zoned.
|
||||
The possible values indicated by zoned are "none" for
|
||||
regular block devices and "host-aware" or "host-managed"
|
||||
for zoned block devices. The characteristics of
|
||||
host-aware and host-managed zoned block devices are
|
||||
described in the ZBC (Zoned Block Commands) and ZAC
|
||||
(Zoned Device ATA Command Set) standards. These standards
|
||||
also define the "drive-managed" zone model. However,
|
||||
since drive-managed zoned block devices do not support
|
||||
zone commands, they will be treated as regular block
|
||||
devices and zoned will report "none".
|
||||
|
||||
What: /sys/block/<disk>/queue/nr_zones
|
||||
Date: November 2018
|
||||
Contact: Damien Le Moal <damien.lemoal@wdc.com>
|
||||
Description:
|
||||
nr_zones indicates the total number of zones of a zoned block
|
||||
device ("host-aware" or "host-managed" zone model). For regular
|
||||
block devices, the value is always 0.
|
||||
|
||||
What: /sys/block/<disk>/queue/max_active_zones
|
||||
Date: July 2020
|
||||
Contact: Niklas Cassel <niklas.cassel@wdc.com>
|
||||
Description:
|
||||
For zoned block devices (zoned attribute indicating
|
||||
"host-managed" or "host-aware"), the sum of zones belonging to
|
||||
any of the zone states: EXPLICIT OPEN, IMPLICIT OPEN or CLOSED,
|
||||
is limited by this value. If this value is 0, there is no limit.
|
||||
|
||||
What: /sys/block/<disk>/queue/max_open_zones
|
||||
Date: July 2020
|
||||
Contact: Niklas Cassel <niklas.cassel@wdc.com>
|
||||
Description:
|
||||
For zoned block devices (zoned attribute indicating
|
||||
"host-managed" or "host-aware"), the sum of zones belonging to
|
||||
any of the zone states: EXPLICIT OPEN or IMPLICIT OPEN,
|
||||
is limited by this value. If this value is 0, there is no limit.
|
||||
|
||||
What: /sys/block/<disk>/queue/chunk_sectors
|
||||
Date: September 2016
|
||||
Contact: Hannes Reinecke <hare@suse.com>
|
||||
Description:
|
||||
chunk_sectors has different meaning depending on the type
|
||||
of the disk. For a RAID device (dm-raid), chunk_sectors
|
||||
indicates the size in 512B sectors of the RAID volume
|
||||
stripe segment. For a zoned block device, either
|
||||
host-aware or host-managed, chunk_sectors indicates the
|
||||
size in 512B sectors of the zones of the device, with
|
||||
the eventual exception of the last zone of the device
|
||||
which may be smaller.
|
||||
|
||||
What: /sys/block/<disk>/queue/io_timeout
|
||||
Date: November 2018
|
||||
Contact: Weiping Zhang <zhangweiping@didiglobal.com>
|
||||
Description:
|
||||
io_timeout is the request timeout in milliseconds. If a request
|
||||
does not complete in this time then the block driver timeout
|
||||
handler is invoked. That timeout handler can decide to retry
|
||||
the request, to fail it or to start a device recovery strategy.
|
@ -244,6 +244,15 @@ Description:
|
||||
is permitted, "u2" if only u2 is permitted, "u1_u2" if both u1 and
|
||||
u2 are permitted.
|
||||
|
||||
What: /sys/bus/usb/devices/.../<hub_interface>/port<X>/connector
|
||||
Date: December 2021
|
||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
Description:
|
||||
Link to the USB Type-C connector when available. This link is
|
||||
only created when USB Type-C Connector Class is enabled, and
|
||||
only if the system firmware is capable of describing the
|
||||
connection between a port and its connector.
|
||||
|
||||
What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout
|
||||
Date: May 2013
|
||||
Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
|
@ -161,6 +161,15 @@ Description:
|
||||
power-on:
|
||||
Representing a password required to use
|
||||
the system
|
||||
system-mgmt:
|
||||
Representing System Management password.
|
||||
See Lenovo extensions section for details
|
||||
HDD:
|
||||
Representing HDD password
|
||||
See Lenovo extensions section for details
|
||||
NVMe:
|
||||
Representing NVMe password
|
||||
See Lenovo extensions section for details
|
||||
|
||||
mechanism:
|
||||
The means of authentication. This attribute is mandatory.
|
||||
@ -207,6 +216,13 @@ Description:
|
||||
|
||||
On Lenovo systems the following additional settings are available:
|
||||
|
||||
role: system-mgmt This gives the same authority as the bios-admin password to control
|
||||
security related features. The authorities allocated can be set via
|
||||
the BIOS menu SMP Access Control Policy
|
||||
|
||||
role: HDD & NVMe This password is used to unlock access to the drive at boot. Note see
|
||||
'level' and 'index' extensions below.
|
||||
|
||||
lenovo_encoding:
|
||||
The encoding method that is used. This can be either "ascii"
|
||||
or "scancode". Default is set to "ascii"
|
||||
@ -216,6 +232,22 @@ Description:
|
||||
two char code (e.g. "us", "fr", "gr") and may vary per platform.
|
||||
Default is set to "us"
|
||||
|
||||
level:
|
||||
Available for HDD and NVMe authentication to set 'user' or 'master'
|
||||
privilege level.
|
||||
If only the user password is configured then this should be used to
|
||||
unlock the drive at boot. If both master and user passwords are set
|
||||
then either can be used. If a master password is set a user password
|
||||
is required.
|
||||
This attribute defaults to 'user' level
|
||||
|
||||
index:
|
||||
Used with HDD and NVME authentication to set the drive index
|
||||
that is being referenced (e.g hdd0, hdd1 etc)
|
||||
This attribute defaults to device 0.
|
||||
|
||||
|
||||
|
||||
What: /sys/class/firmware-attributes/*/attributes/pending_reboot
|
||||
Date: February 2021
|
||||
KernelVersion: 5.11
|
||||
|
@ -413,7 +413,7 @@ Description:
|
||||
"Over voltage", "Unspecified failure", "Cold",
|
||||
"Watchdog timer expire", "Safety timer expire",
|
||||
"Over current", "Calibration required", "Warm",
|
||||
"Cool", "Hot"
|
||||
"Cool", "Hot", "No battery"
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/precharge_current
|
||||
Date: June 2017
|
||||
@ -455,6 +455,20 @@ Description:
|
||||
"Unknown", "Charging", "Discharging",
|
||||
"Not charging", "Full"
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/charge_behaviour
|
||||
Date: November 2021
|
||||
Contact: linux-pm@vger.kernel.org
|
||||
Description:
|
||||
Represents the charging behaviour.
|
||||
|
||||
Access: Read, Write
|
||||
|
||||
Valid values:
|
||||
================ ====================================
|
||||
auto: Charge normally, respect thresholds
|
||||
inhibit-charge: Do not charge while AC is attached
|
||||
force-discharge: Force discharge while AC is attached
|
||||
|
||||
What: /sys/class/power_supply/<supply_name>/technology
|
||||
Date: May 2007
|
||||
Contact: linux-pm@vger.kernel.org
|
||||
|
@ -666,3 +666,18 @@ Description: Preferred MTE tag checking mode
|
||||
================ ==============================================
|
||||
|
||||
See also: Documentation/arm64/memory-tagging-extension.rst
|
||||
|
||||
What: /sys/devices/system/cpu/nohz_full
|
||||
Date: Apr 2015
|
||||
Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
|
||||
Description:
|
||||
(RO) the list of CPUs that are in nohz_full mode.
|
||||
These CPUs are set by boot parameter "nohz_full=".
|
||||
|
||||
What: /sys/devices/system/cpu/isolated
|
||||
Date: Apr 2015
|
||||
Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
|
||||
Description:
|
||||
(RO) the list of CPUs that are isolated and don't
|
||||
participate in load balancing. These CPUs are set by
|
||||
boot parameter "isolcpus=".
|
||||
|
16
Documentation/ABI/testing/sysfs-fs-erofs
Normal file
@ -0,0 +1,16 @@
|
||||
What: /sys/fs/erofs/features/
|
||||
Date: November 2021
|
||||
Contact: "Huang Jianan" <huangjianan@oppo.com>
|
||||
Description: Shows all enabled kernel features.
|
||||
Supported features:
|
||||
zero_padding, compr_cfgs, big_pcluster, chunked_file,
|
||||
device_table, compr_head2, sb_chksum.
|
||||
|
||||
What: /sys/fs/erofs/<disk>/sync_decompress
|
||||
Date: November 2021
|
||||
Contact: "Huang Jianan" <huangjianan@oppo.com>
|
||||
Description: Control strategy of sync decompression
|
||||
- 0 (default, auto): enable for readpage, and enable for
|
||||
readahead on atomic contexts only,
|
||||
- 1 (force on): enable for readpage and readahead.
|
||||
- 2 (force off): disable for all situations.
|
35
Documentation/ABI/testing/sysfs-fs-ubifs
Normal file
@ -0,0 +1,35 @@
|
||||
What: /sys/fs/ubifsX_Y/error_magic
|
||||
Date: October 2021
|
||||
KernelVersion: 5.16
|
||||
Contact: linux-mtd@lists.infradead.org
|
||||
Description:
|
||||
Exposes magic errors: every node starts with a magic number.
|
||||
|
||||
This counter keeps track of the number of accesses of nodes
|
||||
with a corrupted magic number.
|
||||
|
||||
The counter is reset to 0 with a remount.
|
||||
|
||||
What: /sys/fs/ubifsX_Y/error_node
|
||||
Date: October 2021
|
||||
KernelVersion: 5.16
|
||||
Contact: linux-mtd@lists.infradead.org
|
||||
Description:
|
||||
Exposes node errors. Every node embeds its type.
|
||||
|
||||
This counter keeps track of the number of accesses of nodes
|
||||
with a corrupted node type.
|
||||
|
||||
The counter is reset to 0 with a remount.
|
||||
|
||||
What: /sys/fs/ubifsX_Y/error_crc
|
||||
Date: October 2021
|
||||
KernelVersion: 5.16
|
||||
Contact: linux-mtd@lists.infradead.org
|
||||
Description:
|
||||
Exposes crc errors: every node embeds a crc checksum.
|
||||
|
||||
This counter keeps track of the number of accesses of nodes
|
||||
with a bad crc checksum.
|
||||
|
||||
The counter is reset to 0 with a remount.
|
@ -19,6 +19,8 @@ endif
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXOPTS =
|
||||
SPHINXDIRS = .
|
||||
DOCS_THEME =
|
||||
DOCS_CSS =
|
||||
_SPHINXDIRS = $(sort $(patsubst $(srctree)/Documentation/%/index.rst,%,$(wildcard $(srctree)/Documentation/*/index.rst)))
|
||||
SPHINX_CONF = conf.py
|
||||
PAPER =
|
||||
@ -84,7 +86,10 @@ quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4)
|
||||
-D version=$(KERNELVERSION) -D release=$(KERNELRELEASE) \
|
||||
$(ALLSPHINXOPTS) \
|
||||
$(abspath $(srctree)/$(src)/$5) \
|
||||
$(abspath $(BUILDDIR)/$3/$4)
|
||||
$(abspath $(BUILDDIR)/$3/$4) && \
|
||||
if [ "x$(DOCS_CSS)" != "x" ]; then \
|
||||
cp $(if $(patsubst /%,,$(DOCS_CSS)),$(abspath $(srctree)/$(DOCS_CSS)),$(DOCS_CSS)) $(BUILDDIR)/$3/_static/; \
|
||||
fi
|
||||
|
||||
htmldocs:
|
||||
@$(srctree)/scripts/sphinx-pre-install --version-check
|
||||
@ -154,4 +159,8 @@ dochelp:
|
||||
@echo ' make SPHINX_CONF={conf-file} [target] use *additional* sphinx-build'
|
||||
@echo ' configuration. This is e.g. useful to build with nit-picking config.'
|
||||
@echo
|
||||
@echo ' make DOCS_THEME={sphinx-theme} selects a different Sphinx theme.'
|
||||
@echo
|
||||
@echo ' make DOCS_CSS={a .css file} adds a DOCS_CSS override file for html/epub output.'
|
||||
@echo
|
||||
@echo ' Default location for the generated documents is Documentation/output'
|
||||
|
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -125,7 +125,7 @@
|
||||
y="492.36218" /></flowRegion><flowPara
|
||||
id="flowPara2991" /></flowRoot> <text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="362.371"
|
||||
y="262.51819"
|
||||
id="text4441"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -88,7 +88,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -103,7 +103,7 @@
|
||||
id="text2993"
|
||||
y="-261.66608"
|
||||
x="412.12299"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
xml:space="preserve"
|
||||
transform="matrix(0,1,-1,0,0,0)"><tspan
|
||||
y="-261.66608"
|
||||
@ -135,7 +135,7 @@
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.04738"
|
||||
y="268.18076"
|
||||
id="text4429"
|
||||
@ -146,7 +146,7 @@
|
||||
y="268.18076">WRITE_ONCE(a, 1);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.04738"
|
||||
y="439.13766"
|
||||
id="text4441"
|
||||
@ -157,7 +157,7 @@
|
||||
y="439.13766">WRITE_ONCE(b, 1);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="255.60869"
|
||||
y="309.29346"
|
||||
id="text4445"
|
||||
@ -168,7 +168,7 @@
|
||||
y="309.29346">r1 = READ_ONCE(a);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="255.14423"
|
||||
y="520.61786"
|
||||
id="text4449"
|
||||
@ -179,7 +179,7 @@
|
||||
y="520.61786">WRITE_ONCE(c, 1);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="384.71124"
|
||||
id="text4453"
|
||||
@ -190,7 +190,7 @@
|
||||
y="384.71124">r2 = READ_ONCE(b);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="582.13617"
|
||||
id="text4457"
|
||||
@ -201,7 +201,7 @@
|
||||
y="582.13617">r3 = READ_ONCE(c);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.08231"
|
||||
y="213.91006"
|
||||
id="text4461"
|
||||
@ -212,7 +212,7 @@
|
||||
y="213.91006">thread0()</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="252.34512"
|
||||
y="213.91006"
|
||||
id="text4461-6"
|
||||
@ -223,7 +223,7 @@
|
||||
y="213.91006">thread1()</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.42557"
|
||||
y="213.91006"
|
||||
id="text4461-2"
|
||||
@ -251,7 +251,7 @@
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="111.75929"
|
||||
y="251.53981"
|
||||
id="text4429-8"
|
||||
@ -262,7 +262,7 @@
|
||||
y="251.53981">rcu_read_lock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="367.91556"
|
||||
id="text4429-8-9"
|
||||
@ -273,7 +273,7 @@
|
||||
y="367.91556">rcu_read_lock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="597.40289"
|
||||
id="text4429-8-9-3"
|
||||
@ -284,7 +284,7 @@
|
||||
y="597.40289">rcu_read_unlock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="111.75929"
|
||||
y="453.15311"
|
||||
id="text4429-8-9-3-1"
|
||||
@ -300,7 +300,7 @@
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="394.94427"
|
||||
y="345.66351"
|
||||
id="text4648"
|
||||
@ -324,7 +324,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.11968"
|
||||
y="475.77856"
|
||||
id="text4648-4"
|
||||
@ -361,7 +361,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="254.85066"
|
||||
y="348.96619"
|
||||
id="text4648-4-3"
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -116,7 +116,7 @@
|
||||
<flowRoot
|
||||
xml:space="preserve"
|
||||
id="flowRoot2985"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"><flowRegion
|
||||
id="flowRegion2987"><rect
|
||||
id="rect2989"
|
||||
width="82.85714"
|
||||
@ -131,7 +131,7 @@
|
||||
id="text2993"
|
||||
y="-261.66608"
|
||||
x="436.12299"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
xml:space="preserve"
|
||||
transform="matrix(0,1,-1,0,0,0)"><tspan
|
||||
y="-261.66608"
|
||||
@ -163,7 +163,7 @@
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.04738"
|
||||
y="268.18076"
|
||||
id="text4429"
|
||||
@ -174,7 +174,7 @@
|
||||
y="268.18076">WRITE_ONCE(a, 1);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.04738"
|
||||
y="487.13766"
|
||||
id="text4441"
|
||||
@ -185,7 +185,7 @@
|
||||
y="487.13766">WRITE_ONCE(b, 1);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="255.60869"
|
||||
y="297.29346"
|
||||
id="text4445"
|
||||
@ -196,7 +196,7 @@
|
||||
y="297.29346">r1 = READ_ONCE(a);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="255.14423"
|
||||
y="554.61786"
|
||||
id="text4449"
|
||||
@ -207,7 +207,7 @@
|
||||
y="554.61786">WRITE_ONCE(c, 1);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="370.71124"
|
||||
id="text4453"
|
||||
@ -218,7 +218,7 @@
|
||||
y="370.71124">WRITE_ONCE(d, 1);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="572.13617"
|
||||
id="text4457"
|
||||
@ -229,7 +229,7 @@
|
||||
y="572.13617">r2 = READ_ONCE(c);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.08231"
|
||||
y="213.91006"
|
||||
id="text4461"
|
||||
@ -240,7 +240,7 @@
|
||||
y="213.91006">thread0()</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="252.34512"
|
||||
y="213.91006"
|
||||
id="text4461-6"
|
||||
@ -251,7 +251,7 @@
|
||||
y="213.91006">thread1()</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.42557"
|
||||
y="213.91006"
|
||||
id="text4461-2"
|
||||
@ -281,7 +281,7 @@
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="111.75929"
|
||||
y="251.53981"
|
||||
id="text4429-8"
|
||||
@ -292,7 +292,7 @@
|
||||
y="251.53981">rcu_read_lock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="353.91556"
|
||||
id="text4429-8-9"
|
||||
@ -303,7 +303,7 @@
|
||||
y="353.91556">rcu_read_lock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="396.10254"
|
||||
y="587.40289"
|
||||
id="text4429-8-9-3"
|
||||
@ -314,7 +314,7 @@
|
||||
y="587.40289">rcu_read_unlock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="111.75929"
|
||||
y="501.15311"
|
||||
id="text4429-8-9-3-1"
|
||||
@ -331,7 +331,7 @@
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="394.94427"
|
||||
y="331.66351"
|
||||
id="text4648"
|
||||
@ -355,7 +355,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="112.11968"
|
||||
y="523.77856"
|
||||
id="text4648-4"
|
||||
@ -392,7 +392,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="254.85066"
|
||||
y="336.96619"
|
||||
id="text4648-4-3"
|
||||
@ -421,7 +421,7 @@
|
||||
id="text2993-7"
|
||||
y="-261.66608"
|
||||
x="440.12299"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
xml:space="preserve"
|
||||
transform="matrix(0,1,-1,0,0,0)"><tspan
|
||||
y="-261.66608"
|
||||
@ -453,7 +453,7 @@
|
||||
</g>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="541.70508"
|
||||
y="387.6217"
|
||||
id="text4445-0"
|
||||
@ -464,7 +464,7 @@
|
||||
y="387.6217">r3 = READ_ONCE(d);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="541.2406"
|
||||
y="646.94611"
|
||||
id="text4449-6"
|
||||
@ -488,7 +488,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="540.94702"
|
||||
y="427.29443"
|
||||
id="text4648-4-3-1"
|
||||
@ -499,7 +499,7 @@
|
||||
y="427.29443">QS</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="686.27747"
|
||||
y="461.83929"
|
||||
id="text4453-7"
|
||||
@ -510,7 +510,7 @@
|
||||
y="461.83929">r4 = READ_ONCE(b);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="686.27747"
|
||||
y="669.26422"
|
||||
id="text4457-9"
|
||||
@ -521,7 +521,7 @@
|
||||
y="669.26422">r5 = READ_ONCE(e);</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="686.27747"
|
||||
y="445.04358"
|
||||
id="text4429-8-9-33"
|
||||
@ -532,7 +532,7 @@
|
||||
y="445.04358">rcu_read_lock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="686.27747"
|
||||
y="684.53094"
|
||||
id="text4429-8-9-3-8"
|
||||
@ -543,7 +543,7 @@
|
||||
y="684.53094">rcu_read_unlock();</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="685.11914"
|
||||
y="422.79153"
|
||||
id="text4648-9"
|
||||
@ -567,7 +567,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="397.85934"
|
||||
y="609.59003"
|
||||
id="text4648-5"
|
||||
@ -591,7 +591,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="256.75986"
|
||||
y="586.99133"
|
||||
id="text4648-5-2"
|
||||
@ -615,7 +615,7 @@
|
||||
sodipodi:open="true" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="546.22791"
|
||||
y="213.91006"
|
||||
id="text4461-2-5"
|
||||
@ -626,7 +626,7 @@
|
||||
y="213.91006">thread3()</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
|
||||
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:monospace;-inkscape-font-specification:monospace"
|
||||
x="684.00067"
|
||||
y="213.91006"
|
||||
id="text4461-2-1"
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 30 KiB |
@ -254,17 +254,6 @@ period (in this case 2603), the grace-period sequence number (7075), and
|
||||
an estimate of the total number of RCU callbacks queued across all CPUs
|
||||
(625 in this case).
|
||||
|
||||
In kernels with CONFIG_RCU_FAST_NO_HZ, more information is printed
|
||||
for each CPU::
|
||||
|
||||
0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 softirq=82/543 last_accelerate: a345/d342 dyntick_enabled: 1
|
||||
|
||||
The "last_accelerate:" prints the low-order 16 bits (in hex) of the
|
||||
jiffies counter when this CPU last invoked rcu_try_advance_all_cbs()
|
||||
from rcu_needs_cpu() or last invoked rcu_accelerate_cbs() from
|
||||
rcu_prepare_for_idle(). "dyntick_enabled: 1" indicates that dyntick-idle
|
||||
processing is enabled.
|
||||
|
||||
If the grace period ends just as the stall warning starts printing,
|
||||
there will be a spurious stall-warning message, which will include
|
||||
the following::
|
||||
|
@ -39,9 +39,11 @@ different paths, as follows:
|
||||
|
||||
:ref:`6. ANALOGY WITH READER-WRITER LOCKING <6_whatisRCU>`
|
||||
|
||||
:ref:`7. FULL LIST OF RCU APIs <7_whatisRCU>`
|
||||
:ref:`7. ANALOGY WITH REFERENCE COUNTING <7_whatisRCU>`
|
||||
|
||||
:ref:`8. ANSWERS TO QUICK QUIZZES <8_whatisRCU>`
|
||||
:ref:`8. FULL LIST OF RCU APIs <8_whatisRCU>`
|
||||
|
||||
:ref:`9. ANSWERS TO QUICK QUIZZES <9_whatisRCU>`
|
||||
|
||||
People who prefer starting with a conceptual overview should focus on
|
||||
Section 1, though most readers will profit by reading this section at
|
||||
@ -677,7 +679,7 @@ Quick Quiz #1:
|
||||
occur when using this algorithm in a real-world Linux
|
||||
kernel? How could this deadlock be avoided?
|
||||
|
||||
:ref:`Answers to Quick Quiz <8_whatisRCU>`
|
||||
:ref:`Answers to Quick Quiz <9_whatisRCU>`
|
||||
|
||||
5B. "TOY" EXAMPLE #2: CLASSIC RCU
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -732,7 +734,7 @@ Quick Quiz #2:
|
||||
Give an example where Classic RCU's read-side
|
||||
overhead is **negative**.
|
||||
|
||||
:ref:`Answers to Quick Quiz <8_whatisRCU>`
|
||||
:ref:`Answers to Quick Quiz <9_whatisRCU>`
|
||||
|
||||
.. _quiz_3:
|
||||
|
||||
@ -741,7 +743,7 @@ Quick Quiz #3:
|
||||
critical section, what the heck do you do in
|
||||
CONFIG_PREEMPT_RT, where normal spinlocks can block???
|
||||
|
||||
:ref:`Answers to Quick Quiz <8_whatisRCU>`
|
||||
:ref:`Answers to Quick Quiz <9_whatisRCU>`
|
||||
|
||||
.. _6_whatisRCU:
|
||||
|
||||
@ -872,7 +874,79 @@ be used in place of synchronize_rcu().
|
||||
|
||||
.. _7_whatisRCU:
|
||||
|
||||
7. FULL LIST OF RCU APIs
|
||||
7. ANALOGY WITH REFERENCE COUNTING
|
||||
-----------------------------------
|
||||
|
||||
The reader-writer analogy (illustrated by the previous section) is not
|
||||
always the best way to think about using RCU. Another helpful analogy
|
||||
considers RCU an effective reference count on everything which is
|
||||
protected by RCU.
|
||||
|
||||
A reference count typically does not prevent the referenced object's
|
||||
values from changing, but does prevent changes to type -- particularly the
|
||||
gross change of type that happens when that object's memory is freed and
|
||||
re-allocated for some other purpose. Once a type-safe reference to the
|
||||
object is obtained, some other mechanism is needed to ensure consistent
|
||||
access to the data in the object. This could involve taking a spinlock,
|
||||
but with RCU the typical approach is to perform reads with SMP-aware
|
||||
operations such as smp_load_acquire(), to perform updates with atomic
|
||||
read-modify-write operations, and to provide the necessary ordering.
|
||||
RCU provides a number of support functions that embed the required
|
||||
operations and ordering, such as the list_for_each_entry_rcu() macro
|
||||
used in the previous section.
|
||||
|
||||
A more focused view of the reference counting behavior is that,
|
||||
between rcu_read_lock() and rcu_read_unlock(), any reference taken with
|
||||
rcu_dereference() on a pointer marked as ``__rcu`` can be treated as
|
||||
though a reference-count on that object has been temporarily increased.
|
||||
This prevents the object from changing type. Exactly what this means
|
||||
will depend on normal expectations of objects of that type, but it
|
||||
typically includes that spinlocks can still be safely locked, normal
|
||||
reference counters can be safely manipulated, and ``__rcu`` pointers
|
||||
can be safely dereferenced.
|
||||
|
||||
Some operations that one might expect to see on an object for
|
||||
which an RCU reference is held include:
|
||||
|
||||
- Copying out data that is guaranteed to be stable by the object's type.
|
||||
- Using kref_get_unless_zero() or similar to get a longer-term
|
||||
reference. This may fail of course.
|
||||
- Acquiring a spinlock in the object, and checking if the object still
|
||||
is the expected object and if so, manipulating it freely.
|
||||
|
||||
The understanding that RCU provides a reference that only prevents a
|
||||
change of type is particularly visible with objects allocated from a
|
||||
slab cache marked ``SLAB_TYPESAFE_BY_RCU``. RCU operations may yield a
|
||||
reference to an object from such a cache that has been concurrently
|
||||
freed and the memory reallocated to a completely different object,
|
||||
though of the same type. In this case RCU doesn't even protect the
|
||||
identity of the object from changing, only its type. So the object
|
||||
found may not be the one expected, but it will be one where it is safe
|
||||
to take a reference or spinlock and then confirm that the identity
|
||||
matches the expectations.
|
||||
|
||||
With traditional reference counting -- such as that implemented by the
|
||||
kref library in Linux -- there is typically code that runs when the last
|
||||
reference to an object is dropped. With kref, this is the function
|
||||
passed to kref_put(). When RCU is being used, such finalization code
|
||||
must not be run until all ``__rcu`` pointers referencing the object have
|
||||
been updated, and then a grace period has passed. Every remaining
|
||||
globally visible pointer to the object must be considered to be a
|
||||
potential counted reference, and the finalization code is typically run
|
||||
using call_rcu() only after all those pointers have been changed.
|
||||
|
||||
To see how to choose between these two analogies -- of RCU as a
|
||||
reader-writer lock and RCU as a reference counting system -- it is useful
|
||||
to reflect on the scale of the thing being protected. The reader-writer
|
||||
lock analogy looks at larger multi-part objects such as a linked list
|
||||
and shows how RCU can facilitate concurrency while elements are added
|
||||
to, and removed from, the list. The reference-count analogy looks at
|
||||
the individual objects and looks at how they can be accessed safely
|
||||
within whatever whole they are a part of.
|
||||
|
||||
.. _8_whatisRCU:
|
||||
|
||||
8. FULL LIST OF RCU APIs
|
||||
-------------------------
|
||||
|
||||
The RCU APIs are documented in docbook-format header comments in the
|
||||
@ -1035,9 +1109,9 @@ g. Otherwise, use RCU.
|
||||
Of course, this all assumes that you have determined that RCU is in fact
|
||||
the right tool for your job.
|
||||
|
||||
.. _8_whatisRCU:
|
||||
.. _9_whatisRCU:
|
||||
|
||||
8. ANSWERS TO QUICK QUIZZES
|
||||
9. ANSWERS TO QUICK QUIZZES
|
||||
----------------------------
|
||||
|
||||
Quick Quiz #1:
|
||||
|
@ -4,6 +4,8 @@
|
||||
Collaborative Processor Performance Control (CPPC)
|
||||
==================================================
|
||||
|
||||
.. _cppc_sysfs:
|
||||
|
||||
CPPC
|
||||
====
|
||||
|
||||
|
@ -8,11 +8,9 @@ to /proc/cpuinfo output of some architectures. They reside in
|
||||
Documentation/ABI/stable/sysfs-devices-system-cpu.
|
||||
|
||||
Architecture-neutral, drivers/base/topology.c, exports these attributes.
|
||||
However, the book and drawer related sysfs files will only be created if
|
||||
CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are selected, respectively.
|
||||
|
||||
CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are currently only used on s390,
|
||||
where they reflect the cpu and cache hierarchy.
|
||||
However the die, cluster, book, and drawer hierarchy related sysfs files will
|
||||
only be created if an architecture provides the related macros as described
|
||||
below.
|
||||
|
||||
For an architecture to support this feature, it must define some of
|
||||
these macros in include/asm-XXX/topology.h::
|
||||
@ -43,15 +41,14 @@ not defined by include/asm-XXX/topology.h:
|
||||
2) topology_die_id: -1
|
||||
3) topology_cluster_id: -1
|
||||
4) topology_core_id: 0
|
||||
5) topology_sibling_cpumask: just the given CPU
|
||||
6) topology_core_cpumask: just the given CPU
|
||||
7) topology_cluster_cpumask: just the given CPU
|
||||
8) topology_die_cpumask: just the given CPU
|
||||
|
||||
For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
|
||||
default definitions for topology_book_id() and topology_book_cpumask().
|
||||
For architectures that don't support drawers (CONFIG_SCHED_DRAWER) there are
|
||||
no default definitions for topology_drawer_id() and topology_drawer_cpumask().
|
||||
5) topology_book_id: -1
|
||||
6) topology_drawer_id: -1
|
||||
7) topology_sibling_cpumask: just the given CPU
|
||||
8) topology_core_cpumask: just the given CPU
|
||||
9) topology_cluster_cpumask: just the given CPU
|
||||
10) topology_die_cpumask: just the given CPU
|
||||
11) topology_book_cpumask: just the given CPU
|
||||
12) topology_drawer_cpumask: just the given CPU
|
||||
|
||||
Additionally, CPU topology information is provided under
|
||||
/sys/devices/system/cpu and includes these files. The internal
|
||||
|
134
Documentation/admin-guide/gpio/gpio-sim.rst
Normal file
@ -0,0 +1,134 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
Configfs GPIO Simulator
|
||||
=======================
|
||||
|
||||
The configfs GPIO Simulator (gpio-sim) provides a way to create simulated GPIO
|
||||
chips for testing purposes. The lines exposed by these chips can be accessed
|
||||
using the standard GPIO character device interface as well as manipulated
|
||||
using sysfs attributes.
|
||||
|
||||
Creating simulated chips
|
||||
------------------------
|
||||
|
||||
The gpio-sim module registers a configfs subsystem called ``'gpio-sim'``. For
|
||||
details of the configfs filesystem, please refer to the configfs documentation.
|
||||
|
||||
The user can create a hierarchy of configfs groups and items as well as modify
|
||||
values of exposed attributes. Once the chip is instantiated, this hierarchy
|
||||
will be translated to appropriate device properties. The general structure is:
|
||||
|
||||
**Group:** ``/config/gpio-sim``
|
||||
|
||||
This is the top directory of the gpio-sim configfs tree.
|
||||
|
||||
**Group:** ``/config/gpio-sim/gpio-device``
|
||||
|
||||
**Attribute:** ``/config/gpio-sim/gpio-device/dev_name``
|
||||
|
||||
**Attribute:** ``/config/gpio-sim/gpio-device/live``
|
||||
|
||||
This is a directory representing a GPIO platform device. The ``'dev_name'``
|
||||
attribute is read-only and allows the user-space to read the platform device
|
||||
name (e.g. ``'gpio-sim.0'``). The ``'live'`` attribute allows to trigger the
|
||||
actual creation of the device once it's fully configured. The accepted values
|
||||
are: ``'1'`` to enable the simulated device and ``'0'`` to disable and tear
|
||||
it down.
|
||||
|
||||
**Group:** ``/config/gpio-sim/gpio-device/gpio-bankX``
|
||||
|
||||
**Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/chip_name``
|
||||
|
||||
**Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/num_lines``
|
||||
|
||||
This group represents a bank of GPIOs under the top platform device. The
|
||||
``'chip_name'`` attribute is read-only and allows the user-space to read the
|
||||
device name of the bank device. The ``'num_lines'`` attribute allows to specify
|
||||
the number of lines exposed by this bank.
|
||||
|
||||
**Group:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY``
|
||||
|
||||
**Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/name``
|
||||
|
||||
This group represents a single line at the offset Y. The 'name' attribute
|
||||
allows to set the line name as represented by the 'gpio-line-names' property.
|
||||
|
||||
**Item:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/hog``
|
||||
|
||||
**Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/hog/name``
|
||||
|
||||
**Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/hog/direction``
|
||||
|
||||
This item makes the gpio-sim module hog the associated line. The ``'name'``
|
||||
attribute specifies the in-kernel consumer name to use. The ``'direction'``
|
||||
attribute specifies the hog direction and must be one of: ``'input'``,
|
||||
``'output-high'`` and ``'output-low'``.
|
||||
|
||||
Inside each bank directory, there's a set of attributes that can be used to
|
||||
configure the new chip. Additionally the user can ``mkdir()`` subdirectories
|
||||
inside the chip's directory that allow to pass additional configuration for
|
||||
specific lines. The name of those subdirectories must take the form of:
|
||||
``'line<offset>'`` (e.g. ``'line0'``, ``'line20'``, etc.) as the name will be
|
||||
used by the module to assign the config to the specific line at given offset.
|
||||
|
||||
Once the confiuration is complete, the ``'live'`` attribute must be set to 1 in
|
||||
order to instantiate the chip. It can be set back to 0 to destroy the simulated
|
||||
chip. The module will synchronously wait for the new simulated device to be
|
||||
successfully probed and if this doesn't happen, writing to ``'live'`` will
|
||||
result in an error.
|
||||
|
||||
Simulated GPIO chips can also be defined in device-tree. The compatible string
|
||||
must be: ``"gpio-simulator"``. Supported properties are:
|
||||
|
||||
``"gpio-sim,label"`` - chip label
|
||||
|
||||
Other standard GPIO properties (like ``"gpio-line-names"``, ``"ngpios"`` or
|
||||
``"gpio-hog"``) are also supported. Please refer to the GPIO documentation for
|
||||
details.
|
||||
|
||||
An example device-tree code defining a GPIO simulator:
|
||||
|
||||
.. code-block :: none
|
||||
|
||||
gpio-sim {
|
||||
compatible = "gpio-simulator";
|
||||
|
||||
bank0 {
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpios = <16>;
|
||||
gpio-sim,label = "dt-bank0";
|
||||
gpio-line-names = "", "sim-foo", "", "sim-bar";
|
||||
};
|
||||
|
||||
bank1 {
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpios = <8>;
|
||||
gpio-sim,label = "dt-bank1";
|
||||
|
||||
line3 {
|
||||
gpio-hog;
|
||||
gpios = <3 0>;
|
||||
output-high;
|
||||
line-name = "sim-hog-from-dt";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Manipulating simulated lines
|
||||
----------------------------
|
||||
|
||||
Each simulated GPIO chip creates a separate sysfs group under its device
|
||||
directory for each exposed line
|
||||
(e.g. ``/sys/devices/platform/gpio-sim.X/gpiochipY/``). The name of each group
|
||||
is of the form: ``'sim_gpioX'`` where X is the offset of the line. Inside each
|
||||
group there are two attibutes:
|
||||
|
||||
``pull`` - allows to read and set the current simulated pull setting for
|
||||
every line, when writing the value must be one of: ``'pull-up'``,
|
||||
``'pull-down'``
|
||||
|
||||
``value`` - allows to read the current value of the line which may be
|
||||
different from the pull if the line is being driven from
|
||||
user-space
|
@ -468,7 +468,7 @@ Spectre variant 2
|
||||
before invoking any firmware code to prevent Spectre variant 2 exploits
|
||||
using the firmware.
|
||||
|
||||
Using kernel address space randomization (CONFIG_RANDOMIZE_SLAB=y
|
||||
Using kernel address space randomization (CONFIG_RANDOMIZE_BASE=y
|
||||
and CONFIG_SLAB_FREELIST_RANDOM=y in the kernel configuration) makes
|
||||
attacks on the kernel generally more difficult.
|
||||
|
||||
|
@ -225,14 +225,23 @@
|
||||
For broken nForce2 BIOS resulting in XT-PIC timer.
|
||||
|
||||
acpi_sleep= [HW,ACPI] Sleep options
|
||||
Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
|
||||
old_ordering, nonvs, sci_force_enable, nobl }
|
||||
Format: { s3_bios, s3_mode, s3_beep, s4_hwsig,
|
||||
s4_nohwsig, old_ordering, nonvs,
|
||||
sci_force_enable, nobl }
|
||||
See Documentation/power/video.rst for information on
|
||||
s3_bios and s3_mode.
|
||||
s3_beep is for debugging; it makes the PC's speaker beep
|
||||
as soon as the kernel's real-mode entry point is called.
|
||||
s4_hwsig causes the kernel to check the ACPI hardware
|
||||
signature during resume from hibernation, and gracefully
|
||||
refuse to resume if it has changed. This complies with
|
||||
the ACPI specification but not with reality, since
|
||||
Windows does not do this and many laptops do change it
|
||||
on docking. So the default behaviour is to allow resume
|
||||
and simply warn when the signature changes, unless the
|
||||
s4_hwsig option is enabled.
|
||||
s4_nohwsig prevents ACPI hardware signature from being
|
||||
used during resume from hibernation.
|
||||
used (or even warned about) during resume.
|
||||
old_ordering causes the ACPI 1.0 ordering of the _PTS
|
||||
control method, with respect to putting devices into
|
||||
low power states, to be enforced (the ACPI 2.0 ordering
|
||||
@ -3551,6 +3560,13 @@
|
||||
shutdown the other cpus. Instead use the REBOOT_VECTOR
|
||||
irq.
|
||||
|
||||
nomodeset Disable kernel modesetting. DRM drivers will not perform
|
||||
display-mode changes or accelerated rendering. Only the
|
||||
system framebuffer will be available for use if this was
|
||||
set-up by the firmware or boot loader.
|
||||
|
||||
Useful as fallback, or for testing and debugging.
|
||||
|
||||
nomodule Disable module load
|
||||
|
||||
nopat [X86] Disable PAT (page attribute table extension of
|
||||
@ -4349,19 +4365,30 @@
|
||||
Disable the Correctable Errors Collector,
|
||||
see CONFIG_RAS_CEC help text.
|
||||
|
||||
rcu_nocbs= [KNL]
|
||||
The argument is a cpu list, as described above.
|
||||
rcu_nocbs[=cpu-list]
|
||||
[KNL] The optional argument is a cpu list,
|
||||
as described above.
|
||||
|
||||
In kernels built with CONFIG_RCU_NOCB_CPU=y, set
|
||||
the specified list of CPUs to be no-callback CPUs.
|
||||
Invocation of these CPUs' RCU callbacks will be
|
||||
offloaded to "rcuox/N" kthreads created for that
|
||||
purpose, where "x" is "p" for RCU-preempt, and
|
||||
"s" for RCU-sched, and "N" is the CPU number.
|
||||
This reduces OS jitter on the offloaded CPUs,
|
||||
which can be useful for HPC and real-time
|
||||
workloads. It can also improve energy efficiency
|
||||
for asymmetric multiprocessors.
|
||||
In kernels built with CONFIG_RCU_NOCB_CPU=y,
|
||||
enable the no-callback CPU mode, which prevents
|
||||
such CPUs' callbacks from being invoked in
|
||||
softirq context. Invocation of such CPUs' RCU
|
||||
callbacks will instead be offloaded to "rcuox/N"
|
||||
kthreads created for that purpose, where "x" is
|
||||
"p" for RCU-preempt, "s" for RCU-sched, and "g"
|
||||
for the kthreads that mediate grace periods; and
|
||||
"N" is the CPU number. This reduces OS jitter on
|
||||
the offloaded CPUs, which can be useful for HPC
|
||||
and real-time workloads. It can also improve
|
||||
energy efficiency for asymmetric multiprocessors.
|
||||
|
||||
If a cpulist is passed as an argument, the specified
|
||||
list of CPUs is set to no-callback mode from boot.
|
||||
|
||||
Otherwise, if the '=' sign and the cpulist
|
||||
arguments are omitted, no CPU will be set to
|
||||
no-callback mode from boot but the mode may be
|
||||
toggled at runtime via cpusets.
|
||||
|
||||
rcu_nocb_poll [KNL]
|
||||
Rather than requiring that offloaded CPUs
|
||||
@ -4495,10 +4522,6 @@
|
||||
on rcutree.qhimark at boot time and to zero to
|
||||
disable more aggressive help enlistment.
|
||||
|
||||
rcutree.rcu_idle_gp_delay= [KNL]
|
||||
Set wakeup interval for idle CPUs that have
|
||||
RCU callbacks (RCU_FAST_NO_HZ=y).
|
||||
|
||||
rcutree.rcu_kick_kthreads= [KNL]
|
||||
Cause the grace-period kthread to get an extra
|
||||
wake_up() if it sleeps three times longer than
|
||||
@ -4609,8 +4632,12 @@
|
||||
in seconds.
|
||||
|
||||
rcutorture.fwd_progress= [KNL]
|
||||
Enable RCU grace-period forward-progress testing
|
||||
Specifies the number of kthreads to be used
|
||||
for RCU grace-period forward-progress testing
|
||||
for the types of RCU supporting this notion.
|
||||
Defaults to 1 kthread, values less than zero or
|
||||
greater than the number of CPUs cause the number
|
||||
of CPUs to be used.
|
||||
|
||||
rcutorture.fwd_progress_div= [KNL]
|
||||
Specify the fraction of a CPU-stall-warning
|
||||
@ -4811,6 +4838,29 @@
|
||||
period to instead use normal non-expedited
|
||||
grace-period processing.
|
||||
|
||||
rcupdate.rcu_task_collapse_lim= [KNL]
|
||||
Set the maximum number of callbacks present
|
||||
at the beginning of a grace period that allows
|
||||
the RCU Tasks flavors to collapse back to using
|
||||
a single callback queue. This switching only
|
||||
occurs when rcupdate.rcu_task_enqueue_lim is
|
||||
set to the default value of -1.
|
||||
|
||||
rcupdate.rcu_task_contend_lim= [KNL]
|
||||
Set the minimum number of callback-queuing-time
|
||||
lock-contention events per jiffy required to
|
||||
cause the RCU Tasks flavors to switch to per-CPU
|
||||
callback queuing. This switching only occurs
|
||||
when rcupdate.rcu_task_enqueue_lim is set to
|
||||
the default value of -1.
|
||||
|
||||
rcupdate.rcu_task_enqueue_lim= [KNL]
|
||||
Set the number of callback queues to use for the
|
||||
RCU Tasks family of RCU flavors. The default
|
||||
of -1 allows this to be automatically (and
|
||||
dynamically) adjusted. This parameter is intended
|
||||
for use in testing.
|
||||
|
||||
rcupdate.rcu_task_ipi_delay= [KNL]
|
||||
Set time in jiffies during which RCU tasks will
|
||||
avoid sending IPIs, starting with the beginning
|
||||
|
@ -208,7 +208,7 @@ Do at least one of the following:
|
||||
2. Enable RCU to do its processing remotely via dyntick-idle by
|
||||
doing all of the following:
|
||||
|
||||
a. Build with CONFIG_NO_HZ=y and CONFIG_RCU_FAST_NO_HZ=y.
|
||||
a. Build with CONFIG_NO_HZ=y.
|
||||
b. Ensure that the CPU goes idle frequently, allowing other
|
||||
CPUs to detect that it has passed through an RCU quiescent
|
||||
state. If the kernel is built with CONFIG_NO_HZ_FULL=y,
|
||||
|
@ -60,6 +60,7 @@ s5p-mfc Samsung S5P MFC Video Codec
|
||||
sh_veu SuperH VEU mem2mem video processing
|
||||
sh_vou SuperH VOU video output
|
||||
stm32-dcmi STM32 Digital Camera Memory Interface (DCMI)
|
||||
stm32-dma2d STM32 Chrom-Art Accelerator Unit
|
||||
sun4i-csi Allwinner A10 CMOS Sensor Interface Support
|
||||
sun6i-csi Allwinner V3s Camera Sensor Interface
|
||||
sun8i-di Allwinner Deinterlace
|
||||
|
382
Documentation/admin-guide/pm/amd-pstate.rst
Normal file
@ -0,0 +1,382 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
.. include:: <isonum.txt>
|
||||
|
||||
===============================================
|
||||
``amd-pstate`` CPU Performance Scaling Driver
|
||||
===============================================
|
||||
|
||||
:Copyright: |copy| 2021 Advanced Micro Devices, Inc.
|
||||
|
||||
:Author: Huang Rui <ray.huang@amd.com>
|
||||
|
||||
|
||||
Introduction
|
||||
===================
|
||||
|
||||
``amd-pstate`` is the AMD CPU performance scaling driver that introduces a
|
||||
new CPU frequency control mechanism on modern AMD APU and CPU series in
|
||||
Linux kernel. The new mechanism is based on Collaborative Processor
|
||||
Performance Control (CPPC) which provides finer grain frequency management
|
||||
than legacy ACPI hardware P-States. Current AMD CPU/APU platforms are using
|
||||
the ACPI P-states driver to manage CPU frequency and clocks with switching
|
||||
only in 3 P-states. CPPC replaces the ACPI P-states controls, allows a
|
||||
flexible, low-latency interface for the Linux kernel to directly
|
||||
communicate the performance hints to hardware.
|
||||
|
||||
``amd-pstate`` leverages the Linux kernel governors such as ``schedutil``,
|
||||
``ondemand``, etc. to manage the performance hints which are provided by
|
||||
CPPC hardware functionality that internally follows the hardware
|
||||
specification (for details refer to AMD64 Architecture Programmer's Manual
|
||||
Volume 2: System Programming [1]_). Currently ``amd-pstate`` supports basic
|
||||
frequency control function according to kernel governors on some of the
|
||||
Zen2 and Zen3 processors, and we will implement more AMD specific functions
|
||||
in future after we verify them on the hardware and SBIOS.
|
||||
|
||||
|
||||
AMD CPPC Overview
|
||||
=======================
|
||||
|
||||
Collaborative Processor Performance Control (CPPC) interface enumerates a
|
||||
continuous, abstract, and unit-less performance value in a scale that is
|
||||
not tied to a specific performance state / frequency. This is an ACPI
|
||||
standard [2]_ which software can specify application performance goals and
|
||||
hints as a relative target to the infrastructure limits. AMD processors
|
||||
provides the low latency register model (MSR) instead of AML code
|
||||
interpreter for performance adjustments. ``amd-pstate`` will initialize a
|
||||
``struct cpufreq_driver`` instance ``amd_pstate_driver`` with the callbacks
|
||||
to manage each performance update behavior. ::
|
||||
|
||||
Highest Perf ------>+-----------------------+ +-----------------------+
|
||||
| | | |
|
||||
| | | |
|
||||
| | Max Perf ---->| |
|
||||
| | | |
|
||||
| | | |
|
||||
Nominal Perf ------>+-----------------------+ +-----------------------+
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | Desired Perf ---->| |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
Lowest non- | | | |
|
||||
linear perf ------>+-----------------------+ +-----------------------+
|
||||
| | | |
|
||||
| | Lowest perf ---->| |
|
||||
| | | |
|
||||
Lowest perf ------>+-----------------------+ +-----------------------+
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
0 ------>+-----------------------+ +-----------------------+
|
||||
|
||||
AMD P-States Performance Scale
|
||||
|
||||
|
||||
.. _perf_cap:
|
||||
|
||||
AMD CPPC Performance Capability
|
||||
--------------------------------
|
||||
|
||||
Highest Performance (RO)
|
||||
.........................
|
||||
|
||||
It is the absolute maximum performance an individual processor may reach,
|
||||
assuming ideal conditions. This performance level may not be sustainable
|
||||
for long durations and may only be achievable if other platform components
|
||||
are in a specific state; for example, it may require other processors be in
|
||||
an idle state. This would be equivalent to the highest frequencies
|
||||
supported by the processor.
|
||||
|
||||
Nominal (Guaranteed) Performance (RO)
|
||||
......................................
|
||||
|
||||
It is the maximum sustained performance level of the processor, assuming
|
||||
ideal operating conditions. In absence of an external constraint (power,
|
||||
thermal, etc.) this is the performance level the processor is expected to
|
||||
be able to maintain continuously. All cores/processors are expected to be
|
||||
able to sustain their nominal performance state simultaneously.
|
||||
|
||||
Lowest non-linear Performance (RO)
|
||||
...................................
|
||||
|
||||
It is the lowest performance level at which nonlinear power savings are
|
||||
achieved, for example, due to the combined effects of voltage and frequency
|
||||
scaling. Above this threshold, lower performance levels should be generally
|
||||
more energy efficient than higher performance levels. This register
|
||||
effectively conveys the most efficient performance level to ``amd-pstate``.
|
||||
|
||||
Lowest Performance (RO)
|
||||
........................
|
||||
|
||||
It is the absolute lowest performance level of the processor. Selecting a
|
||||
performance level lower than the lowest nonlinear performance level may
|
||||
cause an efficiency penalty but should reduce the instantaneous power
|
||||
consumption of the processor.
|
||||
|
||||
AMD CPPC Performance Control
|
||||
------------------------------
|
||||
|
||||
``amd-pstate`` passes performance goals through these registers. The
|
||||
register drives the behavior of the desired performance target.
|
||||
|
||||
Minimum requested performance (RW)
|
||||
...................................
|
||||
|
||||
``amd-pstate`` specifies the minimum allowed performance level.
|
||||
|
||||
Maximum requested performance (RW)
|
||||
...................................
|
||||
|
||||
``amd-pstate`` specifies a limit the maximum performance that is expected
|
||||
to be supplied by the hardware.
|
||||
|
||||
Desired performance target (RW)
|
||||
...................................
|
||||
|
||||
``amd-pstate`` specifies a desired target in the CPPC performance scale as
|
||||
a relative number. This can be expressed as percentage of nominal
|
||||
performance (infrastructure max). Below the nominal sustained performance
|
||||
level, desired performance expresses the average performance level of the
|
||||
processor subject to hardware. Above the nominal performance level,
|
||||
processor must provide at least nominal performance requested and go higher
|
||||
if current operating conditions allow.
|
||||
|
||||
Energy Performance Preference (EPP) (RW)
|
||||
.........................................
|
||||
|
||||
Provides a hint to the hardware if software wants to bias toward performance
|
||||
(0x0) or energy efficiency (0xff).
|
||||
|
||||
|
||||
Key Governors Support
|
||||
=======================
|
||||
|
||||
``amd-pstate`` can be used with all the (generic) scaling governors listed
|
||||
by the ``scaling_available_governors`` policy attribute in ``sysfs``. Then,
|
||||
it is responsible for the configuration of policy objects corresponding to
|
||||
CPUs and provides the ``CPUFreq`` core (and the scaling governors attached
|
||||
to the policy objects) with accurate information on the maximum and minimum
|
||||
operating frequencies supported by the hardware. Users can check the
|
||||
``scaling_cur_freq`` information comes from the ``CPUFreq`` core.
|
||||
|
||||
``amd-pstate`` mainly supports ``schedutil`` and ``ondemand`` for dynamic
|
||||
frequency control. It is to fine tune the processor configuration on
|
||||
``amd-pstate`` to the ``schedutil`` with CPU CFS scheduler. ``amd-pstate``
|
||||
registers adjust_perf callback to implement the CPPC similar performance
|
||||
update behavior. It is initialized by ``sugov_start`` and then populate the
|
||||
CPU's update_util_data pointer to assign ``sugov_update_single_perf`` as
|
||||
the utilization update callback function in CPU scheduler. CPU scheduler
|
||||
will call ``cpufreq_update_util`` and assign the target performance
|
||||
according to the ``struct sugov_cpu`` that utilization update belongs to.
|
||||
Then ``amd-pstate`` updates the desired performance according to the CPU
|
||||
scheduler assigned.
|
||||
|
||||
|
||||
Processor Support
|
||||
=======================
|
||||
|
||||
The ``amd-pstate`` initialization will fail if the _CPC in ACPI SBIOS is
|
||||
not existed at the detected processor, and it uses ``acpi_cpc_valid`` to
|
||||
check the _CPC existence. All Zen based processors support legacy ACPI
|
||||
hardware P-States function, so while the ``amd-pstate`` fails to be
|
||||
initialized, the kernel will fall back to initialize ``acpi-cpufreq``
|
||||
driver.
|
||||
|
||||
There are two types of hardware implementations for ``amd-pstate``: one is
|
||||
`Full MSR Support <perf_cap_>`_ and another is `Shared Memory Support
|
||||
<perf_cap_>`_. It can use :c:macro:`X86_FEATURE_CPPC` feature flag (for
|
||||
details refer to Processor Programming Reference (PPR) for AMD Family
|
||||
19h Model 51h, Revision A1 Processors [3]_) to indicate the different
|
||||
types. ``amd-pstate`` is to register different ``static_call`` instances
|
||||
for different hardware implementations.
|
||||
|
||||
Currently, some of Zen2 and Zen3 processors support ``amd-pstate``. In the
|
||||
future, it will be supported on more and more AMD processors.
|
||||
|
||||
Full MSR Support
|
||||
-----------------
|
||||
|
||||
Some new Zen3 processors such as Cezanne provide the MSR registers directly
|
||||
while the :c:macro:`X86_FEATURE_CPPC` CPU feature flag is set.
|
||||
``amd-pstate`` can handle the MSR register to implement the fast switch
|
||||
function in ``CPUFreq`` that can shrink latency of frequency control on the
|
||||
interrupt context. The functions with ``pstate_xxx`` prefix represent the
|
||||
operations of MSR registers.
|
||||
|
||||
Shared Memory Support
|
||||
----------------------
|
||||
|
||||
If :c:macro:`X86_FEATURE_CPPC` CPU feature flag is not set, that means the
|
||||
processor supports shared memory solution. In this case, ``amd-pstate``
|
||||
uses the ``cppc_acpi`` helper methods to implement the callback functions
|
||||
that defined on ``static_call``. The functions with ``cppc_xxx`` prefix
|
||||
represent the operations of acpi cppc helpers for shared memory solution.
|
||||
|
||||
|
||||
AMD P-States and ACPI hardware P-States always can be supported in one
|
||||
processor. But AMD P-States has the higher priority and if it is enabled
|
||||
with :c:macro:`MSR_AMD_CPPC_ENABLE` or ``cppc_set_enable``, it will respond
|
||||
to the request from AMD P-States.
|
||||
|
||||
|
||||
User Space Interface in ``sysfs``
|
||||
==================================
|
||||
|
||||
``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to
|
||||
control its functionality at the system level. They located in the
|
||||
``/sys/devices/system/cpu/cpufreq/policyX/`` directory and affect all CPUs. ::
|
||||
|
||||
root@hr-test1:/home/ray# ls /sys/devices/system/cpu/cpufreq/policy0/*amd*
|
||||
/sys/devices/system/cpu/cpufreq/policy0/amd_pstate_highest_perf
|
||||
/sys/devices/system/cpu/cpufreq/policy0/amd_pstate_lowest_nonlinear_freq
|
||||
/sys/devices/system/cpu/cpufreq/policy0/amd_pstate_max_freq
|
||||
|
||||
|
||||
``amd_pstate_highest_perf / amd_pstate_max_freq``
|
||||
|
||||
Maximum CPPC performance and CPU frequency that the driver is allowed to
|
||||
set in percent of the maximum supported CPPC performance level (the highest
|
||||
performance supported in `AMD CPPC Performance Capability <perf_cap_>`_).
|
||||
In some of ASICs, the highest CPPC performance is not the one in the _CPC
|
||||
table, so we need to expose it to sysfs. If boost is not active but
|
||||
supported, this maximum frequency will be larger than the one in
|
||||
``cpuinfo``.
|
||||
This attribute is read-only.
|
||||
|
||||
``amd_pstate_lowest_nonlinear_freq``
|
||||
|
||||
The lowest non-linear CPPC CPU frequency that the driver is allowed to set
|
||||
in percent of the maximum supported CPPC performance level (Please see the
|
||||
lowest non-linear performance in `AMD CPPC Performance Capability
|
||||
<perf_cap_>`_).
|
||||
This attribute is read-only.
|
||||
|
||||
For other performance and frequency values, we can read them back from
|
||||
``/sys/devices/system/cpu/cpuX/acpi_cppc/``, see :ref:`cppc_sysfs`.
|
||||
|
||||
|
||||
``amd-pstate`` vs ``acpi-cpufreq``
|
||||
======================================
|
||||
|
||||
On majority of AMD platforms supported by ``acpi-cpufreq``, the ACPI tables
|
||||
provided by the platform firmware used for CPU performance scaling, but
|
||||
only provides 3 P-states on AMD processors.
|
||||
However, on modern AMD APU and CPU series, it provides the collaborative
|
||||
processor performance control according to ACPI protocol and customize this
|
||||
for AMD platforms. That is fine-grain and continuous frequency range
|
||||
instead of the legacy hardware P-states. ``amd-pstate`` is the kernel
|
||||
module which supports the new AMD P-States mechanism on most of future AMD
|
||||
platforms. The AMD P-States mechanism will be the more performance and energy
|
||||
efficiency frequency management method on AMD processors.
|
||||
|
||||
Kernel Module Options for ``amd-pstate``
|
||||
=========================================
|
||||
|
||||
``shared_mem``
|
||||
Use a module param (shared_mem) to enable related processors manually with
|
||||
**amd_pstate.shared_mem=1**.
|
||||
Due to the performance issue on the processors with `Shared Memory Support
|
||||
<perf_cap_>`_, so we disable it for the moment and will enable this by default
|
||||
once we address performance issue on this solution.
|
||||
|
||||
The way to check whether current processor is `Full MSR Support <perf_cap_>`_
|
||||
or `Shared Memory Support <perf_cap_>`_ : ::
|
||||
|
||||
ray@hr-test1:~$ lscpu | grep cppc
|
||||
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm
|
||||
|
||||
If CPU Flags have cppc, then this processor supports `Full MSR Support
|
||||
<perf_cap_>`_. Otherwise it supports `Shared Memory Support <perf_cap_>`_.
|
||||
|
||||
|
||||
``cpupower`` tool support for ``amd-pstate``
|
||||
===============================================
|
||||
|
||||
``amd-pstate`` is supported on ``cpupower`` tool that can be used to dump the frequency
|
||||
information. And it is in progress to support more and more operations for new
|
||||
``amd-pstate`` module with this tool. ::
|
||||
|
||||
root@hr-test1:/home/ray# cpupower frequency-info
|
||||
analyzing CPU 0:
|
||||
driver: amd-pstate
|
||||
CPUs which run at the same hardware frequency: 0
|
||||
CPUs which need to have their frequency coordinated by software: 0
|
||||
maximum transition latency: 131 us
|
||||
hardware limits: 400 MHz - 4.68 GHz
|
||||
available cpufreq governors: ondemand conservative powersave userspace performance schedutil
|
||||
current policy: frequency should be within 400 MHz and 4.68 GHz.
|
||||
The governor "schedutil" may decide which speed to use
|
||||
within this range.
|
||||
current CPU frequency: Unable to call hardware
|
||||
current CPU frequency: 4.02 GHz (asserted by call to kernel)
|
||||
boost state support:
|
||||
Supported: yes
|
||||
Active: yes
|
||||
AMD PSTATE Highest Performance: 166. Maximum Frequency: 4.68 GHz.
|
||||
AMD PSTATE Nominal Performance: 117. Nominal Frequency: 3.30 GHz.
|
||||
AMD PSTATE Lowest Non-linear Performance: 39. Lowest Non-linear Frequency: 1.10 GHz.
|
||||
AMD PSTATE Lowest Performance: 15. Lowest Frequency: 400 MHz.
|
||||
|
||||
|
||||
Diagnostics and Tuning
|
||||
=======================
|
||||
|
||||
Trace Events
|
||||
--------------
|
||||
|
||||
There are two static trace events that can be used for ``amd-pstate``
|
||||
diagnostics. One of them is the cpu_frequency trace event generally used
|
||||
by ``CPUFreq``, and the other one is the ``amd_pstate_perf`` trace event
|
||||
specific to ``amd-pstate``. The following sequence of shell commands can
|
||||
be used to enable them and see their output (if the kernel is generally
|
||||
configured to support event tracing). ::
|
||||
|
||||
root@hr-test1:/home/ray# cd /sys/kernel/tracing/
|
||||
root@hr-test1:/sys/kernel/tracing# echo 1 > events/amd_cpu/enable
|
||||
root@hr-test1:/sys/kernel/tracing# cat trace
|
||||
# tracer: nop
|
||||
#
|
||||
# entries-in-buffer/entries-written: 47827/42233061 #P:2
|
||||
#
|
||||
# _-----=> irqs-off
|
||||
# / _----=> need-resched
|
||||
# | / _---=> hardirq/softirq
|
||||
# || / _--=> preempt-depth
|
||||
# ||| / delay
|
||||
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
|
||||
# | | | |||| | |
|
||||
<idle>-0 [015] dN... 4995.979886: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=15 changed=false fast_switch=true
|
||||
<idle>-0 [007] d.h.. 4995.979893: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=7 changed=false fast_switch=true
|
||||
cat-2161 [000] d.... 4995.980841: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=0 changed=false fast_switch=true
|
||||
sshd-2125 [004] d.s.. 4995.980968: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=4 changed=false fast_switch=true
|
||||
<idle>-0 [007] d.s.. 4995.980968: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=7 changed=false fast_switch=true
|
||||
<idle>-0 [003] d.s.. 4995.980971: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=3 changed=false fast_switch=true
|
||||
<idle>-0 [011] d.s.. 4995.980996: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=11 changed=false fast_switch=true
|
||||
|
||||
The cpu_frequency trace event will be triggered either by the ``schedutil`` scaling
|
||||
governor (for the policies it is attached to), or by the ``CPUFreq`` core (for the
|
||||
policies with other scaling governors).
|
||||
|
||||
|
||||
Reference
|
||||
===========
|
||||
|
||||
.. [1] AMD64 Architecture Programmer's Manual Volume 2: System Programming,
|
||||
https://www.amd.com/system/files/TechDocs/24593.pdf
|
||||
|
||||
.. [2] Advanced Configuration and Power Interface Specification,
|
||||
https://uefi.org/sites/default/files/resources/ACPI_Spec_6_4_Jan22.pdf
|
||||
|
||||
.. [3] Processor Programming Reference (PPR) for AMD Family 19h Model 51h, Revision A1 Processors
|
||||
https://www.amd.com/system/files/TechDocs/56569-A1-PUB.zip
|
@ -11,6 +11,7 @@ Working-State Power Management
|
||||
intel_idle
|
||||
cpufreq
|
||||
intel_pstate
|
||||
amd-pstate
|
||||
cpufreq_drivers
|
||||
intel_epb
|
||||
intel-speed-select
|
||||
|
85
Documentation/arc/arc.rst
Normal file
@ -0,0 +1,85 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Linux kernel for ARC processors
|
||||
*******************************
|
||||
|
||||
Other sources of information
|
||||
############################
|
||||
|
||||
Below are some resources where more information can be found on
|
||||
ARC processors and relevant open source projects.
|
||||
|
||||
- `<https://embarc.org>`_ - Community portal for open source on ARC.
|
||||
Good place to start to find relevant FOSS projects, toolchain releases,
|
||||
news items and more.
|
||||
|
||||
- `<https://github.com/foss-for-synopsys-dwc-arc-processors>`_ -
|
||||
Home for all development activities regarding open source projects for
|
||||
ARC processors. Some of the projects are forks of various upstream projects,
|
||||
where "work in progress" is hosted prior to submission to upstream projects.
|
||||
Other projects are developed by Synopsys and made available to community
|
||||
as open source for use on ARC Processors.
|
||||
|
||||
- `Official Synopsys ARC Processors website
|
||||
<https://www.synopsys.com/designware-ip/processor-solutions.html>`_ -
|
||||
location, with access to some IP documentation (`Programmer's Reference
|
||||
Manual, AKA PRM for ARC HS processors
|
||||
<https://www.synopsys.com/dw/doc.php/ds/cc/programmers-reference-manual-ARC-HS.pdf>`_)
|
||||
and free versions of some commercial tools (`Free nSIM
|
||||
<https://www.synopsys.com/cgi-bin/dwarcnsim/req1.cgi>`_ and
|
||||
`MetaWare Light Edition <https://www.synopsys.com/cgi-bin/arcmwtk_lite/reg1.cgi>`_).
|
||||
Please note though, registration is required to access both the documentation and
|
||||
the tools.
|
||||
|
||||
Important note on ARC processors configurability
|
||||
################################################
|
||||
|
||||
ARC processors are highly configurable and several configurable options
|
||||
are supported in Linux. Some options are transparent to software
|
||||
(i.e cache geometries, some can be detected at runtime and configured
|
||||
and used accordingly, while some need to be explicitly selected or configured
|
||||
in the kernel's configuration utility (AKA "make menuconfig").
|
||||
|
||||
However not all configurable options are supported when an ARC processor
|
||||
is to run Linux. SoC design teams should refer to "Appendix E:
|
||||
Configuration for ARC Linux" in the ARC HS Databook for configurability
|
||||
guidelines.
|
||||
|
||||
Following these guidelines and selecting valid configuration options
|
||||
up front is critical to help prevent any unwanted issues during
|
||||
SoC bringup and software development in general.
|
||||
|
||||
Building the Linux kernel for ARC processors
|
||||
############################################
|
||||
|
||||
The process of kernel building for ARC processors is the same as for any other
|
||||
architecture and could be done in 2 ways:
|
||||
|
||||
- Cross-compilation: process of compiling for ARC targets on a development
|
||||
host with a different processor architecture (generally x86_64/amd64).
|
||||
- Native compilation: process of compiling for ARC on a ARC platform
|
||||
(hardware board or a simulator like QEMU) with complete development environment
|
||||
(GNU toolchain, dtc, make etc) installed on the platform.
|
||||
|
||||
In both cases, up-to-date GNU toolchain for ARC for the host is needed.
|
||||
Synopsys offers prebuilt toolchain releases which can be used for this purpose,
|
||||
available from:
|
||||
|
||||
- Synopsys GNU toolchain releases:
|
||||
`<https://github.com/foss-for-synopsys-dwc-arc-processors/toolchain/releases>`_
|
||||
|
||||
- Linux kernel compilers collection:
|
||||
`<https://mirrors.edge.kernel.org/pub/tools/crosstool>`_
|
||||
|
||||
- Bootlin's toolchain collection: `<https://toolchains.bootlin.com>`_
|
||||
|
||||
Once the toolchain is installed in the system, make sure its "bin" folder
|
||||
is added in your ``PATH`` environment variable. Then set ``ARCH=arc`` &
|
||||
``CROSS_COMPILE=arc-linux`` (or whatever matches installed ARC toolchain prefix)
|
||||
and then as usual ``make defconfig && make``.
|
||||
|
||||
This will produce "vmlinux" file in the root of the kernel source tree
|
||||
usable for loading on the target system via JTAG.
|
||||
If you need to get an image usable with U-Boot bootloader,
|
||||
type ``make uImage`` and ``uImage`` will be produced in ``arch/arc/boot``
|
||||
folder.
|
3
Documentation/arc/features.rst
Normal file
@ -0,0 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features arc
|
17
Documentation/arc/index.rst
Normal file
@ -0,0 +1,17 @@
|
||||
===================
|
||||
ARC architecture
|
||||
===================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
arc
|
||||
|
||||
features
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
@ -9,6 +9,7 @@ implementation.
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
arc/index
|
||||
arm/index
|
||||
arm64/index
|
||||
ia64/index
|
||||
|
@ -20,7 +20,6 @@ Block
|
||||
kyber-iosched
|
||||
null_blk
|
||||
pr
|
||||
queue-sysfs
|
||||
request
|
||||
stat
|
||||
switching-sched
|
||||
|
@ -1,321 +0,0 @@
|
||||
=================
|
||||
Queue sysfs files
|
||||
=================
|
||||
|
||||
This text file will detail the queue files that are located in the sysfs tree
|
||||
for each block device. Note that stacked devices typically do not export
|
||||
any settings, since their queue merely functions as a remapping target.
|
||||
These files are the ones found in the /sys/block/xxx/queue/ directory.
|
||||
|
||||
Files denoted with a RO postfix are readonly and the RW postfix means
|
||||
read-write.
|
||||
|
||||
add_random (RW)
|
||||
---------------
|
||||
This file allows to turn off the disk entropy contribution. Default
|
||||
value of this file is '1'(on).
|
||||
|
||||
chunk_sectors (RO)
|
||||
------------------
|
||||
This has different meaning depending on the type of the block device.
|
||||
For a RAID device (dm-raid), chunk_sectors indicates the size in 512B sectors
|
||||
of the RAID volume stripe segment. For a zoned block device, either host-aware
|
||||
or host-managed, chunk_sectors indicates the size in 512B sectors of the zones
|
||||
of the device, with the eventual exception of the last zone of the device which
|
||||
may be smaller.
|
||||
|
||||
dax (RO)
|
||||
--------
|
||||
This file indicates whether the device supports Direct Access (DAX),
|
||||
used by CPU-addressable storage to bypass the pagecache. It shows '1'
|
||||
if true, '0' if not.
|
||||
|
||||
discard_granularity (RO)
|
||||
------------------------
|
||||
This shows the size of internal allocation of the device in bytes, if
|
||||
reported by the device. A value of '0' means device does not support
|
||||
the discard functionality.
|
||||
|
||||
discard_max_hw_bytes (RO)
|
||||
-------------------------
|
||||
Devices that support discard functionality may have internal limits on
|
||||
the number of bytes that can be trimmed or unmapped in a single operation.
|
||||
The `discard_max_hw_bytes` parameter is set by the device driver to the
|
||||
maximum number of bytes that can be discarded in a single operation.
|
||||
Discard requests issued to the device must not exceed this limit.
|
||||
A `discard_max_hw_bytes` value of 0 means that the device does not support
|
||||
discard functionality.
|
||||
|
||||
discard_max_bytes (RW)
|
||||
----------------------
|
||||
While discard_max_hw_bytes is the hardware limit for the device, this
|
||||
setting is the software limit. Some devices exhibit large latencies when
|
||||
large discards are issued, setting this value lower will make Linux issue
|
||||
smaller discards and potentially help reduce latencies induced by large
|
||||
discard operations.
|
||||
|
||||
discard_zeroes_data (RO)
|
||||
------------------------
|
||||
Obsolete. Always zero.
|
||||
|
||||
fua (RO)
|
||||
--------
|
||||
Whether or not the block driver supports the FUA flag for write requests.
|
||||
FUA stands for Force Unit Access. If the FUA flag is set that means that
|
||||
write requests must bypass the volatile cache of the storage device.
|
||||
|
||||
hw_sector_size (RO)
|
||||
-------------------
|
||||
This is the hardware sector size of the device, in bytes.
|
||||
|
||||
io_poll (RW)
|
||||
------------
|
||||
When read, this file shows whether polling is enabled (1) or disabled
|
||||
(0). Writing '0' to this file will disable polling for this device.
|
||||
Writing any non-zero value will enable this feature.
|
||||
|
||||
io_poll_delay (RW)
|
||||
------------------
|
||||
If polling is enabled, this controls what kind of polling will be
|
||||
performed. It defaults to -1, which is classic polling. In this mode,
|
||||
the CPU will repeatedly ask for completions without giving up any time.
|
||||
If set to 0, a hybrid polling mode is used, where the kernel will attempt
|
||||
to make an educated guess at when the IO will complete. Based on this
|
||||
guess, the kernel will put the process issuing IO to sleep for an amount
|
||||
of time, before entering a classic poll loop. This mode might be a
|
||||
little slower than pure classic polling, but it will be more efficient.
|
||||
If set to a value larger than 0, the kernel will put the process issuing
|
||||
IO to sleep for this amount of microseconds before entering classic
|
||||
polling.
|
||||
|
||||
io_timeout (RW)
|
||||
---------------
|
||||
io_timeout is the request timeout in milliseconds. If a request does not
|
||||
complete in this time then the block driver timeout handler is invoked.
|
||||
That timeout handler can decide to retry the request, to fail it or to start
|
||||
a device recovery strategy.
|
||||
|
||||
iostats (RW)
|
||||
-------------
|
||||
This file is used to control (on/off) the iostats accounting of the
|
||||
disk.
|
||||
|
||||
logical_block_size (RO)
|
||||
-----------------------
|
||||
This is the logical block size of the device, in bytes.
|
||||
|
||||
max_discard_segments (RO)
|
||||
-------------------------
|
||||
The maximum number of DMA scatter/gather entries in a discard request.
|
||||
|
||||
max_hw_sectors_kb (RO)
|
||||
----------------------
|
||||
This is the maximum number of kilobytes supported in a single data transfer.
|
||||
|
||||
max_integrity_segments (RO)
|
||||
---------------------------
|
||||
Maximum number of elements in a DMA scatter/gather list with integrity
|
||||
data that will be submitted by the block layer core to the associated
|
||||
block driver.
|
||||
|
||||
max_active_zones (RO)
|
||||
---------------------
|
||||
For zoned block devices (zoned attribute indicating "host-managed" or
|
||||
"host-aware"), the sum of zones belonging to any of the zone states:
|
||||
EXPLICIT OPEN, IMPLICIT OPEN or CLOSED, is limited by this value.
|
||||
If this value is 0, there is no limit.
|
||||
|
||||
If the host attempts to exceed this limit, the driver should report this error
|
||||
with BLK_STS_ZONE_ACTIVE_RESOURCE, which user space may see as the EOVERFLOW
|
||||
errno.
|
||||
|
||||
max_open_zones (RO)
|
||||
-------------------
|
||||
For zoned block devices (zoned attribute indicating "host-managed" or
|
||||
"host-aware"), the sum of zones belonging to any of the zone states:
|
||||
EXPLICIT OPEN or IMPLICIT OPEN, is limited by this value.
|
||||
If this value is 0, there is no limit.
|
||||
|
||||
If the host attempts to exceed this limit, the driver should report this error
|
||||
with BLK_STS_ZONE_OPEN_RESOURCE, which user space may see as the ETOOMANYREFS
|
||||
errno.
|
||||
|
||||
max_sectors_kb (RW)
|
||||
-------------------
|
||||
This is the maximum number of kilobytes that the block layer will allow
|
||||
for a filesystem request. Must be smaller than or equal to the maximum
|
||||
size allowed by the hardware.
|
||||
|
||||
max_segments (RO)
|
||||
-----------------
|
||||
Maximum number of elements in a DMA scatter/gather list that is submitted
|
||||
to the associated block driver.
|
||||
|
||||
max_segment_size (RO)
|
||||
---------------------
|
||||
Maximum size in bytes of a single element in a DMA scatter/gather list.
|
||||
|
||||
minimum_io_size (RO)
|
||||
--------------------
|
||||
This is the smallest preferred IO size reported by the device.
|
||||
|
||||
nomerges (RW)
|
||||
-------------
|
||||
This enables the user to disable the lookup logic involved with IO
|
||||
merging requests in the block layer. By default (0) all merges are
|
||||
enabled. When set to 1 only simple one-hit merges will be tried. When
|
||||
set to 2 no merge algorithms will be tried (including one-hit or more
|
||||
complex tree/hash lookups).
|
||||
|
||||
nr_requests (RW)
|
||||
----------------
|
||||
This controls how many requests may be allocated in the block layer for
|
||||
read or write requests. Note that the total allocated number may be twice
|
||||
this amount, since it applies only to reads or writes (not the accumulated
|
||||
sum).
|
||||
|
||||
To avoid priority inversion through request starvation, a request
|
||||
queue maintains a separate request pool per each cgroup when
|
||||
CONFIG_BLK_CGROUP is enabled, and this parameter applies to each such
|
||||
per-block-cgroup request pool. IOW, if there are N block cgroups,
|
||||
each request queue may have up to N request pools, each independently
|
||||
regulated by nr_requests.
|
||||
|
||||
nr_zones (RO)
|
||||
-------------
|
||||
For zoned block devices (zoned attribute indicating "host-managed" or
|
||||
"host-aware"), this indicates the total number of zones of the device.
|
||||
This is always 0 for regular block devices.
|
||||
|
||||
optimal_io_size (RO)
|
||||
--------------------
|
||||
This is the optimal IO size reported by the device.
|
||||
|
||||
physical_block_size (RO)
|
||||
------------------------
|
||||
This is the physical block size of device, in bytes.
|
||||
|
||||
read_ahead_kb (RW)
|
||||
------------------
|
||||
Maximum number of kilobytes to read-ahead for filesystems on this block
|
||||
device.
|
||||
|
||||
rotational (RW)
|
||||
---------------
|
||||
This file is used to stat if the device is of rotational type or
|
||||
non-rotational type.
|
||||
|
||||
rq_affinity (RW)
|
||||
----------------
|
||||
If this option is '1', the block layer will migrate request completions to the
|
||||
cpu "group" that originally submitted the request. For some workloads this
|
||||
provides a significant reduction in CPU cycles due to caching effects.
|
||||
|
||||
For storage configurations that need to maximize distribution of completion
|
||||
processing setting this option to '2' forces the completion to run on the
|
||||
requesting cpu (bypassing the "group" aggregation logic).
|
||||
|
||||
scheduler (RW)
|
||||
--------------
|
||||
When read, this file will display the current and available IO schedulers
|
||||
for this block device. The currently active IO scheduler will be enclosed
|
||||
in [] brackets. Writing an IO scheduler name to this file will switch
|
||||
control of this block device to that new IO scheduler. Note that writing
|
||||
an IO scheduler name to this file will attempt to load that IO scheduler
|
||||
module, if it isn't already present in the system.
|
||||
|
||||
write_cache (RW)
|
||||
----------------
|
||||
When read, this file will display whether the device has write back
|
||||
caching enabled or not. It will return "write back" for the former
|
||||
case, and "write through" for the latter. Writing to this file can
|
||||
change the kernels view of the device, but it doesn't alter the
|
||||
device state. This means that it might not be safe to toggle the
|
||||
setting from "write back" to "write through", since that will also
|
||||
eliminate cache flushes issued by the kernel.
|
||||
|
||||
write_same_max_bytes (RO)
|
||||
-------------------------
|
||||
This is the number of bytes the device can write in a single write-same
|
||||
command. A value of '0' means write-same is not supported by this
|
||||
device.
|
||||
|
||||
wbt_lat_usec (RW)
|
||||
-----------------
|
||||
If the device is registered for writeback throttling, then this file shows
|
||||
the target minimum read latency. If this latency is exceeded in a given
|
||||
window of time (see wb_window_usec), then the writeback throttling will start
|
||||
scaling back writes. Writing a value of '0' to this file disables the
|
||||
feature. Writing a value of '-1' to this file resets the value to the
|
||||
default setting.
|
||||
|
||||
throttle_sample_time (RW)
|
||||
-------------------------
|
||||
This is the time window that blk-throttle samples data, in millisecond.
|
||||
blk-throttle makes decision based on the samplings. Lower time means cgroups
|
||||
have more smooth throughput, but higher CPU overhead. This exists only when
|
||||
CONFIG_BLK_DEV_THROTTLING_LOW is enabled.
|
||||
|
||||
write_zeroes_max_bytes (RO)
|
||||
---------------------------
|
||||
For block drivers that support REQ_OP_WRITE_ZEROES, the maximum number of
|
||||
bytes that can be zeroed at once. The value 0 means that REQ_OP_WRITE_ZEROES
|
||||
is not supported.
|
||||
|
||||
zone_append_max_bytes (RO)
|
||||
--------------------------
|
||||
This is the maximum number of bytes that can be written to a sequential
|
||||
zone of a zoned block device using a zone append write operation
|
||||
(REQ_OP_ZONE_APPEND). This value is always 0 for regular block devices.
|
||||
|
||||
zoned (RO)
|
||||
----------
|
||||
This indicates if the device is a zoned block device and the zone model of the
|
||||
device if it is indeed zoned. The possible values indicated by zoned are
|
||||
"none" for regular block devices and "host-aware" or "host-managed" for zoned
|
||||
block devices. The characteristics of host-aware and host-managed zoned block
|
||||
devices are described in the ZBC (Zoned Block Commands) and ZAC
|
||||
(Zoned Device ATA Command Set) standards. These standards also define the
|
||||
"drive-managed" zone model. However, since drive-managed zoned block devices
|
||||
do not support zone commands, they will be treated as regular block devices
|
||||
and zoned will report "none".
|
||||
|
||||
zone_write_granularity (RO)
|
||||
---------------------------
|
||||
This indicates the alignment constraint, in bytes, for write operations in
|
||||
sequential zones of zoned block devices (devices with a zoned attributed
|
||||
that reports "host-managed" or "host-aware"). This value is always 0 for
|
||||
regular block devices.
|
||||
|
||||
independent_access_ranges (RO)
|
||||
------------------------------
|
||||
|
||||
The presence of this sub-directory of the /sys/block/xxx/queue/ directory
|
||||
indicates that the device is capable of executing requests targeting
|
||||
different sector ranges in parallel. For instance, single LUN multi-actuator
|
||||
hard-disks will have an independent_access_ranges directory if the device
|
||||
correctly advertizes the sector ranges of its actuators.
|
||||
|
||||
The independent_access_ranges directory contains one directory per access
|
||||
range, with each range described using the sector (RO) attribute file to
|
||||
indicate the first sector of the range and the nr_sectors (RO) attribute file
|
||||
to indicate the total number of sectors in the range starting from the first
|
||||
sector of the range. For example, a dual-actuator hard-disk will have the
|
||||
following independent_access_ranges entries.::
|
||||
|
||||
$ tree /sys/block/<device>/queue/independent_access_ranges/
|
||||
/sys/block/<device>/queue/independent_access_ranges/
|
||||
|-- 0
|
||||
| |-- nr_sectors
|
||||
| `-- sector
|
||||
`-- 1
|
||||
|-- nr_sectors
|
||||
`-- sector
|
||||
|
||||
The sector and nr_sectors attributes use 512B sector unit, regardless of
|
||||
the actual block size of the device. Independent access ranges do not
|
||||
overlap and include all sectors within the device capacity. The access
|
||||
ranges are numbered in increasing order of the range start sector,
|
||||
that is, the sector attribute of range 0 always has the value 0.
|
||||
|
||||
Jens Axboe <jens.axboe@oracle.com>, February 2009
|
@ -3,7 +3,7 @@ BPF Type Format (BTF)
|
||||
=====================
|
||||
|
||||
1. Introduction
|
||||
***************
|
||||
===============
|
||||
|
||||
BTF (BPF Type Format) is the metadata format which encodes the debug info
|
||||
related to BPF program/map. The name BTF was used initially to describe data
|
||||
@ -30,7 +30,7 @@ sections are discussed in details in :ref:`BTF_Type_String`.
|
||||
.. _BTF_Type_String:
|
||||
|
||||
2. BTF Type and String Encoding
|
||||
*******************************
|
||||
===============================
|
||||
|
||||
The file ``include/uapi/linux/btf.h`` provides high-level definition of how
|
||||
types/strings are encoded.
|
||||
@ -57,13 +57,13 @@ little-endian target. The ``btf_header`` is designed to be extensible with
|
||||
generated.
|
||||
|
||||
2.1 String Encoding
|
||||
===================
|
||||
-------------------
|
||||
|
||||
The first string in the string section must be a null string. The rest of
|
||||
string table is a concatenation of other null-terminated strings.
|
||||
|
||||
2.2 Type Encoding
|
||||
=================
|
||||
-----------------
|
||||
|
||||
The type id ``0`` is reserved for ``void`` type. The type section is parsed
|
||||
sequentially and type id is assigned to each recognized type starting from id
|
||||
@ -86,6 +86,7 @@ sequentially and type id is assigned to each recognized type starting from id
|
||||
#define BTF_KIND_DATASEC 15 /* Section */
|
||||
#define BTF_KIND_FLOAT 16 /* Floating point */
|
||||
#define BTF_KIND_DECL_TAG 17 /* Decl Tag */
|
||||
#define BTF_KIND_TYPE_TAG 18 /* Type Tag */
|
||||
|
||||
Note that the type section encodes debug info, not just pure types.
|
||||
``BTF_KIND_FUNC`` is not a type, and it represents a defined subprogram.
|
||||
@ -107,7 +108,7 @@ Each type contains the following common data::
|
||||
* "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
* FUNC, FUNC_PROTO and DECL_TAG.
|
||||
* FUNC, FUNC_PROTO, DECL_TAG and TYPE_TAG.
|
||||
* "type" is a type_id referring to another type.
|
||||
*/
|
||||
union {
|
||||
@ -492,8 +493,18 @@ the attribute is applied to a ``struct``/``union`` member or
|
||||
a ``func`` argument, and ``btf_decl_tag.component_idx`` should be a
|
||||
valid index (starting from 0) pointing to a member or an argument.
|
||||
|
||||
2.2.17 BTF_KIND_TYPE_TAG
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``struct btf_type`` encoding requirement:
|
||||
* ``name_off``: offset to a non-empty string
|
||||
* ``info.kind_flag``: 0
|
||||
* ``info.kind``: BTF_KIND_TYPE_TAG
|
||||
* ``info.vlen``: 0
|
||||
* ``type``: the type with ``btf_type_tag`` attribute
|
||||
|
||||
3. BTF Kernel API
|
||||
*****************
|
||||
=================
|
||||
|
||||
The following bpf syscall command involves BTF:
|
||||
* BPF_BTF_LOAD: load a blob of BTF data into kernel
|
||||
@ -536,14 +547,14 @@ The workflow typically looks like:
|
||||
|
||||
|
||||
3.1 BPF_BTF_LOAD
|
||||
================
|
||||
----------------
|
||||
|
||||
Load a blob of BTF data into kernel. A blob of data, described in
|
||||
:ref:`BTF_Type_String`, can be directly loaded into the kernel. A ``btf_fd``
|
||||
is returned to a userspace.
|
||||
|
||||
3.2 BPF_MAP_CREATE
|
||||
==================
|
||||
------------------
|
||||
|
||||
A map can be created with ``btf_fd`` and specified key/value type id.::
|
||||
|
||||
@ -570,7 +581,7 @@ automatically.
|
||||
.. _BPF_Prog_Load:
|
||||
|
||||
3.3 BPF_PROG_LOAD
|
||||
=================
|
||||
-----------------
|
||||
|
||||
During prog_load, func_info and line_info can be passed to kernel with proper
|
||||
values for the following attributes:
|
||||
@ -620,7 +631,7 @@ For line_info, the line number and column number are defined as below:
|
||||
#define BPF_LINE_INFO_LINE_COL(line_col) ((line_col) & 0x3ff)
|
||||
|
||||
3.4 BPF_{PROG,MAP}_GET_NEXT_ID
|
||||
==============================
|
||||
------------------------------
|
||||
|
||||
In kernel, every loaded program, map or btf has a unique id. The id won't
|
||||
change during the lifetime of a program, map, or btf.
|
||||
@ -630,13 +641,13 @@ each command, to user space, for bpf program or maps, respectively, so an
|
||||
inspection tool can inspect all programs and maps.
|
||||
|
||||
3.5 BPF_{PROG,MAP}_GET_FD_BY_ID
|
||||
===============================
|
||||
-------------------------------
|
||||
|
||||
An introspection tool cannot use id to get details about program or maps.
|
||||
A file descriptor needs to be obtained first for reference-counting purpose.
|
||||
|
||||
3.6 BPF_OBJ_GET_INFO_BY_FD
|
||||
==========================
|
||||
--------------------------
|
||||
|
||||
Once a program/map fd is acquired, an introspection tool can get the detailed
|
||||
information from kernel about this fd, some of which are BTF-related. For
|
||||
@ -645,7 +656,7 @@ example, ``bpf_map_info`` returns ``btf_id`` and key/value type ids.
|
||||
bpf byte codes, and jited_line_info.
|
||||
|
||||
3.7 BPF_BTF_GET_FD_BY_ID
|
||||
========================
|
||||
------------------------
|
||||
|
||||
With ``btf_id`` obtained in ``bpf_map_info`` and ``bpf_prog_info``, bpf
|
||||
syscall command BPF_BTF_GET_FD_BY_ID can retrieve a btf fd. Then, with
|
||||
@ -657,10 +668,10 @@ tool has full btf knowledge and is able to pretty print map key/values, dump
|
||||
func signatures and line info, along with byte/jit codes.
|
||||
|
||||
4. ELF File Format Interface
|
||||
****************************
|
||||
============================
|
||||
|
||||
4.1 .BTF section
|
||||
================
|
||||
----------------
|
||||
|
||||
The .BTF section contains type and string data. The format of this section is
|
||||
same as the one describe in :ref:`BTF_Type_String`.
|
||||
@ -668,7 +679,7 @@ same as the one describe in :ref:`BTF_Type_String`.
|
||||
.. _BTF_Ext_Section:
|
||||
|
||||
4.2 .BTF.ext section
|
||||
====================
|
||||
--------------------
|
||||
|
||||
The .BTF.ext section encodes func_info and line_info which needs loader
|
||||
manipulation before loading into the kernel.
|
||||
@ -732,7 +743,7 @@ bpf_insn``. For ELF API, the ``insn_off`` is the byte offset from the
|
||||
beginning of section (``btf_ext_info_sec->sec_name_off``).
|
||||
|
||||
4.2 .BTF_ids section
|
||||
====================
|
||||
--------------------
|
||||
|
||||
The .BTF_ids section encodes BTF ID values that are used within the kernel.
|
||||
|
||||
@ -793,10 +804,10 @@ All the BTF ID lists and sets are compiled in the .BTF_ids section and
|
||||
resolved during the linking phase of kernel build by ``resolve_btfids`` tool.
|
||||
|
||||
5. Using BTF
|
||||
************
|
||||
============
|
||||
|
||||
5.1 bpftool map pretty print
|
||||
============================
|
||||
----------------------------
|
||||
|
||||
With BTF, the map key/value can be printed based on fields rather than simply
|
||||
raw bytes. This is especially valuable for large structure or if your data
|
||||
@ -838,7 +849,7 @@ bpftool is able to pretty print like below:
|
||||
]
|
||||
|
||||
5.2 bpftool prog dump
|
||||
=====================
|
||||
---------------------
|
||||
|
||||
The following is an example showing how func_info and line_info can help prog
|
||||
dump with better kernel symbol names, function prototypes and line
|
||||
@ -872,7 +883,7 @@ information.::
|
||||
[...]
|
||||
|
||||
5.3 Verifier Log
|
||||
================
|
||||
----------------
|
||||
|
||||
The following is an example of how line_info can help debugging verification
|
||||
failure.::
|
||||
@ -898,7 +909,7 @@ failure.::
|
||||
R2 offset is outside of the packet
|
||||
|
||||
6. BTF Generation
|
||||
*****************
|
||||
=================
|
||||
|
||||
You need latest pahole
|
||||
|
||||
@ -1005,6 +1016,6 @@ format.::
|
||||
.long 8206 # Line 8 Col 14
|
||||
|
||||
7. Testing
|
||||
**********
|
||||
==========
|
||||
|
||||
Kernel bpf selftest `test_btf.c` provides extensive set of BTF-related tests.
|
||||
|
376
Documentation/bpf/classic_vs_extended.rst
Normal file
@ -0,0 +1,376 @@
|
||||
|
||||
===================
|
||||
Classic BPF vs eBPF
|
||||
===================
|
||||
|
||||
eBPF is designed to be JITed with one to one mapping, which can also open up
|
||||
the possibility for GCC/LLVM compilers to generate optimized eBPF code through
|
||||
an eBPF backend that performs almost as fast as natively compiled code.
|
||||
|
||||
Some core changes of the eBPF format from classic BPF:
|
||||
|
||||
- Number of registers increase from 2 to 10:
|
||||
|
||||
The old format had two registers A and X, and a hidden frame pointer. The
|
||||
new layout extends this to be 10 internal registers and a read-only frame
|
||||
pointer. Since 64-bit CPUs are passing arguments to functions via registers
|
||||
the number of args from eBPF program to in-kernel function is restricted
|
||||
to 5 and one register is used to accept return value from an in-kernel
|
||||
function. Natively, x86_64 passes first 6 arguments in registers, aarch64/
|
||||
sparcv9/mips64 have 7 - 8 registers for arguments; x86_64 has 6 callee saved
|
||||
registers, and aarch64/sparcv9/mips64 have 11 or more callee saved registers.
|
||||
|
||||
Thus, all eBPF registers map one to one to HW registers on x86_64, aarch64,
|
||||
etc, and eBPF calling convention maps directly to ABIs used by the kernel on
|
||||
64-bit architectures.
|
||||
|
||||
On 32-bit architectures JIT may map programs that use only 32-bit arithmetic
|
||||
and may let more complex programs to be interpreted.
|
||||
|
||||
R0 - R5 are scratch registers and eBPF program needs spill/fill them if
|
||||
necessary across calls. Note that there is only one eBPF program (== one
|
||||
eBPF main routine) and it cannot call other eBPF functions, it can only
|
||||
call predefined in-kernel functions, though.
|
||||
|
||||
- Register width increases from 32-bit to 64-bit:
|
||||
|
||||
Still, the semantics of the original 32-bit ALU operations are preserved
|
||||
via 32-bit subregisters. All eBPF registers are 64-bit with 32-bit lower
|
||||
subregisters that zero-extend into 64-bit if they are being written to.
|
||||
That behavior maps directly to x86_64 and arm64 subregister definition, but
|
||||
makes other JITs more difficult.
|
||||
|
||||
32-bit architectures run 64-bit eBPF programs via interpreter.
|
||||
Their JITs may convert BPF programs that only use 32-bit subregisters into
|
||||
native instruction set and let the rest being interpreted.
|
||||
|
||||
Operation is 64-bit, because on 64-bit architectures, pointers are also
|
||||
64-bit wide, and we want to pass 64-bit values in/out of kernel functions,
|
||||
so 32-bit eBPF registers would otherwise require to define register-pair
|
||||
ABI, thus, there won't be able to use a direct eBPF register to HW register
|
||||
mapping and JIT would need to do combine/split/move operations for every
|
||||
register in and out of the function, which is complex, bug prone and slow.
|
||||
Another reason is the use of atomic 64-bit counters.
|
||||
|
||||
- Conditional jt/jf targets replaced with jt/fall-through:
|
||||
|
||||
While the original design has constructs such as ``if (cond) jump_true;
|
||||
else jump_false;``, they are being replaced into alternative constructs like
|
||||
``if (cond) jump_true; /* else fall-through */``.
|
||||
|
||||
- Introduces bpf_call insn and register passing convention for zero overhead
|
||||
calls from/to other kernel functions:
|
||||
|
||||
Before an in-kernel function call, the eBPF program needs to
|
||||
place function arguments into R1 to R5 registers to satisfy calling
|
||||
convention, then the interpreter will take them from registers and pass
|
||||
to in-kernel function. If R1 - R5 registers are mapped to CPU registers
|
||||
that are used for argument passing on given architecture, the JIT compiler
|
||||
doesn't need to emit extra moves. Function arguments will be in the correct
|
||||
registers and BPF_CALL instruction will be JITed as single 'call' HW
|
||||
instruction. This calling convention was picked to cover common call
|
||||
situations without performance penalty.
|
||||
|
||||
After an in-kernel function call, R1 - R5 are reset to unreadable and R0 has
|
||||
a return value of the function. Since R6 - R9 are callee saved, their state
|
||||
is preserved across the call.
|
||||
|
||||
For example, consider three C functions::
|
||||
|
||||
u64 f1() { return (*_f2)(1); }
|
||||
u64 f2(u64 a) { return f3(a + 1, a); }
|
||||
u64 f3(u64 a, u64 b) { return a - b; }
|
||||
|
||||
GCC can compile f1, f3 into x86_64::
|
||||
|
||||
f1:
|
||||
movl $1, %edi
|
||||
movq _f2(%rip), %rax
|
||||
jmp *%rax
|
||||
f3:
|
||||
movq %rdi, %rax
|
||||
subq %rsi, %rax
|
||||
ret
|
||||
|
||||
Function f2 in eBPF may look like::
|
||||
|
||||
f2:
|
||||
bpf_mov R2, R1
|
||||
bpf_add R1, 1
|
||||
bpf_call f3
|
||||
bpf_exit
|
||||
|
||||
If f2 is JITed and the pointer stored to ``_f2``. The calls f1 -> f2 -> f3 and
|
||||
returns will be seamless. Without JIT, __bpf_prog_run() interpreter needs to
|
||||
be used to call into f2.
|
||||
|
||||
For practical reasons all eBPF programs have only one argument 'ctx' which is
|
||||
already placed into R1 (e.g. on __bpf_prog_run() startup) and the programs
|
||||
can call kernel functions with up to 5 arguments. Calls with 6 or more arguments
|
||||
are currently not supported, but these restrictions can be lifted if necessary
|
||||
in the future.
|
||||
|
||||
On 64-bit architectures all register map to HW registers one to one. For
|
||||
example, x86_64 JIT compiler can map them as ...
|
||||
|
||||
::
|
||||
|
||||
R0 - rax
|
||||
R1 - rdi
|
||||
R2 - rsi
|
||||
R3 - rdx
|
||||
R4 - rcx
|
||||
R5 - r8
|
||||
R6 - rbx
|
||||
R7 - r13
|
||||
R8 - r14
|
||||
R9 - r15
|
||||
R10 - rbp
|
||||
|
||||
... since x86_64 ABI mandates rdi, rsi, rdx, rcx, r8, r9 for argument passing
|
||||
and rbx, r12 - r15 are callee saved.
|
||||
|
||||
Then the following eBPF pseudo-program::
|
||||
|
||||
bpf_mov R6, R1 /* save ctx */
|
||||
bpf_mov R2, 2
|
||||
bpf_mov R3, 3
|
||||
bpf_mov R4, 4
|
||||
bpf_mov R5, 5
|
||||
bpf_call foo
|
||||
bpf_mov R7, R0 /* save foo() return value */
|
||||
bpf_mov R1, R6 /* restore ctx for next call */
|
||||
bpf_mov R2, 6
|
||||
bpf_mov R3, 7
|
||||
bpf_mov R4, 8
|
||||
bpf_mov R5, 9
|
||||
bpf_call bar
|
||||
bpf_add R0, R7
|
||||
bpf_exit
|
||||
|
||||
After JIT to x86_64 may look like::
|
||||
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
sub $0x228,%rsp
|
||||
mov %rbx,-0x228(%rbp)
|
||||
mov %r13,-0x220(%rbp)
|
||||
mov %rdi,%rbx
|
||||
mov $0x2,%esi
|
||||
mov $0x3,%edx
|
||||
mov $0x4,%ecx
|
||||
mov $0x5,%r8d
|
||||
callq foo
|
||||
mov %rax,%r13
|
||||
mov %rbx,%rdi
|
||||
mov $0x6,%esi
|
||||
mov $0x7,%edx
|
||||
mov $0x8,%ecx
|
||||
mov $0x9,%r8d
|
||||
callq bar
|
||||
add %r13,%rax
|
||||
mov -0x228(%rbp),%rbx
|
||||
mov -0x220(%rbp),%r13
|
||||
leaveq
|
||||
retq
|
||||
|
||||
Which is in this example equivalent in C to::
|
||||
|
||||
u64 bpf_filter(u64 ctx)
|
||||
{
|
||||
return foo(ctx, 2, 3, 4, 5) + bar(ctx, 6, 7, 8, 9);
|
||||
}
|
||||
|
||||
In-kernel functions foo() and bar() with prototype: u64 (*)(u64 arg1, u64
|
||||
arg2, u64 arg3, u64 arg4, u64 arg5); will receive arguments in proper
|
||||
registers and place their return value into ``%rax`` which is R0 in eBPF.
|
||||
Prologue and epilogue are emitted by JIT and are implicit in the
|
||||
interpreter. R0-R5 are scratch registers, so eBPF program needs to preserve
|
||||
them across the calls as defined by calling convention.
|
||||
|
||||
For example the following program is invalid::
|
||||
|
||||
bpf_mov R1, 1
|
||||
bpf_call foo
|
||||
bpf_mov R0, R1
|
||||
bpf_exit
|
||||
|
||||
After the call the registers R1-R5 contain junk values and cannot be read.
|
||||
An in-kernel verifier.rst is used to validate eBPF programs.
|
||||
|
||||
Also in the new design, eBPF is limited to 4096 insns, which means that any
|
||||
program will terminate quickly and will only call a fixed number of kernel
|
||||
functions. Original BPF and eBPF are two operand instructions,
|
||||
which helps to do one-to-one mapping between eBPF insn and x86 insn during JIT.
|
||||
|
||||
The input context pointer for invoking the interpreter function is generic,
|
||||
its content is defined by a specific use case. For seccomp register R1 points
|
||||
to seccomp_data, for converted BPF filters R1 points to a skb.
|
||||
|
||||
A program, that is translated internally consists of the following elements::
|
||||
|
||||
op:16, jt:8, jf:8, k:32 ==> op:8, dst_reg:4, src_reg:4, off:16, imm:32
|
||||
|
||||
So far 87 eBPF instructions were implemented. 8-bit 'op' opcode field
|
||||
has room for new instructions. Some of them may use 16/24/32 byte encoding. New
|
||||
instructions must be multiple of 8 bytes to preserve backward compatibility.
|
||||
|
||||
eBPF is a general purpose RISC instruction set. Not every register and
|
||||
every instruction are used during translation from original BPF to eBPF.
|
||||
For example, socket filters are not using ``exclusive add`` instruction, but
|
||||
tracing filters may do to maintain counters of events, for example. Register R9
|
||||
is not used by socket filters either, but more complex filters may be running
|
||||
out of registers and would have to resort to spill/fill to stack.
|
||||
|
||||
eBPF can be used as a generic assembler for last step performance
|
||||
optimizations, socket filters and seccomp are using it as assembler. Tracing
|
||||
filters may use it as assembler to generate code from kernel. In kernel usage
|
||||
may not be bounded by security considerations, since generated eBPF code
|
||||
may be optimizing internal code path and not being exposed to the user space.
|
||||
Safety of eBPF can come from the verifier.rst. In such use cases as
|
||||
described, it may be used as safe instruction set.
|
||||
|
||||
Just like the original BPF, eBPF runs within a controlled environment,
|
||||
is deterministic and the kernel can easily prove that. The safety of the program
|
||||
can be determined in two steps: first step does depth-first-search to disallow
|
||||
loops and other CFG validation; second step starts from the first insn and
|
||||
descends all possible paths. It simulates execution of every insn and observes
|
||||
the state change of registers and stack.
|
||||
|
||||
opcode encoding
|
||||
===============
|
||||
|
||||
eBPF is reusing most of the opcode encoding from classic to simplify conversion
|
||||
of classic BPF to eBPF.
|
||||
|
||||
For arithmetic and jump instructions the 8-bit 'code' field is divided into three
|
||||
parts::
|
||||
|
||||
+----------------+--------+--------------------+
|
||||
| 4 bits | 1 bit | 3 bits |
|
||||
| operation code | source | instruction class |
|
||||
+----------------+--------+--------------------+
|
||||
(MSB) (LSB)
|
||||
|
||||
Three LSB bits store instruction class which is one of:
|
||||
|
||||
=================== ===============
|
||||
Classic BPF classes eBPF classes
|
||||
=================== ===============
|
||||
BPF_LD 0x00 BPF_LD 0x00
|
||||
BPF_LDX 0x01 BPF_LDX 0x01
|
||||
BPF_ST 0x02 BPF_ST 0x02
|
||||
BPF_STX 0x03 BPF_STX 0x03
|
||||
BPF_ALU 0x04 BPF_ALU 0x04
|
||||
BPF_JMP 0x05 BPF_JMP 0x05
|
||||
BPF_RET 0x06 BPF_JMP32 0x06
|
||||
BPF_MISC 0x07 BPF_ALU64 0x07
|
||||
=================== ===============
|
||||
|
||||
The 4th bit encodes the source operand ...
|
||||
|
||||
::
|
||||
|
||||
BPF_K 0x00
|
||||
BPF_X 0x08
|
||||
|
||||
* in classic BPF, this means::
|
||||
|
||||
BPF_SRC(code) == BPF_X - use register X as source operand
|
||||
BPF_SRC(code) == BPF_K - use 32-bit immediate as source operand
|
||||
|
||||
* in eBPF, this means::
|
||||
|
||||
BPF_SRC(code) == BPF_X - use 'src_reg' register as source operand
|
||||
BPF_SRC(code) == BPF_K - use 32-bit immediate as source operand
|
||||
|
||||
... and four MSB bits store operation code.
|
||||
|
||||
If BPF_CLASS(code) == BPF_ALU or BPF_ALU64 [ in eBPF ], BPF_OP(code) is one of::
|
||||
|
||||
BPF_ADD 0x00
|
||||
BPF_SUB 0x10
|
||||
BPF_MUL 0x20
|
||||
BPF_DIV 0x30
|
||||
BPF_OR 0x40
|
||||
BPF_AND 0x50
|
||||
BPF_LSH 0x60
|
||||
BPF_RSH 0x70
|
||||
BPF_NEG 0x80
|
||||
BPF_MOD 0x90
|
||||
BPF_XOR 0xa0
|
||||
BPF_MOV 0xb0 /* eBPF only: mov reg to reg */
|
||||
BPF_ARSH 0xc0 /* eBPF only: sign extending shift right */
|
||||
BPF_END 0xd0 /* eBPF only: endianness conversion */
|
||||
|
||||
If BPF_CLASS(code) == BPF_JMP or BPF_JMP32 [ in eBPF ], BPF_OP(code) is one of::
|
||||
|
||||
BPF_JA 0x00 /* BPF_JMP only */
|
||||
BPF_JEQ 0x10
|
||||
BPF_JGT 0x20
|
||||
BPF_JGE 0x30
|
||||
BPF_JSET 0x40
|
||||
BPF_JNE 0x50 /* eBPF only: jump != */
|
||||
BPF_JSGT 0x60 /* eBPF only: signed '>' */
|
||||
BPF_JSGE 0x70 /* eBPF only: signed '>=' */
|
||||
BPF_CALL 0x80 /* eBPF BPF_JMP only: function call */
|
||||
BPF_EXIT 0x90 /* eBPF BPF_JMP only: function return */
|
||||
BPF_JLT 0xa0 /* eBPF only: unsigned '<' */
|
||||
BPF_JLE 0xb0 /* eBPF only: unsigned '<=' */
|
||||
BPF_JSLT 0xc0 /* eBPF only: signed '<' */
|
||||
BPF_JSLE 0xd0 /* eBPF only: signed '<=' */
|
||||
|
||||
So BPF_ADD | BPF_X | BPF_ALU means 32-bit addition in both classic BPF
|
||||
and eBPF. There are only two registers in classic BPF, so it means A += X.
|
||||
In eBPF it means dst_reg = (u32) dst_reg + (u32) src_reg; similarly,
|
||||
BPF_XOR | BPF_K | BPF_ALU means A ^= imm32 in classic BPF and analogous
|
||||
src_reg = (u32) src_reg ^ (u32) imm32 in eBPF.
|
||||
|
||||
Classic BPF is using BPF_MISC class to represent A = X and X = A moves.
|
||||
eBPF is using BPF_MOV | BPF_X | BPF_ALU code instead. Since there are no
|
||||
BPF_MISC operations in eBPF, the class 7 is used as BPF_ALU64 to mean
|
||||
exactly the same operations as BPF_ALU, but with 64-bit wide operands
|
||||
instead. So BPF_ADD | BPF_X | BPF_ALU64 means 64-bit addition, i.e.:
|
||||
dst_reg = dst_reg + src_reg
|
||||
|
||||
Classic BPF wastes the whole BPF_RET class to represent a single ``ret``
|
||||
operation. Classic BPF_RET | BPF_K means copy imm32 into return register
|
||||
and perform function exit. eBPF is modeled to match CPU, so BPF_JMP | BPF_EXIT
|
||||
in eBPF means function exit only. The eBPF program needs to store return
|
||||
value into register R0 before doing a BPF_EXIT. Class 6 in eBPF is used as
|
||||
BPF_JMP32 to mean exactly the same operations as BPF_JMP, but with 32-bit wide
|
||||
operands for the comparisons instead.
|
||||
|
||||
For load and store instructions the 8-bit 'code' field is divided as::
|
||||
|
||||
+--------+--------+-------------------+
|
||||
| 3 bits | 2 bits | 3 bits |
|
||||
| mode | size | instruction class |
|
||||
+--------+--------+-------------------+
|
||||
(MSB) (LSB)
|
||||
|
||||
Size modifier is one of ...
|
||||
|
||||
::
|
||||
|
||||
BPF_W 0x00 /* word */
|
||||
BPF_H 0x08 /* half word */
|
||||
BPF_B 0x10 /* byte */
|
||||
BPF_DW 0x18 /* eBPF only, double word */
|
||||
|
||||
... which encodes size of load/store operation::
|
||||
|
||||
B - 1 byte
|
||||
H - 2 byte
|
||||
W - 4 byte
|
||||
DW - 8 byte (eBPF only)
|
||||
|
||||
Mode modifier is one of::
|
||||
|
||||
BPF_IMM 0x00 /* used for 32-bit mov in classic BPF and 64-bit in eBPF */
|
||||
BPF_ABS 0x20
|
||||
BPF_IND 0x40
|
||||
BPF_MEM 0x60
|
||||
BPF_LEN 0x80 /* classic BPF only, reserved in eBPF */
|
||||
BPF_MSH 0xa0 /* classic BPF only, reserved in eBPF */
|
||||
BPF_ATOMIC 0xc0 /* eBPF only, atomic operations */
|
11
Documentation/bpf/faq.rst
Normal file
@ -0,0 +1,11 @@
|
||||
================================
|
||||
Frequently asked questions (FAQ)
|
||||
================================
|
||||
|
||||
Two sets of Questions and Answers (Q&A) are maintained.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
bpf_design_QA
|
||||
bpf_devel_QA
|
7
Documentation/bpf/helpers.rst
Normal file
@ -0,0 +1,7 @@
|
||||
Helper functions
|
||||
================
|
||||
|
||||
* `bpf-helpers(7)`_ maintains a list of helpers available to eBPF programs.
|
||||
|
||||
.. Links
|
||||
.. _bpf-helpers(7): https://man7.org/linux/man-pages/man7/bpf-helpers.7.html
|
@ -5,104 +5,33 @@ BPF Documentation
|
||||
This directory contains documentation for the BPF (Berkeley Packet
|
||||
Filter) facility, with a focus on the extended BPF version (eBPF).
|
||||
|
||||
This kernel side documentation is still work in progress. The main
|
||||
textual documentation is (for historical reasons) described in
|
||||
:ref:`networking-filter`, which describe both classical and extended
|
||||
BPF instruction-set.
|
||||
This kernel side documentation is still work in progress.
|
||||
The Cilium project also maintains a `BPF and XDP Reference Guide`_
|
||||
that goes into great technical depth about the BPF Architecture.
|
||||
|
||||
libbpf
|
||||
======
|
||||
|
||||
Documentation/bpf/libbpf/index.rst is a userspace library for loading and interacting with bpf programs.
|
||||
|
||||
BPF Type Format (BTF)
|
||||
=====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
instruction-set
|
||||
verifier
|
||||
libbpf/index
|
||||
btf
|
||||
|
||||
|
||||
Frequently asked questions (FAQ)
|
||||
================================
|
||||
|
||||
Two sets of Questions and Answers (Q&A) are maintained.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
bpf_design_QA
|
||||
bpf_devel_QA
|
||||
|
||||
Syscall API
|
||||
===========
|
||||
|
||||
The primary info for the bpf syscall is available in the `man-pages`_
|
||||
for `bpf(2)`_. For more information about the userspace API, see
|
||||
Documentation/userspace-api/ebpf/index.rst.
|
||||
|
||||
Helper functions
|
||||
================
|
||||
|
||||
* `bpf-helpers(7)`_ maintains a list of helpers available to eBPF programs.
|
||||
|
||||
|
||||
Program types
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
prog_cgroup_sockopt
|
||||
prog_cgroup_sysctl
|
||||
prog_flow_dissector
|
||||
bpf_lsm
|
||||
prog_sk_lookup
|
||||
|
||||
|
||||
Map types
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
map_cgroup_storage
|
||||
|
||||
|
||||
Testing and debugging BPF
|
||||
=========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
drgn
|
||||
s390
|
||||
|
||||
|
||||
Licensing
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
faq
|
||||
syscall_api
|
||||
helpers
|
||||
programs
|
||||
maps
|
||||
classic_vs_extended.rst
|
||||
bpf_licensing
|
||||
test_debug
|
||||
other
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Other
|
||||
=====
|
||||
Indices
|
||||
=======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ringbuf
|
||||
llvm_reloc
|
||||
* :ref:`genindex`
|
||||
|
||||
.. Links:
|
||||
.. _networking-filter: ../networking/filter.rst
|
||||
.. _man-pages: https://www.kernel.org/doc/man-pages/
|
||||
.. _bpf(2): https://man7.org/linux/man-pages/man2/bpf.2.html
|
||||
.. _bpf-helpers(7): https://man7.org/linux/man-pages/man7/bpf-helpers.7.html
|
||||
.. _BPF and XDP Reference Guide: https://docs.cilium.io/en/latest/bpf/
|
||||
|
279
Documentation/bpf/instruction-set.rst
Normal file
@ -0,0 +1,279 @@
|
||||
|
||||
====================
|
||||
eBPF Instruction Set
|
||||
====================
|
||||
|
||||
Registers and calling convention
|
||||
================================
|
||||
|
||||
eBPF has 10 general purpose registers and a read-only frame pointer register,
|
||||
all of which are 64-bits wide.
|
||||
|
||||
The eBPF calling convention is defined as:
|
||||
|
||||
* R0: return value from function calls, and exit value for eBPF programs
|
||||
* R1 - R5: arguments for function calls
|
||||
* R6 - R9: callee saved registers that function calls will preserve
|
||||
* R10: read-only frame pointer to access stack
|
||||
|
||||
R0 - R5 are scratch registers and eBPF programs needs to spill/fill them if
|
||||
necessary across calls.
|
||||
|
||||
Instruction encoding
|
||||
====================
|
||||
|
||||
eBPF uses 64-bit instructions with the following encoding:
|
||||
|
||||
============= ======= =============== ==================== ============
|
||||
32 bits (MSB) 16 bits 4 bits 4 bits 8 bits (LSB)
|
||||
============= ======= =============== ==================== ============
|
||||
immediate offset source register destination register opcode
|
||||
============= ======= =============== ==================== ============
|
||||
|
||||
Note that most instructions do not use all of the fields.
|
||||
Unused fields shall be cleared to zero.
|
||||
|
||||
Instruction classes
|
||||
-------------------
|
||||
|
||||
The three LSB bits of the 'opcode' field store the instruction class:
|
||||
|
||||
========= ===== ===============================
|
||||
class value description
|
||||
========= ===== ===============================
|
||||
BPF_LD 0x00 non-standard load operations
|
||||
BPF_LDX 0x01 load into register operations
|
||||
BPF_ST 0x02 store from immediate operations
|
||||
BPF_STX 0x03 store from register operations
|
||||
BPF_ALU 0x04 32-bit arithmetic operations
|
||||
BPF_JMP 0x05 64-bit jump operations
|
||||
BPF_JMP32 0x06 32-bit jump operations
|
||||
BPF_ALU64 0x07 64-bit arithmetic operations
|
||||
========= ===== ===============================
|
||||
|
||||
Arithmetic and jump instructions
|
||||
================================
|
||||
|
||||
For arithmetic and jump instructions (BPF_ALU, BPF_ALU64, BPF_JMP and
|
||||
BPF_JMP32), the 8-bit 'opcode' field is divided into three parts:
|
||||
|
||||
============== ====== =================
|
||||
4 bits (MSB) 1 bit 3 bits (LSB)
|
||||
============== ====== =================
|
||||
operation code source instruction class
|
||||
============== ====== =================
|
||||
|
||||
The 4th bit encodes the source operand:
|
||||
|
||||
====== ===== ========================================
|
||||
source value description
|
||||
====== ===== ========================================
|
||||
BPF_K 0x00 use 32-bit immediate as source operand
|
||||
BPF_X 0x08 use 'src_reg' register as source operand
|
||||
====== ===== ========================================
|
||||
|
||||
The four MSB bits store the operation code.
|
||||
|
||||
|
||||
Arithmetic instructions
|
||||
-----------------------
|
||||
|
||||
BPF_ALU uses 32-bit wide operands while BPF_ALU64 uses 64-bit wide operands for
|
||||
otherwise identical operations.
|
||||
The code field encodes the operation as below:
|
||||
|
||||
======== ===== ==========================
|
||||
code value description
|
||||
======== ===== ==========================
|
||||
BPF_ADD 0x00 dst += src
|
||||
BPF_SUB 0x10 dst -= src
|
||||
BPF_MUL 0x20 dst \*= src
|
||||
BPF_DIV 0x30 dst /= src
|
||||
BPF_OR 0x40 dst \|= src
|
||||
BPF_AND 0x50 dst &= src
|
||||
BPF_LSH 0x60 dst <<= src
|
||||
BPF_RSH 0x70 dst >>= src
|
||||
BPF_NEG 0x80 dst = ~src
|
||||
BPF_MOD 0x90 dst %= src
|
||||
BPF_XOR 0xa0 dst ^= src
|
||||
BPF_MOV 0xb0 dst = src
|
||||
BPF_ARSH 0xc0 sign extending shift right
|
||||
BPF_END 0xd0 endianness conversion
|
||||
======== ===== ==========================
|
||||
|
||||
BPF_ADD | BPF_X | BPF_ALU means::
|
||||
|
||||
dst_reg = (u32) dst_reg + (u32) src_reg;
|
||||
|
||||
BPF_ADD | BPF_X | BPF_ALU64 means::
|
||||
|
||||
dst_reg = dst_reg + src_reg
|
||||
|
||||
BPF_XOR | BPF_K | BPF_ALU means::
|
||||
|
||||
src_reg = (u32) src_reg ^ (u32) imm32
|
||||
|
||||
BPF_XOR | BPF_K | BPF_ALU64 means::
|
||||
|
||||
src_reg = src_reg ^ imm32
|
||||
|
||||
|
||||
Jump instructions
|
||||
-----------------
|
||||
|
||||
BPF_JMP32 uses 32-bit wide operands while BPF_JMP uses 64-bit wide operands for
|
||||
otherwise identical operations.
|
||||
The code field encodes the operation as below:
|
||||
|
||||
======== ===== ========================= ============
|
||||
code value description notes
|
||||
======== ===== ========================= ============
|
||||
BPF_JA 0x00 PC += off BPF_JMP only
|
||||
BPF_JEQ 0x10 PC += off if dst == src
|
||||
BPF_JGT 0x20 PC += off if dst > src unsigned
|
||||
BPF_JGE 0x30 PC += off if dst >= src unsigned
|
||||
BPF_JSET 0x40 PC += off if dst & src
|
||||
BPF_JNE 0x50 PC += off if dst != src
|
||||
BPF_JSGT 0x60 PC += off if dst > src signed
|
||||
BPF_JSGE 0x70 PC += off if dst >= src signed
|
||||
BPF_CALL 0x80 function call
|
||||
BPF_EXIT 0x90 function / program return BPF_JMP only
|
||||
BPF_JLT 0xa0 PC += off if dst < src unsigned
|
||||
BPF_JLE 0xb0 PC += off if dst <= src unsigned
|
||||
BPF_JSLT 0xc0 PC += off if dst < src signed
|
||||
BPF_JSLE 0xd0 PC += off if dst <= src signed
|
||||
======== ===== ========================= ============
|
||||
|
||||
The eBPF program needs to store the return value into register R0 before doing a
|
||||
BPF_EXIT.
|
||||
|
||||
|
||||
Load and store instructions
|
||||
===========================
|
||||
|
||||
For load and store instructions (BPF_LD, BPF_LDX, BPF_ST and BPF_STX), the
|
||||
8-bit 'opcode' field is divided as:
|
||||
|
||||
============ ====== =================
|
||||
3 bits (MSB) 2 bits 3 bits (LSB)
|
||||
============ ====== =================
|
||||
mode size instruction class
|
||||
============ ====== =================
|
||||
|
||||
The size modifier is one of:
|
||||
|
||||
============= ===== =====================
|
||||
size modifier value description
|
||||
============= ===== =====================
|
||||
BPF_W 0x00 word (4 bytes)
|
||||
BPF_H 0x08 half word (2 bytes)
|
||||
BPF_B 0x10 byte
|
||||
BPF_DW 0x18 double word (8 bytes)
|
||||
============= ===== =====================
|
||||
|
||||
The mode modifier is one of:
|
||||
|
||||
============= ===== ====================================
|
||||
mode modifier value description
|
||||
============= ===== ====================================
|
||||
BPF_IMM 0x00 used for 64-bit mov
|
||||
BPF_ABS 0x20 legacy BPF packet access
|
||||
BPF_IND 0x40 legacy BPF packet access
|
||||
BPF_MEM 0x60 all normal load and store operations
|
||||
BPF_ATOMIC 0xc0 atomic operations
|
||||
============= ===== ====================================
|
||||
|
||||
BPF_MEM | <size> | BPF_STX means::
|
||||
|
||||
*(size *) (dst_reg + off) = src_reg
|
||||
|
||||
BPF_MEM | <size> | BPF_ST means::
|
||||
|
||||
*(size *) (dst_reg + off) = imm32
|
||||
|
||||
BPF_MEM | <size> | BPF_LDX means::
|
||||
|
||||
dst_reg = *(size *) (src_reg + off)
|
||||
|
||||
Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW.
|
||||
|
||||
Atomic operations
|
||||
-----------------
|
||||
|
||||
eBPF includes atomic operations, which use the immediate field for extra
|
||||
encoding::
|
||||
|
||||
.imm = BPF_ADD, .code = BPF_ATOMIC | BPF_W | BPF_STX: lock xadd *(u32 *)(dst_reg + off16) += src_reg
|
||||
.imm = BPF_ADD, .code = BPF_ATOMIC | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg
|
||||
|
||||
The basic atomic operations supported are::
|
||||
|
||||
BPF_ADD
|
||||
BPF_AND
|
||||
BPF_OR
|
||||
BPF_XOR
|
||||
|
||||
Each having equivalent semantics with the ``BPF_ADD`` example, that is: the
|
||||
memory location addresed by ``dst_reg + off`` is atomically modified, with
|
||||
``src_reg`` as the other operand. If the ``BPF_FETCH`` flag is set in the
|
||||
immediate, then these operations also overwrite ``src_reg`` with the
|
||||
value that was in memory before it was modified.
|
||||
|
||||
The more special operations are::
|
||||
|
||||
BPF_XCHG
|
||||
|
||||
This atomically exchanges ``src_reg`` with the value addressed by ``dst_reg +
|
||||
off``. ::
|
||||
|
||||
BPF_CMPXCHG
|
||||
|
||||
This atomically compares the value addressed by ``dst_reg + off`` with
|
||||
``R0``. If they match it is replaced with ``src_reg``. In either case, the
|
||||
value that was there before is zero-extended and loaded back to ``R0``.
|
||||
|
||||
Note that 1 and 2 byte atomic operations are not supported.
|
||||
|
||||
Clang can generate atomic instructions by default when ``-mcpu=v3`` is
|
||||
enabled. If a lower version for ``-mcpu`` is set, the only atomic instruction
|
||||
Clang can generate is ``BPF_ADD`` *without* ``BPF_FETCH``. If you need to enable
|
||||
the atomics features, while keeping a lower ``-mcpu`` version, you can use
|
||||
``-Xclang -target-feature -Xclang +alu32``.
|
||||
|
||||
You may encounter ``BPF_XADD`` - this is a legacy name for ``BPF_ATOMIC``,
|
||||
referring to the exclusive-add operation encoded when the immediate field is
|
||||
zero.
|
||||
|
||||
16-byte instructions
|
||||
--------------------
|
||||
|
||||
eBPF has one 16-byte instruction: ``BPF_LD | BPF_DW | BPF_IMM`` which consists
|
||||
of two consecutive ``struct bpf_insn`` 8-byte blocks and interpreted as single
|
||||
instruction that loads 64-bit immediate value into a dst_reg.
|
||||
|
||||
Packet access instructions
|
||||
--------------------------
|
||||
|
||||
eBPF has two non-generic instructions: (BPF_ABS | <size> | BPF_LD) and
|
||||
(BPF_IND | <size> | BPF_LD) which are used to access packet data.
|
||||
|
||||
They had to be carried over from classic BPF to have strong performance of
|
||||
socket filters running in eBPF interpreter. These instructions can only
|
||||
be used when interpreter context is a pointer to ``struct sk_buff`` and
|
||||
have seven implicit operands. Register R6 is an implicit input that must
|
||||
contain pointer to sk_buff. Register R0 is an implicit output which contains
|
||||
the data fetched from the packet. Registers R1-R5 are scratch registers
|
||||
and must not be used to store the data across BPF_ABS | BPF_LD or
|
||||
BPF_IND | BPF_LD instructions.
|
||||
|
||||
These instructions have implicit program exit condition as well. When
|
||||
eBPF program is trying to access the data beyond the packet boundary,
|
||||
the interpreter will abort the execution of the program. JIT compilers
|
||||
therefore must preserve this property. src_reg and imm32 fields are
|
||||
explicit inputs to these instructions.
|
||||
|
||||
For example, BPF_IND | BPF_W | BPF_LD means::
|
||||
|
||||
R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data + src_reg + imm32))
|
||||
|
||||
and R1 - R5 are clobbered.
|
@ -3,8 +3,6 @@
|
||||
libbpf
|
||||
======
|
||||
|
||||
For API documentation see the `versioned API documentation site <https://libbpf.readthedocs.io/en/latest/api.html>`_.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
@ -14,6 +12,8 @@ For API documentation see the `versioned API documentation site <https://libbpf.
|
||||
This is documentation for libbpf, a userspace library for loading and
|
||||
interacting with bpf programs.
|
||||
|
||||
For API documentation see the `versioned API documentation site <https://libbpf.readthedocs.io/en/latest/api.html>`_.
|
||||
|
||||
All general BPF questions, including kernel functionality, libbpf APIs and
|
||||
their application, should be sent to bpf@vger.kernel.org mailing list.
|
||||
You can `subscribe <http://vger.kernel.org/vger-lists.html#bpf>`_ to the
|
||||
|
52
Documentation/bpf/maps.rst
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
=========
|
||||
eBPF maps
|
||||
=========
|
||||
|
||||
'maps' is a generic storage of different types for sharing data between kernel
|
||||
and userspace.
|
||||
|
||||
The maps are accessed from user space via BPF syscall, which has commands:
|
||||
|
||||
- create a map with given type and attributes
|
||||
``map_fd = bpf(BPF_MAP_CREATE, union bpf_attr *attr, u32 size)``
|
||||
using attr->map_type, attr->key_size, attr->value_size, attr->max_entries
|
||||
returns process-local file descriptor or negative error
|
||||
|
||||
- lookup key in a given map
|
||||
``err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)``
|
||||
using attr->map_fd, attr->key, attr->value
|
||||
returns zero and stores found elem into value or negative error
|
||||
|
||||
- create or update key/value pair in a given map
|
||||
``err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)``
|
||||
using attr->map_fd, attr->key, attr->value
|
||||
returns zero or negative error
|
||||
|
||||
- find and delete element by key in a given map
|
||||
``err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)``
|
||||
using attr->map_fd, attr->key
|
||||
|
||||
- to delete map: close(fd)
|
||||
Exiting process will delete maps automatically
|
||||
|
||||
userspace programs use this syscall to create/access maps that eBPF programs
|
||||
are concurrently updating.
|
||||
|
||||
maps can have different types: hash, array, bloom filter, radix-tree, etc.
|
||||
|
||||
The map is defined by:
|
||||
|
||||
- type
|
||||
- max number of elements
|
||||
- key size in bytes
|
||||
- value size in bytes
|
||||
|
||||
Map Types
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
map_*
|
9
Documentation/bpf/other.rst
Normal file
@ -0,0 +1,9 @@
|
||||
=====
|
||||
Other
|
||||
=====
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ringbuf
|
||||
llvm_reloc
|
9
Documentation/bpf/programs.rst
Normal file
@ -0,0 +1,9 @@
|
||||
=============
|
||||
Program Types
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
prog_*
|
11
Documentation/bpf/syscall_api.rst
Normal file
@ -0,0 +1,11 @@
|
||||
===========
|
||||
Syscall API
|
||||
===========
|
||||
|
||||
The primary info for the bpf syscall is available in the `man-pages`_
|
||||
for `bpf(2)`_. For more information about the userspace API, see
|
||||
Documentation/userspace-api/ebpf/index.rst.
|
||||
|
||||
.. Links:
|
||||
.. _man-pages: https://www.kernel.org/doc/man-pages/
|
||||
.. _bpf(2): https://man7.org/linux/man-pages/man2/bpf.2.html
|
9
Documentation/bpf/test_debug.rst
Normal file
@ -0,0 +1,9 @@
|
||||
=========================
|
||||
Testing and debugging BPF
|
||||
=========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
drgn
|
||||
s390
|
529
Documentation/bpf/verifier.rst
Normal file
@ -0,0 +1,529 @@
|
||||
|
||||
=============
|
||||
eBPF verifier
|
||||
=============
|
||||
|
||||
The safety of the eBPF program is determined in two steps.
|
||||
|
||||
First step does DAG check to disallow loops and other CFG validation.
|
||||
In particular it will detect programs that have unreachable instructions.
|
||||
(though classic BPF checker allows them)
|
||||
|
||||
Second step starts from the first insn and descends all possible paths.
|
||||
It simulates execution of every insn and observes the state change of
|
||||
registers and stack.
|
||||
|
||||
At the start of the program the register R1 contains a pointer to context
|
||||
and has type PTR_TO_CTX.
|
||||
If verifier sees an insn that does R2=R1, then R2 has now type
|
||||
PTR_TO_CTX as well and can be used on the right hand side of expression.
|
||||
If R1=PTR_TO_CTX and insn is R2=R1+R1, then R2=SCALAR_VALUE,
|
||||
since addition of two valid pointers makes invalid pointer.
|
||||
(In 'secure' mode verifier will reject any type of pointer arithmetic to make
|
||||
sure that kernel addresses don't leak to unprivileged users)
|
||||
|
||||
If register was never written to, it's not readable::
|
||||
|
||||
bpf_mov R0 = R2
|
||||
bpf_exit
|
||||
|
||||
will be rejected, since R2 is unreadable at the start of the program.
|
||||
|
||||
After kernel function call, R1-R5 are reset to unreadable and
|
||||
R0 has a return type of the function.
|
||||
|
||||
Since R6-R9 are callee saved, their state is preserved across the call.
|
||||
|
||||
::
|
||||
|
||||
bpf_mov R6 = 1
|
||||
bpf_call foo
|
||||
bpf_mov R0 = R6
|
||||
bpf_exit
|
||||
|
||||
is a correct program. If there was R1 instead of R6, it would have
|
||||
been rejected.
|
||||
|
||||
load/store instructions are allowed only with registers of valid types, which
|
||||
are PTR_TO_CTX, PTR_TO_MAP, PTR_TO_STACK. They are bounds and alignment checked.
|
||||
For example::
|
||||
|
||||
bpf_mov R1 = 1
|
||||
bpf_mov R2 = 2
|
||||
bpf_xadd *(u32 *)(R1 + 3) += R2
|
||||
bpf_exit
|
||||
|
||||
will be rejected, since R1 doesn't have a valid pointer type at the time of
|
||||
execution of instruction bpf_xadd.
|
||||
|
||||
At the start R1 type is PTR_TO_CTX (a pointer to generic ``struct bpf_context``)
|
||||
A callback is used to customize verifier to restrict eBPF program access to only
|
||||
certain fields within ctx structure with specified size and alignment.
|
||||
|
||||
For example, the following insn::
|
||||
|
||||
bpf_ld R0 = *(u32 *)(R6 + 8)
|
||||
|
||||
intends to load a word from address R6 + 8 and store it into R0
|
||||
If R6=PTR_TO_CTX, via is_valid_access() callback the verifier will know
|
||||
that offset 8 of size 4 bytes can be accessed for reading, otherwise
|
||||
the verifier will reject the program.
|
||||
If R6=PTR_TO_STACK, then access should be aligned and be within
|
||||
stack bounds, which are [-MAX_BPF_STACK, 0). In this example offset is 8,
|
||||
so it will fail verification, since it's out of bounds.
|
||||
|
||||
The verifier will allow eBPF program to read data from stack only after
|
||||
it wrote into it.
|
||||
|
||||
Classic BPF verifier does similar check with M[0-15] memory slots.
|
||||
For example::
|
||||
|
||||
bpf_ld R0 = *(u32 *)(R10 - 4)
|
||||
bpf_exit
|
||||
|
||||
is invalid program.
|
||||
Though R10 is correct read-only register and has type PTR_TO_STACK
|
||||
and R10 - 4 is within stack bounds, there were no stores into that location.
|
||||
|
||||
Pointer register spill/fill is tracked as well, since four (R6-R9)
|
||||
callee saved registers may not be enough for some programs.
|
||||
|
||||
Allowed function calls are customized with bpf_verifier_ops->get_func_proto()
|
||||
The eBPF verifier will check that registers match argument constraints.
|
||||
After the call register R0 will be set to return type of the function.
|
||||
|
||||
Function calls is a main mechanism to extend functionality of eBPF programs.
|
||||
Socket filters may let programs to call one set of functions, whereas tracing
|
||||
filters may allow completely different set.
|
||||
|
||||
If a function made accessible to eBPF program, it needs to be thought through
|
||||
from safety point of view. The verifier will guarantee that the function is
|
||||
called with valid arguments.
|
||||
|
||||
seccomp vs socket filters have different security restrictions for classic BPF.
|
||||
Seccomp solves this by two stage verifier: classic BPF verifier is followed
|
||||
by seccomp verifier. In case of eBPF one configurable verifier is shared for
|
||||
all use cases.
|
||||
|
||||
See details of eBPF verifier in kernel/bpf/verifier.c
|
||||
|
||||
Register value tracking
|
||||
=======================
|
||||
|
||||
In order to determine the safety of an eBPF program, the verifier must track
|
||||
the range of possible values in each register and also in each stack slot.
|
||||
This is done with ``struct bpf_reg_state``, defined in include/linux/
|
||||
bpf_verifier.h, which unifies tracking of scalar and pointer values. Each
|
||||
register state has a type, which is either NOT_INIT (the register has not been
|
||||
written to), SCALAR_VALUE (some value which is not usable as a pointer), or a
|
||||
pointer type. The types of pointers describe their base, as follows:
|
||||
|
||||
|
||||
PTR_TO_CTX
|
||||
Pointer to bpf_context.
|
||||
CONST_PTR_TO_MAP
|
||||
Pointer to struct bpf_map. "Const" because arithmetic
|
||||
on these pointers is forbidden.
|
||||
PTR_TO_MAP_VALUE
|
||||
Pointer to the value stored in a map element.
|
||||
PTR_TO_MAP_VALUE_OR_NULL
|
||||
Either a pointer to a map value, or NULL; map accesses
|
||||
(see maps.rst) return this type, which becomes a
|
||||
PTR_TO_MAP_VALUE when checked != NULL. Arithmetic on
|
||||
these pointers is forbidden.
|
||||
PTR_TO_STACK
|
||||
Frame pointer.
|
||||
PTR_TO_PACKET
|
||||
skb->data.
|
||||
PTR_TO_PACKET_END
|
||||
skb->data + headlen; arithmetic forbidden.
|
||||
PTR_TO_SOCKET
|
||||
Pointer to struct bpf_sock_ops, implicitly refcounted.
|
||||
PTR_TO_SOCKET_OR_NULL
|
||||
Either a pointer to a socket, or NULL; socket lookup
|
||||
returns this type, which becomes a PTR_TO_SOCKET when
|
||||
checked != NULL. PTR_TO_SOCKET is reference-counted,
|
||||
so programs must release the reference through the
|
||||
socket release function before the end of the program.
|
||||
Arithmetic on these pointers is forbidden.
|
||||
|
||||
However, a pointer may be offset from this base (as a result of pointer
|
||||
arithmetic), and this is tracked in two parts: the 'fixed offset' and 'variable
|
||||
offset'. The former is used when an exactly-known value (e.g. an immediate
|
||||
operand) is added to a pointer, while the latter is used for values which are
|
||||
not exactly known. The variable offset is also used in SCALAR_VALUEs, to track
|
||||
the range of possible values in the register.
|
||||
|
||||
The verifier's knowledge about the variable offset consists of:
|
||||
|
||||
* minimum and maximum values as unsigned
|
||||
* minimum and maximum values as signed
|
||||
|
||||
* knowledge of the values of individual bits, in the form of a 'tnum': a u64
|
||||
'mask' and a u64 'value'. 1s in the mask represent bits whose value is unknown;
|
||||
1s in the value represent bits known to be 1. Bits known to be 0 have 0 in both
|
||||
mask and value; no bit should ever be 1 in both. For example, if a byte is read
|
||||
into a register from memory, the register's top 56 bits are known zero, while
|
||||
the low 8 are unknown - which is represented as the tnum (0x0; 0xff). If we
|
||||
then OR this with 0x40, we get (0x40; 0xbf), then if we add 1 we get (0x0;
|
||||
0x1ff), because of potential carries.
|
||||
|
||||
Besides arithmetic, the register state can also be updated by conditional
|
||||
branches. For instance, if a SCALAR_VALUE is compared > 8, in the 'true' branch
|
||||
it will have a umin_value (unsigned minimum value) of 9, whereas in the 'false'
|
||||
branch it will have a umax_value of 8. A signed compare (with BPF_JSGT or
|
||||
BPF_JSGE) would instead update the signed minimum/maximum values. Information
|
||||
from the signed and unsigned bounds can be combined; for instance if a value is
|
||||
first tested < 8 and then tested s> 4, the verifier will conclude that the value
|
||||
is also > 4 and s< 8, since the bounds prevent crossing the sign boundary.
|
||||
|
||||
PTR_TO_PACKETs with a variable offset part have an 'id', which is common to all
|
||||
pointers sharing that same variable offset. This is important for packet range
|
||||
checks: after adding a variable to a packet pointer register A, if you then copy
|
||||
it to another register B and then add a constant 4 to A, both registers will
|
||||
share the same 'id' but the A will have a fixed offset of +4. Then if A is
|
||||
bounds-checked and found to be less than a PTR_TO_PACKET_END, the register B is
|
||||
now known to have a safe range of at least 4 bytes. See 'Direct packet access',
|
||||
below, for more on PTR_TO_PACKET ranges.
|
||||
|
||||
The 'id' field is also used on PTR_TO_MAP_VALUE_OR_NULL, common to all copies of
|
||||
the pointer returned from a map lookup. This means that when one copy is
|
||||
checked and found to be non-NULL, all copies can become PTR_TO_MAP_VALUEs.
|
||||
As well as range-checking, the tracked information is also used for enforcing
|
||||
alignment of pointer accesses. For instance, on most systems the packet pointer
|
||||
is 2 bytes after a 4-byte alignment. If a program adds 14 bytes to that to jump
|
||||
over the Ethernet header, then reads IHL and addes (IHL * 4), the resulting
|
||||
pointer will have a variable offset known to be 4n+2 for some n, so adding the 2
|
||||
bytes (NET_IP_ALIGN) gives a 4-byte alignment and so word-sized accesses through
|
||||
that pointer are safe.
|
||||
The 'id' field is also used on PTR_TO_SOCKET and PTR_TO_SOCKET_OR_NULL, common
|
||||
to all copies of the pointer returned from a socket lookup. This has similar
|
||||
behaviour to the handling for PTR_TO_MAP_VALUE_OR_NULL->PTR_TO_MAP_VALUE, but
|
||||
it also handles reference tracking for the pointer. PTR_TO_SOCKET implicitly
|
||||
represents a reference to the corresponding ``struct sock``. To ensure that the
|
||||
reference is not leaked, it is imperative to NULL-check the reference and in
|
||||
the non-NULL case, and pass the valid reference to the socket release function.
|
||||
|
||||
Direct packet access
|
||||
====================
|
||||
|
||||
In cls_bpf and act_bpf programs the verifier allows direct access to the packet
|
||||
data via skb->data and skb->data_end pointers.
|
||||
Ex::
|
||||
|
||||
1: r4 = *(u32 *)(r1 +80) /* load skb->data_end */
|
||||
2: r3 = *(u32 *)(r1 +76) /* load skb->data */
|
||||
3: r5 = r3
|
||||
4: r5 += 14
|
||||
5: if r5 > r4 goto pc+16
|
||||
R1=ctx R3=pkt(id=0,off=0,r=14) R4=pkt_end R5=pkt(id=0,off=14,r=14) R10=fp
|
||||
6: r0 = *(u16 *)(r3 +12) /* access 12 and 13 bytes of the packet */
|
||||
|
||||
this 2byte load from the packet is safe to do, since the program author
|
||||
did check ``if (skb->data + 14 > skb->data_end) goto err`` at insn #5 which
|
||||
means that in the fall-through case the register R3 (which points to skb->data)
|
||||
has at least 14 directly accessible bytes. The verifier marks it
|
||||
as R3=pkt(id=0,off=0,r=14).
|
||||
id=0 means that no additional variables were added to the register.
|
||||
off=0 means that no additional constants were added.
|
||||
r=14 is the range of safe access which means that bytes [R3, R3 + 14) are ok.
|
||||
Note that R5 is marked as R5=pkt(id=0,off=14,r=14). It also points
|
||||
to the packet data, but constant 14 was added to the register, so
|
||||
it now points to ``skb->data + 14`` and accessible range is [R5, R5 + 14 - 14)
|
||||
which is zero bytes.
|
||||
|
||||
More complex packet access may look like::
|
||||
|
||||
|
||||
R0=inv1 R1=ctx R3=pkt(id=0,off=0,r=14) R4=pkt_end R5=pkt(id=0,off=14,r=14) R10=fp
|
||||
6: r0 = *(u8 *)(r3 +7) /* load 7th byte from the packet */
|
||||
7: r4 = *(u8 *)(r3 +12)
|
||||
8: r4 *= 14
|
||||
9: r3 = *(u32 *)(r1 +76) /* load skb->data */
|
||||
10: r3 += r4
|
||||
11: r2 = r1
|
||||
12: r2 <<= 48
|
||||
13: r2 >>= 48
|
||||
14: r3 += r2
|
||||
15: r2 = r3
|
||||
16: r2 += 8
|
||||
17: r1 = *(u32 *)(r1 +80) /* load skb->data_end */
|
||||
18: if r2 > r1 goto pc+2
|
||||
R0=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R1=pkt_end R2=pkt(id=2,off=8,r=8) R3=pkt(id=2,off=0,r=8) R4=inv(id=0,umax_value=3570,var_off=(0x0; 0xfffe)) R5=pkt(id=0,off=14,r=14) R10=fp
|
||||
19: r1 = *(u8 *)(r3 +4)
|
||||
|
||||
The state of the register R3 is R3=pkt(id=2,off=0,r=8)
|
||||
id=2 means that two ``r3 += rX`` instructions were seen, so r3 points to some
|
||||
offset within a packet and since the program author did
|
||||
``if (r3 + 8 > r1) goto err`` at insn #18, the safe range is [R3, R3 + 8).
|
||||
The verifier only allows 'add'/'sub' operations on packet registers. Any other
|
||||
operation will set the register state to 'SCALAR_VALUE' and it won't be
|
||||
available for direct packet access.
|
||||
|
||||
Operation ``r3 += rX`` may overflow and become less than original skb->data,
|
||||
therefore the verifier has to prevent that. So when it sees ``r3 += rX``
|
||||
instruction and rX is more than 16-bit value, any subsequent bounds-check of r3
|
||||
against skb->data_end will not give us 'range' information, so attempts to read
|
||||
through the pointer will give "invalid access to packet" error.
|
||||
|
||||
Ex. after insn ``r4 = *(u8 *)(r3 +12)`` (insn #7 above) the state of r4 is
|
||||
R4=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) which means that upper 56 bits
|
||||
of the register are guaranteed to be zero, and nothing is known about the lower
|
||||
8 bits. After insn ``r4 *= 14`` the state becomes
|
||||
R4=inv(id=0,umax_value=3570,var_off=(0x0; 0xfffe)), since multiplying an 8-bit
|
||||
value by constant 14 will keep upper 52 bits as zero, also the least significant
|
||||
bit will be zero as 14 is even. Similarly ``r2 >>= 48`` will make
|
||||
R2=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff)), since the shift is not sign
|
||||
extending. This logic is implemented in adjust_reg_min_max_vals() function,
|
||||
which calls adjust_ptr_min_max_vals() for adding pointer to scalar (or vice
|
||||
versa) and adjust_scalar_min_max_vals() for operations on two scalars.
|
||||
|
||||
The end result is that bpf program author can access packet directly
|
||||
using normal C code as::
|
||||
|
||||
void *data = (void *)(long)skb->data;
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
struct eth_hdr *eth = data;
|
||||
struct iphdr *iph = data + sizeof(*eth);
|
||||
struct udphdr *udp = data + sizeof(*eth) + sizeof(*iph);
|
||||
|
||||
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*udp) > data_end)
|
||||
return 0;
|
||||
if (eth->h_proto != htons(ETH_P_IP))
|
||||
return 0;
|
||||
if (iph->protocol != IPPROTO_UDP || iph->ihl != 5)
|
||||
return 0;
|
||||
if (udp->dest == 53 || udp->source == 9)
|
||||
...;
|
||||
|
||||
which makes such programs easier to write comparing to LD_ABS insn
|
||||
and significantly faster.
|
||||
|
||||
Pruning
|
||||
=======
|
||||
|
||||
The verifier does not actually walk all possible paths through the program. For
|
||||
each new branch to analyse, the verifier looks at all the states it's previously
|
||||
been in when at this instruction. If any of them contain the current state as a
|
||||
subset, the branch is 'pruned' - that is, the fact that the previous state was
|
||||
accepted implies the current state would be as well. For instance, if in the
|
||||
previous state, r1 held a packet-pointer, and in the current state, r1 holds a
|
||||
packet-pointer with a range as long or longer and at least as strict an
|
||||
alignment, then r1 is safe. Similarly, if r2 was NOT_INIT before then it can't
|
||||
have been used by any path from that point, so any value in r2 (including
|
||||
another NOT_INIT) is safe. The implementation is in the function regsafe().
|
||||
Pruning considers not only the registers but also the stack (and any spilled
|
||||
registers it may hold). They must all be safe for the branch to be pruned.
|
||||
This is implemented in states_equal().
|
||||
|
||||
Understanding eBPF verifier messages
|
||||
====================================
|
||||
|
||||
The following are few examples of invalid eBPF programs and verifier error
|
||||
messages as seen in the log:
|
||||
|
||||
Program with unreachable instructions::
|
||||
|
||||
static struct bpf_insn prog[] = {
|
||||
BPF_EXIT_INSN(),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
|
||||
Error:
|
||||
|
||||
unreachable insn 1
|
||||
|
||||
Program that reads uninitialized register::
|
||||
|
||||
BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (bf) r0 = r2
|
||||
R2 !read_ok
|
||||
|
||||
Program that doesn't initialize R0 before exiting::
|
||||
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (bf) r2 = r1
|
||||
1: (95) exit
|
||||
R0 !read_ok
|
||||
|
||||
Program that accesses stack out of bounds::
|
||||
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, 8, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (7a) *(u64 *)(r10 +8) = 0
|
||||
invalid stack off=8 size=8
|
||||
|
||||
Program that doesn't initialize stack before passing its address into function::
|
||||
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (bf) r2 = r10
|
||||
1: (07) r2 += -8
|
||||
2: (b7) r1 = 0x0
|
||||
3: (85) call 1
|
||||
invalid indirect read from stack off -8+0 size 8
|
||||
|
||||
Program that uses invalid map_fd=0 while calling to map_lookup_elem() function::
|
||||
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (7a) *(u64 *)(r10 -8) = 0
|
||||
1: (bf) r2 = r10
|
||||
2: (07) r2 += -8
|
||||
3: (b7) r1 = 0x0
|
||||
4: (85) call 1
|
||||
fd 0 is not pointing to valid bpf_map
|
||||
|
||||
Program that doesn't check return value of map_lookup_elem() before accessing
|
||||
map element::
|
||||
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (7a) *(u64 *)(r10 -8) = 0
|
||||
1: (bf) r2 = r10
|
||||
2: (07) r2 += -8
|
||||
3: (b7) r1 = 0x0
|
||||
4: (85) call 1
|
||||
5: (7a) *(u64 *)(r0 +0) = 0
|
||||
R0 invalid mem access 'map_value_or_null'
|
||||
|
||||
Program that correctly checks map_lookup_elem() returned value for NULL, but
|
||||
accesses the memory with incorrect alignment::
|
||||
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (7a) *(u64 *)(r10 -8) = 0
|
||||
1: (bf) r2 = r10
|
||||
2: (07) r2 += -8
|
||||
3: (b7) r1 = 1
|
||||
4: (85) call 1
|
||||
5: (15) if r0 == 0x0 goto pc+1
|
||||
R0=map_ptr R10=fp
|
||||
6: (7a) *(u64 *)(r0 +4) = 0
|
||||
misaligned access off 4 size 8
|
||||
|
||||
Program that correctly checks map_lookup_elem() returned value for NULL and
|
||||
accesses memory with correct alignment in one side of 'if' branch, but fails
|
||||
to do so in the other side of 'if' branch::
|
||||
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
|
||||
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (7a) *(u64 *)(r10 -8) = 0
|
||||
1: (bf) r2 = r10
|
||||
2: (07) r2 += -8
|
||||
3: (b7) r1 = 1
|
||||
4: (85) call 1
|
||||
5: (15) if r0 == 0x0 goto pc+2
|
||||
R0=map_ptr R10=fp
|
||||
6: (7a) *(u64 *)(r0 +0) = 0
|
||||
7: (95) exit
|
||||
|
||||
from 5 to 8: R0=imm0 R10=fp
|
||||
8: (7a) *(u64 *)(r0 +0) = 1
|
||||
R0 invalid mem access 'imm'
|
||||
|
||||
Program that performs a socket lookup then sets the pointer to NULL without
|
||||
checking it::
|
||||
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 4),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_5, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp),
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (b7) r2 = 0
|
||||
1: (63) *(u32 *)(r10 -8) = r2
|
||||
2: (bf) r2 = r10
|
||||
3: (07) r2 += -8
|
||||
4: (b7) r3 = 4
|
||||
5: (b7) r4 = 0
|
||||
6: (b7) r5 = 0
|
||||
7: (85) call bpf_sk_lookup_tcp#65
|
||||
8: (b7) r0 = 0
|
||||
9: (95) exit
|
||||
Unreleased reference id=1, alloc_insn=7
|
||||
|
||||
Program that performs a socket lookup but does not NULL-check the returned
|
||||
value::
|
||||
|
||||
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -8),
|
||||
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||
BPF_MOV64_IMM(BPF_REG_3, 4),
|
||||
BPF_MOV64_IMM(BPF_REG_4, 0),
|
||||
BPF_MOV64_IMM(BPF_REG_5, 0),
|
||||
BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp),
|
||||
BPF_EXIT_INSN(),
|
||||
|
||||
Error::
|
||||
|
||||
0: (b7) r2 = 0
|
||||
1: (63) *(u32 *)(r10 -8) = r2
|
||||
2: (bf) r2 = r10
|
||||
3: (07) r2 += -8
|
||||
4: (b7) r3 = 4
|
||||
5: (b7) r4 = 0
|
||||
6: (b7) r5 = 0
|
||||
7: (85) call bpf_sk_lookup_tcp#65
|
||||
8: (95) exit
|
||||
Unreleased reference id=1, alloc_insn=7
|
@ -208,16 +208,86 @@ highlight_language = 'none'
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
|
||||
# The Read the Docs theme is available from
|
||||
# - https://github.com/snide/sphinx_rtd_theme
|
||||
# - https://pypi.python.org/pypi/sphinx_rtd_theme
|
||||
# - python-sphinx-rtd-theme package (on Debian)
|
||||
try:
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
except ImportError:
|
||||
sys.stderr.write('Warning: The Sphinx \'sphinx_rtd_theme\' HTML theme was not found. Make sure you have the theme installed to produce pretty HTML output. Falling back to the default theme.\n')
|
||||
# Default theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_css_files = []
|
||||
|
||||
if "DOCS_THEME" in os.environ:
|
||||
html_theme = os.environ["DOCS_THEME"]
|
||||
|
||||
if html_theme == 'sphinx_rtd_theme' or html_theme == 'sphinx_rtd_dark_mode':
|
||||
# Read the Docs theme
|
||||
try:
|
||||
import sphinx_rtd_theme
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_css_files = [
|
||||
'theme_overrides.css',
|
||||
]
|
||||
|
||||
# Read the Docs dark mode override theme
|
||||
if html_theme == 'sphinx_rtd_dark_mode':
|
||||
try:
|
||||
import sphinx_rtd_dark_mode
|
||||
extensions.append('sphinx_rtd_dark_mode')
|
||||
except ImportError:
|
||||
html_theme == 'sphinx_rtd_theme'
|
||||
|
||||
if html_theme == 'sphinx_rtd_theme':
|
||||
# Add color-specific RTD normal mode
|
||||
html_css_files.append('theme_rtd_colors.css')
|
||||
|
||||
except ImportError:
|
||||
html_theme = 'classic'
|
||||
|
||||
if "DOCS_CSS" in os.environ:
|
||||
css = os.environ["DOCS_CSS"].split(" ")
|
||||
|
||||
for l in css:
|
||||
html_css_files.append(l)
|
||||
|
||||
if major <= 1 and minor < 8:
|
||||
html_context = {
|
||||
'css_files': [],
|
||||
}
|
||||
|
||||
for l in html_css_files:
|
||||
html_context['css_files'].append('_static/' + l)
|
||||
|
||||
if html_theme == 'classic':
|
||||
html_theme_options = {
|
||||
'rightsidebar': False,
|
||||
'stickysidebar': True,
|
||||
'collapsiblesidebar': True,
|
||||
'externalrefs': False,
|
||||
|
||||
'footerbgcolor': "white",
|
||||
'footertextcolor': "white",
|
||||
'sidebarbgcolor': "white",
|
||||
'sidebarbtncolor': "black",
|
||||
'sidebartextcolor': "black",
|
||||
'sidebarlinkcolor': "#686bff",
|
||||
'relbarbgcolor': "#133f52",
|
||||
'relbartextcolor': "white",
|
||||
'relbarlinkcolor': "white",
|
||||
'bgcolor': "white",
|
||||
'textcolor': "black",
|
||||
'headbgcolor': "#f2f2f2",
|
||||
'headtextcolor': "#20435c",
|
||||
'headlinkcolor': "#c60f0f",
|
||||
'linkcolor': "#355f7c",
|
||||
'visitedlinkcolor': "#355f7c",
|
||||
'codebgcolor': "#3f3f3f",
|
||||
'codetextcolor': "white",
|
||||
|
||||
'bodyfont': "serif",
|
||||
'headfont': "sans-serif",
|
||||
}
|
||||
|
||||
sys.stderr.write("Using %s theme\n" % html_theme)
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
@ -246,20 +316,8 @@ except ImportError:
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
|
||||
html_static_path = ['sphinx-static']
|
||||
|
||||
html_css_files = [
|
||||
'theme_overrides.css',
|
||||
]
|
||||
|
||||
if major <= 1 and minor < 8:
|
||||
html_context = {
|
||||
'css_files': [
|
||||
'_static/theme_overrides.css',
|
||||
],
|
||||
}
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
|
@ -279,6 +279,7 @@ Accounting Framework
|
||||
Block Devices
|
||||
=============
|
||||
|
||||
.. kernel-doc:: include/linux/bio.h
|
||||
.. kernel-doc:: block/blk-core.c
|
||||
:export:
|
||||
|
||||
@ -294,9 +295,6 @@ Block Devices
|
||||
.. kernel-doc:: block/blk-settings.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: block/blk-exec.c
|
||||
:export:
|
||||
|
||||
.. kernel-doc:: block/blk-flush.c
|
||||
:export:
|
||||
|
||||
|
@ -118,7 +118,7 @@ Initialization of kobjects
|
||||
Code which creates a kobject must, of course, initialize that object. Some
|
||||
of the internal fields are setup with a (mandatory) call to kobject_init()::
|
||||
|
||||
void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
|
||||
void kobject_init(struct kobject *kobj, const struct kobj_type *ktype);
|
||||
|
||||
The ktype is required for a kobject to be created properly, as every kobject
|
||||
must have an associated kobj_type. After calling kobject_init(), to
|
||||
@ -156,7 +156,7 @@ kobject_name()::
|
||||
There is a helper function to both initialize and add the kobject to the
|
||||
kernel at the same time, called surprisingly enough kobject_init_and_add()::
|
||||
|
||||
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
|
||||
int kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
|
||||
struct kobject *parent, const char *fmt, ...);
|
||||
|
||||
The arguments are the same as the individual kobject_init() and
|
||||
@ -299,7 +299,6 @@ kobj_type::
|
||||
struct kobj_type {
|
||||
void (*release)(struct kobject *kobj);
|
||||
const struct sysfs_ops *sysfs_ops;
|
||||
struct attribute **default_attrs;
|
||||
const struct attribute_group **default_groups;
|
||||
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
|
||||
const void *(*namespace)(struct kobject *kobj);
|
||||
@ -313,10 +312,10 @@ call kobject_init() or kobject_init_and_add().
|
||||
|
||||
The release field in struct kobj_type is, of course, a pointer to the
|
||||
release() method for this type of kobject. The other two fields (sysfs_ops
|
||||
and default_attrs) control how objects of this type are represented in
|
||||
and default_groups) control how objects of this type are represented in
|
||||
sysfs; they are beyond the scope of this document.
|
||||
|
||||
The default_attrs pointer is a list of default attributes that will be
|
||||
The default_groups pointer is a list of default attributes that will be
|
||||
automatically created for any kobject that is registered with this ktype.
|
||||
|
||||
|
||||
@ -373,10 +372,9 @@ If a kset wishes to control the uevent operations of the kobjects
|
||||
associated with it, it can use the struct kset_uevent_ops to handle it::
|
||||
|
||||
struct kset_uevent_ops {
|
||||
int (* const filter)(struct kset *kset, struct kobject *kobj);
|
||||
const char *(* const name)(struct kset *kset, struct kobject *kobj);
|
||||
int (* const uevent)(struct kset *kset, struct kobject *kobj,
|
||||
struct kobj_uevent_env *env);
|
||||
int (* const filter)(struct kobject *kobj);
|
||||
const char *(* const name)(struct kobject *kobj);
|
||||
int (* const uevent)(struct kobject *kobj, struct kobj_uevent_env *env);
|
||||
};
|
||||
|
||||
|
||||
|
@ -32,6 +32,7 @@ Documentation/dev-tools/testing-overview.rst
|
||||
kgdb
|
||||
kselftest
|
||||
kunit/index
|
||||
ktap
|
||||
|
||||
|
||||
.. only:: subproject and html
|
||||
|
@ -204,17 +204,17 @@ Ultimately this allows to determine the possible executions of concurrent code,
|
||||
and if that code is free from data races.
|
||||
|
||||
KCSAN is aware of *marked atomic operations* (``READ_ONCE``, ``WRITE_ONCE``,
|
||||
``atomic_*``, etc.), but is oblivious of any ordering guarantees and simply
|
||||
assumes that memory barriers are placed correctly. In other words, KCSAN
|
||||
assumes that as long as a plain access is not observed to race with another
|
||||
conflicting access, memory operations are correctly ordered.
|
||||
``atomic_*``, etc.), and a subset of ordering guarantees implied by memory
|
||||
barriers. With ``CONFIG_KCSAN_WEAK_MEMORY=y``, KCSAN models load or store
|
||||
buffering, and can detect missing ``smp_mb()``, ``smp_wmb()``, ``smp_rmb()``,
|
||||
``smp_store_release()``, and all ``atomic_*`` operations with equivalent
|
||||
implied barriers.
|
||||
|
||||
This means that KCSAN will not report *potential* data races due to missing
|
||||
memory ordering. Developers should therefore carefully consider the required
|
||||
memory ordering requirements that remain unchecked. If, however, missing
|
||||
memory ordering (that is observable with a particular compiler and
|
||||
architecture) leads to an observable data race (e.g. entering a critical
|
||||
section erroneously), KCSAN would report the resulting data race.
|
||||
Note, KCSAN will not report all data races due to missing memory ordering,
|
||||
specifically where a memory barrier would be required to prohibit subsequent
|
||||
memory operation from reordering before the barrier. Developers should
|
||||
therefore carefully consider the required memory ordering requirements that
|
||||
remain unchecked.
|
||||
|
||||
Race Detection Beyond Data Races
|
||||
--------------------------------
|
||||
@ -268,6 +268,56 @@ marked operations, if all accesses to a variable that is accessed concurrently
|
||||
are properly marked, KCSAN will never trigger a watchpoint and therefore never
|
||||
report the accesses.
|
||||
|
||||
Modeling Weak Memory
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
KCSAN's approach to detecting data races due to missing memory barriers is
|
||||
based on modeling access reordering (with ``CONFIG_KCSAN_WEAK_MEMORY=y``).
|
||||
Each plain memory access for which a watchpoint is set up, is also selected for
|
||||
simulated reordering within the scope of its function (at most 1 in-flight
|
||||
access).
|
||||
|
||||
Once an access has been selected for reordering, it is checked along every
|
||||
other access until the end of the function scope. If an appropriate memory
|
||||
barrier is encountered, the access will no longer be considered for simulated
|
||||
reordering.
|
||||
|
||||
When the result of a memory operation should be ordered by a barrier, KCSAN can
|
||||
then detect data races where the conflict only occurs as a result of a missing
|
||||
barrier. Consider the example::
|
||||
|
||||
int x, flag;
|
||||
void T1(void)
|
||||
{
|
||||
x = 1; // data race!
|
||||
WRITE_ONCE(flag, 1); // correct: smp_store_release(&flag, 1)
|
||||
}
|
||||
void T2(void)
|
||||
{
|
||||
while (!READ_ONCE(flag)); // correct: smp_load_acquire(&flag)
|
||||
... = x; // data race!
|
||||
}
|
||||
|
||||
When weak memory modeling is enabled, KCSAN can consider ``x`` in ``T1`` for
|
||||
simulated reordering. After the write of ``flag``, ``x`` is again checked for
|
||||
concurrent accesses: because ``T2`` is able to proceed after the write of
|
||||
``flag``, a data race is detected. With the correct barriers in place, ``x``
|
||||
would not be considered for reordering after the proper release of ``flag``,
|
||||
and no data race would be detected.
|
||||
|
||||
Deliberate trade-offs in complexity but also practical limitations mean only a
|
||||
subset of data races due to missing memory barriers can be detected. With
|
||||
currently available compiler support, the implementation is limited to modeling
|
||||
the effects of "buffering" (delaying accesses), since the runtime cannot
|
||||
"prefetch" accesses. Also recall that watchpoints are only set up for plain
|
||||
accesses, and the only access type for which KCSAN simulates reordering. This
|
||||
means reordering of marked accesses is not modeled.
|
||||
|
||||
A consequence of the above is that acquire operations do not require barrier
|
||||
instrumentation (no prefetching). Furthermore, marked accesses introducing
|
||||
address or control dependencies do not require special handling (the marked
|
||||
access cannot be reordered, later dependent accesses cannot be prefetched).
|
||||
|
||||
Key Properties
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
@ -290,8 +340,8 @@ Key Properties
|
||||
4. **Detects Racy Writes from Devices:** Due to checking data values upon
|
||||
setting up watchpoints, racy writes from devices can also be detected.
|
||||
|
||||
5. **Memory Ordering:** KCSAN is *not* explicitly aware of the LKMM's ordering
|
||||
rules; this may result in missed data races (false negatives).
|
||||
5. **Memory Ordering:** KCSAN is aware of only a subset of LKMM ordering rules;
|
||||
this may result in missed data races (false negatives).
|
||||
|
||||
6. **Analysis Accuracy:** For observed executions, due to using a sampling
|
||||
strategy, the analysis is *unsound* (false negatives possible), but aims to
|
||||
|
@ -402,7 +402,7 @@ This is a quick example of how to use kdb.
|
||||
2. Enter the kernel debugger manually or by waiting for an oops or
|
||||
fault. There are several ways you can enter the kernel debugger
|
||||
manually; all involve using the :kbd:`SysRq-G`, which means you must have
|
||||
enabled ``CONFIG_MAGIC_SysRq=y`` in your kernel config.
|
||||
enabled ``CONFIG_MAGIC_SYSRQ=y`` in your kernel config.
|
||||
|
||||
- When logged in as root or with a super user session you can run::
|
||||
|
||||
@ -461,7 +461,7 @@ This is a quick example of how to use kdb with a keyboard.
|
||||
2. Enter the kernel debugger manually or by waiting for an oops or
|
||||
fault. There are several ways you can enter the kernel debugger
|
||||
manually; all involve using the :kbd:`SysRq-G`, which means you must have
|
||||
enabled ``CONFIG_MAGIC_SysRq=y`` in your kernel config.
|
||||
enabled ``CONFIG_MAGIC_SYSRQ=y`` in your kernel config.
|
||||
|
||||
- When logged in as root or with a super user session you can run::
|
||||
|
||||
@ -557,7 +557,7 @@ Connecting with gdb to a serial port
|
||||
Example (using a directly connected port)::
|
||||
|
||||
% gdb ./vmlinux
|
||||
(gdb) set remotebaud 115200
|
||||
(gdb) set serial baud 115200
|
||||
(gdb) target remote /dev/ttyS0
|
||||
|
||||
|
||||
|
298
Documentation/dev-tools/ktap.rst
Normal file
@ -0,0 +1,298 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
========================================
|
||||
The Kernel Test Anything Protocol (KTAP)
|
||||
========================================
|
||||
|
||||
TAP, or the Test Anything Protocol is a format for specifying test results used
|
||||
by a number of projects. It's website and specification are found at this `link
|
||||
<https://testanything.org/>`_. The Linux Kernel largely uses TAP output for test
|
||||
results. However, Kernel testing frameworks have special needs for test results
|
||||
which don't align with the original TAP specification. Thus, a "Kernel TAP"
|
||||
(KTAP) format is specified to extend and alter TAP to support these use-cases.
|
||||
This specification describes the generally accepted format of KTAP as it is
|
||||
currently used in the kernel.
|
||||
|
||||
KTAP test results describe a series of tests (which may be nested: i.e., test
|
||||
can have subtests), each of which can contain both diagnostic data -- e.g., log
|
||||
lines -- and a final result. The test structure and results are
|
||||
machine-readable, whereas the diagnostic data is unstructured and is there to
|
||||
aid human debugging.
|
||||
|
||||
KTAP output is built from four different types of lines:
|
||||
- Version lines
|
||||
- Plan lines
|
||||
- Test case result lines
|
||||
- Diagnostic lines
|
||||
|
||||
In general, valid KTAP output should also form valid TAP output, but some
|
||||
information, in particular nested test results, may be lost. Also note that
|
||||
there is a stagnant draft specification for TAP14, KTAP diverges from this in
|
||||
a couple of places (notably the "Subtest" header), which are described where
|
||||
relevant later in this document.
|
||||
|
||||
Version lines
|
||||
-------------
|
||||
|
||||
All KTAP-formatted results begin with a "version line" which specifies which
|
||||
version of the (K)TAP standard the result is compliant with.
|
||||
|
||||
For example:
|
||||
- "KTAP version 1"
|
||||
- "TAP version 13"
|
||||
- "TAP version 14"
|
||||
|
||||
Note that, in KTAP, subtests also begin with a version line, which denotes the
|
||||
start of the nested test results. This differs from TAP14, which uses a
|
||||
separate "Subtest" line.
|
||||
|
||||
While, going forward, "KTAP version 1" should be used by compliant tests, it
|
||||
is expected that most parsers and other tooling will accept the other versions
|
||||
listed here for compatibility with existing tests and frameworks.
|
||||
|
||||
Plan lines
|
||||
----------
|
||||
|
||||
A test plan provides the number of tests (or subtests) in the KTAP output.
|
||||
|
||||
Plan lines must follow the format of "1..N" where N is the number of tests or subtests.
|
||||
Plan lines follow version lines to indicate the number of nested tests.
|
||||
|
||||
While there are cases where the number of tests is not known in advance -- in
|
||||
which case the test plan may be omitted -- it is strongly recommended one is
|
||||
present where possible.
|
||||
|
||||
Test case result lines
|
||||
----------------------
|
||||
|
||||
Test case result lines indicate the final status of a test.
|
||||
They are required and must have the format:
|
||||
|
||||
.. code-block::
|
||||
|
||||
<result> <number> [<description>][ # [<directive>] [<diagnostic data>]]
|
||||
|
||||
The result can be either "ok", which indicates the test case passed,
|
||||
or "not ok", which indicates that the test case failed.
|
||||
|
||||
<number> represents the number of the test being performed. The first test must
|
||||
have the number 1 and the number then must increase by 1 for each additional
|
||||
subtest within the same test at the same nesting level.
|
||||
|
||||
The description is a description of the test, generally the name of
|
||||
the test, and can be any string of words (can't include #). The
|
||||
description is optional, but recommended.
|
||||
|
||||
The directive and any diagnostic data is optional. If either are present, they
|
||||
must follow a hash sign, "#".
|
||||
|
||||
A directive is a keyword that indicates a different outcome for a test other
|
||||
than passed and failed. The directive is optional, and consists of a single
|
||||
keyword preceding the diagnostic data. In the event that a parser encounters
|
||||
a directive it doesn't support, it should fall back to the "ok" / "not ok"
|
||||
result.
|
||||
|
||||
Currently accepted directives are:
|
||||
|
||||
- "SKIP", which indicates a test was skipped (note the result of the test case
|
||||
result line can be either "ok" or "not ok" if the SKIP directive is used)
|
||||
- "TODO", which indicates that a test is not expected to pass at the moment,
|
||||
e.g. because the feature it is testing is known to be broken. While this
|
||||
directive is inherited from TAP, its use in the kernel is discouraged.
|
||||
- "XFAIL", which indicates that a test is expected to fail. This is similar
|
||||
to "TODO", above, and is used by some kselftest tests.
|
||||
- “TIMEOUT”, which indicates a test has timed out (note the result of the test
|
||||
case result line should be “not ok” if the TIMEOUT directive is used)
|
||||
- “ERROR”, which indicates that the execution of a test has failed due to a
|
||||
specific error that is included in the diagnostic data. (note the result of
|
||||
the test case result line should be “not ok” if the ERROR directive is used)
|
||||
|
||||
The diagnostic data is a plain-text field which contains any additional details
|
||||
about why this result was produced. This is typically an error message for ERROR
|
||||
or failed tests, or a description of missing dependencies for a SKIP result.
|
||||
|
||||
The diagnostic data field is optional, and results which have neither a
|
||||
directive nor any diagnostic data do not need to include the "#" field
|
||||
separator.
|
||||
|
||||
Example result lines include:
|
||||
|
||||
.. code-block::
|
||||
|
||||
ok 1 test_case_name
|
||||
|
||||
The test "test_case_name" passed.
|
||||
|
||||
.. code-block::
|
||||
|
||||
not ok 1 test_case_name
|
||||
|
||||
The test "test_case_name" failed.
|
||||
|
||||
.. code-block::
|
||||
|
||||
ok 1 test # SKIP necessary dependency unavailable
|
||||
|
||||
The test "test" was SKIPPED with the diagnostic message "necessary dependency
|
||||
unavailable".
|
||||
|
||||
.. code-block::
|
||||
|
||||
not ok 1 test # TIMEOUT 30 seconds
|
||||
|
||||
The test "test" timed out, with diagnostic data "30 seconds".
|
||||
|
||||
.. code-block::
|
||||
|
||||
ok 5 check return code # rcode=0
|
||||
|
||||
The test "check return code" passed, with additional diagnostic data “rcode=0”
|
||||
|
||||
|
||||
Diagnostic lines
|
||||
----------------
|
||||
|
||||
If tests wish to output any further information, they should do so using
|
||||
"diagnostic lines". Diagnostic lines are optional, freeform text, and are
|
||||
often used to describe what is being tested and any intermediate results in
|
||||
more detail than the final result and diagnostic data line provides.
|
||||
|
||||
Diagnostic lines are formatted as "# <diagnostic_description>", where the
|
||||
description can be any string. Diagnostic lines can be anywhere in the test
|
||||
output. As a rule, diagnostic lines regarding a test are directly before the
|
||||
test result line for that test.
|
||||
|
||||
Note that most tools will treat unknown lines (see below) as diagnostic lines,
|
||||
even if they do not start with a "#": this is to capture any other useful
|
||||
kernel output which may help debug the test. It is nevertheless recommended
|
||||
that tests always prefix any diagnostic output they have with a "#" character.
|
||||
|
||||
Unknown lines
|
||||
-------------
|
||||
|
||||
There may be lines within KTAP output that do not follow the format of one of
|
||||
the four formats for lines described above. This is allowed, however, they will
|
||||
not influence the status of the tests.
|
||||
|
||||
Nested tests
|
||||
------------
|
||||
|
||||
In KTAP, tests can be nested. This is done by having a test include within its
|
||||
output an entire set of KTAP-formatted results. This can be used to categorize
|
||||
and group related tests, or to split out different results from the same test.
|
||||
|
||||
The "parent" test's result should consist of all of its subtests' results,
|
||||
starting with another KTAP version line and test plan, and end with the overall
|
||||
result. If one of the subtests fail, for example, the parent test should also
|
||||
fail.
|
||||
|
||||
Additionally, all result lines in a subtest should be indented. One level of
|
||||
indentation is two spaces: " ". The indentation should begin at the version
|
||||
line and should end before the parent test's result line.
|
||||
|
||||
An example of a test with two nested subtests:
|
||||
|
||||
.. code-block::
|
||||
|
||||
KTAP version 1
|
||||
1..1
|
||||
KTAP version 1
|
||||
1..2
|
||||
ok 1 test_1
|
||||
not ok 2 test_2
|
||||
# example failed
|
||||
not ok 1 example
|
||||
|
||||
An example format with multiple levels of nested testing:
|
||||
|
||||
.. code-block::
|
||||
|
||||
KTAP version 1
|
||||
1..2
|
||||
KTAP version 1
|
||||
1..2
|
||||
KTAP version 1
|
||||
1..2
|
||||
not ok 1 test_1
|
||||
ok 2 test_2
|
||||
not ok 1 test_3
|
||||
ok 2 test_4 # SKIP
|
||||
not ok 1 example_test_1
|
||||
ok 2 example_test_2
|
||||
|
||||
|
||||
Major differences between TAP and KTAP
|
||||
--------------------------------------
|
||||
|
||||
Note the major differences between the TAP and KTAP specification:
|
||||
- yaml and json are not recommended in diagnostic messages
|
||||
- TODO directive not recognized
|
||||
- KTAP allows for an arbitrary number of tests to be nested
|
||||
|
||||
The TAP14 specification does permit nested tests, but instead of using another
|
||||
nested version line, uses a line of the form
|
||||
"Subtest: <name>" where <name> is the name of the parent test.
|
||||
|
||||
Example KTAP output
|
||||
--------------------
|
||||
.. code-block::
|
||||
|
||||
KTAP version 1
|
||||
1..1
|
||||
KTAP version 1
|
||||
1..3
|
||||
KTAP version 1
|
||||
1..1
|
||||
# test_1: initializing test_1
|
||||
ok 1 test_1
|
||||
ok 1 example_test_1
|
||||
KTAP version 1
|
||||
1..2
|
||||
ok 1 test_1 # SKIP test_1 skipped
|
||||
ok 2 test_2
|
||||
ok 2 example_test_2
|
||||
KTAP version 1
|
||||
1..3
|
||||
ok 1 test_1
|
||||
# test_2: FAIL
|
||||
not ok 2 test_2
|
||||
ok 3 test_3 # SKIP test_3 skipped
|
||||
not ok 3 example_test_3
|
||||
not ok 1 main_test
|
||||
|
||||
This output defines the following hierarchy:
|
||||
|
||||
A single test called "main_test", which fails, and has three subtests:
|
||||
- "example_test_1", which passes, and has one subtest:
|
||||
|
||||
- "test_1", which passes, and outputs the diagnostic message "test_1: initializing test_1"
|
||||
|
||||
- "example_test_2", which passes, and has two subtests:
|
||||
|
||||
- "test_1", which is skipped, with the explanation "test_1 skipped"
|
||||
- "test_2", which passes
|
||||
|
||||
- "example_test_3", which fails, and has three subtests
|
||||
|
||||
- "test_1", which passes
|
||||
- "test_2", which outputs the diagnostic line "test_2: FAIL", and fails.
|
||||
- "test_3", which is skipped with the explanation "test_3 skipped"
|
||||
|
||||
Note that the individual subtests with the same names do not conflict, as they
|
||||
are found in different parent tests. This output also exhibits some sensible
|
||||
rules for "bubbling up" test results: a test fails if any of its subtests fail.
|
||||
Skipped tests do not affect the result of the parent test (though it often
|
||||
makes sense for a test to be marked skipped if _all_ of its subtests have been
|
||||
skipped).
|
||||
|
||||
See also:
|
||||
---------
|
||||
|
||||
- The TAP specification:
|
||||
https://testanything.org/tap-version-13-specification.html
|
||||
- The (stagnant) TAP version 14 specification:
|
||||
https://github.com/TestAnything/Specification/blob/tap-14-specification/specification.md
|
||||
- The kselftest documentation:
|
||||
Documentation/dev-tools/kselftest.rst
|
||||
- The KUnit documentation:
|
||||
Documentation/dev-tools/kunit/index.rst
|
@ -12,5 +12,4 @@ following sections:
|
||||
|
||||
Documentation/dev-tools/kunit/api/test.rst
|
||||
|
||||
- documents all of the standard testing API excluding mocking
|
||||
or mocking related features.
|
||||
- documents all of the standard testing API
|
||||
|
@ -4,8 +4,7 @@
|
||||
Test API
|
||||
========
|
||||
|
||||
This file documents all of the standard testing API excluding mocking or mocking
|
||||
related features.
|
||||
This file documents all of the standard testing API.
|
||||
|
||||
.. kernel-doc:: include/kunit/test.h
|
||||
:internal:
|
||||
|
204
Documentation/dev-tools/kunit/architecture.rst
Normal file
@ -0,0 +1,204 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
==================
|
||||
KUnit Architecture
|
||||
==================
|
||||
|
||||
The KUnit architecture can be divided into two parts:
|
||||
|
||||
- Kernel testing library
|
||||
- kunit_tool (Command line test harness)
|
||||
|
||||
In-Kernel Testing Framework
|
||||
===========================
|
||||
|
||||
The kernel testing library supports KUnit tests written in C using
|
||||
KUnit. KUnit tests are kernel code. KUnit does several things:
|
||||
|
||||
- Organizes tests
|
||||
- Reports test results
|
||||
- Provides test utilities
|
||||
|
||||
Test Cases
|
||||
----------
|
||||
|
||||
The fundamental unit in KUnit is the test case. The KUnit test cases are
|
||||
grouped into KUnit suites. A KUnit test case is a function with type
|
||||
signature ``void (*)(struct kunit *test)``.
|
||||
These test case functions are wrapped in a struct called
|
||||
``struct kunit_case``. For code, see:
|
||||
|
||||
.. kernel-doc:: include/kunit/test.h
|
||||
:identifiers: kunit_case
|
||||
|
||||
.. note:
|
||||
``generate_params`` is optional for non-parameterized tests.
|
||||
|
||||
Each KUnit test case gets a ``struct kunit`` context
|
||||
object passed to it that tracks a running test. The KUnit assertion
|
||||
macros and other KUnit utilities use the ``struct kunit`` context
|
||||
object. As an exception, there are two fields:
|
||||
|
||||
- ``->priv``: The setup functions can use it to store arbitrary test
|
||||
user data.
|
||||
|
||||
- ``->param_value``: It contains the parameter value which can be
|
||||
retrieved in the parameterized tests.
|
||||
|
||||
Test Suites
|
||||
-----------
|
||||
|
||||
A KUnit suite includes a collection of test cases. The KUnit suites
|
||||
are represented by the ``struct kunit_suite``. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static struct kunit_case example_test_cases[] = {
|
||||
KUNIT_CASE(example_test_foo),
|
||||
KUNIT_CASE(example_test_bar),
|
||||
KUNIT_CASE(example_test_baz),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite example_test_suite = {
|
||||
.name = "example",
|
||||
.init = example_test_init,
|
||||
.exit = example_test_exit,
|
||||
.test_cases = example_test_cases,
|
||||
};
|
||||
kunit_test_suite(example_test_suite);
|
||||
|
||||
In the above example, the test suite ``example_test_suite``, runs the
|
||||
test cases ``example_test_foo``, ``example_test_bar``, and
|
||||
``example_test_baz``. Before running the test, the ``example_test_init``
|
||||
is called and after running the test, ``example_test_exit`` is called.
|
||||
The ``kunit_test_suite(example_test_suite)`` registers the test suite
|
||||
with the KUnit test framework.
|
||||
|
||||
Executor
|
||||
--------
|
||||
|
||||
The KUnit executor can list and run built-in KUnit tests on boot.
|
||||
The Test suites are stored in a linker section
|
||||
called ``.kunit_test_suites``. For code, see:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/vmlinux.lds.h?h=v5.15#n945.
|
||||
The linker section consists of an array of pointers to
|
||||
``struct kunit_suite``, and is populated by the ``kunit_test_suites()``
|
||||
macro. To run all tests compiled into the kernel, the KUnit executor
|
||||
iterates over the linker section array.
|
||||
|
||||
.. kernel-figure:: kunit_suitememorydiagram.svg
|
||||
:alt: KUnit Suite Memory
|
||||
|
||||
KUnit Suite Memory Diagram
|
||||
|
||||
On the kernel boot, the KUnit executor uses the start and end addresses
|
||||
of this section to iterate over and run all tests. For code, see:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/executor.c
|
||||
|
||||
When built as a module, the ``kunit_test_suites()`` macro defines a
|
||||
``module_init()`` function, which runs all the tests in the compilation
|
||||
unit instead of utilizing the executor.
|
||||
|
||||
In KUnit tests, some error classes do not affect other tests
|
||||
or parts of the kernel, each KUnit case executes in a separate thread
|
||||
context. For code, see:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/try-catch.c?h=v5.15#n58
|
||||
|
||||
Assertion Macros
|
||||
----------------
|
||||
|
||||
KUnit tests verify state using expectations/assertions.
|
||||
All expectations/assertions are formatted as:
|
||||
``KUNIT_{EXPECT|ASSERT}_<op>[_MSG](kunit, property[, message])``
|
||||
|
||||
- ``{EXPECT|ASSERT}`` determines whether the check is an assertion or an
|
||||
expectation.
|
||||
|
||||
- For an expectation, if the check fails, marks the test as failed
|
||||
and logs the failure.
|
||||
|
||||
- An assertion, on failure, causes the test case to terminate
|
||||
immediately.
|
||||
|
||||
- Assertions call function:
|
||||
``void __noreturn kunit_abort(struct kunit *)``.
|
||||
|
||||
- ``kunit_abort`` calls function:
|
||||
``void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)``.
|
||||
|
||||
- ``kunit_try_catch_throw`` calls function:
|
||||
``void complete_and_exit(struct completion *, long) __noreturn;``
|
||||
and terminates the special thread context.
|
||||
|
||||
- ``<op>`` denotes a check with options: ``TRUE`` (supplied property
|
||||
has the boolean value “true”), ``EQ`` (two supplied properties are
|
||||
equal), ``NOT_ERR_OR_NULL`` (supplied pointer is not null and does not
|
||||
contain an “err” value).
|
||||
|
||||
- ``[_MSG]`` prints a custom message on failure.
|
||||
|
||||
Test Result Reporting
|
||||
---------------------
|
||||
KUnit prints test results in KTAP format. KTAP is based on TAP14, see:
|
||||
https://github.com/isaacs/testanything.github.io/blob/tap14/tap-version-14-specification.md.
|
||||
KTAP (yet to be standardized format) works with KUnit and Kselftest.
|
||||
The KUnit executor prints KTAP results to dmesg, and debugfs
|
||||
(if configured).
|
||||
|
||||
Parameterized Tests
|
||||
-------------------
|
||||
|
||||
Each KUnit parameterized test is associated with a collection of
|
||||
parameters. The test is invoked multiple times, once for each parameter
|
||||
value and the parameter is stored in the ``param_value`` field.
|
||||
The test case includes a ``KUNIT_CASE_PARAM()`` macro that accepts a
|
||||
generator function.
|
||||
The generator function is passed the previous parameter and returns the next
|
||||
parameter. It also provides a macro to generate common-case generators based on
|
||||
arrays.
|
||||
|
||||
For code, see:
|
||||
|
||||
.. kernel-doc:: include/kunit/test.h
|
||||
:identifiers: KUNIT_ARRAY_PARAM
|
||||
|
||||
|
||||
kunit_tool (Command Line Test Harness)
|
||||
======================================
|
||||
|
||||
kunit_tool is a Python script ``(tools/testing/kunit/kunit.py)``
|
||||
that can be used to configure, build, exec, parse and run (runs other
|
||||
commands in order) test results. You can either run KUnit tests using
|
||||
kunit_tool or can include KUnit in kernel and parse manually.
|
||||
|
||||
- ``configure`` command generates the kernel ``.config`` from a
|
||||
``.kunitconfig`` file (and any architecture-specific options).
|
||||
For some architectures, additional config options are specified in the
|
||||
``qemu_config`` Python script
|
||||
(For example: ``tools/testing/kunit/qemu_configs/powerpc.py``).
|
||||
It parses both the existing ``.config`` and the ``.kunitconfig`` files
|
||||
and ensures that ``.config`` is a superset of ``.kunitconfig``.
|
||||
If this is not the case, it will combine the two and run
|
||||
``make olddefconfig`` to regenerate the ``.config`` file. It then
|
||||
verifies that ``.config`` is now a superset. This checks if all
|
||||
Kconfig dependencies are correctly specified in ``.kunitconfig``.
|
||||
``kunit_config.py`` includes the parsing Kconfigs code. The code which
|
||||
runs ``make olddefconfig`` is a part of ``kunit_kernel.py``. You can
|
||||
invoke this command via: ``./tools/testing/kunit/kunit.py config`` and
|
||||
generate a ``.config`` file.
|
||||
- ``build`` runs ``make`` on the kernel tree with required options
|
||||
(depends on the architecture and some options, for example: build_dir)
|
||||
and reports any errors.
|
||||
To build a KUnit kernel from the current ``.config``, you can use the
|
||||
``build`` argument: ``./tools/testing/kunit/kunit.py build``.
|
||||
- ``exec`` command executes kernel results either directly (using
|
||||
User-mode Linux configuration), or via an emulator such
|
||||
as QEMU. It reads results from the log via standard
|
||||
output (stdout), and passes them to ``parse`` to be parsed.
|
||||
If you already have built a kernel with built-in KUnit tests,
|
||||
you can run the kernel and display the test results with the ``exec``
|
||||
argument: ``./tools/testing/kunit/kunit.py exec``.
|
||||
- ``parse`` extracts the KTAP output from a kernel log, parses
|
||||
the test results, and prints a summary. For failed tests, any
|
||||
diagnostic output will be included.
|
@ -4,56 +4,55 @@
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
How is this different from Autotest, kselftest, etc?
|
||||
====================================================
|
||||
How is this different from Autotest, kselftest, and so on?
|
||||
==========================================================
|
||||
KUnit is a unit testing framework. Autotest, kselftest (and some others) are
|
||||
not.
|
||||
|
||||
A `unit test <https://martinfowler.com/bliki/UnitTest.html>`_ is supposed to
|
||||
test a single unit of code in isolation, hence the name. A unit test should be
|
||||
the finest granularity of testing and as such should allow all possible code
|
||||
paths to be tested in the code under test; this is only possible if the code
|
||||
under test is very small and does not have any external dependencies outside of
|
||||
test a single unit of code in isolation and hence the name *unit test*. A unit
|
||||
test should be the finest granularity of testing and should allow all possible
|
||||
code paths to be tested in the code under test. This is only possible if the
|
||||
code under test is small and does not have any external dependencies outside of
|
||||
the test's control like hardware.
|
||||
|
||||
There are no testing frameworks currently available for the kernel that do not
|
||||
require installing the kernel on a test machine or in a VM and all require
|
||||
tests to be written in userspace and run on the kernel under test; this is true
|
||||
for Autotest, kselftest, and some others, disqualifying any of them from being
|
||||
considered unit testing frameworks.
|
||||
require installing the kernel on a test machine or in a virtual machine. All
|
||||
testing frameworks require tests to be written in userspace and run on the
|
||||
kernel under test. This is true for Autotest, kselftest, and some others,
|
||||
disqualifying any of them from being considered unit testing frameworks.
|
||||
|
||||
Does KUnit support running on architectures other than UML?
|
||||
===========================================================
|
||||
|
||||
Yes, well, mostly.
|
||||
Yes, mostly.
|
||||
|
||||
For the most part, the KUnit core framework (what you use to write the tests)
|
||||
can compile to any architecture; it compiles like just another part of the
|
||||
For the most part, the KUnit core framework (what we use to write the tests)
|
||||
can compile to any architecture. It compiles like just another part of the
|
||||
kernel and runs when the kernel boots, or when built as a module, when the
|
||||
module is loaded. However, there is some infrastructure,
|
||||
like the KUnit Wrapper (``tools/testing/kunit/kunit.py``) that does not support
|
||||
other architectures.
|
||||
module is loaded. However, there is infrastructure, like the KUnit Wrapper
|
||||
(``tools/testing/kunit/kunit.py``) that does not support other architectures.
|
||||
|
||||
In short, this means that, yes, you can run KUnit on other architectures, but
|
||||
it might require more work than using KUnit on UML.
|
||||
In short, yes, you can run KUnit on other architectures, but it might require
|
||||
more work than using KUnit on UML.
|
||||
|
||||
For more information, see :ref:`kunit-on-non-uml`.
|
||||
|
||||
What is the difference between a unit test and these other kinds of tests?
|
||||
==========================================================================
|
||||
What is the difference between a unit test and other kinds of tests?
|
||||
====================================================================
|
||||
Most existing tests for the Linux kernel would be categorized as an integration
|
||||
test, or an end-to-end test.
|
||||
|
||||
- A unit test is supposed to test a single unit of code in isolation, hence the
|
||||
name. A unit test should be the finest granularity of testing and as such
|
||||
should allow all possible code paths to be tested in the code under test; this
|
||||
is only possible if the code under test is very small and does not have any
|
||||
external dependencies outside of the test's control like hardware.
|
||||
- A unit test is supposed to test a single unit of code in isolation. A unit
|
||||
test should be the finest granularity of testing and, as such, allows all
|
||||
possible code paths to be tested in the code under test. This is only possible
|
||||
if the code under test is small and does not have any external dependencies
|
||||
outside of the test's control like hardware.
|
||||
- An integration test tests the interaction between a minimal set of components,
|
||||
usually just two or three. For example, someone might write an integration
|
||||
test to test the interaction between a driver and a piece of hardware, or to
|
||||
test the interaction between the userspace libraries the kernel provides and
|
||||
the kernel itself; however, one of these tests would probably not test the
|
||||
the kernel itself. However, one of these tests would probably not test the
|
||||
entire kernel along with hardware interactions and interactions with the
|
||||
userspace.
|
||||
- An end-to-end test usually tests the entire system from the perspective of the
|
||||
@ -62,26 +61,26 @@ test, or an end-to-end test.
|
||||
hardware with a production userspace and then trying to exercise some behavior
|
||||
that depends on interactions between the hardware, the kernel, and userspace.
|
||||
|
||||
KUnit isn't working, what should I do?
|
||||
======================================
|
||||
KUnit is not working, what should I do?
|
||||
=======================================
|
||||
|
||||
Unfortunately, there are a number of things which can break, but here are some
|
||||
things to try.
|
||||
|
||||
1. Try running ``./tools/testing/kunit/kunit.py run`` with the ``--raw_output``
|
||||
1. Run ``./tools/testing/kunit/kunit.py run`` with the ``--raw_output``
|
||||
parameter. This might show details or error messages hidden by the kunit_tool
|
||||
parser.
|
||||
2. Instead of running ``kunit.py run``, try running ``kunit.py config``,
|
||||
``kunit.py build``, and ``kunit.py exec`` independently. This can help track
|
||||
down where an issue is occurring. (If you think the parser is at fault, you
|
||||
can run it manually against stdin or a file with ``kunit.py parse``.)
|
||||
3. Running the UML kernel directly can often reveal issues or error messages
|
||||
kunit_tool ignores. This should be as simple as running ``./vmlinux`` after
|
||||
building the UML kernel (e.g., by using ``kunit.py build``). Note that UML
|
||||
has some unusual requirements (such as the host having a tmpfs filesystem
|
||||
mounted), and has had issues in the past when built statically and the host
|
||||
has KASLR enabled. (On older host kernels, you may need to run ``setarch
|
||||
`uname -m` -R ./vmlinux`` to disable KASLR.)
|
||||
can run it manually against ``stdin`` or a file with ``kunit.py parse``.)
|
||||
3. Running the UML kernel directly can often reveal issues or error messages,
|
||||
``kunit_tool`` ignores. This should be as simple as running ``./vmlinux``
|
||||
after building the UML kernel (for example, by using ``kunit.py build``).
|
||||
Note that UML has some unusual requirements (such as the host having a tmpfs
|
||||
filesystem mounted), and has had issues in the past when built statically and
|
||||
the host has KASLR enabled. (On older host kernels, you may need to run
|
||||
``setarch `uname -m` -R ./vmlinux`` to disable KASLR.)
|
||||
4. Make sure the kernel .config has ``CONFIG_KUNIT=y`` and at least one test
|
||||
(e.g. ``CONFIG_KUNIT_EXAMPLE_TEST=y``). kunit_tool will keep its .config
|
||||
around, so you can see what config was used after running ``kunit.py run``.
|
||||
|
@ -1,13 +1,17 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================================
|
||||
KUnit - Unit Testing for the Linux Kernel
|
||||
=========================================
|
||||
=================================
|
||||
KUnit - Linux Kernel Unit Testing
|
||||
=================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
start
|
||||
architecture
|
||||
run_wrapper
|
||||
run_manual
|
||||
usage
|
||||
kunit-tool
|
||||
api/index
|
||||
@ -16,82 +20,94 @@ KUnit - Unit Testing for the Linux Kernel
|
||||
tips
|
||||
running_tips
|
||||
|
||||
What is KUnit?
|
||||
==============
|
||||
This section details the kernel unit testing framework.
|
||||
|
||||
KUnit is a lightweight unit testing and mocking framework for the Linux kernel.
|
||||
Introduction
|
||||
============
|
||||
|
||||
KUnit is heavily inspired by JUnit, Python's unittest.mock, and
|
||||
Googletest/Googlemock for C++. KUnit provides facilities for defining unit test
|
||||
cases, grouping related test cases into test suites, providing common
|
||||
infrastructure for running tests, and much more.
|
||||
KUnit (Kernel unit testing framework) provides a common framework for
|
||||
unit tests within the Linux kernel. Using KUnit, you can define groups
|
||||
of test cases called test suites. The tests either run on kernel boot
|
||||
if built-in, or load as a module. KUnit automatically flags and reports
|
||||
failed test cases in the kernel log. The test results appear in `TAP
|
||||
(Test Anything Protocol) format <https://testanything.org/>`_. It is inspired by
|
||||
JUnit, Python’s unittest.mock, and GoogleTest/GoogleMock (C++ unit testing
|
||||
framework).
|
||||
|
||||
KUnit consists of a kernel component, which provides a set of macros for easily
|
||||
writing unit tests. Tests written against KUnit will run on kernel boot if
|
||||
built-in, or when loaded if built as a module. These tests write out results to
|
||||
the kernel log in `TAP <https://testanything.org/>`_ format.
|
||||
KUnit tests are part of the kernel, written in the C (programming)
|
||||
language, and test parts of the Kernel implementation (example: a C
|
||||
language function). Excluding build time, from invocation to
|
||||
completion, KUnit can run around 100 tests in less than 10 seconds.
|
||||
KUnit can test any kernel component, for example: file system, system
|
||||
calls, memory management, device drivers and so on.
|
||||
|
||||
To make running these tests (and reading the results) easier, KUnit offers
|
||||
:doc:`kunit_tool <kunit-tool>`, which builds a `User Mode Linux
|
||||
<http://user-mode-linux.sourceforge.net>`_ kernel, runs it, and parses the test
|
||||
results. This provides a quick way of running KUnit tests during development,
|
||||
without requiring a virtual machine or separate hardware.
|
||||
KUnit follows the white-box testing approach. The test has access to
|
||||
internal system functionality. KUnit runs in kernel space and is not
|
||||
restricted to things exposed to user-space.
|
||||
|
||||
Get started now: Documentation/dev-tools/kunit/start.rst
|
||||
In addition, KUnit has kunit_tool, a script (``tools/testing/kunit/kunit.py``)
|
||||
that configures the Linux kernel, runs KUnit tests under QEMU or UML (`User Mode
|
||||
Linux <http://user-mode-linux.sourceforge.net/>`_), parses the test results and
|
||||
displays them in a user friendly manner.
|
||||
|
||||
Why KUnit?
|
||||
==========
|
||||
Features
|
||||
--------
|
||||
|
||||
A unit test is supposed to test a single unit of code in isolation, hence the
|
||||
name. A unit test should be the finest granularity of testing and as such should
|
||||
allow all possible code paths to be tested in the code under test; this is only
|
||||
possible if the code under test is very small and does not have any external
|
||||
dependencies outside of the test's control like hardware.
|
||||
- Provides a framework for writing unit tests.
|
||||
- Runs tests on any kernel architecture.
|
||||
- Runs a test in milliseconds.
|
||||
|
||||
KUnit provides a common framework for unit tests within the kernel.
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
KUnit tests can be run on most architectures, and most tests are architecture
|
||||
independent. All built-in KUnit tests run on kernel startup. Alternatively,
|
||||
KUnit and KUnit tests can be built as modules and tests will run when the test
|
||||
module is loaded.
|
||||
- Any Linux kernel compatible hardware.
|
||||
- For Kernel under test, Linux kernel version 5.5 or greater.
|
||||
|
||||
.. note::
|
||||
Unit Testing
|
||||
============
|
||||
|
||||
KUnit can also run tests without needing a virtual machine or actual
|
||||
hardware under User Mode Linux. User Mode Linux is a Linux architecture,
|
||||
like ARM or x86, which compiles the kernel as a Linux executable. KUnit
|
||||
can be used with UML either by building with ``ARCH=um`` (like any other
|
||||
architecture), or by using :doc:`kunit_tool <kunit-tool>`.
|
||||
A unit test tests a single unit of code in isolation. A unit test is the finest
|
||||
granularity of testing and allows all possible code paths to be tested in the
|
||||
code under test. This is possible if the code under test is small and does not
|
||||
have any external dependencies outside of the test's control like hardware.
|
||||
|
||||
KUnit is fast. Excluding build time, from invocation to completion KUnit can run
|
||||
several dozen tests in only 10 to 20 seconds; this might not sound like a big
|
||||
deal to some people, but having such fast and easy to run tests fundamentally
|
||||
changes the way you go about testing and even writing code in the first place.
|
||||
Linus himself said in his `git talk at Google
|
||||
<https://gist.github.com/lorn/1272686/revisions#diff-53c65572127855f1b003db4064a94573R874>`_:
|
||||
|
||||
"... a lot of people seem to think that performance is about doing the
|
||||
same thing, just doing it faster, and that is not true. That is not what
|
||||
performance is all about. If you can do something really fast, really
|
||||
well, people will start using it differently."
|
||||
Write Unit Tests
|
||||
----------------
|
||||
|
||||
In this context Linus was talking about branching and merging,
|
||||
but this point also applies to testing. If your tests are slow, unreliable, are
|
||||
difficult to write, and require a special setup or special hardware to run,
|
||||
then you wait a lot longer to write tests, and you wait a lot longer to run
|
||||
tests; this means that tests are likely to break, unlikely to test a lot of
|
||||
things, and are unlikely to be rerun once they pass. If your tests are really
|
||||
fast, you run them all the time, every time you make a change, and every time
|
||||
someone sends you some code. Why trust that someone ran all their tests
|
||||
correctly on every change when you can just run them yourself in less time than
|
||||
it takes to read their test log?
|
||||
To write good unit tests, there is a simple but powerful pattern:
|
||||
Arrange-Act-Assert. This is a great way to structure test cases and
|
||||
defines an order of operations.
|
||||
|
||||
- Arrange inputs and targets: At the start of the test, arrange the data
|
||||
that allows a function to work. Example: initialize a statement or
|
||||
object.
|
||||
- Act on the target behavior: Call your function/code under test.
|
||||
- Assert expected outcome: Verify that the result (or resulting state) is as
|
||||
expected.
|
||||
|
||||
Unit Testing Advantages
|
||||
-----------------------
|
||||
|
||||
- Increases testing speed and development in the long run.
|
||||
- Detects bugs at initial stage and therefore decreases bug fix cost
|
||||
compared to acceptance testing.
|
||||
- Improves code quality.
|
||||
- Encourages writing testable code.
|
||||
|
||||
How do I use it?
|
||||
================
|
||||
|
||||
* Documentation/dev-tools/kunit/start.rst - for new users of KUnit
|
||||
* Documentation/dev-tools/kunit/tips.rst - for short examples of best practices
|
||||
* Documentation/dev-tools/kunit/usage.rst - for a more detailed explanation of KUnit features
|
||||
* Documentation/dev-tools/kunit/api/index.rst - for the list of KUnit APIs used for testing
|
||||
* Documentation/dev-tools/kunit/kunit-tool.rst - for more information on the kunit_tool helper script
|
||||
* Documentation/dev-tools/kunit/faq.rst - for answers to some common questions about KUnit
|
||||
* Documentation/dev-tools/kunit/start.rst - for KUnit new users.
|
||||
* Documentation/dev-tools/kunit/architecture.rst - KUnit architecture.
|
||||
* Documentation/dev-tools/kunit/run_wrapper.rst - run kunit_tool.
|
||||
* Documentation/dev-tools/kunit/run_manual.rst - run tests without kunit_tool.
|
||||
* Documentation/dev-tools/kunit/usage.rst - write tests.
|
||||
* Documentation/dev-tools/kunit/tips.rst - best practices with
|
||||
examples.
|
||||
* Documentation/dev-tools/kunit/api/index.rst - KUnit APIs
|
||||
used for testing.
|
||||
* Documentation/dev-tools/kunit/kunit-tool.rst - kunit_tool helper
|
||||
script.
|
||||
* Documentation/dev-tools/kunit/faq.rst - KUnit common questions and
|
||||
answers.
|
||||
|
81
Documentation/dev-tools/kunit/kunit_suitememorydiagram.svg
Normal file
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="796.93" height="555.73" version="1.1" viewBox="0 0 796.93 555.73" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-13.724 -17.943)">
|
||||
<g fill="#dad4d4" fill-opacity=".91765" stroke="#1a1a1a">
|
||||
<rect x="323.56" y="18.443" width="115.75" height="41.331"/>
|
||||
<rect x="323.56" y="463.09" width="115.75" height="41.331"/>
|
||||
<rect x="323.56" y="531.84" width="115.75" height="41.331"/>
|
||||
<rect x="323.56" y="88.931" width="115.75" height="74.231"/>
|
||||
</g>
|
||||
<g>
|
||||
<rect x="323.56" y="421.76" width="115.75" height="41.331" fill="#b9dbc6" stroke="#1a1a1a"/>
|
||||
<text x="328.00888" y="446.61826" fill="#000000" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="328.00888" y="446.61826" font-family="monospace" font-size="16px">kunit_suite</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(0 -258.6)">
|
||||
<rect x="323.56" y="421.76" width="115.75" height="41.331" fill="#b9dbc6" stroke="#1a1a1a"/>
|
||||
<text x="328.00888" y="446.61826" fill="#000000" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="328.00888" y="446.61826" font-family="monospace" font-size="16px">kunit_suite</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(0 -217.27)">
|
||||
<rect x="323.56" y="421.76" width="115.75" height="41.331" fill="#b9dbc6" stroke="#1a1a1a"/>
|
||||
<text x="328.00888" y="446.61826" fill="#000000" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="328.00888" y="446.61826" font-family="monospace" font-size="16px">kunit_suite</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(0 -175.94)">
|
||||
<rect x="323.56" y="421.76" width="115.75" height="41.331" fill="#b9dbc6" stroke="#1a1a1a"/>
|
||||
<text x="328.00888" y="446.61826" fill="#000000" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="328.00888" y="446.61826" font-family="monospace" font-size="16px">kunit_suite</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(0 -134.61)">
|
||||
<rect x="323.56" y="421.76" width="115.75" height="41.331" fill="#b9dbc6" stroke="#1a1a1a"/>
|
||||
<text x="328.00888" y="446.61826" fill="#000000" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="328.00888" y="446.61826" font-family="monospace" font-size="16px">kunit_suite</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(0 -41.331)">
|
||||
<rect x="323.56" y="421.76" width="115.75" height="41.331" fill="#b9dbc6" stroke="#1a1a1a"/>
|
||||
<text x="328.00888" y="446.61826" fill="#000000" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="328.00888" y="446.61826" font-family="monospace" font-size="16px">kunit_suite</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(3.4459e-5 -.71088)">
|
||||
<rect x="502.19" y="143.16" width="201.13" height="41.331" fill="#dad4d4" fill-opacity=".91765" stroke="#1a1a1a"/>
|
||||
<text x="512.02319" y="168.02026" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="512.02319" y="168.02026" font-family="monospace">_kunit_suites_start</tspan></text>
|
||||
</g>
|
||||
<g transform="translate(3.0518e-5 -3.1753)">
|
||||
<rect x="502.19" y="445.69" width="201.13" height="41.331" fill="#dad4d4" fill-opacity=".91765" stroke="#1a1a1a"/>
|
||||
<text x="521.61694" y="470.54846" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="521.61694" y="470.54846" font-family="monospace">_kunit_suites_end</tspan></text>
|
||||
</g>
|
||||
<rect x="14.224" y="277.78" width="134.47" height="41.331" fill="#dad4d4" fill-opacity=".91765" stroke="#1a1a1a"/>
|
||||
<text x="32.062176" y="304.41287" font-family="sans-serif" font-size="16px" style="line-height:1.25" xml:space="preserve"><tspan x="32.062176" y="304.41287" font-family="monospace">.init.data</tspan></text>
|
||||
<g transform="translate(217.98 145.12)" stroke="#1a1a1a">
|
||||
<circle cx="149.97" cy="373.01" r="3.4012"/>
|
||||
<circle cx="163.46" cy="373.01" r="3.4012"/>
|
||||
<circle cx="176.95" cy="373.01" r="3.4012"/>
|
||||
</g>
|
||||
<g transform="translate(217.98 -298.66)" stroke="#1a1a1a">
|
||||
<circle cx="149.97" cy="373.01" r="3.4012"/>
|
||||
<circle cx="163.46" cy="373.01" r="3.4012"/>
|
||||
<circle cx="176.95" cy="373.01" r="3.4012"/>
|
||||
</g>
|
||||
<g stroke="#1a1a1a">
|
||||
<rect x="323.56" y="328.49" width="115.75" height="51.549" fill="#b9dbc6"/>
|
||||
<g transform="translate(217.98 -18.75)">
|
||||
<circle cx="149.97" cy="373.01" r="3.4012"/>
|
||||
<circle cx="163.46" cy="373.01" r="3.4012"/>
|
||||
<circle cx="176.95" cy="373.01" r="3.4012"/>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="scale(1.0933 .9147)" stroke-width="32.937" aria-label="{">
|
||||
<path d="m275.49 545.57c-35.836-8.432-47.43-24.769-47.957-64.821v-88.536c-0.527-44.795-10.54-57.97-49.538-67.456 38.998-10.013 49.011-23.715 49.538-67.983v-88.536c0.527-40.052 12.121-56.389 47.957-64.821v-5.797c-65.348 0-85.901 17.391-86.955 73.253v93.806c-0.527 36.89-10.013 50.065-44.795 59.551 34.782 10.013 44.268 23.188 44.795 60.078v93.279c1.581 56.389 21.607 73.78 86.955 73.78z"/>
|
||||
</g>
|
||||
<g transform="scale(1.1071 .90325)" stroke-width="14.44" aria-label="{">
|
||||
<path d="m461.46 443.55c-15.711-3.6967-20.794-10.859-21.025-28.418v-38.815c-0.23104-19.639-4.6209-25.415-21.718-29.574 17.097-4.3898 21.487-10.397 21.718-29.805v-38.815c0.23105-17.559 5.314-24.722 21.025-28.418v-2.5415c-28.649 0-37.66 7.6244-38.122 32.115v41.126c-0.23105 16.173-4.3898 21.949-19.639 26.108 15.249 4.3898 19.408 10.166 19.639 26.339v40.895c0.69313 24.722 9.4728 32.346 38.122 32.346z"/>
|
||||
</g>
|
||||
<path d="m449.55 161.84v2.5h49.504v-2.5z" color="#000000" style="-inkscape-stroke:none"/>
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m443.78 163.09 8.65-5v10z" color="#000000" stroke-width="1pt" style="-inkscape-stroke:none"/>
|
||||
<path d="m453.1 156.94-10.648 6.1543 0.99804 0.57812 9.6504 5.5781zm-1.334 2.3125v7.6856l-6.6504-3.8438z" color="#000000" style="-inkscape-stroke:none"/>
|
||||
</g>
|
||||
<path d="m449.55 461.91v2.5h49.504v-2.5z" color="#000000" style="-inkscape-stroke:none"/>
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m443.78 463.16 8.65-5v10z" color="#000000" stroke-width="1pt" style="-inkscape-stroke:none"/>
|
||||
<path d="m453.1 457-10.648 6.1562 0.99804 0.57617 9.6504 5.5781zm-1.334 2.3125v7.6856l-6.6504-3.8438z" color="#000000" style="-inkscape-stroke:none"/>
|
||||
</g>
|
||||
<rect x="515.64" y="223.9" width="294.52" height="178.49" fill="#dad4d4" fill-opacity=".91765" stroke="#1a1a1a"/>
|
||||
<text x="523.33319" y="262.52542" font-family="monospace" font-size="14.667px" style="line-height:1.25" xml:space="preserve"><tspan x="523.33319" y="262.52542"><tspan fill="#008000" font-family="monospace" font-size="14.667px" font-weight="bold">struct</tspan> kunit_suite {</tspan><tspan x="523.33319" y="280.8588"><tspan fill="#008000" font-family="monospace" font-size="14.667px" font-weight="bold"> const char</tspan> name[<tspan fill="#ff00ff" font-size="14.667px">256</tspan>];</tspan><tspan x="523.33319" y="299.19217"> <tspan fill="#008000" font-family="monospace" font-size="14.667px" font-weight="bold">int</tspan> (*init)(<tspan fill="#008000" font-family="monospace" font-size="14.667px" font-weight="bold">struct</tspan> kunit *);</tspan><tspan x="523.33319" y="317.52554"> <tspan fill="#008000" font-family="monospace" font-size="14.667px" font-weight="bold">void</tspan> (*exit)(<tspan fill="#008000" font-family="monospace" font-size="14.667px" font-weight="bold">struct</tspan> kunit *);</tspan><tspan x="523.33319" y="335.85892"> <tspan fill="#008000" font-family="monospace" font-size="14.667px" font-weight="bold">struct</tspan> kunit_case *test_cases;</tspan><tspan x="523.33319" y="354.19229"> ...</tspan><tspan x="523.33319" y="372.52567">};</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.6 KiB |
57
Documentation/dev-tools/kunit/run_manual.rst
Normal file
@ -0,0 +1,57 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
============================
|
||||
Run Tests without kunit_tool
|
||||
============================
|
||||
|
||||
If we do not want to use kunit_tool (For example: we want to integrate
|
||||
with other systems, or run tests on real hardware), we can
|
||||
include KUnit in any kernel, read out results, and parse manually.
|
||||
|
||||
.. note:: KUnit is not designed for use in a production system. It is
|
||||
possible that tests may reduce the stability or security of
|
||||
the system.
|
||||
|
||||
Configure the Kernel
|
||||
====================
|
||||
|
||||
KUnit tests can run without kunit_tool. This can be useful, if:
|
||||
|
||||
- We have an existing kernel configuration to test.
|
||||
- Need to run on real hardware (or using an emulator/VM kunit_tool
|
||||
does not support).
|
||||
- Wish to integrate with some existing testing systems.
|
||||
|
||||
KUnit is configured with the ``CONFIG_KUNIT`` option, and individual
|
||||
tests can also be built by enabling their config options in our
|
||||
``.config``. KUnit tests usually (but don't always) have config options
|
||||
ending in ``_KUNIT_TEST``. Most tests can either be built as a module,
|
||||
or be built into the kernel.
|
||||
|
||||
.. note ::
|
||||
|
||||
We can enable the ``KUNIT_ALL_TESTS`` config option to
|
||||
automatically enable all tests with satisfied dependencies. This is
|
||||
a good way of quickly testing everything applicable to the current
|
||||
config.
|
||||
|
||||
Once we have built our kernel (and/or modules), it is simple to run
|
||||
the tests. If the tests are built-in, they will run automatically on the
|
||||
kernel boot. The results will be written to the kernel log (``dmesg``)
|
||||
in TAP format.
|
||||
|
||||
If the tests are built as modules, they will run when the module is
|
||||
loaded.
|
||||
|
||||
.. code-block :: bash
|
||||
|
||||
# modprobe example-test
|
||||
|
||||
The results will appear in TAP format in ``dmesg``.
|
||||
|
||||
.. note ::
|
||||
|
||||
If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will
|
||||
be accessible from the ``debugfs`` filesystem (if mounted).
|
||||
They will be in ``/sys/kernel/debug/kunit/<test_suite>/results``, in
|
||||
TAP format.
|
247
Documentation/dev-tools/kunit/run_wrapper.rst
Normal file
@ -0,0 +1,247 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================
|
||||
Run Tests with kunit_tool
|
||||
=========================
|
||||
|
||||
We can either run KUnit tests using kunit_tool or can run tests
|
||||
manually, and then use kunit_tool to parse the results. To run tests
|
||||
manually, see: Documentation/dev-tools/kunit/run_manual.rst.
|
||||
As long as we can build the kernel, we can run KUnit.
|
||||
|
||||
kunit_tool is a Python script which configures and builds a kernel, runs
|
||||
tests, and formats the test results.
|
||||
|
||||
Run command:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py run
|
||||
|
||||
We should see the following:
|
||||
|
||||
.. code-block::
|
||||
|
||||
Generating .config...
|
||||
Building KUnit kernel...
|
||||
Starting KUnit kernel...
|
||||
|
||||
We may want to use the following options:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py run --timeout=30 --jobs=`nproc --all
|
||||
|
||||
- ``--timeout`` sets a maximum amount of time for tests to run.
|
||||
- ``--jobs`` sets the number of threads to build the kernel.
|
||||
|
||||
kunit_tool will generate a ``.kunitconfig`` with a default
|
||||
configuration, if no other ``.kunitconfig`` file exists
|
||||
(in the build directory). In addition, it verifies that the
|
||||
generated ``.config`` file contains the ``CONFIG`` options in the
|
||||
``.kunitconfig``.
|
||||
It is also possible to pass a separate ``.kunitconfig`` fragment to
|
||||
kunit_tool. This is useful if we have several different groups of
|
||||
tests we want to run independently, or if we want to use pre-defined
|
||||
test configs for certain subsystems.
|
||||
|
||||
To use a different ``.kunitconfig`` file (such as one
|
||||
provided to test a particular subsystem), pass it as an option:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py run --kunitconfig=fs/ext4/.kunitconfig
|
||||
|
||||
To view kunit_tool flags (optional command-line arguments), run:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py run --help
|
||||
|
||||
Create a ``.kunitconfig`` File
|
||||
===============================
|
||||
|
||||
If we want to run a specific set of tests (rather than those listed
|
||||
in the KUnit ``defconfig``), we can provide Kconfig options in the
|
||||
``.kunitconfig`` file. For default .kunitconfig, see:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/testing/kunit/configs/default.config.
|
||||
A ``.kunitconfig`` is a ``minconfig`` (a .config
|
||||
generated by running ``make savedefconfig``), used for running a
|
||||
specific set of tests. This file contains the regular Kernel configs
|
||||
with specific test targets. The ``.kunitconfig`` also
|
||||
contains any other config options required by the tests (For example:
|
||||
dependencies for features under tests, configs that enable/disable
|
||||
certain code blocks, arch configs and so on).
|
||||
|
||||
To create a ``.kunitconfig``, using the KUnit ``defconfig``:
|
||||
|
||||
.. code-block::
|
||||
|
||||
cd $PATH_TO_LINUX_REPO
|
||||
cp tools/testing/kunit/configs/default.config .kunit/.kunitconfig
|
||||
|
||||
We can then add any other Kconfig options. For example:
|
||||
|
||||
.. code-block::
|
||||
|
||||
CONFIG_LIST_KUNIT_TEST=y
|
||||
|
||||
kunit_tool ensures that all config options in ``.kunitconfig`` are
|
||||
set in the kernel ``.config`` before running the tests. It warns if we
|
||||
have not included the options dependencies.
|
||||
|
||||
.. note:: Removing something from the ``.kunitconfig`` will
|
||||
not rebuild the ``.config file``. The configuration is only
|
||||
updated if the ``.kunitconfig`` is not a subset of ``.config``.
|
||||
This means that we can use other tools
|
||||
(For example: ``make menuconfig``) to adjust other config options.
|
||||
The build dir needs to be set for ``make menuconfig`` to
|
||||
work, therefore by default use ``make O=.kunit menuconfig``.
|
||||
|
||||
Configure, Build, and Run Tests
|
||||
===============================
|
||||
|
||||
If we want to make manual changes to the KUnit build process, we
|
||||
can run part of the KUnit build process independently.
|
||||
When running kunit_tool, from a ``.kunitconfig``, we can generate a
|
||||
``.config`` by using the ``config`` argument:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py config
|
||||
|
||||
To build a KUnit kernel from the current ``.config``, we can use the
|
||||
``build`` argument:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py build
|
||||
|
||||
If we already have built UML kernel with built-in KUnit tests, we
|
||||
can run the kernel, and display the test results with the ``exec``
|
||||
argument:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py exec
|
||||
|
||||
The ``run`` command discussed in section: **Run Tests with kunit_tool**,
|
||||
is equivalent to running the above three commands in sequence.
|
||||
|
||||
Parse Test Results
|
||||
==================
|
||||
|
||||
KUnit tests output displays results in TAP (Test Anything Protocol)
|
||||
format. When running tests, kunit_tool parses this output and prints
|
||||
a summary. To see the raw test results in TAP format, we can pass the
|
||||
``--raw_output`` argument:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py run --raw_output
|
||||
|
||||
If we have KUnit results in the raw TAP format, we can parse them and
|
||||
print the human-readable summary with the ``parse`` command for
|
||||
kunit_tool. This accepts a filename for an argument, or will read from
|
||||
standard input.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Reading from a file
|
||||
./tools/testing/kunit/kunit.py parse /var/log/dmesg
|
||||
# Reading from stdin
|
||||
dmesg | ./tools/testing/kunit/kunit.py parse
|
||||
|
||||
Run Selected Test Suites
|
||||
========================
|
||||
|
||||
By passing a bash style glob filter to the ``exec`` or ``run``
|
||||
commands, we can run a subset of the tests built into a kernel . For
|
||||
example: if we only want to run KUnit resource tests, use:
|
||||
|
||||
.. code-block::
|
||||
|
||||
./tools/testing/kunit/kunit.py run 'kunit-resource*'
|
||||
|
||||
This uses the standard glob format with wildcard characters.
|
||||
|
||||
Run Tests on qemu
|
||||
=================
|
||||
|
||||
kunit_tool supports running tests on qemu as well as
|
||||
via UML. To run tests on qemu, by default it requires two flags:
|
||||
|
||||
- ``--arch``: Selects a configs collection (Kconfig, qemu config options
|
||||
and so on), that allow KUnit tests to be run on the specified
|
||||
architecture in a minimal way. The architecture argument is same as
|
||||
the option name passed to the ``ARCH`` variable used by Kbuild.
|
||||
Not all architectures currently support this flag, but we can use
|
||||
``--qemu_config`` to handle it. If ``um`` is passed (or this flag
|
||||
is ignored), the tests will run via UML. Non-UML architectures,
|
||||
for example: i386, x86_64, arm and so on; run on qemu.
|
||||
|
||||
- ``--cross_compile``: Specifies the Kbuild toolchain. It passes the
|
||||
same argument as passed to the ``CROSS_COMPILE`` variable used by
|
||||
Kbuild. As a reminder, this will be the prefix for the toolchain
|
||||
binaries such as GCC. For example:
|
||||
|
||||
- ``sparc64-linux-gnu`` if we have the sparc toolchain installed on
|
||||
our system.
|
||||
|
||||
- ``$HOME/toolchains/microblaze/gcc-9.2.0-nolibc/microblaze-linux/bin/microblaze-linux``
|
||||
if we have downloaded the microblaze toolchain from the 0-day
|
||||
website to a directory in our home directory called toolchains.
|
||||
|
||||
If we want to run KUnit tests on an architecture not supported by
|
||||
the ``--arch`` flag, or want to run KUnit tests on qemu using a
|
||||
non-default configuration; then we can write our own``QemuConfig``.
|
||||
These ``QemuConfigs`` are written in Python. They have an import line
|
||||
``from..qemu_config import QemuArchParams`` at the top of the file.
|
||||
The file must contain a variable called ``QEMU_ARCH`` that has an
|
||||
instance of ``QemuArchParams`` assigned to it. See example in:
|
||||
``tools/testing/kunit/qemu_configs/x86_64.py``.
|
||||
|
||||
Once we have a ``QemuConfig``, we can pass it into kunit_tool,
|
||||
using the ``--qemu_config`` flag. When used, this flag replaces the
|
||||
``--arch`` flag. For example: using
|
||||
``tools/testing/kunit/qemu_configs/x86_64.py``, the invocation appear
|
||||
as
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./tools/testing/kunit/kunit.py run \
|
||||
--timeout=60 \
|
||||
--jobs=12 \
|
||||
--qemu_config=./tools/testing/kunit/qemu_configs/x86_64.py
|
||||
|
||||
To run existing KUnit tests on non-UML architectures, see:
|
||||
Documentation/dev-tools/kunit/non_uml.rst.
|
||||
|
||||
Command-Line Arguments
|
||||
======================
|
||||
|
||||
kunit_tool has a number of other command-line arguments which can
|
||||
be useful for our test environment. Below the most commonly used
|
||||
command line arguments:
|
||||
|
||||
- ``--help``: Lists all available options. To list common options,
|
||||
place ``--help`` before the command. To list options specific to that
|
||||
command, place ``--help`` after the command.
|
||||
|
||||
.. note:: Different commands (``config``, ``build``, ``run``, etc)
|
||||
have different supported options.
|
||||
- ``--build_dir``: Specifies kunit_tool build directory. It includes
|
||||
the ``.kunitconfig``, ``.config`` files and compiled kernel.
|
||||
|
||||
- ``--make_options``: Specifies additional options to pass to make, when
|
||||
compiling a kernel (using ``build`` or ``run`` commands). For example:
|
||||
to enable compiler warnings, we can pass ``--make_options W=1``.
|
||||
|
||||
- ``--alltests``: Builds a UML kernel with all config options enabled
|
||||
using ``make allyesconfig``. This allows us to run as many tests as
|
||||
possible.
|
||||
|
||||
.. note:: It is slow and prone to breakage as new options are
|
||||
added or modified. Instead, enable all tests
|
||||
which have satisfied dependencies by adding
|
||||
``CONFIG_KUNIT_ALL_TESTS=y`` to your ``.kunitconfig``.
|
@ -4,132 +4,137 @@
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
Installing dependencies
|
||||
Installing Dependencies
|
||||
=======================
|
||||
KUnit has the same dependencies as the Linux kernel. As long as you can build
|
||||
the kernel, you can run KUnit.
|
||||
KUnit has the same dependencies as the Linux kernel. As long as you can
|
||||
build the kernel, you can run KUnit.
|
||||
|
||||
Running tests with the KUnit Wrapper
|
||||
====================================
|
||||
Included with KUnit is a simple Python wrapper which runs tests under User Mode
|
||||
Linux, and formats the test results.
|
||||
|
||||
The wrapper can be run with:
|
||||
Running tests with kunit_tool
|
||||
=============================
|
||||
kunit_tool is a Python script, which configures and builds a kernel, runs
|
||||
tests, and formats the test results. From the kernel repository, you
|
||||
can run kunit_tool:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./tools/testing/kunit/kunit.py run
|
||||
|
||||
For more information on this wrapper (also called kunit_tool) check out the
|
||||
Documentation/dev-tools/kunit/kunit-tool.rst page.
|
||||
For more information on this wrapper, see:
|
||||
Documentation/dev-tools/kunit/run_wrapper.rst.
|
||||
|
||||
Creating a .kunitconfig
|
||||
-----------------------
|
||||
If you want to run a specific set of tests (rather than those listed in the
|
||||
KUnit defconfig), you can provide Kconfig options in the ``.kunitconfig`` file.
|
||||
This file essentially contains the regular Kernel config, with the specific
|
||||
test targets as well. The ``.kunitconfig`` should also contain any other config
|
||||
options required by the tests.
|
||||
Creating a ``.kunitconfig``
|
||||
---------------------------
|
||||
|
||||
A good starting point for a ``.kunitconfig`` is the KUnit defconfig:
|
||||
By default, kunit_tool runs a selection of tests. However, you can specify which
|
||||
unit tests to run by creating a ``.kunitconfig`` file with kernel config options
|
||||
that enable only a specific set of tests and their dependencies.
|
||||
The ``.kunitconfig`` file contains a list of kconfig options which are required
|
||||
to run the desired targets. The ``.kunitconfig`` also contains any other test
|
||||
specific config options, such as test dependencies. For example: the
|
||||
``FAT_FS`` tests - ``FAT_KUNIT_TEST``, depends on
|
||||
``FAT_FS``. ``FAT_FS`` can be enabled by selecting either ``MSDOS_FS``
|
||||
or ``VFAT_FS``. To run ``FAT_KUNIT_TEST``, the ``.kunitconfig`` has:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_FAT_KUNIT_TEST=y
|
||||
|
||||
1. A good starting point for the ``.kunitconfig``, is the KUnit default
|
||||
config. Run the command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd $PATH_TO_LINUX_REPO
|
||||
cp tools/testing/kunit/configs/default.config .kunitconfig
|
||||
|
||||
You can then add any other Kconfig options you wish, e.g.:
|
||||
.. note ::
|
||||
You may want to remove CONFIG_KUNIT_ALL_TESTS from the ``.kunitconfig`` as
|
||||
it will enable a number of additional tests that you may not want.
|
||||
|
||||
2. You can then add any other Kconfig options, for example:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
CONFIG_LIST_KUNIT_TEST=y
|
||||
|
||||
:doc:`kunit_tool <kunit-tool>` will ensure that all config options set in
|
||||
``.kunitconfig`` are set in the kernel ``.config`` before running the tests.
|
||||
It'll warn you if you haven't included the dependencies of the options you're
|
||||
using.
|
||||
Before running the tests, kunit_tool ensures that all config options
|
||||
set in ``.kunitconfig`` are set in the kernel ``.config``. It will warn
|
||||
you if you have not included dependencies for the options used.
|
||||
|
||||
.. note::
|
||||
Note that removing something from the ``.kunitconfig`` will not trigger a
|
||||
rebuild of the ``.config`` file: the configuration is only updated if the
|
||||
``.kunitconfig`` is not a subset of ``.config``. This means that you can use
|
||||
other tools (such as make menuconfig) to adjust other config options.
|
||||
.. note ::
|
||||
If you change the ``.kunitconfig``, kunit.py will trigger a rebuild of the
|
||||
``.config`` file. But you can edit the ``.config`` file directly or with
|
||||
tools like ``make menuconfig O=.kunit``. As long as its a superset of
|
||||
``.kunitconfig``, kunit.py won't overwrite your changes.
|
||||
|
||||
|
||||
Running the tests (KUnit Wrapper)
|
||||
---------------------------------
|
||||
|
||||
To make sure that everything is set up correctly, simply invoke the Python
|
||||
wrapper from your kernel repo:
|
||||
Running Tests (KUnit Wrapper)
|
||||
-----------------------------
|
||||
1. To make sure that everything is set up correctly, invoke the Python
|
||||
wrapper from your kernel repository:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./tools/testing/kunit/kunit.py run
|
||||
|
||||
.. note::
|
||||
You may want to run ``make mrproper`` first.
|
||||
|
||||
If everything worked correctly, you should see the following:
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block::
|
||||
|
||||
Generating .config ...
|
||||
Building KUnit Kernel ...
|
||||
Starting KUnit Kernel ...
|
||||
|
||||
followed by a list of tests that are run. All of them should be passing.
|
||||
The tests will pass or fail.
|
||||
|
||||
.. note::
|
||||
Because it is building a lot of sources for the first time, the
|
||||
``Building KUnit kernel`` step may take a while.
|
||||
.. note ::
|
||||
Because it is building a lot of sources for the first time, the
|
||||
``Building KUnit kernel`` may take a while.
|
||||
|
||||
Running tests without the KUnit Wrapper
|
||||
Running Tests without the KUnit Wrapper
|
||||
=======================================
|
||||
If you do not want to use the KUnit Wrapper (for example: you want code
|
||||
under test to integrate with other systems, or use a different/
|
||||
unsupported architecture or configuration), KUnit can be included in
|
||||
any kernel, and the results are read out and parsed manually.
|
||||
|
||||
If you'd rather not use the KUnit Wrapper (if, for example, you need to
|
||||
integrate with other systems, or use an architecture other than UML), KUnit can
|
||||
be included in any kernel, and the results read out and parsed manually.
|
||||
.. note ::
|
||||
``CONFIG_KUNIT`` should not be enabled in a production environment.
|
||||
Enabling KUnit disables Kernel Address-Space Layout Randomization
|
||||
(KASLR), and tests may affect the state of the kernel in ways not
|
||||
suitable for production.
|
||||
|
||||
.. note::
|
||||
KUnit is not designed for use in a production system, and it's possible that
|
||||
tests may reduce the stability or security of the system.
|
||||
|
||||
|
||||
|
||||
Configuring the kernel
|
||||
Configuring the Kernel
|
||||
----------------------
|
||||
To enable KUnit itself, you need to enable the ``CONFIG_KUNIT`` Kconfig
|
||||
option (under Kernel Hacking/Kernel Testing and Coverage in
|
||||
``menuconfig``). From there, you can enable any KUnit tests. They
|
||||
usually have config options ending in ``_KUNIT_TEST``.
|
||||
|
||||
In order to enable KUnit itself, you simply need to enable the ``CONFIG_KUNIT``
|
||||
Kconfig option (it's under Kernel Hacking/Kernel Testing and Coverage in
|
||||
menuconfig). From there, you can enable any KUnit tests you want: they usually
|
||||
have config options ending in ``_KUNIT_TEST``.
|
||||
KUnit and KUnit tests can be compiled as modules. The tests in a module
|
||||
will run when the module is loaded.
|
||||
|
||||
KUnit and KUnit tests can be compiled as modules: in this case the tests in a
|
||||
module will be run when the module is loaded.
|
||||
|
||||
|
||||
Running the tests (w/o KUnit Wrapper)
|
||||
Running Tests (without KUnit Wrapper)
|
||||
-------------------------------------
|
||||
Build and run your kernel. In the kernel log, the test output is printed
|
||||
out in the TAP format. This will only happen by default if KUnit/tests
|
||||
are built-in. Otherwise the module will need to be loaded.
|
||||
|
||||
Build and run your kernel as usual. Test output will be written to the kernel
|
||||
log in `TAP <https://testanything.org/>`_ format.
|
||||
.. note ::
|
||||
Some lines and/or data may get interspersed in the TAP output.
|
||||
|
||||
.. note::
|
||||
It's possible that there will be other lines and/or data interspersed in the
|
||||
TAP output.
|
||||
|
||||
|
||||
Writing your first test
|
||||
Writing Your First Test
|
||||
=======================
|
||||
In your kernel repository, let's add some code that we can test.
|
||||
|
||||
In your kernel repo let's add some code that we can test. Create a file
|
||||
``drivers/misc/example.h`` with the contents:
|
||||
1. Create a file ``drivers/misc/example.h``, which includes:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int misc_example_add(int left, int right);
|
||||
|
||||
create a file ``drivers/misc/example.c``:
|
||||
2. Create a file ``drivers/misc/example.c``, which includes:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -142,21 +147,22 @@ create a file ``drivers/misc/example.c``:
|
||||
return left + right;
|
||||
}
|
||||
|
||||
Now add the following lines to ``drivers/misc/Kconfig``:
|
||||
3. Add the following lines to ``drivers/misc/Kconfig``:
|
||||
|
||||
.. code-block:: kconfig
|
||||
|
||||
config MISC_EXAMPLE
|
||||
bool "My example"
|
||||
|
||||
and the following lines to ``drivers/misc/Makefile``:
|
||||
4. Add the following lines to ``drivers/misc/Makefile``:
|
||||
|
||||
.. code-block:: make
|
||||
|
||||
obj-$(CONFIG_MISC_EXAMPLE) += example.o
|
||||
|
||||
Now we are ready to write the test. The test will be in
|
||||
``drivers/misc/example-test.c``:
|
||||
Now we are ready to write the test cases.
|
||||
|
||||
1. Add the below test case in ``drivers/misc/example_test.c``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -191,7 +197,7 @@ Now we are ready to write the test. The test will be in
|
||||
};
|
||||
kunit_test_suite(misc_example_test_suite);
|
||||
|
||||
Now add the following to ``drivers/misc/Kconfig``:
|
||||
2. Add the following lines to ``drivers/misc/Kconfig``:
|
||||
|
||||
.. code-block:: kconfig
|
||||
|
||||
@ -200,20 +206,20 @@ Now add the following to ``drivers/misc/Kconfig``:
|
||||
depends on MISC_EXAMPLE && KUNIT=y
|
||||
default KUNIT_ALL_TESTS
|
||||
|
||||
and the following to ``drivers/misc/Makefile``:
|
||||
3. Add the following lines to ``drivers/misc/Makefile``:
|
||||
|
||||
.. code-block:: make
|
||||
|
||||
obj-$(CONFIG_MISC_EXAMPLE_TEST) += example-test.o
|
||||
obj-$(CONFIG_MISC_EXAMPLE_TEST) += example_test.o
|
||||
|
||||
Now add it to your ``.kunitconfig``:
|
||||
4. Add the following lines to ``.kunitconfig``:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
CONFIG_MISC_EXAMPLE=y
|
||||
CONFIG_MISC_EXAMPLE_TEST=y
|
||||
|
||||
Now you can run the test:
|
||||
5. Run the test:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@ -227,16 +233,23 @@ You should see the following failure:
|
||||
[16:08:57] [PASSED] misc-example:misc_example_add_test_basic
|
||||
[16:08:57] [FAILED] misc-example:misc_example_test_failure
|
||||
[16:08:57] EXPECTATION FAILED at drivers/misc/example-test.c:17
|
||||
[16:08:57] This test never passes.
|
||||
[16:08:57] This test never passes.
|
||||
...
|
||||
|
||||
Congrats! You just wrote your first KUnit test!
|
||||
Congrats! You just wrote your first KUnit test.
|
||||
|
||||
Next Steps
|
||||
==========
|
||||
* Check out the Documentation/dev-tools/kunit/tips.rst page for tips on
|
||||
writing idiomatic KUnit tests.
|
||||
* Check out the :doc:`running_tips` page for tips on
|
||||
how to make running KUnit tests easier.
|
||||
* Optional: see the :doc:`usage` page for a more
|
||||
in-depth explanation of KUnit.
|
||||
|
||||
* Documentation/dev-tools/kunit/architecture.rst - KUnit architecture.
|
||||
* Documentation/dev-tools/kunit/run_wrapper.rst - run kunit_tool.
|
||||
* Documentation/dev-tools/kunit/run_manual.rst - run tests without kunit_tool.
|
||||
* Documentation/dev-tools/kunit/usage.rst - write tests.
|
||||
* Documentation/dev-tools/kunit/tips.rst - best practices with
|
||||
examples.
|
||||
* Documentation/dev-tools/kunit/api/index.rst - KUnit APIs
|
||||
used for testing.
|
||||
* Documentation/dev-tools/kunit/kunit-tool.rst - kunit_tool helper
|
||||
script.
|
||||
* Documentation/dev-tools/kunit/faq.rst - KUnit common questions and
|
||||
answers.
|
||||
|
@ -4,37 +4,36 @@
|
||||
Test Style and Nomenclature
|
||||
===========================
|
||||
|
||||
To make finding, writing, and using KUnit tests as simple as possible, it's
|
||||
To make finding, writing, and using KUnit tests as simple as possible, it is
|
||||
strongly encouraged that they are named and written according to the guidelines
|
||||
below. While it's possible to write KUnit tests which do not follow these rules,
|
||||
below. While it is possible to write KUnit tests which do not follow these rules,
|
||||
they may break some tooling, may conflict with other tests, and may not be run
|
||||
automatically by testing systems.
|
||||
|
||||
It's recommended that you only deviate from these guidelines when:
|
||||
It is recommended that you only deviate from these guidelines when:
|
||||
|
||||
1. Porting tests to KUnit which are already known with an existing name, or
|
||||
2. Writing tests which would cause serious problems if automatically run (e.g.,
|
||||
non-deterministically producing false positives or negatives, or taking an
|
||||
extremely long time to run).
|
||||
1. Porting tests to KUnit which are already known with an existing name.
|
||||
2. Writing tests which would cause serious problems if automatically run. For
|
||||
example, non-deterministically producing false positives or negatives, or
|
||||
taking a long time to run.
|
||||
|
||||
Subsystems, Suites, and Tests
|
||||
=============================
|
||||
|
||||
In order to make tests as easy to find as possible, they're grouped into suites
|
||||
and subsystems. A test suite is a group of tests which test a related area of
|
||||
the kernel, and a subsystem is a set of test suites which test different parts
|
||||
of the same kernel subsystem or driver.
|
||||
To make tests easy to find, they are grouped into suites and subsystems. A test
|
||||
suite is a group of tests which test a related area of the kernel. A subsystem
|
||||
is a set of test suites which test different parts of a kernel subsystem
|
||||
or a driver.
|
||||
|
||||
Subsystems
|
||||
----------
|
||||
|
||||
Every test suite must belong to a subsystem. A subsystem is a collection of one
|
||||
or more KUnit test suites which test the same driver or part of the kernel. A
|
||||
rule of thumb is that a test subsystem should match a single kernel module. If
|
||||
the code being tested can't be compiled as a module, in many cases the subsystem
|
||||
should correspond to a directory in the source tree or an entry in the
|
||||
MAINTAINERS file. If unsure, follow the conventions set by tests in similar
|
||||
areas.
|
||||
test subsystem should match a single kernel module. If the code being tested
|
||||
cannot be compiled as a module, in many cases the subsystem should correspond to
|
||||
a directory in the source tree or an entry in the ``MAINTAINERS`` file. If
|
||||
unsure, follow the conventions set by tests in similar areas.
|
||||
|
||||
Test subsystems should be named after the code being tested, either after the
|
||||
module (wherever possible), or after the directory or files being tested. Test
|
||||
@ -42,9 +41,8 @@ subsystems should be named to avoid ambiguity where necessary.
|
||||
|
||||
If a test subsystem name has multiple components, they should be separated by
|
||||
underscores. *Do not* include "test" or "kunit" directly in the subsystem name
|
||||
unless you are actually testing other tests or the kunit framework itself.
|
||||
|
||||
Example subsystems could be:
|
||||
unless we are actually testing other tests or the kunit framework itself. For
|
||||
example, subsystems could be called:
|
||||
|
||||
``ext4``
|
||||
Matches the module and filesystem name.
|
||||
@ -56,48 +54,46 @@ Example subsystems could be:
|
||||
Has several components (``snd``, ``hda``, ``codec``, ``hdmi``) separated by
|
||||
underscores. Matches the module name.
|
||||
|
||||
Avoid names like these:
|
||||
Avoid names as shown in examples below:
|
||||
|
||||
``linear-ranges``
|
||||
Names should use underscores, not dashes, to separate words. Prefer
|
||||
``linear_ranges``.
|
||||
``qos-kunit-test``
|
||||
As well as using underscores, this name should not have "kunit-test" as a
|
||||
suffix, and ``qos`` is ambiguous as a subsystem name. ``power_qos`` would be a
|
||||
better name.
|
||||
This name should use underscores, and not have "kunit-test" as a
|
||||
suffix. ``qos`` is also ambiguous as a subsystem name, because several parts
|
||||
of the kernel have a ``qos`` subsystem. ``power_qos`` would be a better name.
|
||||
``pc_parallel_port``
|
||||
The corresponding module name is ``parport_pc``, so this subsystem should also
|
||||
be named ``parport_pc``.
|
||||
|
||||
.. note::
|
||||
The KUnit API and tools do not explicitly know about subsystems. They're
|
||||
simply a way of categorising test suites and naming modules which
|
||||
provides a simple, consistent way for humans to find and run tests. This
|
||||
may change in the future, though.
|
||||
The KUnit API and tools do not explicitly know about subsystems. They are
|
||||
a way of categorizing test suites and naming modules which provides a
|
||||
simple, consistent way for humans to find and run tests. This may change
|
||||
in the future.
|
||||
|
||||
Suites
|
||||
------
|
||||
|
||||
KUnit tests are grouped into test suites, which cover a specific area of
|
||||
functionality being tested. Test suites can have shared initialisation and
|
||||
shutdown code which is run for all tests in the suite.
|
||||
Not all subsystems will need to be split into multiple test suites (e.g. simple drivers).
|
||||
functionality being tested. Test suites can have shared initialization and
|
||||
shutdown code which is run for all tests in the suite. Not all subsystems need
|
||||
to be split into multiple test suites (for example, simple drivers).
|
||||
|
||||
Test suites are named after the subsystem they are part of. If a subsystem
|
||||
contains several suites, the specific area under test should be appended to the
|
||||
subsystem name, separated by an underscore.
|
||||
|
||||
In the event that there are multiple types of test using KUnit within a
|
||||
subsystem (e.g., both unit tests and integration tests), they should be put into
|
||||
separate suites, with the type of test as the last element in the suite name.
|
||||
Unless these tests are actually present, avoid using ``_test``, ``_unittest`` or
|
||||
similar in the suite name.
|
||||
subsystem (for example, both unit tests and integration tests), they should be
|
||||
put into separate suites, with the type of test as the last element in the suite
|
||||
name. Unless these tests are actually present, avoid using ``_test``, ``_unittest``
|
||||
or similar in the suite name.
|
||||
|
||||
The full test suite name (including the subsystem name) should be specified as
|
||||
the ``.name`` member of the ``kunit_suite`` struct, and forms the base for the
|
||||
module name (see below).
|
||||
|
||||
Example test suites could include:
|
||||
module name. For example, test suites could include:
|
||||
|
||||
``ext4_inode``
|
||||
Part of the ``ext4`` subsystem, testing the ``inode`` area.
|
||||
@ -109,26 +105,27 @@ Example test suites could include:
|
||||
The ``kasan`` subsystem has only one suite, so the suite name is the same as
|
||||
the subsystem name.
|
||||
|
||||
Avoid names like:
|
||||
Avoid names, for example:
|
||||
|
||||
``ext4_ext4_inode``
|
||||
There's no reason to state the subsystem twice.
|
||||
There is no reason to state the subsystem twice.
|
||||
``property_entry``
|
||||
The suite name is ambiguous without the subsystem name.
|
||||
``kasan_integration_test``
|
||||
Because there is only one suite in the ``kasan`` subsystem, the suite should
|
||||
just be called ``kasan``. There's no need to redundantly add
|
||||
``integration_test``. Should a separate test suite with, for example, unit
|
||||
tests be added, then that suite could be named ``kasan_unittest`` or similar.
|
||||
just be called as ``kasan``. Do not redundantly add
|
||||
``integration_test``. It should be a separate test suite. For example, if the
|
||||
unit tests are added, then that suite could be named as ``kasan_unittest`` or
|
||||
similar.
|
||||
|
||||
Test Cases
|
||||
----------
|
||||
|
||||
Individual tests consist of a single function which tests a constrained
|
||||
codepath, property, or function. In the test output, individual tests' results
|
||||
will show up as subtests of the suite's results.
|
||||
codepath, property, or function. In the test output, an individual test's
|
||||
results will show up as subtests of the suite's results.
|
||||
|
||||
Tests should be named after what they're testing. This is often the name of the
|
||||
Tests should be named after what they are testing. This is often the name of the
|
||||
function being tested, with a description of the input or codepath being tested.
|
||||
As tests are C functions, they should be named and written in accordance with
|
||||
the kernel coding style.
|
||||
@ -136,7 +133,7 @@ the kernel coding style.
|
||||
.. note::
|
||||
As tests are themselves functions, their names cannot conflict with
|
||||
other C identifiers in the kernel. This may require some creative
|
||||
naming. It's a good idea to make your test functions `static` to avoid
|
||||
naming. It is a good idea to make your test functions `static` to avoid
|
||||
polluting the global namespace.
|
||||
|
||||
Example test names include:
|
||||
@ -162,16 +159,16 @@ This Kconfig entry must:
|
||||
* be named ``CONFIG_<name>_KUNIT_TEST``: where <name> is the name of the test
|
||||
suite.
|
||||
* be listed either alongside the config entries for the driver/subsystem being
|
||||
tested, or be under [Kernel Hacking]→[Kernel Testing and Coverage]
|
||||
* depend on ``CONFIG_KUNIT``
|
||||
tested, or be under [Kernel Hacking]->[Kernel Testing and Coverage]
|
||||
* depend on ``CONFIG_KUNIT``.
|
||||
* be visible only if ``CONFIG_KUNIT_ALL_TESTS`` is not enabled.
|
||||
* have a default value of ``CONFIG_KUNIT_ALL_TESTS``.
|
||||
* have a brief description of KUnit in the help text
|
||||
* have a brief description of KUnit in the help text.
|
||||
|
||||
Unless there's a specific reason not to (e.g. the test is unable to be built as
|
||||
a module), Kconfig entries for tests should be tristate.
|
||||
If we are not able to meet above conditions (for example, the test is unable to
|
||||
be built as a module), Kconfig entries for tests should be tristate.
|
||||
|
||||
An example Kconfig entry:
|
||||
For example, a Kconfig entry might look like:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
@ -182,8 +179,8 @@ An example Kconfig entry:
|
||||
help
|
||||
This builds unit tests for foo.
|
||||
|
||||
For more information on KUnit and unit tests in general, please refer
|
||||
to the KUnit documentation in Documentation/dev-tools/kunit/.
|
||||
For more information on KUnit and unit tests in general,
|
||||
please refer to the KUnit documentation in Documentation/dev-tools/kunit/.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -1,57 +1,13 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===========
|
||||
Using KUnit
|
||||
===========
|
||||
|
||||
The purpose of this document is to describe what KUnit is, how it works, how it
|
||||
is intended to be used, and all the concepts and terminology that are needed to
|
||||
understand it. This guide assumes a working knowledge of the Linux kernel and
|
||||
some basic knowledge of testing.
|
||||
|
||||
For a high level introduction to KUnit, including setting up KUnit for your
|
||||
project, see Documentation/dev-tools/kunit/start.rst.
|
||||
|
||||
Organization of this document
|
||||
=============================
|
||||
|
||||
This document is organized into two main sections: Testing and Common Patterns.
|
||||
The first covers what unit tests are and how to use KUnit to write them. The
|
||||
second covers common testing patterns, e.g. how to isolate code and make it
|
||||
possible to unit test code that was otherwise un-unit-testable.
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
What is KUnit?
|
||||
--------------
|
||||
|
||||
"K" is short for "kernel" so "KUnit" is the "(Linux) Kernel Unit Testing
|
||||
Framework." KUnit is intended first and foremost for writing unit tests; it is
|
||||
general enough that it can be used to write integration tests; however, this is
|
||||
a secondary goal. KUnit has no ambition of being the only testing framework for
|
||||
the kernel; for example, it does not intend to be an end-to-end testing
|
||||
framework.
|
||||
|
||||
What is Unit Testing?
|
||||
---------------------
|
||||
|
||||
A `unit test <https://martinfowler.com/bliki/UnitTest.html>`_ is a test that
|
||||
tests code at the smallest possible scope, a *unit* of code. In the C
|
||||
programming language that's a function.
|
||||
|
||||
Unit tests should be written for all the publicly exposed functions in a
|
||||
compilation unit; so that is all the functions that are exported in either a
|
||||
*class* (defined below) or all functions which are **not** static.
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
=============
|
||||
|
||||
Test Cases
|
||||
~~~~~~~~~~
|
||||
----------
|
||||
|
||||
The fundamental unit in KUnit is the test case. A test case is a function with
|
||||
the signature ``void (*)(struct kunit *test)``. It calls a function to be tested
|
||||
the signature ``void (*)(struct kunit *test)``. It calls the function under test
|
||||
and then sets *expectations* for what should happen. For example:
|
||||
|
||||
.. code-block:: c
|
||||
@ -65,18 +21,19 @@ and then sets *expectations* for what should happen. For example:
|
||||
KUNIT_FAIL(test, "This test never passes.");
|
||||
}
|
||||
|
||||
In the above example ``example_test_success`` always passes because it does
|
||||
nothing; no expectations are set, so all expectations pass. On the other hand
|
||||
``example_test_failure`` always fails because it calls ``KUNIT_FAIL``, which is
|
||||
a special expectation that logs a message and causes the test case to fail.
|
||||
In the above example, ``example_test_success`` always passes because it does
|
||||
nothing; no expectations are set, and therefore all expectations pass. On the
|
||||
other hand ``example_test_failure`` always fails because it calls ``KUNIT_FAIL``,
|
||||
which is a special expectation that logs a message and causes the test case to
|
||||
fail.
|
||||
|
||||
Expectations
|
||||
~~~~~~~~~~~~
|
||||
An *expectation* is a way to specify that you expect a piece of code to do
|
||||
something in a test. An expectation is called like a function. A test is made
|
||||
by setting expectations about the behavior of a piece of code under test; when
|
||||
one or more of the expectations fail, the test case fails and information about
|
||||
the failure is logged. For example:
|
||||
An *expectation* specifies that we expect a piece of code to do something in a
|
||||
test. An expectation is called like a function. A test is made by setting
|
||||
expectations about the behavior of a piece of code under test. When one or more
|
||||
expectations fail, the test case fails and information about the failure is
|
||||
logged. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -86,29 +43,28 @@ the failure is logged. For example:
|
||||
KUNIT_EXPECT_EQ(test, 2, add(1, 1));
|
||||
}
|
||||
|
||||
In the above example ``add_test_basic`` makes a number of assertions about the
|
||||
behavior of a function called ``add``; the first parameter is always of type
|
||||
``struct kunit *``, which contains information about the current test context;
|
||||
the second parameter, in this case, is what the value is expected to be; the
|
||||
In the above example, ``add_test_basic`` makes a number of assertions about the
|
||||
behavior of a function called ``add``. The first parameter is always of type
|
||||
``struct kunit *``, which contains information about the current test context.
|
||||
The second parameter, in this case, is what the value is expected to be. The
|
||||
last value is what the value actually is. If ``add`` passes all of these
|
||||
expectations, the test case, ``add_test_basic`` will pass; if any one of these
|
||||
expectations fails, the test case will fail.
|
||||
|
||||
It is important to understand that a test case *fails* when any expectation is
|
||||
violated; however, the test will continue running, potentially trying other
|
||||
expectations until the test case ends or is otherwise terminated. This is as
|
||||
opposed to *assertions* which are discussed later.
|
||||
A test case *fails* when any expectation is violated; however, the test will
|
||||
continue to run, and try other expectations until the test case ends or is
|
||||
otherwise terminated. This is as opposed to *assertions* which are discussed
|
||||
later.
|
||||
|
||||
To learn about more expectations supported by KUnit, see
|
||||
Documentation/dev-tools/kunit/api/test.rst.
|
||||
To learn about more KUnit expectations, see Documentation/dev-tools/kunit/api/test.rst.
|
||||
|
||||
.. note::
|
||||
A single test case should be pretty short, pretty easy to understand,
|
||||
focused on a single behavior.
|
||||
A single test case should be short, easy to understand, and focused on a
|
||||
single behavior.
|
||||
|
||||
For example, if we wanted to properly test the add function above, we would
|
||||
create additional tests cases which would each test a different property that an
|
||||
add function should have like this:
|
||||
For example, if we want to rigorously test the ``add`` function above, create
|
||||
additional tests cases which would test each property that an ``add`` function
|
||||
should have as shown below:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -134,56 +90,43 @@ add function should have like this:
|
||||
KUNIT_EXPECT_EQ(test, INT_MIN, add(INT_MAX, 1));
|
||||
}
|
||||
|
||||
Notice how it is immediately obvious what all the properties that we are testing
|
||||
for are.
|
||||
|
||||
Assertions
|
||||
~~~~~~~~~~
|
||||
|
||||
KUnit also has the concept of an *assertion*. An assertion is just like an
|
||||
expectation except the assertion immediately terminates the test case if it is
|
||||
not satisfied.
|
||||
|
||||
For example:
|
||||
An assertion is like an expectation, except that the assertion immediately
|
||||
terminates the test case if the condition is not satisfied. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void mock_test_do_expect_default_return(struct kunit *test)
|
||||
static void test_sort(struct kunit *test)
|
||||
{
|
||||
struct mock_test_context *ctx = test->priv;
|
||||
struct mock *mock = ctx->mock;
|
||||
int param0 = 5, param1 = -5;
|
||||
const char *two_param_types[] = {"int", "int"};
|
||||
const void *two_params[] = {¶m0, ¶m1};
|
||||
const void *ret;
|
||||
|
||||
ret = mock->do_expect(mock,
|
||||
"test_printk", test_printk,
|
||||
two_param_types, two_params,
|
||||
ARRAY_SIZE(two_params));
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ret);
|
||||
KUNIT_EXPECT_EQ(test, -4, *((int *) ret));
|
||||
int *a, i, r = 1;
|
||||
a = kunit_kmalloc_array(test, TEST_LEN, sizeof(*a), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, a);
|
||||
for (i = 0; i < TEST_LEN; i++) {
|
||||
r = (r * 725861) % 6599;
|
||||
a[i] = r;
|
||||
}
|
||||
sort(a, TEST_LEN, sizeof(*a), cmpint, NULL);
|
||||
for (i = 0; i < TEST_LEN-1; i++)
|
||||
KUNIT_EXPECT_LE(test, a[i], a[i + 1]);
|
||||
}
|
||||
|
||||
In this example, the method under test should return a pointer to a value, so
|
||||
if the pointer returned by the method is null or an errno, we don't want to
|
||||
bother continuing the test since the following expectation could crash the test
|
||||
case. `ASSERT_NOT_ERR_OR_NULL(...)` allows us to bail out of the test case if
|
||||
the appropriate conditions have not been satisfied to complete the test.
|
||||
In this example, the method under test should return pointer to a value. If the
|
||||
pointer returns null or an errno, we want to stop the test since the following
|
||||
expectation could crash the test case. `ASSERT_NOT_ERR_OR_NULL(...)` allows us
|
||||
to bail out of the test case if the appropriate conditions are not satisfied to
|
||||
complete the test.
|
||||
|
||||
Test Suites
|
||||
~~~~~~~~~~~
|
||||
|
||||
Now obviously one unit test isn't very helpful; the power comes from having
|
||||
many test cases covering all of a unit's behaviors. Consequently it is common
|
||||
to have many *similar* tests; in order to reduce duplication in these closely
|
||||
related tests most unit testing frameworks - including KUnit - provide the
|
||||
concept of a *test suite*. A *test suite* is just a collection of test cases
|
||||
for a unit of code with a set up function that gets invoked before every test
|
||||
case and then a tear down function that gets invoked after every test case
|
||||
completes.
|
||||
|
||||
Example:
|
||||
We need many test cases covering all the unit's behaviors. It is common to have
|
||||
many similar tests. In order to reduce duplication in these closely related
|
||||
tests, most unit testing frameworks (including KUnit) provide the concept of a
|
||||
*test suite*. A test suite is a collection of test cases for a unit of code
|
||||
with a setup function that gets invoked before every test case and then a tear
|
||||
down function that gets invoked after every test case completes. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -202,23 +145,48 @@ Example:
|
||||
};
|
||||
kunit_test_suite(example_test_suite);
|
||||
|
||||
In the above example the test suite, ``example_test_suite``, would run the test
|
||||
cases ``example_test_foo``, ``example_test_bar``, and ``example_test_baz``;
|
||||
each would have ``example_test_init`` called immediately before it and would
|
||||
have ``example_test_exit`` called immediately after it.
|
||||
In the above example, the test suite ``example_test_suite`` would run the test
|
||||
cases ``example_test_foo``, ``example_test_bar``, and ``example_test_baz``. Each
|
||||
would have ``example_test_init`` called immediately before it and
|
||||
``example_test_exit`` called immediately after it.
|
||||
``kunit_test_suite(example_test_suite)`` registers the test suite with the
|
||||
KUnit test framework.
|
||||
|
||||
.. note::
|
||||
A test case will only be run if it is associated with a test suite.
|
||||
A test case will only run if it is associated with a test suite.
|
||||
|
||||
``kunit_test_suite(...)`` is a macro which tells the linker to put the specified
|
||||
test suite in a special linker section so that it can be run by KUnit either
|
||||
after late_init, or when the test module is loaded (depending on whether the
|
||||
test was built in or not).
|
||||
``kunit_test_suite(...)`` is a macro which tells the linker to put the
|
||||
specified test suite in a special linker section so that it can be run by KUnit
|
||||
either after ``late_init``, or when the test module is loaded (if the test was
|
||||
built as a module).
|
||||
|
||||
For more information on these types of things see the
|
||||
Documentation/dev-tools/kunit/api/test.rst.
|
||||
For more information, see Documentation/dev-tools/kunit/api/test.rst.
|
||||
|
||||
Writing Tests For Other Architectures
|
||||
-------------------------------------
|
||||
|
||||
It is better to write tests that run on UML to tests that only run under a
|
||||
particular architecture. It is better to write tests that run under QEMU or
|
||||
another easy to obtain (and monetarily free) software environment to a specific
|
||||
piece of hardware.
|
||||
|
||||
Nevertheless, there are still valid reasons to write a test that is architecture
|
||||
or hardware specific. For example, we might want to test code that really
|
||||
belongs in ``arch/some-arch/*``. Even so, try to write the test so that it does
|
||||
not depend on physical hardware. Some of our test cases may not need hardware,
|
||||
only few tests actually require the hardware to test it. When hardware is not
|
||||
available, instead of disabling tests, we can skip them.
|
||||
|
||||
Now that we have narrowed down exactly what bits are hardware specific, the
|
||||
actual procedure for writing and running the tests is same as writing normal
|
||||
KUnit tests.
|
||||
|
||||
.. important::
|
||||
We may have to reset hardware state. If this is not possible, we may only
|
||||
be able to run one test case per invocation.
|
||||
|
||||
.. TODO(brendanhiggins@google.com): Add an actual example of an architecture-
|
||||
dependent KUnit test.
|
||||
|
||||
Common Patterns
|
||||
===============
|
||||
@ -226,43 +194,39 @@ Common Patterns
|
||||
Isolating Behavior
|
||||
------------------
|
||||
|
||||
The most important aspect of unit testing that other forms of testing do not
|
||||
provide is the ability to limit the amount of code under test to a single unit.
|
||||
In practice, this is only possible by being able to control what code gets run
|
||||
when the unit under test calls a function and this is usually accomplished
|
||||
through some sort of indirection where a function is exposed as part of an API
|
||||
such that the definition of that function can be changed without affecting the
|
||||
rest of the code base. In the kernel this primarily comes from two constructs,
|
||||
classes, structs that contain function pointers that are provided by the
|
||||
implementer, and architecture-specific functions which have definitions selected
|
||||
at compile time.
|
||||
Unit testing limits the amount of code under test to a single unit. It controls
|
||||
what code gets run when the unit under test calls a function. Where a function
|
||||
is exposed as part of an API such that the definition of that function can be
|
||||
changed without affecting the rest of the code base. In the kernel, this comes
|
||||
from two constructs: classes, which are structs that contain function pointers
|
||||
provided by the implementer, and architecture-specific functions, which have
|
||||
definitions selected at compile time.
|
||||
|
||||
Classes
|
||||
~~~~~~~
|
||||
|
||||
Classes are not a construct that is built into the C programming language;
|
||||
however, it is an easily derived concept. Accordingly, pretty much every project
|
||||
that does not use a standardized object oriented library (like GNOME's GObject)
|
||||
has their own slightly different way of doing object oriented programming; the
|
||||
Linux kernel is no exception.
|
||||
however, it is an easily derived concept. Accordingly, in most cases, every
|
||||
project that does not use a standardized object oriented library (like GNOME's
|
||||
GObject) has their own slightly different way of doing object oriented
|
||||
programming; the Linux kernel is no exception.
|
||||
|
||||
The central concept in kernel object oriented programming is the class. In the
|
||||
kernel, a *class* is a struct that contains function pointers. This creates a
|
||||
contract between *implementers* and *users* since it forces them to use the
|
||||
same function signature without having to call the function directly. In order
|
||||
for it to truly be a class, the function pointers must specify that a pointer
|
||||
to the class, known as a *class handle*, be one of the parameters; this makes
|
||||
it possible for the member functions (also known as *methods*) to have access
|
||||
to member variables (more commonly known as *fields*) allowing the same
|
||||
implementation to have multiple *instances*.
|
||||
same function signature without having to call the function directly. To be a
|
||||
class, the function pointers must specify that a pointer to the class, known as
|
||||
a *class handle*, be one of the parameters. Thus the member functions (also
|
||||
known as *methods*) have access to member variables (also known as *fields*)
|
||||
allowing the same implementation to have multiple *instances*.
|
||||
|
||||
Typically a class can be *overridden* by *child classes* by embedding the
|
||||
*parent class* in the child class. Then when a method provided by the child
|
||||
class is called, the child implementation knows that the pointer passed to it is
|
||||
of a parent contained within the child; because of this, the child can compute
|
||||
the pointer to itself because the pointer to the parent is always a fixed offset
|
||||
from the pointer to the child; this offset is the offset of the parent contained
|
||||
in the child struct. For example:
|
||||
A class can be *overridden* by *child classes* by embedding the *parent class*
|
||||
in the child class. Then when the child class *method* is called, the child
|
||||
implementation knows that the pointer passed to it is of a parent contained
|
||||
within the child. Thus, the child can compute the pointer to itself because the
|
||||
pointer to the parent is always a fixed offset from the pointer to the child.
|
||||
This offset is the offset of the parent contained in the child struct. For
|
||||
example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -290,8 +254,8 @@ in the child struct. For example:
|
||||
self->width = width;
|
||||
}
|
||||
|
||||
In this example (as in most kernel code) the operation of computing the pointer
|
||||
to the child from the pointer to the parent is done by ``container_of``.
|
||||
In this example, computing the pointer to the child from the pointer to the
|
||||
parent is done by ``container_of``.
|
||||
|
||||
Faking Classes
|
||||
~~~~~~~~~~~~~~
|
||||
@ -300,14 +264,11 @@ In order to unit test a piece of code that calls a method in a class, the
|
||||
behavior of the method must be controllable, otherwise the test ceases to be a
|
||||
unit test and becomes an integration test.
|
||||
|
||||
A fake just provides an implementation of a piece of code that is different than
|
||||
what runs in a production instance, but behaves identically from the standpoint
|
||||
of the callers; this is usually done to replace a dependency that is hard to
|
||||
deal with, or is slow.
|
||||
|
||||
A good example for this might be implementing a fake EEPROM that just stores the
|
||||
"contents" in an internal buffer. For example, let's assume we have a class that
|
||||
represents an EEPROM:
|
||||
A fake class implements a piece of code that is different than what runs in a
|
||||
production instance, but behaves identical from the standpoint of the callers.
|
||||
This is done to replace a dependency that is hard to deal with, or is slow. For
|
||||
example, implementing a fake EEPROM that stores the "contents" in an
|
||||
internal buffer. Assume we have a class that represents an EEPROM:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -316,7 +277,7 @@ represents an EEPROM:
|
||||
ssize_t (*write)(struct eeprom *this, size_t offset, const char *buffer, size_t count);
|
||||
};
|
||||
|
||||
And we want to test some code that buffers writes to the EEPROM:
|
||||
And we want to test code that buffers writes to the EEPROM:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -329,7 +290,7 @@ And we want to test some code that buffers writes to the EEPROM:
|
||||
struct eeprom_buffer *new_eeprom_buffer(struct eeprom *eeprom);
|
||||
void destroy_eeprom_buffer(struct eeprom *eeprom);
|
||||
|
||||
We can easily test this code by *faking out* the underlying EEPROM:
|
||||
We can test this code by *faking out* the underlying EEPROM:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -456,14 +417,14 @@ We can now use it to test ``struct eeprom_buffer``:
|
||||
destroy_eeprom_buffer(ctx->eeprom_buffer);
|
||||
}
|
||||
|
||||
Testing against multiple inputs
|
||||
Testing Against Multiple Inputs
|
||||
-------------------------------
|
||||
|
||||
Testing just a few inputs might not be enough to have confidence that the code
|
||||
works correctly, e.g. for a hash function.
|
||||
Testing just a few inputs is not enough to ensure that the code works correctly,
|
||||
for example: testing a hash function.
|
||||
|
||||
In such cases, it can be helpful to have a helper macro or function, e.g. this
|
||||
fictitious example for ``sha1sum(1)``
|
||||
We can write a helper macro or function. The function is called for each input.
|
||||
For example, to test ``sha1sum(1)``, we can write:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -475,16 +436,15 @@ fictitious example for ``sha1sum(1)``
|
||||
TEST_SHA1("hello world", "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
|
||||
TEST_SHA1("hello world!", "430ce34d020724ed75a196dfc2ad67c77772d169");
|
||||
|
||||
Note the use of the ``_MSG`` version of ``KUNIT_EXPECT_STREQ`` to print a more
|
||||
detailed error and make the assertions clearer within the helper macros.
|
||||
|
||||
Note the use of ``KUNIT_EXPECT_STREQ_MSG`` to give more context when it fails
|
||||
and make it easier to track down. (Yes, in this example, ``want`` is likely
|
||||
going to be unique enough on its own).
|
||||
The ``_MSG`` variants are useful when the same expectation is called multiple
|
||||
times (in a loop or helper function) and thus the line number is not enough to
|
||||
identify what failed, as shown below.
|
||||
|
||||
The ``_MSG`` variants are even more useful when the same expectation is called
|
||||
multiple times (in a loop or helper function) and thus the line number isn't
|
||||
enough to identify what failed, like below.
|
||||
|
||||
In some cases, it can be helpful to write a *table-driven test* instead, e.g.
|
||||
In complicated cases, we recommend using a *table-driven test* compared to the
|
||||
helper macro variation, for example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
@ -513,17 +473,18 @@ In some cases, it can be helpful to write a *table-driven test* instead, e.g.
|
||||
}
|
||||
|
||||
|
||||
There's more boilerplate involved, but it can:
|
||||
There is more boilerplate code involved, but it can:
|
||||
|
||||
* be more readable when there are multiple inputs/outputs thanks to field names,
|
||||
* be more readable when there are multiple inputs/outputs (due to field names).
|
||||
|
||||
* E.g. see ``fs/ext4/inode-test.c`` for an example of both.
|
||||
* reduce duplication if test cases can be shared across multiple tests.
|
||||
* For example, see ``fs/ext4/inode-test.c``.
|
||||
|
||||
* E.g. if we wanted to also test ``sha256sum``, we could add a ``sha256``
|
||||
* reduce duplication if test cases are shared across multiple tests.
|
||||
|
||||
* For example: if we want to test ``sha256sum``, we could add a ``sha256``
|
||||
field and reuse ``cases``.
|
||||
|
||||
* be converted to a "parameterized test", see below.
|
||||
* be converted to a "parameterized test".
|
||||
|
||||
Parameterized Testing
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -531,7 +492,7 @@ Parameterized Testing
|
||||
The table-driven testing pattern is common enough that KUnit has special
|
||||
support for it.
|
||||
|
||||
Reusing the same ``cases`` array from above, we can write the test as a
|
||||
By reusing the same ``cases`` array from above, we can write the test as a
|
||||
"parameterized test" with the following.
|
||||
|
||||
.. code-block:: c
|
||||
@ -582,193 +543,160 @@ Reusing the same ``cases`` array from above, we can write the test as a
|
||||
|
||||
.. _kunit-on-non-uml:
|
||||
|
||||
KUnit on non-UML architectures
|
||||
==============================
|
||||
Exiting Early on Failed Expectations
|
||||
------------------------------------
|
||||
|
||||
By default KUnit uses UML as a way to provide dependencies for code under test.
|
||||
Under most circumstances KUnit's usage of UML should be treated as an
|
||||
implementation detail of how KUnit works under the hood. Nevertheless, there
|
||||
are instances where being able to run architecture-specific code or test
|
||||
against real hardware is desirable. For these reasons KUnit supports running on
|
||||
other architectures.
|
||||
We can use ``KUNIT_EXPECT_EQ`` to mark the test as failed and continue
|
||||
execution. In some cases, it is unsafe to continue. We can use the
|
||||
``KUNIT_ASSERT`` variant to exit on failure.
|
||||
|
||||
Running existing KUnit tests on non-UML architectures
|
||||
-----------------------------------------------------
|
||||
.. code-block:: c
|
||||
|
||||
There are some special considerations when running existing KUnit tests on
|
||||
non-UML architectures:
|
||||
void example_test_user_alloc_function(struct kunit *test)
|
||||
{
|
||||
void *object = alloc_some_object_for_me();
|
||||
|
||||
* Hardware may not be deterministic, so a test that always passes or fails
|
||||
when run under UML may not always do so on real hardware.
|
||||
* Hardware and VM environments may not be hermetic. KUnit tries its best to
|
||||
provide a hermetic environment to run tests; however, it cannot manage state
|
||||
that it doesn't know about outside of the kernel. Consequently, tests that
|
||||
may be hermetic on UML may not be hermetic on other architectures.
|
||||
* Some features and tooling may not be supported outside of UML.
|
||||
* Hardware and VMs are slower than UML.
|
||||
/* Make sure we got a valid pointer back. */
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, object);
|
||||
do_something_with_object(object);
|
||||
}
|
||||
|
||||
None of these are reasons not to run your KUnit tests on real hardware; they are
|
||||
only things to be aware of when doing so.
|
||||
Allocating Memory
|
||||
-----------------
|
||||
|
||||
Currently, the KUnit Wrapper (``tools/testing/kunit/kunit.py``) (aka
|
||||
kunit_tool) only fully supports running tests inside of UML and QEMU; however,
|
||||
this is only due to our own time limitations as humans working on KUnit. It is
|
||||
entirely possible to support other emulators and even actual hardware, but for
|
||||
now QEMU and UML is what is fully supported within the KUnit Wrapper. Again, to
|
||||
be clear, this is just the Wrapper. The actualy KUnit tests and the KUnit
|
||||
library they are written in is fully architecture agnostic and can be used in
|
||||
virtually any setup, you just won't have the benefit of typing a single command
|
||||
out of the box and having everything magically work perfectly.
|
||||
Where you might use ``kzalloc``, you can instead use ``kunit_kzalloc`` as KUnit
|
||||
will then ensure that the memory is freed once the test completes.
|
||||
|
||||
Again, all core KUnit framework features are fully supported on all
|
||||
architectures, and using them is straightforward: Most popular architectures
|
||||
are supported directly in the KUnit Wrapper via QEMU. Currently, supported
|
||||
architectures on QEMU include:
|
||||
This is useful because it lets us use the ``KUNIT_ASSERT_EQ`` macros to exit
|
||||
early from a test without having to worry about remembering to call ``kfree``.
|
||||
For example:
|
||||
|
||||
* i386
|
||||
* x86_64
|
||||
* arm
|
||||
* arm64
|
||||
* alpha
|
||||
* powerpc
|
||||
* riscv
|
||||
* s390
|
||||
* sparc
|
||||
.. code-block:: c
|
||||
|
||||
In order to run KUnit tests on one of these architectures via QEMU with the
|
||||
KUnit wrapper, all you need to do is specify the flags ``--arch`` and
|
||||
``--cross_compile`` when invoking the KUnit Wrapper. For example, we could run
|
||||
the default KUnit tests on ARM in the following manner (assuming we have an ARM
|
||||
toolchain installed):
|
||||
void example_test_allocation(struct kunit *test)
|
||||
{
|
||||
char *buffer = kunit_kzalloc(test, 16, GFP_KERNEL);
|
||||
/* Ensure allocation succeeded. */
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tools/testing/kunit/kunit.py run --timeout=60 --jobs=12 --arch=arm --cross_compile=arm-linux-gnueabihf-
|
||||
|
||||
Alternatively, if you want to run your tests on real hardware or in some other
|
||||
emulation environment, all you need to do is to take your kunitconfig, your
|
||||
Kconfig options for the tests you would like to run, and merge them into
|
||||
whatever config your are using for your platform. That's it!
|
||||
|
||||
For example, let's say you have the following kunitconfig:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_KUNIT_EXAMPLE_TEST=y
|
||||
|
||||
If you wanted to run this test on an x86 VM, you might add the following config
|
||||
options to your ``.config``:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_KUNIT_EXAMPLE_TEST=y
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
|
||||
All these new options do is enable support for a common serial console needed
|
||||
for logging.
|
||||
|
||||
Next, you could build a kernel with these tests as follows:
|
||||
KUNIT_ASSERT_STREQ(test, buffer, "");
|
||||
}
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
Testing Static Functions
|
||||
------------------------
|
||||
|
||||
make ARCH=x86 olddefconfig
|
||||
make ARCH=x86
|
||||
If we do not want to expose functions or variables for testing, one option is to
|
||||
conditionally ``#include`` the test file at the end of your .c file. For
|
||||
example:
|
||||
|
||||
Once you have built a kernel, you could run it on QEMU as follows:
|
||||
.. code-block:: c
|
||||
|
||||
.. code-block:: bash
|
||||
/* In my_file.c */
|
||||
|
||||
qemu-system-x86_64 -enable-kvm \
|
||||
-m 1024 \
|
||||
-kernel arch/x86_64/boot/bzImage \
|
||||
-append 'console=ttyS0' \
|
||||
--nographic
|
||||
static int do_interesting_thing();
|
||||
|
||||
Interspersed in the kernel logs you might see the following:
|
||||
#ifdef CONFIG_MY_KUNIT_TEST
|
||||
#include "my_kunit_test.c"
|
||||
#endif
|
||||
|
||||
.. code-block:: none
|
||||
Injecting Test-Only Code
|
||||
------------------------
|
||||
|
||||
TAP version 14
|
||||
# Subtest: example
|
||||
1..1
|
||||
# example_simple_test: initializing
|
||||
ok 1 - example_simple_test
|
||||
ok 1 - example
|
||||
Similar to as shown above, we can add test-specific logic. For example:
|
||||
|
||||
Congratulations, you just ran a KUnit test on the x86 architecture!
|
||||
.. code-block:: c
|
||||
|
||||
In a similar manner, kunit and kunit tests can also be built as modules,
|
||||
so if you wanted to run tests in this way you might add the following config
|
||||
options to your ``.config``:
|
||||
/* In my_file.h */
|
||||
|
||||
.. code-block:: none
|
||||
#ifdef CONFIG_MY_KUNIT_TEST
|
||||
/* Defined in my_kunit_test.c */
|
||||
void test_only_hook(void);
|
||||
#else
|
||||
void test_only_hook(void) { }
|
||||
#endif
|
||||
|
||||
CONFIG_KUNIT=m
|
||||
CONFIG_KUNIT_EXAMPLE_TEST=m
|
||||
This test-only code can be made more useful by accessing the current ``kunit_test``
|
||||
as shown in next section: *Accessing The Current Test*.
|
||||
|
||||
Once the kernel is built and installed, a simple
|
||||
Accessing The Current Test
|
||||
--------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
In some cases, we need to call test-only code from outside the test file.
|
||||
For example, see example in section *Injecting Test-Only Code* or if
|
||||
we are providing a fake implementation of an ops struct. Using
|
||||
``kunit_test`` field in ``task_struct``, we can access it via
|
||||
``current->kunit_test``.
|
||||
|
||||
modprobe example-test
|
||||
The example below includes how to implement "mocking":
|
||||
|
||||
...will run the tests.
|
||||
.. code-block:: c
|
||||
|
||||
.. note::
|
||||
Note that you should make sure your test depends on ``KUNIT=y`` in Kconfig
|
||||
if the test does not support module build. Otherwise, it will trigger
|
||||
compile errors if ``CONFIG_KUNIT`` is ``m``.
|
||||
#include <linux/sched.h> /* for current */
|
||||
|
||||
Writing new tests for other architectures
|
||||
-----------------------------------------
|
||||
struct test_data {
|
||||
int foo_result;
|
||||
int want_foo_called_with;
|
||||
};
|
||||
|
||||
The first thing you must do is ask yourself whether it is necessary to write a
|
||||
KUnit test for a specific architecture, and then whether it is necessary to
|
||||
write that test for a particular piece of hardware. In general, writing a test
|
||||
that depends on having access to a particular piece of hardware or software (not
|
||||
included in the Linux source repo) should be avoided at all costs.
|
||||
static int fake_foo(int arg)
|
||||
{
|
||||
struct kunit *test = current->kunit_test;
|
||||
struct test_data *test_data = test->priv;
|
||||
|
||||
Even if you only ever plan on running your KUnit test on your hardware
|
||||
configuration, other people may want to run your tests and may not have access
|
||||
to your hardware. If you write your test to run on UML, then anyone can run your
|
||||
tests without knowing anything about your particular setup, and you can still
|
||||
run your tests on your hardware setup just by compiling for your architecture.
|
||||
KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
|
||||
return test_data->foo_result;
|
||||
}
|
||||
|
||||
.. important::
|
||||
Always prefer tests that run on UML to tests that only run under a particular
|
||||
architecture, and always prefer tests that run under QEMU or another easy
|
||||
(and monetarily free) to obtain software environment to a specific piece of
|
||||
hardware.
|
||||
static void example_simple_test(struct kunit *test)
|
||||
{
|
||||
/* Assume priv (private, a member used to pass test data from
|
||||
* the init function) is allocated in the suite's .init */
|
||||
struct test_data *test_data = test->priv;
|
||||
|
||||
Nevertheless, there are still valid reasons to write an architecture or hardware
|
||||
specific test: for example, you might want to test some code that really belongs
|
||||
in ``arch/some-arch/*``. Even so, try your best to write the test so that it
|
||||
does not depend on physical hardware: if some of your test cases don't need the
|
||||
hardware, only require the hardware for tests that actually need it.
|
||||
test_data->foo_result = 42;
|
||||
test_data->want_foo_called_with = 1;
|
||||
|
||||
Now that you have narrowed down exactly what bits are hardware specific, the
|
||||
actual procedure for writing and running the tests is pretty much the same as
|
||||
writing normal KUnit tests. One special caveat is that you have to reset
|
||||
hardware state in between test cases; if this is not possible, you may only be
|
||||
able to run one test case per invocation.
|
||||
/* In a real test, we'd probably pass a pointer to fake_foo somewhere
|
||||
* like an ops struct, etc. instead of calling it directly. */
|
||||
KUNIT_EXPECT_EQ(test, fake_foo(1), 42);
|
||||
}
|
||||
|
||||
.. TODO(brendanhiggins@google.com): Add an actual example of an architecture-
|
||||
dependent KUnit test.
|
||||
In this example, we are using the ``priv`` member of ``struct kunit`` as a way
|
||||
of passing data to the test from the init function. In general ``priv`` is
|
||||
pointer that can be used for any user data. This is preferred over static
|
||||
variables, as it avoids concurrency issues.
|
||||
|
||||
KUnit debugfs representation
|
||||
============================
|
||||
When kunit test suites are initialized, they create an associated directory
|
||||
in ``/sys/kernel/debug/kunit/<test-suite>``. The directory contains one file
|
||||
Had we wanted something more flexible, we could have used a named ``kunit_resource``.
|
||||
Each test can have multiple resources which have string names providing the same
|
||||
flexibility as a ``priv`` member, but also, for example, allowing helper
|
||||
functions to create resources without conflicting with each other. It is also
|
||||
possible to define a clean up function for each resource, making it easy to
|
||||
avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/test.rst.
|
||||
|
||||
- results: "cat results" displays results of each test case and the results
|
||||
of the entire suite for the last test run.
|
||||
Failing The Current Test
|
||||
------------------------
|
||||
|
||||
If we want to fail the current test, we can use ``kunit_fail_current_test(fmt, args...)``
|
||||
which is defined in ``<kunit/test-bug.h>`` and does not require pulling in ``<kunit/test.h>``.
|
||||
For example, we have an option to enable some extra debug checks on some data
|
||||
structures as shown below:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <kunit/test-bug.h>
|
||||
|
||||
#ifdef CONFIG_EXTRA_DEBUG_CHECKS
|
||||
static void validate_my_data(struct data *data)
|
||||
{
|
||||
if (is_valid(data))
|
||||
return;
|
||||
|
||||
kunit_fail_current_test("data %p is invalid", data);
|
||||
|
||||
/* Normal, non-KUnit, error reporting code here. */
|
||||
}
|
||||
#else
|
||||
static void my_debug_function(void) { }
|
||||
#endif
|
||||
|
||||
The debugfs representation is primarily of use when kunit test suites are
|
||||
run in a native environment, either as modules or builtin. Having a way
|
||||
to display results like this is valuable as otherwise results can be
|
||||
intermixed with other events in dmesg output. The maximum size of each
|
||||
results file is KUNIT_LOG_SIZE bytes (defined in ``include/kunit/test.h``).
|
||||
|
@ -65,7 +65,9 @@ DT_DOCS = $(patsubst $(srctree)/%,%,$(shell $(find_all_cmd)))
|
||||
override DTC_FLAGS := \
|
||||
-Wno-avoid_unnecessary_addr_size \
|
||||
-Wno-graph_child_address \
|
||||
-Wno-interrupt_provider
|
||||
-Wno-interrupt_provider \
|
||||
-Wno-unique_unit_address \
|
||||
-Wunique_unit_address_if_enabled
|
||||
|
||||
# Disable undocumented compatible checks until warning free
|
||||
override DT_CHECKER_FLAGS ?=
|
||||
|
@ -166,16 +166,6 @@ examples:
|
||||
};
|
||||
};
|
||||
|
||||
dma0: dma@3000000 {
|
||||
/* compatible = "arm,pl330", "arm,primecell"; */
|
||||
cci-control-port = <&cci_control0>;
|
||||
reg = <0x0 0x3000000 0x0 0x1000>;
|
||||
interrupts = <10>;
|
||||
#dma-cells = <1>;
|
||||
#dma-channels = <8>;
|
||||
#dma-requests = <32>;
|
||||
};
|
||||
|
||||
cci@2c090000 {
|
||||
compatible = "arm,cci-400";
|
||||
#address-cells = <1>;
|
||||
|
@ -1,27 +0,0 @@
|
||||
* ARM DynamIQ Shared Unit (DSU) Performance Monitor Unit (PMU)
|
||||
|
||||
ARM DyanmIQ Shared Unit (DSU) integrates one or more CPU cores
|
||||
with a shared L3 memory system, control logic and external interfaces to
|
||||
form a multicore cluster. The PMU enables to gather various statistics on
|
||||
the operations of the DSU. The PMU provides independent 32bit counters that
|
||||
can count any of the supported events, along with a 64bit cycle counter.
|
||||
The PMU is accessed via CPU system registers and has no MMIO component.
|
||||
|
||||
** DSU PMU required properties:
|
||||
|
||||
- compatible : should be one of :
|
||||
|
||||
"arm,dsu-pmu"
|
||||
|
||||
- interrupts : Exactly 1 SPI must be listed.
|
||||
|
||||
- cpus : List of phandles for the CPUs connected to this DSU instance.
|
||||
|
||||
|
||||
** Example:
|
||||
|
||||
dsu-pmu-0 {
|
||||
compatible = "arm,dsu-pmu";
|
||||
interrupts = <GIC_SPI 02 IRQ_TYPE_LEVEL_HIGH>;
|
||||
cpus = <&cpu_0>, <&cpu_1>;
|
||||
};
|
@ -137,6 +137,9 @@ properties:
|
||||
- arm,cortex-a75
|
||||
- arm,cortex-a76
|
||||
- arm,cortex-a77
|
||||
- arm,cortex-a78
|
||||
- arm,cortex-a510
|
||||
- arm,cortex-a710
|
||||
- arm,cortex-m0
|
||||
- arm,cortex-m0+
|
||||
- arm,cortex-m1
|
||||
@ -145,8 +148,12 @@ properties:
|
||||
- arm,cortex-r4
|
||||
- arm,cortex-r5
|
||||
- arm,cortex-r7
|
||||
- arm,cortex-x1
|
||||
- arm,cortex-x2
|
||||
- arm,neoverse-e1
|
||||
- arm,neoverse-n1
|
||||
- arm,neoverse-n2
|
||||
- arm,neoverse-v1
|
||||
- brcm,brahma-b15
|
||||
- brcm,brahma-b53
|
||||
- brcm,vulcan
|
||||
|
@ -14,6 +14,7 @@ Required Properties:
|
||||
- "mediatek,mt7622-apmixedsys"
|
||||
- "mediatek,mt7623-apmixedsys", "mediatek,mt2701-apmixedsys"
|
||||
- "mediatek,mt7629-apmixedsys"
|
||||
- "mediatek,mt7986-apmixedsys"
|
||||
- "mediatek,mt8135-apmixedsys"
|
||||
- "mediatek,mt8167-apmixedsys", "syscon"
|
||||
- "mediatek,mt8173-apmixedsys"
|
||||
|
@ -10,6 +10,7 @@ Required Properties:
|
||||
- "mediatek,mt7622-ethsys", "syscon"
|
||||
- "mediatek,mt7623-ethsys", "mediatek,mt2701-ethsys", "syscon"
|
||||
- "mediatek,mt7629-ethsys", "syscon"
|
||||
- "mediatek,mt7986-ethsys", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
- #reset-cells: Must be 1
|
||||
|
||||
|
@ -15,6 +15,7 @@ Required Properties:
|
||||
- "mediatek,mt7622-infracfg", "syscon"
|
||||
- "mediatek,mt7623-infracfg", "mediatek,mt2701-infracfg", "syscon"
|
||||
- "mediatek,mt7629-infracfg", "syscon"
|
||||
- "mediatek,mt7986-infracfg", "syscon"
|
||||
- "mediatek,mt8135-infracfg", "syscon"
|
||||
- "mediatek,mt8167-infracfg", "syscon"
|
||||
- "mediatek,mt8173-infracfg", "syscon"
|
||||
|
@ -8,6 +8,8 @@ Required Properties:
|
||||
- compatible: Should be:
|
||||
- "mediatek,mt7622-sgmiisys", "syscon"
|
||||
- "mediatek,mt7629-sgmiisys", "syscon"
|
||||
- "mediatek,mt7986-sgmiisys_0", "syscon"
|
||||
- "mediatek,mt7986-sgmiisys_1", "syscon"
|
||||
- #clock-cells: Must be 1
|
||||
|
||||
The SGMIISYS controller uses the common clk binding from
|
||||
|
@ -14,6 +14,7 @@ Required Properties:
|
||||
- "mediatek,mt7622-topckgen"
|
||||
- "mediatek,mt7623-topckgen", "mediatek,mt2701-topckgen"
|
||||
- "mediatek,mt7629-topckgen"
|
||||
- "mediatek,mt7986-topckgen", "syscon"
|
||||
- "mediatek,mt8135-topckgen"
|
||||
- "mediatek,mt8167-topckgen", "syscon"
|
||||
- "mediatek,mt8173-topckgen"
|
||||
|
@ -44,10 +44,18 @@ properties:
|
||||
- arm,cortex-a76-pmu
|
||||
- arm,cortex-a77-pmu
|
||||
- arm,cortex-a78-pmu
|
||||
- arm,cortex-a510-pmu
|
||||
- arm,cortex-a710-pmu
|
||||
- arm,cortex-x1-pmu
|
||||
- arm,cortex-x2-pmu
|
||||
- arm,neoverse-e1-pmu
|
||||
- arm,neoverse-n1-pmu
|
||||
- arm,neoverse-n2-pmu
|
||||
- arm,neoverse-v1-pmu
|
||||
- brcm,vulcan-pmu
|
||||
- cavium,thunder-pmu
|
||||
- nvidia,denver-pmu
|
||||
- nvidia,carmel-pmu
|
||||
- qcom,krait-pmu
|
||||
- qcom,scorpion-pmu
|
||||
- qcom,scorpion-mp-pmu
|
||||
|
@ -20,6 +20,11 @@ properties:
|
||||
- const: st-ericsson,mop500
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
- description: ST-Ericsson HREF520
|
||||
items:
|
||||
- const: st-ericsson,href520
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
- description: ST-Ericsson HREF (v60+)
|
||||
items:
|
||||
- const: st-ericsson,hrefv60+
|
||||
@ -30,9 +35,34 @@ properties:
|
||||
- const: calaosystems,snowball-a9500
|
||||
- const: st-ericsson,u9500
|
||||
|
||||
- description: Samsung Galaxy Ace 2 (GT-I8160)
|
||||
items:
|
||||
- const: samsung,codina
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
- description: Samsung Galaxy Beam (GT-I8530)
|
||||
items:
|
||||
- const: samsung,gavini
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
- description: Samsung Galaxy S III mini (GT-I8190)
|
||||
items:
|
||||
- const: samsung,golden
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
- description: Samsung Galaxy S Advance (GT-I9070)
|
||||
items:
|
||||
- const: samsung,janice
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
- description: Samsung Galaxy Amp (SGH-I407)
|
||||
items:
|
||||
- const: samsung,kyle
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
- description: Samsung Galaxy XCover 2 (GT-S7710)
|
||||
items:
|
||||
- const: samsung,skomer
|
||||
- const: st-ericsson,u8500
|
||||
|
||||
additionalProperties: true
|
||||
|
@ -7,15 +7,17 @@ the following properties:
|
||||
compatible = "xen,xen-<version>", "xen,xen";
|
||||
where <version> is the version of the Xen ABI of the platform.
|
||||
|
||||
- reg: specifies the base physical address and size of a region in
|
||||
memory where the grant table should be mapped to, using an
|
||||
HYPERVISOR_memory_op hypercall. The memory region is large enough to map
|
||||
the whole grant table (it is larger or equal to gnttab_max_grant_frames()).
|
||||
This property is unnecessary when booting Dom0 using ACPI.
|
||||
- reg: specifies the base physical address and size of the regions in memory
|
||||
where the special resources should be mapped to, using an HYPERVISOR_memory_op
|
||||
hypercall.
|
||||
Region 0 is reserved for mapping grant table, it must be always present.
|
||||
The memory region is large enough to map the whole grant table (it is larger
|
||||
or equal to gnttab_max_grant_frames()).
|
||||
Regions 1...N are extended regions (unused address space) for mapping foreign
|
||||
GFNs and grants, they might be absent if there is nothing to expose.
|
||||
|
||||
- interrupts: the interrupt used by Xen to inject event notifications.
|
||||
A GIC node is also required.
|
||||
This property is unnecessary when booting Dom0 using ACPI.
|
||||
|
||||
To support UEFI on Xen ARM virtual platforms, Xen populates the FDT "uefi" node
|
||||
under /hypervisor with following parameters:
|
||||
|
@ -1,45 +0,0 @@
|
||||
* Broadcom SATA3 AHCI Controller
|
||||
|
||||
SATA nodes are defined to describe on-chip Serial ATA controllers.
|
||||
Each SATA controller should have its own node.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one or more of
|
||||
"brcm,bcm7216-ahci"
|
||||
"brcm,bcm7425-ahci"
|
||||
"brcm,bcm7445-ahci"
|
||||
"brcm,bcm-nsp-ahci"
|
||||
"brcm,sata3-ahci"
|
||||
"brcm,bcm63138-ahci"
|
||||
- reg : register mappings for AHCI and SATA_TOP_CTRL
|
||||
- reg-names : "ahci" and "top-ctrl"
|
||||
- interrupts : interrupt mapping for SATA IRQ
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset: for "brcm,bcm7216-ahci" must be a valid reset phandle
|
||||
pointing to the RESCAL reset controller provider node.
|
||||
- reset-names: for "brcm,bcm7216-ahci", must be "rescal".
|
||||
|
||||
Also see ahci-platform.txt.
|
||||
|
||||
Example:
|
||||
|
||||
sata@f045a000 {
|
||||
compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci";
|
||||
reg = <0xf045a000 0xa9c>, <0xf0458040 0x24>;
|
||||
reg-names = "ahci", "top-ctrl";
|
||||
interrupts = <0 30 0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sata0: sata-port@0 {
|
||||
reg = <0>;
|
||||
phys = <&sata_phy 0>;
|
||||
};
|
||||
|
||||
sata1: sata-port@1 {
|
||||
reg = <1>;
|
||||
phys = <&sata_phy 1>;
|
||||
};
|
||||
};
|
90
Documentation/devicetree/bindings/ata/brcm,sata-brcm.yaml
Normal file
@ -0,0 +1,90 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/ata/brcm,sata-brcm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom SATA3 AHCI Controller
|
||||
|
||||
description:
|
||||
SATA nodes are defined to describe on-chip Serial ATA controllers.
|
||||
Each SATA controller should have its own node.
|
||||
|
||||
maintainers:
|
||||
- Florian Fainelli <f.fainelli@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: sata-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- brcm,bcm7216-ahci
|
||||
- brcm,bcm7445-ahci
|
||||
- brcm,bcm7425-ahci
|
||||
- brcm,bcm63138-ahci
|
||||
- const: brcm,sata3-ahci
|
||||
- items:
|
||||
- const: brcm,bcm-nsp-ahci
|
||||
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: ahci
|
||||
- const: top-ctrl
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- brcm,bcm7216-ahci
|
||||
- brcm,bcm63138-ahci
|
||||
then:
|
||||
properties:
|
||||
resets:
|
||||
maxItems: 1
|
||||
reset-names:
|
||||
enum:
|
||||
- rescal
|
||||
- ahci
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
sata@f045a000 {
|
||||
compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci";
|
||||
reg = <0xf045a000 0xa9c>, <0xf0458040 0x24>;
|
||||
reg-names = "ahci", "top-ctrl";
|
||||
interrupts = <0 30 0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sata0: sata-port@0 {
|
||||
reg = <0>;
|
||||
phys = <&sata_phy 0>;
|
||||
};
|
||||
|
||||
sata1: sata-port@1 {
|
||||
reg = <1>;
|
||||
phys = <&sata_phy 1>;
|
||||
};
|
||||
};
|
@ -1,34 +0,0 @@
|
||||
Broadcom GISB bus Arbiter controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible:
|
||||
"brcm,bcm7278-gisb-arb" for V7 28nm chips
|
||||
"brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for other 28nm chips
|
||||
"brcm,bcm7435-gisb-arb" for newer 40nm chips
|
||||
"brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips
|
||||
"brcm,bcm7038-gisb-arb" for 130nm chips
|
||||
- reg: specifies the base physical address and size of the registers
|
||||
- interrupts: specifies the two interrupts (timeout and TEA) to be used from
|
||||
the parent interrupt controller. A third optional interrupt may be specified
|
||||
for breakpoints.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- brcm,gisb-arb-master-mask: 32-bits wide bitmask used to specify which GISB
|
||||
masters are valid at the system level
|
||||
- brcm,gisb-arb-master-names: string list of the litteral name of the GISB
|
||||
masters. Should match the number of bits set in brcm,gisb-master-mask and
|
||||
the order in which they appear
|
||||
|
||||
Example:
|
||||
|
||||
gisb-arb@f0400000 {
|
||||
compatible = "brcm,gisb-arb";
|
||||
reg = <0xf0400000 0x800>;
|
||||
interrupts = <0>, <2>;
|
||||
interrupt-parent = <&sun_l2_intc>;
|
||||
|
||||
brcm,gisb-arb-master-mask = <0x7>;
|
||||
brcm,gisb-arb-master-names = "bsp_0", "scpu_0", "cpu_0";
|
||||
};
|
66
Documentation/devicetree/bindings/bus/brcm,gisb-arb.yaml
Normal file
@ -0,0 +1,66 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/bus/brcm,gisb-arb.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom GISB bus Arbiter controller
|
||||
|
||||
maintainers:
|
||||
- Florian Fainelli <f.fainelli@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- brcm,bcm7445-gisb-arb # for other 28nm chips
|
||||
- const: brcm,gisb-arb
|
||||
- items:
|
||||
- enum:
|
||||
- brcm,bcm7278-gisb-arb # for V7 28nm chips
|
||||
- brcm,bcm7435-gisb-arb # for newer 40nm chips
|
||||
- brcm,bcm7400-gisb-arb # for older 40nm chips and all 65nm chips
|
||||
- brcm,bcm7038-gisb-arb # for 130nm chips
|
||||
- brcm,gisb-arb # fallback compatible
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 2
|
||||
items:
|
||||
- description: timeout interrupt line
|
||||
- description: target abort interrupt line
|
||||
- description: breakpoint interrupt line
|
||||
|
||||
brcm,gisb-arb-master-mask:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: >
|
||||
32-bits wide bitmask used to specify which GISB masters are valid at the
|
||||
system level
|
||||
|
||||
brcm,gisb-arb-master-names:
|
||||
$ref: /schemas/types.yaml#/definitions/string-array
|
||||
description: >
|
||||
String list of the litteral name of the GISB masters. Should match the
|
||||
number of bits set in brcm,gisb-master-mask and the order in which they
|
||||
appear from MSB to LSB.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
gisb-arb@f0400000 {
|
||||
compatible = "brcm,gisb-arb";
|
||||
reg = <0xf0400000 0x800>;
|
||||
interrupts = <0>, <2>;
|
||||
interrupt-parent = <&sun_l2_intc>;
|
||||
brcm,gisb-arb-master-mask = <0x7>;
|
||||
brcm,gisb-arb-master-names = "bsp_0", "scpu_0", "cpu_0";
|
||||
};
|
@ -34,6 +34,8 @@ properties:
|
||||
- allwinner,sun8i-v3-ccu
|
||||
- allwinner,sun8i-v3s-ccu
|
||||
- allwinner,sun9i-a80-ccu
|
||||
- allwinner,sun20i-d1-ccu
|
||||
- allwinner,sun20i-d1-r-ccu
|
||||
- allwinner,sun50i-a64-ccu
|
||||
- allwinner,sun50i-a64-r-ccu
|
||||
- allwinner,sun50i-a100-ccu
|
||||
@ -79,6 +81,7 @@ if:
|
||||
enum:
|
||||
- allwinner,sun8i-a83t-r-ccu
|
||||
- allwinner,sun8i-h3-r-ccu
|
||||
- allwinner,sun20i-d1-r-ccu
|
||||
- allwinner,sun50i-a64-r-ccu
|
||||
- allwinner,sun50i-a100-r-ccu
|
||||
- allwinner,sun50i-h6-r-ccu
|
||||
@ -99,6 +102,7 @@ else:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun20i-d1-ccu
|
||||
- allwinner,sun50i-a100-ccu
|
||||
- allwinner,sun50i-h6-ccu
|
||||
- allwinner,sun50i-h616-ccu
|
||||
|
@ -1,190 +0,0 @@
|
||||
* Samsung Exynos5260 Clock Controller
|
||||
|
||||
Exynos5260 has 13 clock controllers which are instantiated
|
||||
independently from the device-tree. These clock controllers
|
||||
generate and supply clocks to various hardware blocks within
|
||||
the SoC.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use
|
||||
this identifier to specify the clock which they consume. All
|
||||
available clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/exynos5260-clk.h header and can be used in
|
||||
device tree sources.
|
||||
|
||||
External clocks:
|
||||
|
||||
There are several clocks that are generated outside the SoC. It
|
||||
is expected that they are defined using standard clock bindings
|
||||
with following clock-output-names:
|
||||
|
||||
- "fin_pll" - PLL input clock from XXTI
|
||||
- "xrtcxti" - input clock from XRTCXTI
|
||||
- "ioclk_pcm_extclk" - pcm external operation clock
|
||||
- "ioclk_spdif_extclk" - spdif external operation clock
|
||||
- "ioclk_i2s_cdclk" - i2s0 codec clock
|
||||
|
||||
Phy clocks:
|
||||
|
||||
There are several clocks which are generated by specific PHYs.
|
||||
These clocks are fed into the clock controller and then routed to
|
||||
the hardware blocks. These clocks are defined as fixed clocks in the
|
||||
driver with following names:
|
||||
|
||||
- "phyclk_dptx_phy_ch3_txd_clk" - dp phy clock for channel 3
|
||||
- "phyclk_dptx_phy_ch2_txd_clk" - dp phy clock for channel 2
|
||||
- "phyclk_dptx_phy_ch1_txd_clk" - dp phy clock for channel 1
|
||||
- "phyclk_dptx_phy_ch0_txd_clk" - dp phy clock for channel 0
|
||||
- "phyclk_hdmi_phy_tmds_clko" - hdmi phy tmds clock
|
||||
- "phyclk_hdmi_phy_pixel_clko" - hdmi phy pixel clock
|
||||
- "phyclk_hdmi_link_o_tmds_clkhi" - hdmi phy for hdmi link
|
||||
- "phyclk_dptx_phy_o_ref_clk_24m" - dp phy reference clock
|
||||
- "phyclk_dptx_phy_clk_div2"
|
||||
- "phyclk_mipi_dphy_4l_m_rxclkesc0"
|
||||
- "phyclk_usbhost20_phy_phyclock" - usb 2.0 phy clock
|
||||
- "phyclk_usbhost20_phy_freeclk"
|
||||
- "phyclk_usbhost20_phy_clk48mohci"
|
||||
- "phyclk_usbdrd30_udrd30_pipe_pclk"
|
||||
- "phyclk_usbdrd30_udrd30_phyclock" - usb 3.0 phy clock
|
||||
|
||||
Required Properties for Clock Controller:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
1) "samsung,exynos5260-clock-top"
|
||||
2) "samsung,exynos5260-clock-peri"
|
||||
3) "samsung,exynos5260-clock-egl"
|
||||
4) "samsung,exynos5260-clock-kfc"
|
||||
5) "samsung,exynos5260-clock-g2d"
|
||||
6) "samsung,exynos5260-clock-mif"
|
||||
7) "samsung,exynos5260-clock-mfc"
|
||||
8) "samsung,exynos5260-clock-g3d"
|
||||
9) "samsung,exynos5260-clock-fsys"
|
||||
10) "samsung,exynos5260-clock-aud"
|
||||
11) "samsung,exynos5260-clock-isp"
|
||||
12) "samsung,exynos5260-clock-gscl"
|
||||
13) "samsung,exynos5260-clock-disp"
|
||||
|
||||
- reg: physical base address of the controller and the length of
|
||||
memory mapped region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
- clocks: list of clock identifiers which are fed as the input to
|
||||
the given clock controller. Please refer the next section to find
|
||||
the input clocks for a given controller.
|
||||
|
||||
- clock-names: list of names of clocks which are fed as the input
|
||||
to the given clock controller.
|
||||
|
||||
Input clocks for top clock controller:
|
||||
- fin_pll
|
||||
- dout_mem_pll
|
||||
- dout_bus_pll
|
||||
- dout_media_pll
|
||||
|
||||
Input clocks for peri clock controller:
|
||||
- fin_pll
|
||||
- ioclk_pcm_extclk
|
||||
- ioclk_i2s_cdclk
|
||||
- ioclk_spdif_extclk
|
||||
- phyclk_hdmi_phy_ref_cko
|
||||
- dout_aclk_peri_66
|
||||
- dout_sclk_peri_uart0
|
||||
- dout_sclk_peri_uart1
|
||||
- dout_sclk_peri_uart2
|
||||
- dout_sclk_peri_spi0_b
|
||||
- dout_sclk_peri_spi1_b
|
||||
- dout_sclk_peri_spi2_b
|
||||
- dout_aclk_peri_aud
|
||||
- dout_sclk_peri_spi0_b
|
||||
|
||||
Input clocks for egl clock controller:
|
||||
- fin_pll
|
||||
- dout_bus_pll
|
||||
|
||||
Input clocks for kfc clock controller:
|
||||
- fin_pll
|
||||
- dout_media_pll
|
||||
|
||||
Input clocks for g2d clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_g2d_333
|
||||
|
||||
Input clocks for mif clock controller:
|
||||
- fin_pll
|
||||
|
||||
Input clocks for mfc clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_mfc_333
|
||||
|
||||
Input clocks for g3d clock controller:
|
||||
- fin_pll
|
||||
|
||||
Input clocks for fsys clock controller:
|
||||
- fin_pll
|
||||
- phyclk_usbhost20_phy_phyclock
|
||||
- phyclk_usbhost20_phy_freeclk
|
||||
- phyclk_usbhost20_phy_clk48mohci
|
||||
- phyclk_usbdrd30_udrd30_pipe_pclk
|
||||
- phyclk_usbdrd30_udrd30_phyclock
|
||||
- dout_aclk_fsys_200
|
||||
|
||||
Input clocks for aud clock controller:
|
||||
- fin_pll
|
||||
- fout_aud_pll
|
||||
- ioclk_i2s_cdclk
|
||||
- ioclk_pcm_extclk
|
||||
|
||||
Input clocks for isp clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_isp1_266
|
||||
- dout_aclk_isp1_400
|
||||
- mout_aclk_isp1_266
|
||||
|
||||
Input clocks for gscl clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_gscl_400
|
||||
- dout_aclk_gscl_333
|
||||
|
||||
Input clocks for disp clock controller:
|
||||
- fin_pll
|
||||
- phyclk_dptx_phy_ch3_txd_clk
|
||||
- phyclk_dptx_phy_ch2_txd_clk
|
||||
- phyclk_dptx_phy_ch1_txd_clk
|
||||
- phyclk_dptx_phy_ch0_txd_clk
|
||||
- phyclk_hdmi_phy_tmds_clko
|
||||
- phyclk_hdmi_phy_ref_clko
|
||||
- phyclk_hdmi_phy_pixel_clko
|
||||
- phyclk_hdmi_link_o_tmds_clkhi
|
||||
- phyclk_mipi_dphy_4l_m_txbyte_clkhs
|
||||
- phyclk_dptx_phy_o_ref_clk_24m
|
||||
- phyclk_dptx_phy_clk_div2
|
||||
- phyclk_mipi_dphy_4l_m_rxclkesc0
|
||||
- phyclk_hdmi_phy_ref_cko
|
||||
- ioclk_spdif_extclk
|
||||
- dout_aclk_peri_aud
|
||||
- dout_aclk_disp_222
|
||||
- dout_sclk_disp_pixel
|
||||
- dout_aclk_disp_333
|
||||
|
||||
Example 1: An example of a clock controller node is listed below.
|
||||
|
||||
clock_mfc: clock-controller@11090000 {
|
||||
compatible = "samsung,exynos5260-clock-mfc";
|
||||
clock = <&fin_pll>, <&clock_top TOP_DOUT_ACLK_MFC_333>;
|
||||
clock-names = "fin_pll", "dout_aclk_mfc_333";
|
||||
reg = <0x11090000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
Example 2: UART controller node that consumes the clock generated by the
|
||||
peri clock controller. Refer to the standard clock bindings for
|
||||
information about 'clocks' and 'clock-names' property.
|
||||
|
||||
serial@12c00000 {
|
||||
compatible = "samsung,exynos4210-uart";
|
||||
reg = <0x12C00000 0x100>;
|
||||
interrupts = <0 146 0>;
|
||||
clocks = <&clock_peri PERI_PCLK_UART0>, <&clock_peri PERI_SCLK_UART0>;
|
||||
clock-names = "uart", "clk_uart_baud0";
|
||||
};
|
||||
|
@ -1,50 +0,0 @@
|
||||
* Samsung Exynos5410 Clock Controller
|
||||
|
||||
The Exynos5410 clock controller generates and supplies clock to various
|
||||
controllers within the Exynos5410 SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be "samsung,exynos5410-clock"
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
- clocks: should contain an entry specifying the root clock from external
|
||||
oscillator supplied through XXTI or XusbXTI pin. This clock should be
|
||||
defined using standard clock bindings with "fin_pll" clock-output-name.
|
||||
That clock is being passed internally to the 9 PLLs.
|
||||
|
||||
All available clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/exynos5410.h header and can be used in device
|
||||
tree sources.
|
||||
|
||||
Example 1: An example of a clock controller node is listed below.
|
||||
|
||||
fin_pll: xxti {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "fin_pll";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
clock: clock-controller@10010000 {
|
||||
compatible = "samsung,exynos5410-clock";
|
||||
reg = <0x10010000 0x30000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&fin_pll>;
|
||||
};
|
||||
|
||||
Example 2: UART controller node that consumes the clock generated by the clock
|
||||
controller. Refer to the standard clock bindings for information
|
||||
about 'clocks' and 'clock-names' property.
|
||||
|
||||
serial@12c20000 {
|
||||
compatible = "samsung,exynos4210-uart";
|
||||
reg = <0x12C00000 0x100>;
|
||||
interrupts = <0 51 0>;
|
||||
clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
|
||||
clock-names = "uart", "clk_uart_baud0";
|
||||
};
|
@ -1,507 +0,0 @@
|
||||
* Samsung Exynos5433 CMU (Clock Management Units)
|
||||
|
||||
The Exynos5433 clock controller generates and supplies clock to various
|
||||
controllers within the Exynos5433 SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
- "samsung,exynos5433-cmu-top" - clock controller compatible for CMU_TOP
|
||||
which generates clocks for IMEM/FSYS/G3D/GSCL/HEVC/MSCL/G2D/MFC/PERIC/PERIS
|
||||
domains and bus clocks.
|
||||
- "samsung,exynos5433-cmu-cpif" - clock controller compatible for CMU_CPIF
|
||||
which generates clocks for LLI (Low Latency Interface) IP.
|
||||
- "samsung,exynos5433-cmu-mif" - clock controller compatible for CMU_MIF
|
||||
which generates clocks for DRAM Memory Controller domain.
|
||||
- "samsung,exynos5433-cmu-peric" - clock controller compatible for CMU_PERIC
|
||||
which generates clocks for UART/I2C/SPI/I2S/PCM/SPDIF/PWM/SLIMBUS IPs.
|
||||
- "samsung,exynos5433-cmu-peris" - clock controller compatible for CMU_PERIS
|
||||
which generates clocks for PMU/TMU/MCT/WDT/RTC/SECKEY/TZPC IPs.
|
||||
- "samsung,exynos5433-cmu-fsys" - clock controller compatible for CMU_FSYS
|
||||
which generates clocks for USB/UFS/SDMMC/TSI/PDMA IPs.
|
||||
- "samsung,exynos5433-cmu-g2d" - clock controller compatible for CMU_G2D
|
||||
which generates clocks for G2D/MDMA IPs.
|
||||
- "samsung,exynos5433-cmu-disp" - clock controller compatible for CMU_DISP
|
||||
which generates clocks for Display (DECON/HDMI/DSIM/MIXER) IPs.
|
||||
- "samsung,exynos5433-cmu-aud" - clock controller compatible for CMU_AUD
|
||||
which generates clocks for Cortex-A5/BUS/AUDIO clocks.
|
||||
- "samsung,exynos5433-cmu-bus0", "samsung,exynos5433-cmu-bus1"
|
||||
and "samsung,exynos5433-cmu-bus2" - clock controller compatible for CMU_BUS
|
||||
which generates global data buses clock and global peripheral buses clock.
|
||||
- "samsung,exynos5433-cmu-g3d" - clock controller compatible for CMU_G3D
|
||||
which generates clocks for 3D Graphics Engine IP.
|
||||
- "samsung,exynos5433-cmu-gscl" - clock controller compatible for CMU_GSCL
|
||||
which generates clocks for GSCALER IPs.
|
||||
- "samsung,exynos5433-cmu-apollo"- clock controller compatible for CMU_APOLLO
|
||||
which generates clocks for Cortex-A53 Quad-core processor.
|
||||
- "samsung,exynos5433-cmu-atlas" - clock controller compatible for CMU_ATLAS
|
||||
which generates clocks for Cortex-A57 Quad-core processor, CoreSight and
|
||||
L2 cache controller.
|
||||
- "samsung,exynos5433-cmu-mscl" - clock controller compatible for CMU_MSCL
|
||||
which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs.
|
||||
- "samsung,exynos5433-cmu-mfc" - clock controller compatible for CMU_MFC
|
||||
which generates clocks for MFC(Multi-Format Codec) IP.
|
||||
- "samsung,exynos5433-cmu-hevc" - clock controller compatible for CMU_HEVC
|
||||
which generates clocks for HEVC(High Efficiency Video Codec) decoder IP.
|
||||
- "samsung,exynos5433-cmu-isp" - clock controller compatible for CMU_ISP
|
||||
which generates clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs.
|
||||
- "samsung,exynos5433-cmu-cam0" - clock controller compatible for CMU_CAM0
|
||||
which generates clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1}
|
||||
IPs.
|
||||
- "samsung,exynos5433-cmu-cam1" - clock controller compatible for CMU_CAM1
|
||||
which generates clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs.
|
||||
- "samsung,exynos5433-cmu-imem" - clock controller compatible for CMU_IMEM
|
||||
which generates clocks for SSS (Security SubSystem) and SlimSSS IPs.
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
- clocks: list of the clock controller input clock identifiers,
|
||||
from common clock bindings. Please refer the next section
|
||||
to find the input clocks for a given controller.
|
||||
|
||||
- clock-names: list of the clock controller input clock names,
|
||||
as described in clock-bindings.txt.
|
||||
|
||||
Input clocks for top clock controller:
|
||||
- oscclk
|
||||
- sclk_mphy_pll
|
||||
- sclk_mfc_pll
|
||||
- sclk_bus_pll
|
||||
|
||||
Input clocks for cpif clock controller:
|
||||
- oscclk
|
||||
|
||||
Input clocks for mif clock controller:
|
||||
- oscclk
|
||||
- sclk_mphy_pll
|
||||
|
||||
Input clocks for fsys clock controller:
|
||||
- oscclk
|
||||
- sclk_ufs_mphy
|
||||
- aclk_fsys_200
|
||||
- sclk_pcie_100_fsys
|
||||
- sclk_ufsunipro_fsys
|
||||
- sclk_mmc2_fsys
|
||||
- sclk_mmc1_fsys
|
||||
- sclk_mmc0_fsys
|
||||
- sclk_usbhost30_fsys
|
||||
- sclk_usbdrd30_fsys
|
||||
|
||||
Input clocks for g2d clock controller:
|
||||
- oscclk
|
||||
- aclk_g2d_266
|
||||
- aclk_g2d_400
|
||||
|
||||
Input clocks for disp clock controller:
|
||||
- oscclk
|
||||
- sclk_dsim1_disp
|
||||
- sclk_dsim0_disp
|
||||
- sclk_dsd_disp
|
||||
- sclk_decon_tv_eclk_disp
|
||||
- sclk_decon_vclk_disp
|
||||
- sclk_decon_eclk_disp
|
||||
- sclk_decon_tv_vclk_disp
|
||||
- aclk_disp_333
|
||||
|
||||
Input clocks for audio clock controller:
|
||||
- oscclk
|
||||
- fout_aud_pll
|
||||
|
||||
Input clocks for bus0 clock controller:
|
||||
- aclk_bus0_400
|
||||
|
||||
Input clocks for bus1 clock controller:
|
||||
- aclk_bus1_400
|
||||
|
||||
Input clocks for bus2 clock controller:
|
||||
- oscclk
|
||||
- aclk_bus2_400
|
||||
|
||||
Input clocks for g3d clock controller:
|
||||
- oscclk
|
||||
- aclk_g3d_400
|
||||
|
||||
Input clocks for gscl clock controller:
|
||||
- oscclk
|
||||
- aclk_gscl_111
|
||||
- aclk_gscl_333
|
||||
|
||||
Input clocks for apollo clock controller:
|
||||
- oscclk
|
||||
- sclk_bus_pll_apollo
|
||||
|
||||
Input clocks for atlas clock controller:
|
||||
- oscclk
|
||||
- sclk_bus_pll_atlas
|
||||
|
||||
Input clocks for mscl clock controller:
|
||||
- oscclk
|
||||
- sclk_jpeg_mscl
|
||||
- aclk_mscl_400
|
||||
|
||||
Input clocks for mfc clock controller:
|
||||
- oscclk
|
||||
- aclk_mfc_400
|
||||
|
||||
Input clocks for hevc clock controller:
|
||||
- oscclk
|
||||
- aclk_hevc_400
|
||||
|
||||
Input clocks for isp clock controller:
|
||||
- oscclk
|
||||
- aclk_isp_dis_400
|
||||
- aclk_isp_400
|
||||
|
||||
Input clocks for cam0 clock controller:
|
||||
- oscclk
|
||||
- aclk_cam0_333
|
||||
- aclk_cam0_400
|
||||
- aclk_cam0_552
|
||||
|
||||
Input clocks for cam1 clock controller:
|
||||
- oscclk
|
||||
- sclk_isp_uart_cam1
|
||||
- sclk_isp_spi1_cam1
|
||||
- sclk_isp_spi0_cam1
|
||||
- aclk_cam1_333
|
||||
- aclk_cam1_400
|
||||
- aclk_cam1_552
|
||||
|
||||
Input clocks for imem clock controller:
|
||||
- oscclk
|
||||
- aclk_imem_sssx_266
|
||||
- aclk_imem_266
|
||||
- aclk_imem_200
|
||||
|
||||
Optional properties:
|
||||
- power-domains: a phandle to respective power domain node as described by
|
||||
generic PM domain bindings (see power/power_domain.txt for more
|
||||
information).
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume.
|
||||
|
||||
All available clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/exynos5433.h header and can be used in device
|
||||
tree sources.
|
||||
|
||||
Example 1: Examples of 'oscclk' source clock node are listed below.
|
||||
|
||||
xxti: xxti {
|
||||
compatible = "fixed-clock";
|
||||
clock-output-names = "oscclk";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
Example 2: Examples of clock controller nodes are listed below.
|
||||
|
||||
cmu_top: clock-controller@10030000 {
|
||||
compatible = "samsung,exynos5433-cmu-top";
|
||||
reg = <0x10030000 0x0c04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"sclk_mphy_pll",
|
||||
"sclk_mfc_pll",
|
||||
"sclk_bus_pll";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_cpif CLK_SCLK_MPHY_PLL>,
|
||||
<&cmu_mif CLK_SCLK_MFC_PLL>,
|
||||
<&cmu_mif CLK_SCLK_BUS_PLL>;
|
||||
};
|
||||
|
||||
cmu_cpif: clock-controller@10fc0000 {
|
||||
compatible = "samsung,exynos5433-cmu-cpif";
|
||||
reg = <0x10fc0000 0x0c04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk";
|
||||
clocks = <&xxti>;
|
||||
};
|
||||
|
||||
cmu_mif: clock-controller@105b0000 {
|
||||
compatible = "samsung,exynos5433-cmu-mif";
|
||||
reg = <0x105b0000 0x100c>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"sclk_mphy_pll";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_cpif CLK_SCLK_MPHY_PLL>;
|
||||
};
|
||||
|
||||
cmu_peric: clock-controller@14c80000 {
|
||||
compatible = "samsung,exynos5433-cmu-peric";
|
||||
reg = <0x14c80000 0x0b08>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
cmu_peris: clock-controller@10040000 {
|
||||
compatible = "samsung,exynos5433-cmu-peris";
|
||||
reg = <0x10040000 0x0b20>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
cmu_fsys: clock-controller@156e0000 {
|
||||
compatible = "samsung,exynos5433-cmu-fsys";
|
||||
reg = <0x156e0000 0x0b04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"sclk_ufs_mphy",
|
||||
"aclk_fsys_200",
|
||||
"sclk_pcie_100_fsys",
|
||||
"sclk_ufsunipro_fsys",
|
||||
"sclk_mmc2_fsys",
|
||||
"sclk_mmc1_fsys",
|
||||
"sclk_mmc0_fsys",
|
||||
"sclk_usbhost30_fsys",
|
||||
"sclk_usbdrd30_fsys";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_cpif CLK_SCLK_UFS_MPHY>,
|
||||
<&cmu_top CLK_ACLK_FSYS_200>,
|
||||
<&cmu_top CLK_SCLK_PCIE_100_FSYS>,
|
||||
<&cmu_top CLK_SCLK_UFSUNIPRO_FSYS>,
|
||||
<&cmu_top CLK_SCLK_MMC2_FSYS>,
|
||||
<&cmu_top CLK_SCLK_MMC1_FSYS>,
|
||||
<&cmu_top CLK_SCLK_MMC0_FSYS>,
|
||||
<&cmu_top CLK_SCLK_USBHOST30_FSYS>,
|
||||
<&cmu_top CLK_SCLK_USBDRD30_FSYS>;
|
||||
};
|
||||
|
||||
cmu_g2d: clock-controller@12460000 {
|
||||
compatible = "samsung,exynos5433-cmu-g2d";
|
||||
reg = <0x12460000 0x0b08>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"aclk_g2d_266",
|
||||
"aclk_g2d_400";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_top CLK_ACLK_G2D_266>,
|
||||
<&cmu_top CLK_ACLK_G2D_400>;
|
||||
power-domains = <&pd_g2d>;
|
||||
};
|
||||
|
||||
cmu_disp: clock-controller@13b90000 {
|
||||
compatible = "samsung,exynos5433-cmu-disp";
|
||||
reg = <0x13b90000 0x0c04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"sclk_dsim1_disp",
|
||||
"sclk_dsim0_disp",
|
||||
"sclk_dsd_disp",
|
||||
"sclk_decon_tv_eclk_disp",
|
||||
"sclk_decon_vclk_disp",
|
||||
"sclk_decon_eclk_disp",
|
||||
"sclk_decon_tv_vclk_disp",
|
||||
"aclk_disp_333";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_mif CLK_SCLK_DSIM1_DISP>,
|
||||
<&cmu_mif CLK_SCLK_DSIM0_DISP>,
|
||||
<&cmu_mif CLK_SCLK_DSD_DISP>,
|
||||
<&cmu_mif CLK_SCLK_DECON_TV_ECLK_DISP>,
|
||||
<&cmu_mif CLK_SCLK_DECON_VCLK_DISP>,
|
||||
<&cmu_mif CLK_SCLK_DECON_ECLK_DISP>,
|
||||
<&cmu_mif CLK_SCLK_DECON_TV_VCLK_DISP>,
|
||||
<&cmu_mif CLK_ACLK_DISP_333>;
|
||||
power-domains = <&pd_disp>;
|
||||
};
|
||||
|
||||
cmu_aud: clock-controller@114c0000 {
|
||||
compatible = "samsung,exynos5433-cmu-aud";
|
||||
reg = <0x114c0000 0x0b04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk", "fout_aud_pll";
|
||||
clocks = <&xxti>, <&cmu_top CLK_FOUT_AUD_PLL>;
|
||||
power-domains = <&pd_aud>;
|
||||
};
|
||||
|
||||
cmu_bus0: clock-controller@13600000 {
|
||||
compatible = "samsung,exynos5433-cmu-bus0";
|
||||
reg = <0x13600000 0x0b04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "aclk_bus0_400";
|
||||
clocks = <&cmu_top CLK_ACLK_BUS0_400>;
|
||||
};
|
||||
|
||||
cmu_bus1: clock-controller@14800000 {
|
||||
compatible = "samsung,exynos5433-cmu-bus1";
|
||||
reg = <0x14800000 0x0b04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "aclk_bus1_400";
|
||||
clocks = <&cmu_top CLK_ACLK_BUS1_400>;
|
||||
};
|
||||
|
||||
cmu_bus2: clock-controller@13400000 {
|
||||
compatible = "samsung,exynos5433-cmu-bus2";
|
||||
reg = <0x13400000 0x0b04>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk", "aclk_bus2_400";
|
||||
clocks = <&xxti>, <&cmu_mif CLK_ACLK_BUS2_400>;
|
||||
};
|
||||
|
||||
cmu_g3d: clock-controller@14aa0000 {
|
||||
compatible = "samsung,exynos5433-cmu-g3d";
|
||||
reg = <0x14aa0000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk", "aclk_g3d_400";
|
||||
clocks = <&xxti>, <&cmu_top CLK_ACLK_G3D_400>;
|
||||
power-domains = <&pd_g3d>;
|
||||
};
|
||||
|
||||
cmu_gscl: clock-controller@13cf0000 {
|
||||
compatible = "samsung,exynos5433-cmu-gscl";
|
||||
reg = <0x13cf0000 0x0b10>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"aclk_gscl_111",
|
||||
"aclk_gscl_333";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_top CLK_ACLK_GSCL_111>,
|
||||
<&cmu_top CLK_ACLK_GSCL_333>;
|
||||
power-domains = <&pd_gscl>;
|
||||
};
|
||||
|
||||
cmu_apollo: clock-controller@11900000 {
|
||||
compatible = "samsung,exynos5433-cmu-apollo";
|
||||
reg = <0x11900000 0x1088>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk", "sclk_bus_pll_apollo";
|
||||
clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_APOLLO>;
|
||||
};
|
||||
|
||||
cmu_atlas: clock-controller@11800000 {
|
||||
compatible = "samsung,exynos5433-cmu-atlas";
|
||||
reg = <0x11800000 0x1088>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk", "sclk_bus_pll_atlas";
|
||||
clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_ATLAS>;
|
||||
};
|
||||
|
||||
cmu_mscl: clock-controller@105d0000 {
|
||||
compatible = "samsung,exynos5433-cmu-mscl";
|
||||
reg = <0x105d0000 0x0b10>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"sclk_jpeg_mscl",
|
||||
"aclk_mscl_400";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_top CLK_SCLK_JPEG_MSCL>,
|
||||
<&cmu_top CLK_ACLK_MSCL_400>;
|
||||
power-domains = <&pd_mscl>;
|
||||
};
|
||||
|
||||
cmu_mfc: clock-controller@15280000 {
|
||||
compatible = "samsung,exynos5433-cmu-mfc";
|
||||
reg = <0x15280000 0x0b08>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk", "aclk_mfc_400";
|
||||
clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>;
|
||||
power-domains = <&pd_mfc>;
|
||||
};
|
||||
|
||||
cmu_hevc: clock-controller@14f80000 {
|
||||
compatible = "samsung,exynos5433-cmu-hevc";
|
||||
reg = <0x14f80000 0x0b08>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk", "aclk_hevc_400";
|
||||
clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>;
|
||||
power-domains = <&pd_hevc>;
|
||||
};
|
||||
|
||||
cmu_isp: clock-controller@146d0000 {
|
||||
compatible = "samsung,exynos5433-cmu-isp";
|
||||
reg = <0x146d0000 0x0b0c>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"aclk_isp_dis_400",
|
||||
"aclk_isp_400";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_top CLK_ACLK_ISP_DIS_400>,
|
||||
<&cmu_top CLK_ACLK_ISP_400>;
|
||||
power-domains = <&pd_isp>;
|
||||
};
|
||||
|
||||
cmu_cam0: clock-controller@120d0000 {
|
||||
compatible = "samsung,exynos5433-cmu-cam0";
|
||||
reg = <0x120d0000 0x0b0c>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"aclk_cam0_333",
|
||||
"aclk_cam0_400",
|
||||
"aclk_cam0_552";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_top CLK_ACLK_CAM0_333>,
|
||||
<&cmu_top CLK_ACLK_CAM0_400>,
|
||||
<&cmu_top CLK_ACLK_CAM0_552>;
|
||||
power-domains = <&pd_cam0>;
|
||||
};
|
||||
|
||||
cmu_cam1: clock-controller@145d0000 {
|
||||
compatible = "samsung,exynos5433-cmu-cam1";
|
||||
reg = <0x145d0000 0x0b08>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"sclk_isp_uart_cam1",
|
||||
"sclk_isp_spi1_cam1",
|
||||
"sclk_isp_spi0_cam1",
|
||||
"aclk_cam1_333",
|
||||
"aclk_cam1_400",
|
||||
"aclk_cam1_552";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_top CLK_SCLK_ISP_UART_CAM1>,
|
||||
<&cmu_top CLK_SCLK_ISP_SPI1_CAM1>,
|
||||
<&cmu_top CLK_SCLK_ISP_SPI0_CAM1>,
|
||||
<&cmu_top CLK_ACLK_CAM1_333>,
|
||||
<&cmu_top CLK_ACLK_CAM1_400>,
|
||||
<&cmu_top CLK_ACLK_CAM1_552>;
|
||||
power-domains = <&pd_cam1>;
|
||||
};
|
||||
|
||||
cmu_imem: clock-controller@11060000 {
|
||||
compatible = "samsung,exynos5433-cmu-imem";
|
||||
reg = <0x11060000 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
clock-names = "oscclk",
|
||||
"aclk_imem_sssx_266",
|
||||
"aclk_imem_266",
|
||||
"aclk_imem_200";
|
||||
clocks = <&xxti>,
|
||||
<&cmu_top CLK_DIV_ACLK_IMEM_SSSX_266>,
|
||||
<&cmu_top CLK_DIV_ACLK_IMEM_266>,
|
||||
<&cmu_top CLK_DIV_ACLK_IMEM_200>;
|
||||
};
|
||||
|
||||
Example 3: UART controller node that consumes the clock generated by the clock
|
||||
controller.
|
||||
|
||||
serial_0: serial@14c10000 {
|
||||
compatible = "samsung,exynos5433-uart";
|
||||
reg = <0x14C10000 0x100>;
|
||||
interrupts = <0 421 0>;
|
||||
clocks = <&cmu_peric CLK_PCLK_UART0>,
|
||||
<&cmu_peric CLK_SCLK_UART0>;
|
||||
clock-names = "uart", "clk_uart_baud0";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart0_bus>;
|
||||
};
|
@ -1,108 +0,0 @@
|
||||
* Samsung Exynos7 Clock Controller
|
||||
|
||||
Exynos7 clock controller has various blocks which are instantiated
|
||||
independently from the device-tree. These clock controllers
|
||||
generate and supply clocks to various hardware blocks within
|
||||
the SoC.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use
|
||||
this identifier to specify the clock which they consume. All
|
||||
available clocks are defined as preprocessor macros in
|
||||
dt-bindings/clock/exynos7-clk.h header and can be used in
|
||||
device tree sources.
|
||||
|
||||
External clocks:
|
||||
|
||||
There are several clocks that are generated outside the SoC. It
|
||||
is expected that they are defined using standard clock bindings
|
||||
with following clock-output-names:
|
||||
|
||||
- "fin_pll" - PLL input clock from XXTI
|
||||
|
||||
Required Properties for Clock Controller:
|
||||
|
||||
- compatible: clock controllers will use one of the following
|
||||
compatible strings to indicate the clock controller
|
||||
functionality.
|
||||
|
||||
- "samsung,exynos7-clock-topc"
|
||||
- "samsung,exynos7-clock-top0"
|
||||
- "samsung,exynos7-clock-top1"
|
||||
- "samsung,exynos7-clock-ccore"
|
||||
- "samsung,exynos7-clock-peric0"
|
||||
- "samsung,exynos7-clock-peric1"
|
||||
- "samsung,exynos7-clock-peris"
|
||||
- "samsung,exynos7-clock-fsys0"
|
||||
- "samsung,exynos7-clock-fsys1"
|
||||
- "samsung,exynos7-clock-mscl"
|
||||
- "samsung,exynos7-clock-aud"
|
||||
|
||||
- reg: physical base address of the controller and the length of
|
||||
memory mapped region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
- clocks: list of clock identifiers which are fed as the input to
|
||||
the given clock controller. Please refer the next section to
|
||||
find the input clocks for a given controller.
|
||||
|
||||
- clock-names: list of names of clocks which are fed as the input
|
||||
to the given clock controller.
|
||||
|
||||
Input clocks for top0 clock controller:
|
||||
- fin_pll
|
||||
- dout_sclk_bus0_pll
|
||||
- dout_sclk_bus1_pll
|
||||
- dout_sclk_cc_pll
|
||||
- dout_sclk_mfc_pll
|
||||
- dout_sclk_aud_pll
|
||||
|
||||
Input clocks for top1 clock controller:
|
||||
- fin_pll
|
||||
- dout_sclk_bus0_pll
|
||||
- dout_sclk_bus1_pll
|
||||
- dout_sclk_cc_pll
|
||||
- dout_sclk_mfc_pll
|
||||
|
||||
Input clocks for ccore clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_ccore_133
|
||||
|
||||
Input clocks for peric0 clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_peric0_66
|
||||
- sclk_uart0
|
||||
|
||||
Input clocks for peric1 clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_peric1_66
|
||||
- sclk_uart1
|
||||
- sclk_uart2
|
||||
- sclk_uart3
|
||||
- sclk_spi0
|
||||
- sclk_spi1
|
||||
- sclk_spi2
|
||||
- sclk_spi3
|
||||
- sclk_spi4
|
||||
- sclk_i2s1
|
||||
- sclk_pcm1
|
||||
- sclk_spdif
|
||||
|
||||
Input clocks for peris clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_peris_66
|
||||
|
||||
Input clocks for fsys0 clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_fsys0_200
|
||||
- dout_sclk_mmc2
|
||||
|
||||
Input clocks for fsys1 clock controller:
|
||||
- fin_pll
|
||||
- dout_aclk_fsys1_200
|
||||
- dout_sclk_mmc0
|
||||
- dout_sclk_mmc1
|
||||
|
||||
Input clocks for aud clock controller:
|
||||
- fin_pll
|
||||
- fout_aud_pll
|
@ -55,11 +55,4 @@ examples:
|
||||
<0 72 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
can@53fc8000 {
|
||||
compatible = "fsl,imx53-flexcan", "fsl,imx25-flexcan";
|
||||
reg = <0x53fc8000 0x4000>;
|
||||
interrupts = <82>;
|
||||
clocks = <&clks IMX5_CLK_CAN1_IPG_GATE>, <&clks IMX5_CLK_CAN1_SERIAL_GATE>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
...
|
||||
|
@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/microchip,lan966x-gck.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip LAN966X Generic Clock Controller
|
||||
|
||||
maintainers:
|
||||
- Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>
|
||||
|
||||
description: |
|
||||
The LAN966X Generic clock controller contains 3 PLLs - cpu_clk,
|
||||
ddr_clk and sys_clk. This clock controller generates and supplies
|
||||
clock to various peripherals within the SoC.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: microchip,lan966x-gck
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: Generic clock registers
|
||||
- description: Optional gate clock registers
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: CPU clock source
|
||||
- description: DDR clock source
|
||||
- description: System clock source
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: cpu
|
||||
- const: ddr
|
||||
- const: sys
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clks: clock-controller@e00c00a8 {
|
||||
compatible = "microchip,lan966x-gck";
|
||||
#clock-cells = <1>;
|
||||
clocks = <&cpu_clk>, <&ddr_clk>, <&sys_clk>;
|
||||
clock-names = "cpu", "ddr", "sys";
|
||||
reg = <0xe00c00a8 0x38>;
|
||||
};
|
||||
...
|
@ -0,0 +1,97 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,gcc-msm8976.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller Binding for MSM8976
|
||||
|
||||
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 MSM8976.
|
||||
|
||||
See also:
|
||||
- dt-bindings/clock/qcom,gcc-msm8976.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,gcc-msm8976
|
||||
- qcom,gcc-msm8976-v1.1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XO source
|
||||
- description: Always-on XO source
|
||||
- description: Pixel clock from DSI PHY0
|
||||
- description: Byte clock from DSI PHY0
|
||||
- description: Pixel clock from DSI PHY1
|
||||
- description: Byte clock from DSI PHY1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xo
|
||||
- const: xo_a
|
||||
- const: dsi0pll
|
||||
- const: dsi0pllbyte
|
||||
- const: dsi1pll
|
||||
- const: dsi1pllbyte
|
||||
|
||||
vdd_gfx-supply:
|
||||
description:
|
||||
Phandle to voltage regulator providing power to the GX domain.
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- vdd_gfx-supply
|
||||
- '#clock-cells'
|
||||
- '#reset-cells'
|
||||
- '#power-domain-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@1800000 {
|
||||
compatible = "qcom,gcc-msm8976";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
reg = <0x1800000 0x80000>;
|
||||
|
||||
clocks = <&xo_board>,
|
||||
<&xo_board>,
|
||||
<&dsi0_phy 1>,
|
||||
<&dsi0_phy 0>,
|
||||
<&dsi1_phy 1>,
|
||||
<&dsi1_phy 0>;
|
||||
|
||||
clock-names = "xo",
|
||||
"xo_a",
|
||||
"dsi0pll",
|
||||
"dsi0pllbyte",
|
||||
"dsi1pll",
|
||||
"dsi1pllbyte";
|
||||
|
||||
vdd_gfx-supply = <&pm8004_s5>;
|
||||
};
|
||||
...
|
@ -22,10 +22,12 @@ properties:
|
||||
- qcom,sc8180x-rpmh-clk
|
||||
- qcom,sdm845-rpmh-clk
|
||||
- qcom,sdx55-rpmh-clk
|
||||
- qcom,sdx65-rpmh-clk
|
||||
- qcom,sm6350-rpmh-clk
|
||||
- qcom,sm8150-rpmh-clk
|
||||
- qcom,sm8250-rpmh-clk
|
||||
- qcom,sm8350-rpmh-clk
|
||||
- qcom,sm8450-rpmh-clk
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
@ -48,6 +48,7 @@ properties:
|
||||
- renesas,r8a77990-cpg-mssr # R-Car E3
|
||||
- renesas,r8a77995-cpg-mssr # R-Car D3
|
||||
- renesas,r8a779a0-cpg-mssr # R-Car V3U
|
||||
- renesas,r8a779f0-cpg-mssr # R-Car S4-8
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -0,0 +1,382 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/samsung,exynos5260-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung Exynos5260 SoC clock controller
|
||||
|
||||
maintainers:
|
||||
- Chanwoo Choi <cw00.choi@samsung.com>
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
- Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
- Tomasz Figa <tomasz.figa@gmail.com>
|
||||
|
||||
description: |
|
||||
Expected external clocks, defined in DTS as fixed-rate clocks with a matching
|
||||
name::
|
||||
- "fin_pll" - PLL input clock from XXTI
|
||||
- "xrtcxti" - input clock from XRTCXTI
|
||||
- "ioclk_pcm_extclk" - pcm external operation clock
|
||||
- "ioclk_spdif_extclk" - spdif external operation clock
|
||||
- "ioclk_i2s_cdclk" - i2s0 codec clock
|
||||
|
||||
Phy clocks::
|
||||
There are several clocks which are generated by specific PHYs. These clocks
|
||||
are fed into the clock controller and then routed to the hardware blocks.
|
||||
These clocks are defined as fixed clocks in the driver with following names::
|
||||
- "phyclk_dptx_phy_ch3_txd_clk" - dp phy clock for channel 3
|
||||
- "phyclk_dptx_phy_ch2_txd_clk" - dp phy clock for channel 2
|
||||
- "phyclk_dptx_phy_ch1_txd_clk" - dp phy clock for channel 1
|
||||
- "phyclk_dptx_phy_ch0_txd_clk" - dp phy clock for channel 0
|
||||
- "phyclk_hdmi_phy_tmds_clko" - hdmi phy tmds clock
|
||||
- "phyclk_hdmi_phy_pixel_clko" - hdmi phy pixel clock
|
||||
- "phyclk_hdmi_link_o_tmds_clkhi" - hdmi phy for hdmi link
|
||||
- "phyclk_dptx_phy_o_ref_clk_24m" - dp phy reference clock
|
||||
- "phyclk_dptx_phy_clk_div2"
|
||||
- "phyclk_mipi_dphy_4l_m_rxclkesc0"
|
||||
- "phyclk_usbhost20_phy_phyclock" - usb 2.0 phy clock
|
||||
- "phyclk_usbhost20_phy_freeclk"
|
||||
- "phyclk_usbhost20_phy_clk48mohci"
|
||||
- "phyclk_usbdrd30_udrd30_pipe_pclk"
|
||||
- "phyclk_usbdrd30_udrd30_phyclock" - usb 3.0 phy clock
|
||||
|
||||
All available clocks are defined as preprocessor macros in
|
||||
include/dt-bindings/clock/exynos5260-clk.h header.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,exynos5260-clock-top
|
||||
- samsung,exynos5260-clock-peri
|
||||
- samsung,exynos5260-clock-egl
|
||||
- samsung,exynos5260-clock-kfc
|
||||
- samsung,exynos5260-clock-g2d
|
||||
- samsung,exynos5260-clock-mif
|
||||
- samsung,exynos5260-clock-mfc
|
||||
- samsung,exynos5260-clock-g3d
|
||||
- samsung,exynos5260-clock-fsys
|
||||
- samsung,exynos5260-clock-aud
|
||||
- samsung,exynos5260-clock-isp
|
||||
- samsung,exynos5260-clock-gscl
|
||||
- samsung,exynos5260-clock-disp
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 19
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 19
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#clock-cells"
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-top
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_mem_pll
|
||||
- const: dout_bus_pll
|
||||
- const: dout_media_pll
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-peri
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 13
|
||||
maxItems: 13
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: ioclk_pcm_extclk
|
||||
- const: ioclk_i2s_cdclk
|
||||
- const: ioclk_spdif_extclk
|
||||
- const: phyclk_hdmi_phy_ref_cko
|
||||
- const: dout_aclk_peri_66
|
||||
- const: dout_sclk_peri_uart0
|
||||
- const: dout_sclk_peri_uart1
|
||||
- const: dout_sclk_peri_uart2
|
||||
- const: dout_sclk_peri_spi0_b
|
||||
- const: dout_sclk_peri_spi1_b
|
||||
- const: dout_sclk_peri_spi2_b
|
||||
- const: dout_aclk_peri_aud
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-egl
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_bus_pll
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-kfc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_media_pll
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-g2d
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_aclk_g2d_333
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-mif
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-mfc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_aclk_mfc_333
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-g3d
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-fsys
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 7
|
||||
maxItems: 7
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: phyclk_usbhost20_phy_phyclock
|
||||
- const: phyclk_usbhost20_phy_freeclk
|
||||
- const: phyclk_usbhost20_phy_clk48mohci
|
||||
- const: phyclk_usbdrd30_udrd30_pipe_pclk
|
||||
- const: phyclk_usbdrd30_udrd30_phyclock
|
||||
- const: dout_aclk_fsys_200
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-aud
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: fout_aud_pll
|
||||
- const: ioclk_i2s_cdclk
|
||||
- const: ioclk_pcm_extclk
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-isp
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_aclk_isp1_266
|
||||
- const: dout_aclk_isp1_400
|
||||
- const: mout_aclk_isp1_266
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-gscl
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: dout_aclk_gscl_400
|
||||
- const: dout_aclk_gscl_333
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: samsung,exynos5260-clock-disp
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 19
|
||||
maxItems: 19
|
||||
clock-names:
|
||||
items:
|
||||
- const: fin_pll
|
||||
- const: phyclk_dptx_phy_ch3_txd_clk
|
||||
- const: phyclk_dptx_phy_ch2_txd_clk
|
||||
- const: phyclk_dptx_phy_ch1_txd_clk
|
||||
- const: phyclk_dptx_phy_ch0_txd_clk
|
||||
- const: phyclk_hdmi_phy_tmds_clko
|
||||
- const: phyclk_hdmi_phy_ref_clko
|
||||
- const: phyclk_hdmi_phy_pixel_clko
|
||||
- const: phyclk_hdmi_link_o_tmds_clkhi
|
||||
- const: phyclk_mipi_dphy_4l_m_txbyte_clkhs
|
||||
- const: phyclk_dptx_phy_o_ref_clk_24m
|
||||
- const: phyclk_dptx_phy_clk_div2
|
||||
- const: phyclk_mipi_dphy_4l_m_rxclkesc0
|
||||
- const: phyclk_hdmi_phy_ref_cko
|
||||
- const: ioclk_spdif_extclk
|
||||
- const: dout_aclk_peri_aud
|
||||
- const: dout_aclk_disp_222
|
||||
- const: dout_sclk_disp_pixel
|
||||
- const: dout_aclk_disp_333
|
||||
required:
|
||||
- clock-names
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/exynos5260-clk.h>
|
||||
|
||||
fin_pll: clock {
|
||||
compatible = "fixed-clock";
|
||||
clock-output-names = "fin_pll";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
};
|
||||
|
||||
clock-controller@10010000 {
|
||||
compatible = "samsung,exynos5260-clock-top";
|
||||
reg = <0x10010000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&fin_pll>,
|
||||
<&clock_mif MIF_DOUT_MEM_PLL>,
|
||||
<&clock_mif MIF_DOUT_BUS_PLL>,
|
||||
<&clock_mif MIF_DOUT_MEDIA_PLL>;
|
||||
clock-names = "fin_pll",
|
||||
"dout_mem_pll",
|
||||
"dout_bus_pll",
|
||||
"dout_media_pll";
|
||||
};
|