Merge branches 'akpm' and 'akpm-hotfixes' (patches from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Sep 2021 01:52:05 +0000 (18:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Sep 2021 01:52:05 +0000 (18:52 -0700)
Merge yet more updates and hotfixes from Andrew Morton:
 "Post-linux-next material, based upon latest upstream to catch the
  now-merged dependencies:

   - 10 patches.

     Subsystems affected by this patch series: mm (vmstat and migration)
     and compat.

  And bunch of hotfixes, mostly cc:stable:

   - 8 patches.

     Subsystems affected by this patch series: mm (hmm, hugetlb, vmscan,
     pagealloc, pagemap, kmemleak, mempolicy, and memblock)"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  arch: remove compat_alloc_user_space
  compat: remove some compat entry points
  mm: simplify compat numa syscalls
  mm: simplify compat_sys_move_pages
  kexec: avoid compat_alloc_user_space
  kexec: move locking into do_kexec_load
  mm: migrate: change to use bool type for 'page_was_mapped'
  mm: migrate: fix the incorrect function name in comments
  mm: migrate: introduce a local variable to get the number of pages
  mm/vmstat: protect per cpu variables with preempt disable on RT

* emailed hotfixes from Andrew Morton <akpm@linux-foundation.org>:
  nds32/setup: remove unused memblock_region variable in setup_memory()
  mm/mempolicy: fix a race between offset_il_node and mpol_rebind_task
  mm/kmemleak: allow __GFP_NOLOCKDEP passed to kmemleak's gfp
  mmap_lock: change trace and locking order
  mm/page_alloc.c: avoid accessing uninitialized pcp page migratetype
  mm,vmscan: fix divide by zero in get_scan_count
  mm/hugetlb: initialize hugetlb_usage in mm_init
  mm/hmm: bypass devmap pte when all pfn requested flags are fulfilled

186 files changed:
Documentation/admin-guide/acpi/ssdt-overlays.rst
Documentation/arm/marvell.rst
Documentation/block/blk-mq.rst
Documentation/conf.py
Documentation/cpu-freq/cpu-drivers.rst
Documentation/devicetree/bindings/cpufreq/cpufreq-dt.txt
Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek.txt
Documentation/devicetree/bindings/cpufreq/cpufreq-st.txt
Documentation/devicetree/bindings/cpufreq/nvidia,tegra20-cpufreq.txt
Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt
Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml
Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml
Documentation/devicetree/bindings/interconnect/fsl,imx8m-noc.yaml
Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml
Documentation/devicetree/bindings/opp/opp-v1.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/opp/opp-v2-base.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/opp/opp-v2.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/opp/opp.txt [deleted file]
Documentation/devicetree/bindings/opp/qcom-opp.txt
Documentation/devicetree/bindings/opp/ti-omap5-opp-supply.txt
Documentation/devicetree/bindings/power/power-domain.yaml
Documentation/features/vm/huge-vmap/arch-support.txt
Documentation/kernel-hacking/hacking.rst
Documentation/kernel-hacking/locking.rst
Documentation/locking/futex-requeue-pi.rst
Documentation/locking/ww-mutex-design.rst
Documentation/process/applying-patches.rst
Documentation/process/kernel-docs.rst
Documentation/process/maintainer-pgp-guide.rst
Documentation/translations/it_IT/kernel-hacking/hacking.rst
Documentation/translations/it_IT/kernel-hacking/locking.rst
Documentation/translations/zh_CN/core-api/cachetlb.rst
Documentation/translations/zh_CN/core-api/index.rst
Documentation/translations/zh_CN/core-api/irq/concepts.rst
Documentation/translations/zh_CN/core-api/irq/index.rst
Documentation/translations/zh_CN/core-api/irq/irq-affinity.rst
Documentation/translations/zh_CN/core-api/irq/irq-domain.rst
Documentation/translations/zh_CN/core-api/irq/irqflags-tracing.rst
Documentation/translations/zh_CN/core-api/kernel-api.rst
Documentation/translations/zh_CN/core-api/kobject.rst
Documentation/translations/zh_CN/core-api/local_ops.rst
Documentation/translations/zh_CN/core-api/padata.rst
Documentation/translations/zh_CN/core-api/printk-basics.rst
Documentation/translations/zh_CN/core-api/printk-formats.rst
Documentation/translations/zh_CN/core-api/refcount-vs-atomic.rst
Documentation/translations/zh_CN/core-api/symbol-namespaces.rst
Documentation/translations/zh_CN/core-api/workqueue.rst
Documentation/translations/zh_CN/cpu-freq/core.rst
Documentation/translations/zh_CN/cpu-freq/cpu-drivers.rst
Documentation/translations/zh_CN/cpu-freq/cpufreq-stats.rst
Documentation/translations/zh_CN/cpu-freq/index.rst
Documentation/translations/zh_CN/filesystems/debugfs.rst
Documentation/translations/zh_CN/iio/ep93xx_adc.rst
Documentation/translations/zh_CN/iio/iio_configfs.rst
Documentation/translations/zh_CN/iio/index.rst
Documentation/translations/zh_CN/kernel-hacking/hacking.rst
Documentation/translations/zh_CN/mips/booting.rst
Documentation/translations/zh_CN/mips/features.rst
Documentation/translations/zh_CN/mips/index.rst
Documentation/translations/zh_CN/mips/ingenic-tcu.rst
Documentation/translations/zh_CN/openrisc/index.rst
Documentation/translations/zh_CN/openrisc/openrisc_port.rst
Documentation/translations/zh_CN/openrisc/todo.rst
Documentation/translations/zh_CN/parisc/debugging.rst
Documentation/translations/zh_CN/parisc/index.rst
Documentation/translations/zh_CN/parisc/registers.rst
Documentation/translations/zh_CN/riscv/boot-image-header.rst
Documentation/translations/zh_CN/riscv/index.rst
Documentation/translations/zh_CN/riscv/patch-acceptance.rst
Documentation/translations/zh_CN/riscv/pmu.rst
Documentation/translations/zh_TW/arm64/amu.rst [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/booting.txt [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/elf_hwcaps.rst [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/hugetlbpage.rst [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/index.rst [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/legacy_instructions.txt [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/memory.txt [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/perf.rst [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/silicon-errata.txt [new file with mode: 0644]
Documentation/translations/zh_TW/arm64/tagged-pointers.txt [new file with mode: 0644]
Documentation/translations/zh_TW/cpu-freq/core.rst [new file with mode: 0644]
Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst [new file with mode: 0644]
Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst [new file with mode: 0644]
Documentation/translations/zh_TW/cpu-freq/index.rst [new file with mode: 0644]
Documentation/translations/zh_TW/filesystems/debugfs.rst [new file with mode: 0644]
Documentation/translations/zh_TW/filesystems/index.rst [new file with mode: 0644]
Documentation/translations/zh_TW/filesystems/sysfs.txt [new file with mode: 0644]
Documentation/translations/zh_TW/filesystems/tmpfs.rst [new file with mode: 0644]
Documentation/translations/zh_TW/filesystems/virtiofs.rst [new file with mode: 0644]
Documentation/translations/zh_TW/index.rst
Documentation/x86/x86_64/mm.rst
MAINTAINERS
arch/arm/boot/dts/omap34xx.dtsi
arch/arm/boot/dts/omap36xx.dtsi
arch/arm64/include/asm/compat.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/asm/unistd32.h
arch/arm64/lib/Makefile
arch/arm64/lib/copy_in_user.S [deleted file]
arch/microblaze/Kbuild
arch/microblaze/Makefile
arch/mips/cavium-octeon/octeon-memcpy.S
arch/mips/include/asm/compat.h
arch/mips/include/asm/uaccess.h
arch/mips/kernel/syscalls/syscall_n32.tbl
arch/mips/kernel/syscalls/syscall_o32.tbl
arch/mips/lib/memcpy.S
arch/parisc/include/asm/compat.h
arch/parisc/include/asm/uaccess.h
arch/parisc/kernel/syscalls/syscall.tbl
arch/parisc/lib/memcpy.c
arch/powerpc/include/asm/compat.h
arch/powerpc/kernel/syscalls/syscall.tbl
arch/s390/include/asm/compat.h
arch/s390/include/asm/uaccess.h
arch/s390/kernel/syscalls/syscall.tbl
arch/s390/lib/uaccess.c
arch/sparc/include/asm/compat.h
arch/sparc/kernel/process_64.c
arch/sparc/kernel/signal32.c
arch/sparc/kernel/signal_64.c
arch/sparc/kernel/syscalls/syscall.tbl
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
arch/x86/include/asm/compat.h
arch/x86/include/asm/uaccess_64.h
drivers/acpi/x86/s2idle.c
drivers/base/arch_topology.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/mediatek-cpufreq-hw.c [new file with mode: 0644]
drivers/cpufreq/mediatek-cpufreq.c
drivers/cpufreq/omap-cpufreq.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpufreq/scmi-cpufreq.c
drivers/cpufreq/scpi-cpufreq.c
drivers/cpufreq/sh-cpufreq.c
drivers/cpufreq/vexpress-spc-cpufreq.c
drivers/pci/controller/vmd.c
drivers/pci/host-bridge.c
drivers/pci/pci-acpi.c
drivers/platform/chrome/Makefile
drivers/platform/chrome/cros_ec_proto.c
drivers/platform/chrome/cros_ec_sensorhub_ring.c
drivers/platform/chrome/cros_ec_trace.h
drivers/platform/chrome/cros_ec_typec.c
fs/ceph/addr.c
fs/ceph/cache.h
fs/ceph/caps.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/mdsmap.c
fs/ceph/metric.c
fs/ceph/snap.c
fs/ceph/strings.c
fs/ceph/super.h
fs/ceph/xattr.c
include/linux/ceph/ceph_fs.h
include/linux/compat.h
include/linux/cpufreq.h
include/linux/pci-acpi.h
include/linux/uaccess.h
include/uapi/asm-generic/unistd.h
kernel/compat.c
kernel/kexec.c
kernel/sys_ni.c
mm/mempolicy.c
mm/migrate.c
mm/vmstat.c
net/9p/client.c
net/9p/trans_fd.c
net/9p/trans_virtio.c
net/9p/trans_xen.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/svc_xprt.c
scripts/module.lds.S

index 5d7e259..b5fbf54 100644 (file)
@@ -30,22 +30,21 @@ following ASL code can be used::
         {
             Device (STAC)
             {
-                Name (_ADR, Zero)
                 Name (_HID, "BMA222E")
+                Name (RBUF, ResourceTemplate ()
+                {
+                    I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
+                                AddressingMode7Bit, "\\_SB.I2C6", 0x00,
+                                ResourceConsumer, ,)
+                    GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
+                            "\\_SB.GPO2", 0x00, ResourceConsumer, , )
+                    { // Pin list
+                        0
+                    }
+                })
 
                 Method (_CRS, 0, Serialized)
                 {
-                    Name (RBUF, ResourceTemplate ()
-                    {
-                        I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
-                                    AddressingMode7Bit, "\\_SB.I2C6", 0x00,
-                                    ResourceConsumer, ,)
-                        GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
-                                "\\_SB.GPO2", 0x00, ResourceConsumer, , )
-                        { // Pin list
-                            0
-                        }
-                    })
                     Return (RBUF)
                 }
             }
@@ -75,7 +74,7 @@ This option allows loading of user defined SSDTs from initrd and it is useful
 when the system does not support EFI or when there is not enough EFI storage.
 
 It works in a similar way with initrd based ACPI tables override/upgrade: SSDT
-aml code must be placed in the first, uncompressed, initrd under the
+AML code must be placed in the first, uncompressed, initrd under the
 "kernel/firmware/acpi" path. Multiple files can be used and this will translate
 in loading multiple tables. Only SSDT and OEM tables are allowed. See
 initrd_table_override.txt for more details.
@@ -103,12 +102,14 @@ This is the preferred method, when EFI is supported on the platform, because it
 allows a persistent, OS independent way of storing the user defined SSDTs. There
 is also work underway to implement EFI support for loading user defined SSDTs
 and using this method will make it easier to convert to the EFI loading
-mechanism when that will arrive.
+mechanism when that will arrive. To enable it, the
+CONFIG_EFI_CUSTOM_SSDT_OVERLAYS shoyld be chosen to y.
 
-In order to load SSDTs from an EFI variable the efivar_ssdt kernel command line
-parameter can be used. The argument for the option is the variable name to
-use. If there are multiple variables with the same name but with different
-vendor GUIDs, all of them will be loaded.
+In order to load SSDTs from an EFI variable the ``"efivar_ssdt=..."`` kernel
+command line parameter can be used (the name has a limitation of 16 characters).
+The argument for the option is the variable name to use. If there are multiple
+variables with the same name but with different vendor GUIDs, all of them will
+be loaded.
 
 In order to store the AML code in an EFI variable the efivarfs filesystem can be
 used. It is enabled and mounted by default in /sys/firmware/efi/efivars in all
@@ -127,7 +128,7 @@ variable with the content from a given file::
 
     #!/bin/sh -e
 
-    while ! [ -z "$1" ]; do
+    while [ -n "$1" ]; do
             case "$1" in
             "-f") filename="$2"; shift;;
             "-g") guid="$2"; shift;;
@@ -167,14 +168,14 @@ variable with the content from a given file::
 Loading ACPI SSDTs from configfs
 ================================
 
-This option allows loading of user defined SSDTs from userspace via the configfs
+This option allows loading of user defined SSDTs from user space via the configfs
 interface. The CONFIG_ACPI_CONFIGFS option must be select and configfs must be
 mounted. In the following examples, we assume that configfs has been mounted in
-/config.
+/sys/kernel/config.
 
-New tables can be loading by creating new directories in /config/acpi/table/ and
-writing the SSDT aml code in the aml attribute::
+New tables can be loading by creating new directories in /sys/kernel/config/acpi/table
+and writing the SSDT AML code in the aml attribute::
 
-    cd /config/acpi/table
+    cd /sys/kernel/config/acpi/table
     mkdir my_ssdt
     cat ~/ssdt.aml > my_ssdt/aml
index 85169bc..56bb592 100644 (file)
@@ -140,6 +140,7 @@ EBU Armada family
        - 88F6821 Armada 382
        - 88F6W21 Armada 383
        - 88F6820 Armada 385
+       - 88F6825
        - 88F6828 Armada 388
 
     - Product infos:   https://web.archive.org/web/20181006144616/http://www.marvell.com/embedded-processors/armada-38x/
index d96118c..31f52f3 100644 (file)
@@ -54,7 +54,7 @@ layer or if we want to try to merge requests. In both cases, requests will be
 sent to the software queue.
 
 Then, after the requests are processed by software queues, they will be placed
-at the hardware queue, a second stage queue were the hardware has direct access
+at the hardware queue, a second stage queue where the hardware has direct access
 to process those requests. However, if the hardware does not have enough
 resources to accept more requests, blk-mq will places requests on a temporary
 queue, to be sent in the future, when the hardware is able.
index 75650f6..948a97d 100644 (file)
@@ -463,8 +463,8 @@ latex_elements['preamble']  += '''
        \\newcommand{\\kerneldocEndTC}{}
        \\newcommand{\\kerneldocBeginKR}{}
        \\newcommand{\\kerneldocEndKR}{}
-       \\newcommand{\\kerneldocBeginSC}{}
-       \\newcommand{\\kerneldocEndKR}{}
+       \\newcommand{\\kerneldocBeginJP}{}
+       \\newcommand{\\kerneldocEndJP}{}
     }
 '''
 
index d84eded..3b32336 100644 (file)
@@ -75,9 +75,6 @@ And optionally
  .resume - A pointer to a per-policy resume function which is called
  with interrupts disabled and _before_ the governor is started again.
 
- .ready - A pointer to a per-policy ready function which is called after
- the policy is fully initialized.
-
  .attr - A pointer to a NULL-terminated list of "struct freq_attr" which
  allow to export values to sysfs.
 
index 56f4423..1d7e491 100644 (file)
@@ -11,7 +11,7 @@ Required properties:
 - None
 
 Optional properties:
-- operating-points: Refer to Documentation/devicetree/bindings/opp/opp.txt for
+- operating-points: Refer to Documentation/devicetree/bindings/opp/opp-v1.yaml for
   details. OPPs *must* be supplied either via DT, i.e. this property, or
   populated at runtime.
 - clock-latency: Specify the possible maximum transition latency for clock,
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml
new file mode 100644 (file)
index 0000000..9cd42a6
--- /dev/null
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/cpufreq/cpufreq-mediatek-hw.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek's CPUFREQ Bindings
+
+maintainers:
+  - Hector Yuan <hector.yuan@mediatek.com>
+
+description:
+  CPUFREQ HW is a hardware engine used by MediaTek SoCs to
+  manage frequency in hardware. It is capable of controlling
+  frequency for multiple clusters.
+
+properties:
+  compatible:
+    const: mediatek,cpufreq-hw
+
+  reg:
+    minItems: 1
+    maxItems: 2
+    description:
+      Addresses and sizes for the memory of the HW bases in
+      each frequency domain. Each entry corresponds to
+      a register bank for each frequency domain present.
+
+  "#performance-domain-cells":
+    description:
+      Number of cells in a performance domain specifier.
+      Set const to 1 here for nodes providing multiple
+      performance domains.
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - "#performance-domain-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    cpus {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            cpu0: cpu@0 {
+                device_type = "cpu";
+                compatible = "arm,cortex-a55";
+                enable-method = "psci";
+                performance-domains = <&performance 0>;
+                reg = <0x000>;
+            };
+    };
+
+    /* ... */
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        performance: performance-controller@11bc00 {
+            compatible = "mediatek,cpufreq-hw";
+            reg = <0 0x0011bc10 0 0x120>, <0 0x0011bd30 0 0x120>;
+
+            #performance-domain-cells = <1>;
+        };
+    };
index ef68711..b8233ec 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
                          transition and not stable yet.
        Please refer to Documentation/devicetree/bindings/clock/clock-bindings.txt for
        generic clock consumer properties.
-- operating-points-v2: Please refer to Documentation/devicetree/bindings/opp/opp.txt
+- operating-points-v2: Please refer to Documentation/devicetree/bindings/opp/opp-v2.yaml
        for detail.
 - proc-supply: Regulator for Vproc of CPU cluster.
 
index d91a02a..6b0b452 100644 (file)
@@ -6,8 +6,6 @@ from the SoC, then supplies the OPP framework with 'prop' and 'supported
 hardware' information respectively.  The framework is then able to read
 the DT and operate in the usual way.
 
-For more information about the expected DT format [See: ../opp/opp.txt].
-
 Frequency Scaling only
 ----------------------
 
@@ -15,7 +13,7 @@ No vendor specific driver required for this.
 
 Located in CPU's node:
 
-- operating-points             : [See: ../power/opp.txt]
+- operating-points             : [See: ../power/opp-v1.yaml]
 
 Example [safe]
 --------------
@@ -37,7 +35,7 @@ This requires the ST CPUFreq driver to supply 'process' and 'version' info.
 
 Located in CPU's node:
 
-- operating-points-v2          : [See ../power/opp.txt]
+- operating-points-v2          : [See ../power/opp-v2.yaml]
 
 Example [unsafe]
 ----------------
index 52a24b8..bdbfd7c 100644 (file)
@@ -4,7 +4,7 @@ Binding for NVIDIA Tegra20 CPUFreq
 Required properties:
 - clocks: Must contain an entry for the CPU clock.
   See ../clocks/clock-bindings.txt for details.
-- operating-points-v2: See ../bindings/opp/opp.txt for details.
+- operating-points-v2: See ../bindings/opp/opp-v2.yaml for details.
 - #cooling-cells: Should be 2. See ../thermal/thermal-cooling-devices.yaml for details.
 
 For each opp entry in 'operating-points-v2' table:
index ac189dd..3fbeb37 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
 - clocks:               Phandles for clock specified in "clock-names" property
 - clock-names :                 The name of clock used by the DFI, must be
                         "pclk_ddr_mon";
-- operating-points-v2:  Refer to Documentation/devicetree/bindings/opp/opp.txt
+- operating-points-v2:  Refer to Documentation/devicetree/bindings/opp/opp-v2.yaml
                         for details.
 - center-supply:        DMC supply node.
 - status:               Marks the node enabled/disabled.
index c5f6092..6f98dd5 100644 (file)
@@ -137,7 +137,7 @@ examples:
       resets = <&reset 0>, <&reset 1>;
     };
 
-    gpu_opp_table: opp_table0 {
+    gpu_opp_table: opp-table {
       compatible = "operating-points-v2";
 
       opp-533000000 {
index 696c17a..d209f27 100644 (file)
@@ -160,7 +160,7 @@ examples:
       #cooling-cells = <2>;
     };
 
-    gpu_opp_table: opp_table0 {
+    gpu_opp_table: opp-table {
       compatible = "operating-points-v2";
 
       opp-533000000 {
index a887373..b8204ed 100644 (file)
@@ -81,10 +81,10 @@ examples:
         noc_opp_table: opp-table {
             compatible = "operating-points-v2";
 
-            opp-133M {
+            opp-133333333 {
                 opp-hz = /bits/ 64 <133333333>;
             };
-            opp-800M {
+            opp-800000000 {
                 opp-hz = /bits/ 64 <800000000>;
             };
         };
index aeff2bd..729ae97 100644 (file)
@@ -18,6 +18,9 @@ description: |
   sun50i-cpufreq-nvmem driver reads the efuse value from the SoC to
   provide the OPP framework with required information.
 
+allOf:
+  - $ref: opp-v2-base.yaml#
+
 properties:
   compatible:
     const: allwinner,sun50i-h6-operating-points
@@ -43,6 +46,7 @@ patternProperties:
 
     properties:
       opp-hz: true
+      clock-latency-ns: true
 
     patternProperties:
       "opp-microvolt-.*": true
diff --git a/Documentation/devicetree/bindings/opp/opp-v1.yaml b/Documentation/devicetree/bindings/opp/opp-v1.yaml
new file mode 100644 (file)
index 0000000..d585d53
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/opp/opp-v1.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic OPP (Operating Performance Points) v1 Bindings
+
+maintainers:
+  - Viresh Kumar <viresh.kumar@linaro.org>
+
+description: |+
+  Devices work at voltage-current-frequency combinations and some implementations
+  have the liberty of choosing these. These combinations are called Operating
+  Performance Points aka OPPs. This document defines bindings for these OPPs
+  applicable across wide range of devices. For illustration purpose, this document
+  uses CPU as a device.
+
+  This binding only supports voltage-frequency pairs.
+
+select: true
+
+properties:
+  operating-points:
+    $ref: /schemas/types.yaml#/definitions/uint32-matrix
+    items:
+      items:
+        - description: Frequency in kHz
+        - description: Voltage for OPP in uV
+
+
+additionalProperties: true
+examples:
+  - |
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "arm,cortex-a9";
+            device_type = "cpu";
+            reg = <0>;
+            next-level-cache = <&L2>;
+            operating-points =
+                /* kHz    uV */
+                <792000 1100000>,
+                <396000 950000>,
+                <198000 850000>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/opp/opp-v2-base.yaml b/Documentation/devicetree/bindings/opp/opp-v2-base.yaml
new file mode 100644 (file)
index 0000000..ae3ae4d
--- /dev/null
@@ -0,0 +1,214 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/opp/opp-v2-base.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic OPP (Operating Performance Points) Common Binding
+
+maintainers:
+  - Viresh Kumar <viresh.kumar@linaro.org>
+
+description: |
+  Devices work at voltage-current-frequency combinations and some implementations
+  have the liberty of choosing these. These combinations are called Operating
+  Performance Points aka OPPs. This document defines bindings for these OPPs
+  applicable across wide range of devices. For illustration purpose, this document
+  uses CPU as a device.
+
+  This describes the OPPs belonging to a device.
+
+select: false
+
+properties:
+  $nodename:
+    pattern: '^opp-table(-[a-z0-9]+)?$'
+
+  opp-shared:
+    description:
+      Indicates that device nodes using this OPP Table Node's phandle switch
+      their DVFS state together, i.e. they share clock/voltage/current lines.
+      Missing property means devices have independent clock/voltage/current
+      lines, but they share OPP tables.
+    type: boolean
+
+patternProperties:
+  '^opp-?[0-9]+$':
+    type: object
+    description:
+      One or more OPP nodes describing voltage-current-frequency combinations.
+      Their name isn't significant but their phandle can be used to reference an
+      OPP. These are mandatory except for the case where the OPP table is
+      present only to indicate dependency between devices using the opp-shared
+      property.
+
+    properties:
+      opp-hz:
+        description:
+          Frequency in Hz, expressed as a 64-bit big-endian integer. This is a
+          required property for all device nodes, unless another "required"
+          property to uniquely identify the OPP nodes exists. Devices like power
+          domains must have another (implementation dependent) property.
+
+      opp-microvolt:
+        description: |
+          Voltage for the OPP
+
+          A single regulator's voltage is specified with an array of size one or three.
+          Single entry is for target voltage and three entries are for <target min max>
+          voltages.
+
+          Entries for multiple regulators shall be provided in the same field separated
+          by angular brackets <>. The OPP binding doesn't provide any provisions to
+          relate the values to their power supplies or the order in which the supplies
+          need to be configured and that is left for the implementation specific
+          binding.
+
+          Entries for all regulators shall be of the same size, i.e. either all use a
+          single value or triplets.
+        minItems: 1
+        maxItems: 8   # Should be enough regulators
+        items:
+          minItems: 1
+          maxItems: 3
+
+      opp-microamp:
+        description: |
+          The maximum current drawn by the device in microamperes considering
+          system specific parameters (such as transients, process, aging,
+          maximum operating temperature range etc.) as necessary. This may be
+          used to set the most efficient regulator operating mode.
+
+          Should only be set if opp-microvolt or opp-microvolt-<name> is set for
+          the OPP.
+
+          Entries for multiple regulators shall be provided in the same field
+          separated by angular brackets <>. If current values aren't required
+          for a regulator, then it shall be filled with 0. If current values
+          aren't required for any of the regulators, then this field is not
+          required. The OPP binding doesn't provide any provisions to relate the
+          values to their power supplies or the order in which the supplies need
+          to be configured and that is left for the implementation specific
+          binding.
+        minItems: 1
+        maxItems: 8   # Should be enough regulators
+
+      opp-level:
+        description:
+          A value representing the performance level of the device.
+        $ref: /schemas/types.yaml#/definitions/uint32
+
+      opp-peak-kBps:
+        description:
+          Peak bandwidth in kilobytes per second, expressed as an array of
+          32-bit big-endian integers. Each element of the array represents the
+          peak bandwidth value of each interconnect path. The number of elements
+          should match the number of interconnect paths.
+        minItems: 1
+        maxItems: 32  # Should be enough
+
+      opp-avg-kBps:
+        description:
+          Average bandwidth in kilobytes per second, expressed as an array
+          of 32-bit big-endian integers. Each element of the array represents the
+          average bandwidth value of each interconnect path. The number of elements
+          should match the number of interconnect paths. This property is only
+          meaningful in OPP tables where opp-peak-kBps is present.
+        minItems: 1
+        maxItems: 32  # Should be enough
+
+      clock-latency-ns:
+        description:
+          Specifies the maximum possible transition latency (in nanoseconds) for
+          switching to this OPP from any other OPP.
+
+      turbo-mode:
+        description:
+          Marks the OPP to be used only for turbo modes. Turbo mode is available
+          on some platforms, where the device can run over its operating
+          frequency for a short duration of time limited by the device's power,
+          current and thermal limits.
+        type: boolean
+
+      opp-suspend:
+        description:
+          Marks the OPP to be used during device suspend. If multiple OPPs in
+          the table have this, the OPP with highest opp-hz will be used.
+        type: boolean
+
+      opp-supported-hw:
+        description: |
+          This property allows a platform to enable only a subset of the OPPs
+          from the larger set present in the OPP table, based on the current
+          version of the hardware (already known to the operating system).
+
+          Each block present in the array of blocks in this property, represents
+          a sub-group of hardware versions supported by the OPP. i.e. <sub-group
+          A>, <sub-group B>, etc. The OPP will be enabled if _any_ of these
+          sub-groups match the hardware's version.
+
+          Each sub-group is a platform defined array representing the hierarchy
+          of hardware versions supported by the platform. For a platform with
+          three hierarchical levels of version (X.Y.Z), this field shall look
+          like
+
+          opp-supported-hw = <X1 Y1 Z1>, <X2 Y2 Z2>, <X3 Y3 Z3>.
+
+          Each level (eg. X1) in version hierarchy is represented by a 32 bit
+          value, one bit per version and so there can be maximum 32 versions per
+          level. Logical AND (&) operation is performed for each level with the
+          hardware's level version and a non-zero output for _all_ the levels in
+          a sub-group means the OPP is supported by hardware. A value of
+          0xFFFFFFFF for each level in the sub-group will enable the OPP for all
+          versions for the hardware.
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        maxItems: 32
+        items:
+          minItems: 1
+          maxItems: 4
+
+      required-opps:
+        description:
+          This contains phandle to an OPP node in another device's OPP table. It
+          may contain an array of phandles, where each phandle points to an OPP
+          of a different device. It should not contain multiple phandles to the
+          OPP nodes in the same OPP table. This specifies the minimum required
+          OPP of the device(s), whose OPP's phandle is present in this property,
+          for the functioning of the current device at the current OPP (where
+          this property is present).
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+
+    patternProperties:
+      '^opp-microvolt-':
+        description:
+          Named opp-microvolt property. This is exactly similar to the above
+          opp-microvolt property, but allows multiple voltage ranges to be
+          provided for the same OPP. At runtime, the platform can pick a <name>
+          and matching opp-microvolt-<name> property will be enabled for all
+          OPPs. If the platform doesn't pick a specific <name> or the <name>
+          doesn't match with any opp-microvolt-<name> properties, then
+          opp-microvolt property shall be used, if present.
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        minItems: 1
+        maxItems: 8   # Should be enough regulators
+        items:
+          minItems: 1
+          maxItems: 3
+
+      '^opp-microamp-':
+        description:
+          Named opp-microamp property. Similar to opp-microvolt-<name> property,
+          but for microamp instead.
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        maxItems: 8   # Should be enough regulators
+
+    dependencies:
+      opp-avg-kBps: [ opp-peak-kBps ]
+
+required:
+  - compatible
+
+additionalProperties: true
+
+...
diff --git a/Documentation/devicetree/bindings/opp/opp-v2.yaml b/Documentation/devicetree/bindings/opp/opp-v2.yaml
new file mode 100644 (file)
index 0000000..eaf8fba
--- /dev/null
@@ -0,0 +1,475 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/opp/opp-v2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic OPP (Operating Performance Points) Bindings
+
+maintainers:
+  - Viresh Kumar <viresh.kumar@linaro.org>
+
+allOf:
+  - $ref: opp-v2-base.yaml#
+
+properties:
+  compatible:
+    const: operating-points-v2
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    /*
+     * Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states
+     * together.
+     */
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "arm,cortex-a9";
+            device_type = "cpu";
+            reg = <0>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 0>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply0>;
+            operating-points-v2 = <&cpu0_opp_table0>;
+        };
+
+        cpu@1 {
+            compatible = "arm,cortex-a9";
+            device_type = "cpu";
+            reg = <1>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 0>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply0>;
+            operating-points-v2 = <&cpu0_opp_table0>;
+        };
+    };
+
+    cpu0_opp_table0: opp-table {
+        compatible = "operating-points-v2";
+        opp-shared;
+
+        opp-1000000000 {
+            opp-hz = /bits/ 64 <1000000000>;
+            opp-microvolt = <975000 970000 985000>;
+            opp-microamp = <70000>;
+            clock-latency-ns = <300000>;
+            opp-suspend;
+        };
+        opp-1100000000 {
+            opp-hz = /bits/ 64 <1100000000>;
+            opp-microvolt = <1000000 980000 1010000>;
+            opp-microamp = <80000>;
+            clock-latency-ns = <310000>;
+        };
+        opp-1200000000 {
+            opp-hz = /bits/ 64 <1200000000>;
+            opp-microvolt = <1025000>;
+            clock-latency-ns = <290000>;
+            turbo-mode;
+        };
+    };
+
+  - |
+    /*
+     * Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states
+     * independently.
+     */
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "qcom,krait";
+            device_type = "cpu";
+            reg = <0>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 0>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply0>;
+            operating-points-v2 = <&cpu_opp_table>;
+        };
+
+        cpu@1 {
+            compatible = "qcom,krait";
+            device_type = "cpu";
+            reg = <1>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 1>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply1>;
+            operating-points-v2 = <&cpu_opp_table>;
+        };
+
+        cpu@2 {
+            compatible = "qcom,krait";
+            device_type = "cpu";
+            reg = <2>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 2>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply2>;
+            operating-points-v2 = <&cpu_opp_table>;
+        };
+
+        cpu@3 {
+            compatible = "qcom,krait";
+            device_type = "cpu";
+            reg = <3>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 3>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply3>;
+            operating-points-v2 = <&cpu_opp_table>;
+        };
+    };
+
+    cpu_opp_table: opp-table {
+        compatible = "operating-points-v2";
+
+        /*
+         * Missing opp-shared property means CPUs switch DVFS states
+         * independently.
+         */
+
+        opp-1000000000 {
+            opp-hz = /bits/ 64 <1000000000>;
+            opp-microvolt = <975000 970000 985000>;
+            opp-microamp = <70000>;
+            clock-latency-ns = <300000>;
+            opp-suspend;
+        };
+        opp-1100000000 {
+            opp-hz = /bits/ 64 <1100000000>;
+            opp-microvolt = <1000000 980000 1010000>;
+            opp-microamp = <80000>;
+            clock-latency-ns = <310000>;
+        };
+        opp-1200000000 {
+            opp-hz = /bits/ 64 <1200000000>;
+            opp-microvolt = <1025000>;
+            opp-microamp = <90000>;
+            lock-latency-ns = <290000>;
+            turbo-mode;
+        };
+    };
+
+  - |
+    /*
+     * Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch
+     * DVFS state together.
+     */
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "arm,cortex-a7";
+            device_type = "cpu";
+            reg = <0>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 0>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply0>;
+            operating-points-v2 = <&cluster0_opp>;
+        };
+
+        cpu@1 {
+            compatible = "arm,cortex-a7";
+            device_type = "cpu";
+            reg = <1>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 0>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply0>;
+            operating-points-v2 = <&cluster0_opp>;
+        };
+
+        cpu@100 {
+            compatible = "arm,cortex-a15";
+            device_type = "cpu";
+            reg = <100>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 1>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply1>;
+            operating-points-v2 = <&cluster1_opp>;
+        };
+
+        cpu@101 {
+            compatible = "arm,cortex-a15";
+            device_type = "cpu";
+            reg = <101>;
+            next-level-cache = <&L2>;
+            clocks = <&clk_controller 1>;
+            clock-names = "cpu";
+            cpu-supply = <&cpu_supply1>;
+            operating-points-v2 = <&cluster1_opp>;
+        };
+    };
+
+    cluster0_opp: opp-table-0 {
+        compatible = "operating-points-v2";
+        opp-shared;
+
+        opp-1000000000 {
+            opp-hz = /bits/ 64 <1000000000>;
+            opp-microvolt = <975000 970000 985000>;
+            opp-microamp = <70000>;
+            clock-latency-ns = <300000>;
+            opp-suspend;
+        };
+        opp-1100000000 {
+            opp-hz = /bits/ 64 <1100000000>;
+            opp-microvolt = <1000000 980000 1010000>;
+            opp-microamp = <80000>;
+            clock-latency-ns = <310000>;
+        };
+        opp-1200000000 {
+            opp-hz = /bits/ 64 <1200000000>;
+            opp-microvolt = <1025000>;
+            opp-microamp = <90000>;
+            clock-latency-ns = <290000>;
+            turbo-mode;
+        };
+    };
+
+    cluster1_opp: opp-table-1 {
+        compatible = "operating-points-v2";
+        opp-shared;
+
+        opp-1300000000 {
+            opp-hz = /bits/ 64 <1300000000>;
+            opp-microvolt = <1050000 1045000 1055000>;
+            opp-microamp = <95000>;
+            clock-latency-ns = <400000>;
+            opp-suspend;
+        };
+        opp-1400000000 {
+            opp-hz = /bits/ 64 <1400000000>;
+            opp-microvolt = <1075000>;
+            opp-microamp = <100000>;
+            clock-latency-ns = <400000>;
+        };
+        opp-1500000000 {
+            opp-hz = /bits/ 64 <1500000000>;
+            opp-microvolt = <1100000 1010000 1110000>;
+            opp-microamp = <95000>;
+            clock-latency-ns = <400000>;
+            turbo-mode;
+        };
+    };
+
+  - |
+    /* Example 4: Handling multiple regulators */
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "foo,cpu-type";
+            device_type = "cpu";
+            reg = <0>;
+
+            vcc0-supply = <&cpu_supply0>;
+            vcc1-supply = <&cpu_supply1>;
+            vcc2-supply = <&cpu_supply2>;
+            operating-points-v2 = <&cpu0_opp_table4>;
+        };
+    };
+
+    cpu0_opp_table4: opp-table-0 {
+        compatible = "operating-points-v2";
+        opp-shared;
+
+        opp-1000000000 {
+            opp-hz = /bits/ 64 <1000000000>;
+            opp-microvolt = <970000>, /* Supply 0 */
+                            <960000>, /* Supply 1 */
+                            <960000>; /* Supply 2 */
+            opp-microamp =  <70000>,  /* Supply 0 */
+                            <70000>,  /* Supply 1 */
+                            <70000>;  /* Supply 2 */
+            clock-latency-ns = <300000>;
+        };
+
+        /* OR */
+
+        opp-1000000001 {
+            opp-hz = /bits/ 64 <1000000001>;
+            opp-microvolt = <975000 970000 985000>, /* Supply 0 */
+                            <965000 960000 975000>, /* Supply 1 */
+                            <965000 960000 975000>; /* Supply 2 */
+            opp-microamp =  <70000>,    /* Supply 0 */
+                <70000>,    /* Supply 1 */
+                <70000>;    /* Supply 2 */
+            clock-latency-ns = <300000>;
+        };
+
+        /* OR */
+
+        opp-1000000002 {
+            opp-hz = /bits/ 64 <1000000002>;
+            opp-microvolt = <975000 970000 985000>, /* Supply 0 */
+                <965000 960000 975000>, /* Supply 1 */
+                <965000 960000 975000>; /* Supply 2 */
+            opp-microamp =  <70000>,    /* Supply 0 */
+                <0>,      /* Supply 1 doesn't need this */
+                <70000>;    /* Supply 2 */
+            clock-latency-ns = <300000>;
+        };
+    };
+
+  - |
+    /*
+     * Example 5: opp-supported-hw
+     * (example: three level hierarchy of versions: cuts, substrate and process)
+     */
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "arm,cortex-a7";
+            device_type = "cpu";
+            reg = <0>;
+            cpu-supply = <&cpu_supply>;
+            operating-points-v2 = <&cpu0_opp_table_slow>;
+        };
+    };
+
+    cpu0_opp_table_slow: opp-table {
+        compatible = "operating-points-v2";
+        opp-shared;
+
+        opp-600000000 {
+            /*
+             * Supports all substrate and process versions for 0xF
+             * cuts, i.e. only first four cuts.
+             */
+            opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF>;
+            opp-hz = /bits/ 64 <600000000>;
+        };
+
+        opp-800000000 {
+            /*
+             * Supports:
+             * - cuts: only one, 6th cut (represented by 6th bit).
+             * - substrate: supports 16 different substrate versions
+             * - process: supports 9 different process versions
+             */
+            opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0>;
+            opp-hz = /bits/ 64 <800000000>;
+        };
+
+        opp-900000000 {
+            /*
+             * Supports:
+             * - All cuts and substrate where process version is 0x2.
+             * - All cuts and process where substrate version is 0x2.
+             */
+            opp-supported-hw = <0xFFFFFFFF 0xFFFFFFFF 0x02>,
+                               <0xFFFFFFFF 0x01 0xFFFFFFFF>;
+            opp-hz = /bits/ 64 <900000000>;
+        };
+    };
+
+  - |
+    /*
+     * Example 6: opp-microvolt-<name>, opp-microamp-<name>:
+     * (example: device with two possible microvolt ranges: slow and fast)
+     */
+    cpus {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "arm,cortex-a7";
+            device_type = "cpu";
+            reg = <0>;
+            operating-points-v2 = <&cpu0_opp_table6>;
+        };
+    };
+
+    cpu0_opp_table6: opp-table-0 {
+        compatible = "operating-points-v2";
+        opp-shared;
+
+        opp-1000000000 {
+            opp-hz = /bits/ 64 <1000000000>;
+            opp-microvolt-slow = <915000 900000 925000>;
+            opp-microvolt-fast = <975000 970000 985000>;
+            opp-microamp-slow =  <70000>;
+            opp-microamp-fast =  <71000>;
+        };
+
+        opp-1200000000 {
+            opp-hz = /bits/ 64 <1200000000>;
+            opp-microvolt-slow = <915000 900000 925000>, /* Supply vcc0 */
+                                 <925000 910000 935000>; /* Supply vcc1 */
+            opp-microvolt-fast = <975000 970000 985000>, /* Supply vcc0 */
+                                 <965000 960000 975000>; /* Supply vcc1 */
+            opp-microamp =  <70000>; /* Will be used for both slow/fast */
+        };
+    };
+
+  - |
+    /*
+     * Example 7: Single cluster Quad-core ARM cortex A53, OPP points from firmware,
+     * distinct clock controls but two sets of clock/voltage/current lines.
+     */
+    cpus {
+        #address-cells = <2>;
+        #size-cells = <0>;
+
+        cpu@0 {
+            compatible = "arm,cortex-a53";
+            device_type = "cpu";
+            reg = <0x0 0x100>;
+            next-level-cache = <&A53_L2>;
+            clocks = <&dvfs_controller 0>;
+            operating-points-v2 = <&cpu_opp0_table>;
+        };
+        cpu@1 {
+            compatible = "arm,cortex-a53";
+            device_type = "cpu";
+            reg = <0x0 0x101>;
+            next-level-cache = <&A53_L2>;
+            clocks = <&dvfs_controller 1>;
+            operating-points-v2 = <&cpu_opp0_table>;
+        };
+        cpu@2 {
+            compatible = "arm,cortex-a53";
+            device_type = "cpu";
+            reg = <0x0 0x102>;
+            next-level-cache = <&A53_L2>;
+            clocks = <&dvfs_controller 2>;
+            operating-points-v2 = <&cpu_opp1_table>;
+        };
+        cpu@3 {
+            compatible = "arm,cortex-a53";
+            device_type = "cpu";
+            reg = <0x0 0x103>;
+            next-level-cache = <&A53_L2>;
+            clocks = <&dvfs_controller 3>;
+            operating-points-v2 = <&cpu_opp1_table>;
+        };
+
+    };
+
+    cpu_opp0_table: opp-table-0 {
+        compatible = "operating-points-v2";
+        opp-shared;
+    };
+
+    cpu_opp1_table: opp-table-1 {
+        compatible = "operating-points-v2";
+        opp-shared;
+    };
+...
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt
deleted file mode 100644 (file)
index 08b3da4..0000000
+++ /dev/null
@@ -1,622 +0,0 @@
-Generic OPP (Operating Performance Points) Bindings
-----------------------------------------------------
-
-Devices work at voltage-current-frequency combinations and some implementations
-have the liberty of choosing these. These combinations are called Operating
-Performance Points aka OPPs. This document defines bindings for these OPPs
-applicable across wide range of devices. For illustration purpose, this document
-uses CPU as a device.
-
-This document contain multiple versions of OPP binding and only one of them
-should be used per device.
-
-Binding 1: operating-points
-============================
-
-This binding only supports voltage-frequency pairs.
-
-Properties:
-- operating-points: An array of 2-tuples items, and each item consists
-  of frequency and voltage like <freq-kHz vol-uV>.
-       freq: clock frequency in kHz
-       vol: voltage in microvolt
-
-Examples:
-
-cpu@0 {
-       compatible = "arm,cortex-a9";
-       reg = <0>;
-       next-level-cache = <&L2>;
-       operating-points = <
-               /* kHz    uV */
-               792000  1100000
-               396000  950000
-               198000  850000
-       >;
-};
-
-
-Binding 2: operating-points-v2
-============================
-
-* Property: operating-points-v2
-
-Devices supporting OPPs must set their "operating-points-v2" property with
-phandle to a OPP table in their DT node. The OPP core will use this phandle to
-find the operating points for the device.
-
-This can contain more than one phandle for power domain providers that provide
-multiple power domains. That is, one phandle for each power domain. If only one
-phandle is available, then the same OPP table will be used for all power domains
-provided by the power domain provider.
-
-If required, this can be extended for SoC vendor specific bindings. Such bindings
-should be documented as Documentation/devicetree/bindings/power/<vendor>-opp.txt
-and should have a compatible description like: "operating-points-v2-<vendor>".
-
-* OPP Table Node
-
-This describes the OPPs belonging to a device. This node can have following
-properties:
-
-Required properties:
-- compatible: Allow OPPs to express their compatibility. It should be:
-  "operating-points-v2".
-
-- OPP nodes: One or more OPP nodes describing voltage-current-frequency
-  combinations. Their name isn't significant but their phandle can be used to
-  reference an OPP. These are mandatory except for the case where the OPP table
-  is present only to indicate dependency between devices using the opp-shared
-  property.
-
-Optional properties:
-- opp-shared: Indicates that device nodes using this OPP Table Node's phandle
-  switch their DVFS state together, i.e. they share clock/voltage/current lines.
-  Missing property means devices have independent clock/voltage/current lines,
-  but they share OPP tables.
-
-- status: Marks the OPP table enabled/disabled.
-
-
-* OPP Node
-
-This defines voltage-current-frequency combinations along with other related
-properties.
-
-Required properties:
-- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. This is a
-  required property for all device nodes, unless another "required" property to
-  uniquely identify the OPP nodes exists. Devices like power domains must have
-  another (implementation dependent) property.
-
-- opp-peak-kBps: Peak bandwidth in kilobytes per second, expressed as an array
-  of 32-bit big-endian integers. Each element of the array represents the
-  peak bandwidth value of each interconnect path. The number of elements should
-  match the number of interconnect paths.
-
-Optional properties:
-- opp-microvolt: voltage in micro Volts.
-
-  A single regulator's voltage is specified with an array of size one or three.
-  Single entry is for target voltage and three entries are for <target min max>
-  voltages.
-
-  Entries for multiple regulators shall be provided in the same field separated
-  by angular brackets <>. The OPP binding doesn't provide any provisions to
-  relate the values to their power supplies or the order in which the supplies
-  need to be configured and that is left for the implementation specific
-  binding.
-
-  Entries for all regulators shall be of the same size, i.e. either all use a
-  single value or triplets.
-
-- opp-microvolt-<name>: Named opp-microvolt property. This is exactly similar to
-  the above opp-microvolt property, but allows multiple voltage ranges to be
-  provided for the same OPP. At runtime, the platform can pick a <name> and
-  matching opp-microvolt-<name> property will be enabled for all OPPs. If the
-  platform doesn't pick a specific <name> or the <name> doesn't match with any
-  opp-microvolt-<name> properties, then opp-microvolt property shall be used, if
-  present.
-
-- opp-microamp: The maximum current drawn by the device in microamperes
-  considering system specific parameters (such as transients, process, aging,
-  maximum operating temperature range etc.) as necessary. This may be used to
-  set the most efficient regulator operating mode.
-
-  Should only be set if opp-microvolt is set for the OPP.
-
-  Entries for multiple regulators shall be provided in the same field separated
-  by angular brackets <>. If current values aren't required for a regulator,
-  then it shall be filled with 0. If current values aren't required for any of
-  the regulators, then this field is not required. The OPP binding doesn't
-  provide any provisions to relate the values to their power supplies or the
-  order in which the supplies need to be configured and that is left for the
-  implementation specific binding.
-
-- opp-microamp-<name>: Named opp-microamp property. Similar to
-  opp-microvolt-<name> property, but for microamp instead.
-
-- opp-level: A value representing the performance level of the device,
-  expressed as a 32-bit integer.
-
-- opp-avg-kBps: Average bandwidth in kilobytes per second, expressed as an array
-  of 32-bit big-endian integers. Each element of the array represents the
-  average bandwidth value of each interconnect path. The number of elements
-  should match the number of interconnect paths. This property is only
-  meaningful in OPP tables where opp-peak-kBps is present.
-
-- clock-latency-ns: Specifies the maximum possible transition latency (in
-  nanoseconds) for switching to this OPP from any other OPP.
-
-- turbo-mode: Marks the OPP to be used only for turbo modes. Turbo mode is
-  available on some platforms, where the device can run over its operating
-  frequency for a short duration of time limited by the device's power, current
-  and thermal limits.
-
-- opp-suspend: Marks the OPP to be used during device suspend. If multiple OPPs
-  in the table have this, the OPP with highest opp-hz will be used.
-
-- opp-supported-hw: This property allows a platform to enable only a subset of
-  the OPPs from the larger set present in the OPP table, based on the current
-  version of the hardware (already known to the operating system).
-
-  Each block present in the array of blocks in this property, represents a
-  sub-group of hardware versions supported by the OPP. i.e. <sub-group A>,
-  <sub-group B>, etc. The OPP will be enabled if _any_ of these sub-groups match
-  the hardware's version.
-
-  Each sub-group is a platform defined array representing the hierarchy of
-  hardware versions supported by the platform. For a platform with three
-  hierarchical levels of version (X.Y.Z), this field shall look like
-
-  opp-supported-hw = <X1 Y1 Z1>, <X2 Y2 Z2>, <X3 Y3 Z3>.
-
-  Each level (eg. X1) in version hierarchy is represented by a 32 bit value, one
-  bit per version and so there can be maximum 32 versions per level. Logical AND
-  (&) operation is performed for each level with the hardware's level version
-  and a non-zero output for _all_ the levels in a sub-group means the OPP is
-  supported by hardware. A value of 0xFFFFFFFF for each level in the sub-group
-  will enable the OPP for all versions for the hardware.
-
-- status: Marks the node enabled/disabled.
-
-- required-opps: This contains phandle to an OPP node in another device's OPP
-  table. It may contain an array of phandles, where each phandle points to an
-  OPP of a different device. It should not contain multiple phandles to the OPP
-  nodes in the same OPP table. This specifies the minimum required OPP of the
-  device(s), whose OPP's phandle is present in this property, for the
-  functioning of the current device at the current OPP (where this property is
-  present).
-
-Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together.
-
-/ {
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               cpu@0 {
-                       compatible = "arm,cortex-a9";
-                       reg = <0>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 0>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply0>;
-                       operating-points-v2 = <&cpu0_opp_table>;
-               };
-
-               cpu@1 {
-                       compatible = "arm,cortex-a9";
-                       reg = <1>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 0>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply0>;
-                       operating-points-v2 = <&cpu0_opp_table>;
-               };
-       };
-
-       cpu0_opp_table: opp_table0 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-1000000000 {
-                       opp-hz = /bits/ 64 <1000000000>;
-                       opp-microvolt = <975000 970000 985000>;
-                       opp-microamp = <70000>;
-                       clock-latency-ns = <300000>;
-                       opp-suspend;
-               };
-               opp-1100000000 {
-                       opp-hz = /bits/ 64 <1100000000>;
-                       opp-microvolt = <1000000 980000 1010000>;
-                       opp-microamp = <80000>;
-                       clock-latency-ns = <310000>;
-               };
-               opp-1200000000 {
-                       opp-hz = /bits/ 64 <1200000000>;
-                       opp-microvolt = <1025000>;
-                       clock-latency-ns = <290000>;
-                       turbo-mode;
-               };
-       };
-};
-
-Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states
-independently.
-
-/ {
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               cpu@0 {
-                       compatible = "qcom,krait";
-                       reg = <0>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 0>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply0>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
-
-               cpu@1 {
-                       compatible = "qcom,krait";
-                       reg = <1>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 1>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply1>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
-
-               cpu@2 {
-                       compatible = "qcom,krait";
-                       reg = <2>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 2>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply2>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
-
-               cpu@3 {
-                       compatible = "qcom,krait";
-                       reg = <3>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 3>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply3>;
-                       operating-points-v2 = <&cpu_opp_table>;
-               };
-       };
-
-       cpu_opp_table: opp_table {
-               compatible = "operating-points-v2";
-
-               /*
-                * Missing opp-shared property means CPUs switch DVFS states
-                * independently.
-                */
-
-               opp-1000000000 {
-                       opp-hz = /bits/ 64 <1000000000>;
-                       opp-microvolt = <975000 970000 985000>;
-                       opp-microamp = <70000>;
-                       clock-latency-ns = <300000>;
-                       opp-suspend;
-               };
-               opp-1100000000 {
-                       opp-hz = /bits/ 64 <1100000000>;
-                       opp-microvolt = <1000000 980000 1010000>;
-                       opp-microamp = <80000>;
-                       clock-latency-ns = <310000>;
-               };
-               opp-1200000000 {
-                       opp-hz = /bits/ 64 <1200000000>;
-                       opp-microvolt = <1025000>;
-                       opp-microamp = <90000;
-                       lock-latency-ns = <290000>;
-                       turbo-mode;
-               };
-       };
-};
-
-Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch
-DVFS state together.
-
-/ {
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               cpu@0 {
-                       compatible = "arm,cortex-a7";
-                       reg = <0>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 0>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply0>;
-                       operating-points-v2 = <&cluster0_opp>;
-               };
-
-               cpu@1 {
-                       compatible = "arm,cortex-a7";
-                       reg = <1>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 0>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply0>;
-                       operating-points-v2 = <&cluster0_opp>;
-               };
-
-               cpu@100 {
-                       compatible = "arm,cortex-a15";
-                       reg = <100>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 1>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply1>;
-                       operating-points-v2 = <&cluster1_opp>;
-               };
-
-               cpu@101 {
-                       compatible = "arm,cortex-a15";
-                       reg = <101>;
-                       next-level-cache = <&L2>;
-                       clocks = <&clk_controller 1>;
-                       clock-names = "cpu";
-                       cpu-supply = <&cpu_supply1>;
-                       operating-points-v2 = <&cluster1_opp>;
-               };
-       };
-
-       cluster0_opp: opp_table0 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-1000000000 {
-                       opp-hz = /bits/ 64 <1000000000>;
-                       opp-microvolt = <975000 970000 985000>;
-                       opp-microamp = <70000>;
-                       clock-latency-ns = <300000>;
-                       opp-suspend;
-               };
-               opp-1100000000 {
-                       opp-hz = /bits/ 64 <1100000000>;
-                       opp-microvolt = <1000000 980000 1010000>;
-                       opp-microamp = <80000>;
-                       clock-latency-ns = <310000>;
-               };
-               opp-1200000000 {
-                       opp-hz = /bits/ 64 <1200000000>;
-                       opp-microvolt = <1025000>;
-                       opp-microamp = <90000>;
-                       clock-latency-ns = <290000>;
-                       turbo-mode;
-               };
-       };
-
-       cluster1_opp: opp_table1 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-1300000000 {
-                       opp-hz = /bits/ 64 <1300000000>;
-                       opp-microvolt = <1050000 1045000 1055000>;
-                       opp-microamp = <95000>;
-                       clock-latency-ns = <400000>;
-                       opp-suspend;
-               };
-               opp-1400000000 {
-                       opp-hz = /bits/ 64 <1400000000>;
-                       opp-microvolt = <1075000>;
-                       opp-microamp = <100000>;
-                       clock-latency-ns = <400000>;
-               };
-               opp-1500000000 {
-                       opp-hz = /bits/ 64 <1500000000>;
-                       opp-microvolt = <1100000 1010000 1110000>;
-                       opp-microamp = <95000>;
-                       clock-latency-ns = <400000>;
-                       turbo-mode;
-               };
-       };
-};
-
-Example 4: Handling multiple regulators
-
-/ {
-       cpus {
-               cpu@0 {
-                       compatible = "vendor,cpu-type";
-                       ...
-
-                       vcc0-supply = <&cpu_supply0>;
-                       vcc1-supply = <&cpu_supply1>;
-                       vcc2-supply = <&cpu_supply2>;
-                       operating-points-v2 = <&cpu0_opp_table>;
-               };
-       };
-
-       cpu0_opp_table: opp_table0 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-1000000000 {
-                       opp-hz = /bits/ 64 <1000000000>;
-                       opp-microvolt = <970000>, /* Supply 0 */
-                                       <960000>, /* Supply 1 */
-                                       <960000>; /* Supply 2 */
-                       opp-microamp =  <70000>,  /* Supply 0 */
-                                       <70000>,  /* Supply 1 */
-                                       <70000>;  /* Supply 2 */
-                       clock-latency-ns = <300000>;
-               };
-
-               /* OR */
-
-               opp-1000000000 {
-                       opp-hz = /bits/ 64 <1000000000>;
-                       opp-microvolt = <975000 970000 985000>, /* Supply 0 */
-                                       <965000 960000 975000>, /* Supply 1 */
-                                       <965000 960000 975000>; /* Supply 2 */
-                       opp-microamp =  <70000>,                /* Supply 0 */
-                                       <70000>,                /* Supply 1 */
-                                       <70000>;                /* Supply 2 */
-                       clock-latency-ns = <300000>;
-               };
-
-               /* OR */
-
-               opp-1000000000 {
-                       opp-hz = /bits/ 64 <1000000000>;
-                       opp-microvolt = <975000 970000 985000>, /* Supply 0 */
-                                       <965000 960000 975000>, /* Supply 1 */
-                                       <965000 960000 975000>; /* Supply 2 */
-                       opp-microamp =  <70000>,                /* Supply 0 */
-                                       <0>,                    /* Supply 1 doesn't need this */
-                                       <70000>;                /* Supply 2 */
-                       clock-latency-ns = <300000>;
-               };
-       };
-};
-
-Example 5: opp-supported-hw
-(example: three level hierarchy of versions: cuts, substrate and process)
-
-/ {
-       cpus {
-               cpu@0 {
-                       compatible = "arm,cortex-a7";
-                       ...
-
-                       cpu-supply = <&cpu_supply>
-                       operating-points-v2 = <&cpu0_opp_table_slow>;
-               };
-       };
-
-       opp_table {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-600000000 {
-                       /*
-                        * Supports all substrate and process versions for 0xF
-                        * cuts, i.e. only first four cuts.
-                        */
-                       opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF>
-                       opp-hz = /bits/ 64 <600000000>;
-                       ...
-               };
-
-               opp-800000000 {
-                       /*
-                        * Supports:
-                        * - cuts: only one, 6th cut (represented by 6th bit).
-                        * - substrate: supports 16 different substrate versions
-                        * - process: supports 9 different process versions
-                        */
-                       opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0>
-                       opp-hz = /bits/ 64 <800000000>;
-                       ...
-               };
-
-               opp-900000000 {
-                       /*
-                        * Supports:
-                        * - All cuts and substrate where process version is 0x2.
-                        * - All cuts and process where substrate version is 0x2.
-                        */
-                       opp-supported-hw = <0xFFFFFFFF 0xFFFFFFFF 0x02>, <0xFFFFFFFF 0x01 0xFFFFFFFF>
-                       opp-hz = /bits/ 64 <900000000>;
-                       ...
-               };
-       };
-};
-
-Example 6: opp-microvolt-<name>, opp-microamp-<name>:
-(example: device with two possible microvolt ranges: slow and fast)
-
-/ {
-       cpus {
-               cpu@0 {
-                       compatible = "arm,cortex-a7";
-                       ...
-
-                       operating-points-v2 = <&cpu0_opp_table>;
-               };
-       };
-
-       cpu0_opp_table: opp_table0 {
-               compatible = "operating-points-v2";
-               opp-shared;
-
-               opp-1000000000 {
-                       opp-hz = /bits/ 64 <1000000000>;
-                       opp-microvolt-slow = <915000 900000 925000>;
-                       opp-microvolt-fast = <975000 970000 985000>;
-                       opp-microamp-slow =  <70000>;
-                       opp-microamp-fast =  <71000>;
-               };
-
-               opp-1200000000 {
-                       opp-hz = /bits/ 64 <1200000000>;
-                       opp-microvolt-slow = <915000 900000 925000>, /* Supply vcc0 */
-                                             <925000 910000 935000>; /* Supply vcc1 */
-                       opp-microvolt-fast = <975000 970000 985000>, /* Supply vcc0 */
-                                            <965000 960000 975000>; /* Supply vcc1 */
-                       opp-microamp =  <70000>; /* Will be used for both slow/fast */
-               };
-       };
-};
-
-Example 7: Single cluster Quad-core ARM cortex A53, OPP points from firmware,
-distinct clock controls but two sets of clock/voltage/current lines.
-
-/ {
-       cpus {
-               #address-cells = <2>;
-               #size-cells = <0>;
-
-               cpu@0 {
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0 0x100>;
-                       next-level-cache = <&A53_L2>;
-                       clocks = <&dvfs_controller 0>;
-                       operating-points-v2 = <&cpu_opp0_table>;
-               };
-               cpu@1 {
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0 0x101>;
-                       next-level-cache = <&A53_L2>;
-                       clocks = <&dvfs_controller 1>;
-                       operating-points-v2 = <&cpu_opp0_table>;
-               };
-               cpu@2 {
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0 0x102>;
-                       next-level-cache = <&A53_L2>;
-                       clocks = <&dvfs_controller 2>;
-                       operating-points-v2 = <&cpu_opp1_table>;
-               };
-               cpu@3 {
-                       compatible = "arm,cortex-a53";
-                       reg = <0x0 0x103>;
-                       next-level-cache = <&A53_L2>;
-                       clocks = <&dvfs_controller 3>;
-                       operating-points-v2 = <&cpu_opp1_table>;
-               };
-
-       };
-
-       cpu_opp0_table: opp0_table {
-               compatible = "operating-points-v2";
-               opp-shared;
-       };
-
-       cpu_opp1_table: opp1_table {
-               compatible = "operating-points-v2";
-               opp-shared;
-       };
-};
index 32eb079..41d3e4f 100644 (file)
@@ -1,7 +1,7 @@
 Qualcomm OPP bindings to describe OPP nodes
 
 The bindings are based on top of the operating-points-v2 bindings
-described in Documentation/devicetree/bindings/opp/opp.txt
+described in Documentation/devicetree/bindings/opp/opp-v2-base.yaml
 Additional properties are described below.
 
 * OPP Table Node
index 832346e..b70d326 100644 (file)
@@ -13,7 +13,7 @@ regulators to the device that will undergo OPP transitions we can make use
 of the multi regulator binding that is part of the OPP core described here [1]
 to describe both regulators needed by the platform.
 
-[1] Documentation/devicetree/bindings/opp/opp.txt
+[1] Documentation/devicetree/bindings/opp/opp-v2.yaml
 
 Required Properties for Device Node:
 - vdd-supply: phandle to regulator controlling VDD supply
index aed51e9..3143ed9 100644 (file)
@@ -46,7 +46,7 @@ properties:
       Phandles to the OPP tables of power domains provided by a power domain
       provider. If the provider provides a single power domain only or all
       the power domains provided by the provider have identical OPP tables,
-      then this shall contain a single phandle. Refer to ../opp/opp.txt
+      then this shall contain a single phandle. Refer to ../opp/opp-v2-base.yaml
       for more information.
 
   "#power-domain-cells":
index 439fd90..bc53905 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Feature name:          huge-vmap
 #         Kconfig:       HAVE_ARCH_HUGE_VMAP
-#         description:   arch supports the ioremap_pud_enabled() and ioremap_pmd_enabled() VM APIs
+#         description:   arch supports the arch_vmap_pud_supported() and arch_vmap_pmd_supported() VM APIs
 #
     -----------------------
     |         arch |status|
index df65c19..55bd37a 100644 (file)
@@ -76,8 +76,8 @@ handler is never re-entered: if the same interrupt arrives, it is queued
 fast: frequently it simply acknowledges the interrupt, marks a 'software
 interrupt' for execution and exits.
 
-You can tell you are in a hardware interrupt, because
-:c:func:`in_irq()` returns true.
+You can tell you are in a hardware interrupt, because in_hardirq() returns
+true.
 
 .. warning::
 
index ed1284c..90bc3f5 100644 (file)
@@ -94,16 +94,10 @@ primitives, but I'll pretend they don't exist.
 Locking in the Linux Kernel
 ===========================
 
-If I could give you one piece of advice: never sleep with anyone crazier
-than yourself. But if I had to give you advice on locking: **keep it
-simple**.
+If I could give you one piece of advice on locking: **keep it simple**.
 
 Be reluctant to introduce new locks.
 
-Strangely enough, this last one is the exact reverse of my advice when
-you **have** slept with someone crazier than yourself. And you should
-think about getting a big dog.
-
 Two Main Types of Kernel Locks: Spinlocks and Mutexes
 -----------------------------------------------------
 
@@ -1406,7 +1400,7 @@ bh
   half will be running at any time.
 
 Hardware Interrupt / Hardware IRQ
-  Hardware interrupt request. in_irq() returns true in a
+  Hardware interrupt request. in_hardirq() returns true in a
   hardware interrupt handler.
 
 Interrupt Context
@@ -1418,7 +1412,7 @@ SMP
   (``CONFIG_SMP=y``).
 
 Software Interrupt / softirq
-  Software interrupt handler. in_irq() returns false;
+  Software interrupt handler. in_hardirq() returns false;
   in_softirq() returns true. Tasklets and softirqs both
   fall into the category of 'software interrupts'.
 
index 14ab578..dd4ecf4 100644 (file)
@@ -5,7 +5,7 @@ Futex Requeue PI
 Requeueing of tasks from a non-PI futex to a PI futex requires
 special handling in order to ensure the underlying rt_mutex is never
 left without an owner if it has waiters; doing so would break the PI
-boosting logic [see rt-mutex-desgin.txt] For the purposes of
+boosting logic [see rt-mutex-design.rst] For the purposes of
 brevity, this action will be referred to as "requeue_pi" throughout
 this document.  Priority inheritance is abbreviated throughout as
 "PI".
index 54d9c17..6a4d731 100644 (file)
@@ -2,7 +2,7 @@
 Wound/Wait Deadlock-Proof Mutex Design
 ======================================
 
-Please read mutex-design.txt first, as it applies to wait/wound mutexes too.
+Please read mutex-design.rst first, as it applies to wait/wound mutexes too.
 
 Motivation for WW-Mutexes
 -------------------------
index 2e7017b..c2121c1 100644 (file)
@@ -389,7 +389,7 @@ The -mm patches are experimental patches released by Andrew Morton.
 
 In the past, -mm tree were used to also test subsystem patches, but this
 function is now done via the
-`linux-next <https://www.kernel.org/doc/man-pages/linux-next.html>`
+`linux-next` (https://www.kernel.org/doc/man-pages/linux-next.html)
 tree. The Subsystem maintainers push their patches first to linux-next,
 and, during the merge window, sends them directly to Linus.
 
index 22d9ace..da95275 100644 (file)
@@ -126,15 +126,17 @@ On-line docs
         describes how to write user-mode utilities for communicating with
         Card Services.
 
-    * Title: **Linux Kernel Module Programming Guide**
+    * Title: **The Linux Kernel Module Programming Guide**
 
-      :Author: Ori Pomerantz.
-      :URL: https://tldp.org/LDP/lkmpg/2.6/html/index.html
-      :Date: 2001
+      :Author: Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram,
+        Jim Huang.
+      :URL: https://sysprog21.github.io/lkmpg/
+      :Date: 2021
       :Keywords: modules, GPL book, /proc, ioctls, system calls,
         interrupt handlers .
-      :Description: Very nice 92 pages GPL book on the topic of modules
-        programming. Lots of examples.
+      :Description: A very nice GPL book on the topic of modules
+        programming. Lots of examples. Currently the new version is being
+        actively maintained at https://github.com/sysprog21/lkmpg.
 
     * Title: **Global spinlock list and usage**
 
index 8f8f1fe..29e7d7b 100644 (file)
@@ -944,12 +944,11 @@ have on your keyring::
     uid           [ unknown] Linus Torvalds <torvalds@kernel.org>
     sub   rsa2048 2011-09-20 [E]
 
-Next, open the `PGP pathfinder`_. In the "From" field, paste the key
-fingerprint of Linus Torvalds from the output above. In the "To" field,
-paste the key-id you found via ``gpg --search`` of the unknown key, and
-check the results:
-
-- `Finding paths to Linus`_
+Next, find a trust path from Linus Torvalds to the key-id you found via ``gpg
+--search`` of the unknown key.  For this, you can use several tools including
+https://github.com/mricon/wotmate,
+https://git.kernel.org/pub/scm/docs/kernel/pgpkeys.git/tree/graphs, and
+https://the.earth.li/~noodles/pathfind.html.
 
 If you get a few decent trust paths, then it's a pretty good indication
 that it is a valid key. You can add it to your keyring from the
@@ -962,6 +961,3 @@ administrators of the PGP Pathfinder service to not be malicious (in
 fact, this goes against :ref:`devs_not_infra`). However, if you
 do not carefully maintain your own web of trust, then it is a marked
 improvement over blindly trusting keyservers.
-
-.. _`PGP pathfinder`: https://pgp.cs.uu.nl/
-.. _`Finding paths to Linus`: https://pgp.cs.uu.nl/paths/79BE3E4300411886/to/C94035C21B4F2AEB.html
index b4ea00f..d5c5213 100644 (file)
@@ -90,7 +90,7 @@ i gestori d'interruzioni devono essere veloci: spesso si limitano
 esclusivamente a notificare la presa in carico dell'interruzione,
 programmare una 'interruzione software' per l'esecuzione e quindi terminare.
 
-Potete dire d'essere in una interruzione hardware perché :c:func:`in_irq()`
+Potete dire d'essere in una interruzione hardware perché in_hardirq()
 ritorna vero.
 
 .. warning::
index 1e7c84d..1efb829 100644 (file)
@@ -1459,11 +1459,11 @@ contesto utente
   che hardware.
 
 interruzione hardware
-  Richiesta di interruzione hardware. in_irq() ritorna vero in un
+  Richiesta di interruzione hardware. in_hardirq() ritorna vero in un
   gestore d'interruzioni hardware.
 
 interruzione software / softirq
-  Gestore di interruzioni software: in_irq() ritorna falso;
+  Gestore di interruzioni software: in_hardirq() ritorna falso;
   in_softirq() ritorna vero. I tasklet e le softirq sono entrambi
   considerati 'interruzioni software'.
 
index 55827b8..6fee45f 100644 (file)
@@ -80,7 +80,7 @@ cpu上对这个地址空间进行刷新。
 5) ``void update_mmu_cache(struct vm_area_struct *vma,
    unsigned long address, pte_t *ptep)``
 
-       在每个页面故障结束时,这个程序被调用,以告诉体系结构特定的代码,在
+       在每个缺页异常结束时,这个程序被调用,以告诉体系结构特定的代码,在
        软件页表中,在地址空间“vma->vm_mm”的虚拟地址“地址”处,现在存在
        一个翻译。
 
index d5e947d..72f0a36 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../core-api/irq/index`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/core-api/index.rst
 
-.. _cn_core-api_index.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_core-api_index.rst:
 
 ===========
 核心API文档
index 41455bf..9957f04 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../../core-api/irq/concepts`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/core-api/irq/concepts.rst
 
-.. _cn_concepts.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_concepts.rst:
 
 ===========
 什么是IRQ?
index 910ccab..ba6acc4 100644 (file)
@@ -1,7 +1,10 @@
 .. include:: ../../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../../core-api/irq/index`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/core-api/irq/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_irq_index.rst:
 
index 82a4428..7addd5f 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../../core-api/irq/irq-affinity`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/core-api/irq/irq-affinity
 
-.. _cn_irq-affinity.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_irq-affinity.rst:
 
 ==============
 SMP IRQ 亲和性
index 3c82dd3..7d07774 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../../core-api/irq/irq-domain`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/core-api/irq/irq-domain.rst
 
-.. _cn_irq-domain.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_irq-domain.rst:
 
 =======================
 irq_domain 中断号映射库
index c889bd0..9af50b4 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../../core-api/irq/irqflags-tracing`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/core-api/irq/irqflags-tracing.rst
 
-.. _cn_irqflags-tracing.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_irqflags-tracing.rst:
 
 =================
 IRQ-flags状态追踪
index d6f815e..ab7d818 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/kernel-api.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
 
-.. _cn_kernel-api.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_kernel-api.rst:
 
 ============
 Linux内核API
index f0e6a4a..b7c3779 100644 (file)
@@ -1,7 +1,10 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/kobject.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_core_api_kobject.rst:
 
index ee67379..41e4525 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/local_ops.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
 
-.. _cn_local_ops:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_local_ops:
 
 ========================
 本地原子操作的语义和行为
index c627f8f..781d306 100644 (file)
@@ -3,7 +3,10 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/padata.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_core_api_padata.rst:
 
index 2b20f63..d574de3 100644 (file)
@@ -2,10 +2,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/printk-basics.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
 
-.. _cn_printk-basics.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_printk-basics.rst:
 
 ==================
 使用printk记录消息
index a680c8f..ce39c78 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/printk-formats.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
 
-.. _cn_printk-formats.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_printk-formats.rst:
 
 ==============================
 如何获得正确的printk格式占位符
index ea834e3..e2467fd 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/refcount-vs-atomic.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
 
-.. _cn_refcount-vs-atomic:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_refcount-vs-atomic:
 
 =======================================
 与atomic_t相比,refcount_t的API是这样的
index ce05c29..6abf7ed 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/symbol-namespaces.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
 
-.. _cn_symbol-namespaces.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_symbol-namespaces.rst:
 
 =================================
 符号命名空间(Symbol Namespaces)
index 0b8f730..e372fa5 100644 (file)
@@ -2,10 +2,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/core-api/workqueue.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
 
-.. _cn_workqueue.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_workqueue.rst:
 
 =========================
 并发管理的工作队列 (cmwq)
index 19fb9c0..0c6fd44 100644 (file)
@@ -1,11 +1,13 @@
 .. SPDX-License-Identifier: GPL-2.0
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../cpu-freq/core`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/cpu-freq/core.rst
 
-.. _cn_core.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_core.rst:
 
 ====================================
 CPUFreq核心和CPUFreq通知器的通用说明
index 5ae9cfa..0fc5d14 100644 (file)
@@ -2,11 +2,13 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../cpu-freq/cpu-drivers`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/cpu-freq/cpu-drivers.rst
 
-.. _cn_cpu-drivers.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_cpu-drivers.rst:
 
 =======================================
 如何实现一个新的CPUFreq处理器驱动程序?
@@ -80,8 +82,6 @@ CPUfreq核心层注册一个cpufreq_driver结构体。
  .resume - 一个指向per-policy恢复函数的指针,该函数在关中断且在调节器再一次开始前被
  调用。
 
- .ready - 一个指向per-policy准备函数的指针,该函数在策略完全初始化之后被调用。
-
  .attr - 一个指向NULL结尾的"struct freq_attr"列表的指针,该函数允许导出值到
  sysfs。
 
index c90d1d8..f144230 100644 (file)
@@ -2,11 +2,13 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../cpu-freq/cpufreq-stats`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/cpu-freq/cpufreq-stats.rst
 
-.. _cn_cpufreq-stats.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_cpufreq-stats.rst:
 
 ==========================================
 sysfs CPUFreq Stats的一般说明
index 65074e2..c6e5096 100644 (file)
@@ -2,11 +2,13 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../cpu-freq/index`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/cpu-freq/index.rst
 
-.. _cn_index.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_index.rst:
 
 =======================================================
 Linux CPUFreq - Linux(TM)内核中的CPU频率和电压升降代码
index 822c4d4..4981a82 100644 (file)
@@ -2,7 +2,7 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../filesystems/debugfs`
+:Original: Documentation/filesystems/debugfs.rst
 
 =======
 Debugfs
index 7e91d21..64f3f35 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../iio/ep93xx_adc`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/iio/ep93xx_adc.rst
 
-.. _cn_iio_ep93xx_adc:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_iio_ep93xx_adc:
 
 ==================================
 思睿逻辑 EP93xx 模拟数字转换器驱动
index 274488e..d5460e9 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../iio/iio_configfs`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/iio/iio_configfs.rst
 
-.. _cn_iio_configfs:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_iio_configfs:
 
 =====================
 工业 IIO configfs支持
index 7087076..32d6904 100644 (file)
@@ -2,11 +2,13 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../iio/index`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/iio/index.rst
 
-.. _cn_iio_index:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_iio_index:
 
 ========
 工业 I/O
index ab974fa..f2bc154 100644 (file)
@@ -68,7 +68,7 @@
 它将被排队(或丢弃)。因为它会关闭中断,所以处理程序必须很快:通常它只是
 确认中断,标记一个“软件中断”以执行并退出。
 
-您可以通过 :c:func:`in_irq()` 返回真来判断您处于硬件中断状态。
+您可以通过 in_hardirq() 返回真来判断您处于硬件中断状态。
 
 .. warning::
 
index 96453e1..e0bbd3f 100644 (file)
@@ -2,8 +2,11 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../mips/booting`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/mips/booting.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_booting:
 
index 93d93d0..b61dab0 100644 (file)
@@ -2,8 +2,11 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../mips/features`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/mips/features.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_features:
 
index b85033f..192c6ad 100644 (file)
@@ -2,8 +2,11 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../mips/index`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/mips/index.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 ===========================
 MIPS特性文档
index f04ba40..ddbe149 100644 (file)
@@ -2,8 +2,11 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../mips/ingenic-tcu`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/mips/ingenic-tcu.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_ingenic-tcu:
 
index d722642..9ad6cc6 100644 (file)
@@ -2,11 +2,13 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../openrisc/index`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/openrisc/index.rst
 
-.. _cn_openrisc_index:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_openrisc_index:
 
 =================
 OpenRISC 体系架构
index e87d0ee..b8a6767 100644 (file)
@@ -1,7 +1,10 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../openrisc/openrisc_port`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/openrisc/openrisc_port.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_openrisc_port:
 
index 9944ad0..63c3871 100644 (file)
@@ -1,7 +1,10 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../openrisc/todo`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/openrisc/todo.rst
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_openrisc_todo.rst:
 
index c21beb9..68b73eb 100644 (file)
@@ -1,7 +1,10 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/parisc/debugging.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_parisc_debugging:
 
index a47454e..0cc553f 100644 (file)
@@ -2,7 +2,10 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/parisc/index.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_parisc_index:
 
index 71e2404..d2ab187 100644 (file)
@@ -1,7 +1,10 @@
 .. include:: ../disclaimer-zh_CN.rst
 
 :Original: Documentation/parisc/registers.rst
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
 .. _cn_parisc_registers:
 
index 241bf9c..0234c28 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../riscv/boot-image-header`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/riscv/boot-image-header.rst
 
-.. _cn_boot-image-header.rst:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_boot-image-header.rst:
 
 ==========================
 RISC-V Linux启动镜像文件头
index db13b11..bbf5d7b 100644 (file)
@@ -2,11 +2,13 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../riscv/index`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/riscv/index.rst
 
-.. _cn_riscv_index:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_riscv_index:
 
 ===============
 RISC-V 体系结构
index 9fd1c82..d180d24 100644 (file)
@@ -2,11 +2,13 @@
 
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../riscv/patch-acceptance`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/riscv/patch-acceptance.rst
 
-.. _cn_riscv_patch-acceptance:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_riscv_patch-acceptance:
 
 arch/riscv 开发者维护指南
 =========================
index 22dcf3a..7ec8010 100644 (file)
@@ -1,10 +1,12 @@
 .. include:: ../disclaimer-zh_CN.rst
 
-:Original: :doc:`../../../riscv/pmu`
-:Translator: Yanteng Si <siyanteng@loongson.cn>
+:Original: Documentation/riscv/pmu.rst
 
-.. _cn_riscv_pmu:
+:翻译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
 
+.. _cn_riscv_pmu:
 
 ========================
 RISC-V平台上对PMUs的支持
diff --git a/Documentation/translations/zh_TW/arm64/amu.rst b/Documentation/translations/zh_TW/arm64/amu.rst
new file mode 100644 (file)
index 0000000..ffdc466
--- /dev/null
@@ -0,0 +1,104 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arm64/amu.rst <amu_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+            Hu Haowen <src.res@email.cn>
+
+==================================
+AArch64 Linux 中擴展的活動監控單元
+==================================
+
+作者: Ionela Voinescu <ionela.voinescu@arm.com>
+
+日期: 2019-09-10
+
+本文檔簡要描述了 AArch64 Linux 支持的活動監控單元的規範。
+
+
+架構總述
+--------
+
+活動監控是 ARMv8.4 CPU 架構引入的一個可選擴展特性。
+
+活動監控單元(在每個 CPU 中實現)爲系統管理提供了性能計數器。既可以通
+過系統寄存器的方式訪問計數器,同時也支持外部內存映射的方式訪問計數器。
+
+AMUv1 架構實現了一個由4個固定的64位事件計數器組成的計數器組。
+
+  - CPU 周期計數器:同 CPU 的頻率增長
+  - 常量計數器:同固定的系統時鐘頻率增長
+  - 淘汰指令計數器: 同每次架構指令執行增長
+  - 內存停頓周期計數器:計算由在時鐘域內的最後一級緩存中未命中而引起
+    的指令調度停頓周期數
+
+當處於 WFI 或者 WFE 狀態時,計數器不會增長。
+
+AMU 架構提供了一個高達16位的事件計數器空間,未來新的 AMU 版本中可能
+用它來實現新增的事件計數器。
+
+另外,AMUv1 實現了一個多達16個64位輔助事件計數器的計數器組。
+
+冷復位時所有的計數器會清零。
+
+
+基本支持
+--------
+
+內核可以安全地運行在支持 AMU 和不支持 AMU 的 CPU 組合中。
+因此,當配置 CONFIG_ARM64_AMU_EXTN 後我們無條件使能後續
+(secondary or hotplugged) CPU 檢測和使用這個特性。
+
+當在 CPU 上檢測到該特性時,我們會標記爲特性可用但是不能保證計數器的功能,
+僅表明有擴展屬性。
+
+固件(代碼運行在高異常級別,例如 arm-tf )需支持以下功能:
+
+ - 提供低異常級別(EL2 和 EL1)訪問 AMU 寄存器的能力。
+ - 使能計數器。如果未使能,它的值應爲 0。
+ - 在從電源關閉狀態啓動 CPU 前或後保存或者恢復計數器。
+
+當使用使能了該特性的內核啓動但固件損壞時,訪問計數器寄存器可能會遭遇
+panic 或者死鎖。即使未發現這些症狀,計數器寄存器返回的數據結果並不一
+定能反映真實情況。通常,計數器會返回 0,表明他們未被使能。
+
+如果固件沒有提供適當的支持最好關閉 CONFIG_ARM64_AMU_EXTN。
+值得注意的是,出於安全原因,不要繞過 AMUSERRENR_EL0 設置而捕獲從
+EL0(用戶空間) 訪問 EL1(內核空間)。 因此,固件應該確保訪問 AMU寄存器
+不會困在 EL2或EL3。
+
+AMUv1 的固定計數器可以通過如下系統寄存器訪問:
+
+ - SYS_AMEVCNTR0_CORE_EL0
+ - SYS_AMEVCNTR0_CONST_EL0
+ - SYS_AMEVCNTR0_INST_RET_EL0
+ - SYS_AMEVCNTR0_MEM_STALL_EL0
+
+特定輔助計數器可以通過 SYS_AMEVCNTR1_EL0(n) 訪問,其中n介於0到15。
+
+詳細信息定義在目錄:arch/arm64/include/asm/sysreg.h。
+
+
+用戶空間訪問
+------------
+
+由於以下原因,當前禁止從用戶空間訪問 AMU 的寄存器:
+
+  - 安全因數:可能會暴露處於安全模式執行的代碼信息。
+  - 意願:AMU 是用於系統管理的。
+
+同樣,該功能對用戶空間不可見。
+
+
+虛擬化
+------
+
+由於以下原因,當前禁止從 KVM 客戶端的用戶空間(EL0)和內核空間(EL1)
+訪問 AMU 的寄存器:
+
+  - 安全因數:可能會暴露給其他客戶端或主機端執行的代碼信息。
+
+任何試圖訪問 AMU 寄存器的行爲都會觸發一個註冊在客戶端的未定義異常。
+
diff --git a/Documentation/translations/zh_TW/arm64/booting.txt b/Documentation/translations/zh_TW/arm64/booting.txt
new file mode 100644 (file)
index 0000000..b9439dd
--- /dev/null
@@ -0,0 +1,251 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arm64/booting.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+M:     Will Deacon <will.deacon@arm.com>
+zh_CN: Fu Wei <wefu@redhat.com>
+zh_TW: Hu Haowen <src.res@email.cn>
+C:     55f058e7574c3615dea4615573a19bdb258696c6
+---------------------------------------------------------------------
+Documentation/arm64/booting.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+英文版維護者: Will Deacon <will.deacon@arm.com>
+中文版維護者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒  Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文  Hu Haowen <src.res@email.cn>
+本文翻譯提交時的 Git 檢出點爲: 55f058e7574c3615dea4615573a19bdb258696c6
+
+以下爲正文
+---------------------------------------------------------------------
+                       啓動 AArch64 Linux
+                       ==================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2012 年 09 月 07 日
+
+本文檔基於 Russell King 的 ARM 啓動文檔,且適用於所有公開發布的
+AArch64 Linux 內核代碼。
+
+AArch64 異常模型由多個異常級(EL0 - EL3)組成,對於 EL0 和 EL1 異常級
+有對應的安全和非安全模式。EL2 是系統管理級,且僅存在於非安全模式下。
+EL3 是最高特權級,且僅存在於安全模式下。
+
+基於本文檔的目的,我們將簡單地使用『引導裝載程序』(『boot loader』)
+這個術語來定義在將控制權交給 Linux 內核前 CPU 上執行的所有軟體。
+這可能包含安全監控和系統管理代碼,或者它可能只是一些用於準備最小啓動
+環境的指令。
+
+基本上,引導裝載程序(至少)應實現以下操作:
+
+1、設置和初始化 RAM
+2、設置設備樹數據
+3、解壓內核映像
+4、調用內核映像
+
+
+1、設置和初始化 RAM
+-----------------
+
+必要性: 強制
+
+引導裝載程序應該找到並初始化系統中所有內核用於保持系統變量數據的 RAM。
+這個操作的執行方式因設備而異。(它可能使用內部算法來自動定位和計算所有
+RAM,或可能使用對這個設備已知的 RAM 信息,還可能是引導裝載程序設計者
+想到的任何合適的方法。)
+
+
+2、設置設備樹數據
+---------------
+
+必要性: 強制
+
+設備樹數據塊(dtb)必須 8 字節對齊,且大小不能超過 2MB。由於設備樹
+數據塊將在使能緩存的情況下以 2MB 粒度被映射,故其不能被置於必須以特定
+屬性映射的2M區域內。
+
+註: v4.2 之前的版本同時要求設備樹數據塊被置於從內核映像以下
+text_offset 字節處算起第一個 512MB 內。
+
+3、解壓內核映像
+-------------
+
+必要性: 可選
+
+AArch64 內核當前沒有提供自解壓代碼,因此如果使用了壓縮內核映像文件
+(比如 Image.gz),則需要通過引導裝載程序(使用 gzip 等)來進行解壓。
+若引導裝載程序沒有實現這個功能,就要使用非壓縮內核映像文件。
+
+
+4、調用內核映像
+-------------
+
+必要性: 強制
+
+已解壓的內核映像包含一個 64 字節的頭,內容如下:
+
+  u32 code0;                   /* 可執行代碼 */
+  u32 code1;                   /* 可執行代碼 */
+  u64 text_offset;             /* 映像裝載偏移,小端模式 */
+  u64 image_size;              /* 映像實際大小, 小端模式 */
+  u64 flags;                   /* 內核旗標, 小端模式 *
+  u64 res2     = 0;            /* 保留 */
+  u64 res3     = 0;            /* 保留 */
+  u64 res4     = 0;            /* 保留 */
+  u32 magic    = 0x644d5241;   /* 魔數, 小端, "ARM\x64" */
+  u32 res5;                    /* 保留 (用於 PE COFF 偏移) */
+
+
+映像頭注釋:
+
+- 自 v3.17 起,除非另有說明,所有域都是小端模式。
+
+- code0/code1 負責跳轉到 stext.
+
+- 當通過 EFI 啓動時, 最初 code0/code1 被跳過。
+  res5 是到 PE 文件頭的偏移,而 PE 文件頭含有 EFI 的啓動入口點
+  (efi_stub_entry)。當 stub 代碼完成了它的使命,它會跳轉到 code0
+  繼續正常的啓動流程。
+
+- v3.17 之前,未明確指定 text_offset 的字節序。此時,image_size 爲零,
+  且 text_offset 依照內核字節序爲 0x80000。
+  當 image_size 非零,text_offset 爲小端模式且是有效值,應被引導加載
+  程序使用。當 image_size 爲零,text_offset 可假定爲 0x80000。
+
+- flags 域 (v3.17 引入) 爲 64 位小端模式,其編碼如下:
+  位 0:       內核字節序。 1 表示大端模式,0 表示小端模式。
+  位 1-2:     內核頁大小。
+                       0 - 未指定。
+                       1 - 4K
+                       2 - 16K
+                       3 - 64K
+  位 3:               內核物理位置
+                       0 - 2MB 對齊基址應儘量靠近內存起始處,因爲
+                           其基址以下的內存無法通過線性映射訪問
+                       1 - 2MB 對齊基址可以在物理內存的任意位置
+  位 4-63:    保留。
+
+- 當 image_size 爲零時,引導裝載程序應試圖在內核映像末尾之後儘可能
+  多地保留空閒內存供內核直接使用。對內存空間的需求量因所選定的內核
+  特性而異, 並無實際限制。
+
+內核映像必須被放置在任意一個可用系統內存 2MB 對齊基址的 text_offset
+字節處,並從該處被調用。2MB 對齊基址和內核映像起始地址之間的區域對於
+內核來說沒有特殊意義,且可能被用於其他目的。
+從映像起始地址算起,最少必須準備 image_size 字節的空閒內存供內核使用。
+註: v4.6 之前的版本無法使用內核映像物理偏移以下的內存,所以當時建議
+將映像儘量放置在靠近系統內存起始的地方。
+
+任何提供給內核的內存(甚至在映像起始地址之前),若未從內核中標記爲保留
+(如在設備樹(dtb)的 memreserve 區域),都將被認爲對內核是可用。
+
+在跳轉入內核前,必須符合以下狀態:
+
+- 停止所有 DMA 設備,這樣內存數據就不會因爲虛假網絡包或磁碟數據而
+  被破壞。這可能可以節省你許多的調試時間。
+
+- 主 CPU 通用寄存器設置
+  x0 = 系統 RAM 中設備樹數據塊(dtb)的物理地址。
+  x1 = 0 (保留,將來可能使用)
+  x2 = 0 (保留,將來可能使用)
+  x3 = 0 (保留,將來可能使用)
+
+- CPU 模式
+  所有形式的中斷必須在 PSTATE.DAIF 中被屏蔽(Debug、SError、IRQ
+  和 FIQ)。
+  CPU 必須處於 EL2(推薦,可訪問虛擬化擴展)或非安全 EL1 模式下。
+
+- 高速緩存、MMU
+  MMU 必須關閉。
+  指令緩存開啓或關閉皆可。
+  已載入的內核映像的相應內存區必須被清理,以達到緩存一致性點(PoC)。
+  當存在系統緩存或其他使能緩存的一致性主控器時,通常需使用虛擬地址
+  維護其緩存,而非 set/way 操作。
+  遵從通過虛擬地址操作維護構架緩存的系統緩存必須被配置,並可以被使能。
+  而不通過虛擬地址操作維護構架緩存的系統緩存(不推薦),必須被配置且
+  禁用。
+
+  *譯者註:對於 PoC 以及緩存相關內容,請參考 ARMv8 構架參考手冊
+   ARM DDI 0487A
+
+- 架構計時器
+  CNTFRQ 必須設定爲計時器的頻率,且 CNTVOFF 必須設定爲對所有 CPU
+  都一致的值。如果在 EL1 模式下進入內核,則 CNTHCTL_EL2 中的
+  EL1PCTEN (bit 0) 必須置位。
+
+- 一致性
+  通過內核啓動的所有 CPU 在內核入口地址上必須處於相同的一致性域中。
+  這可能要根據具體實現來定義初始化過程,以使能每個CPU上對維護操作的
+  接收。
+
+- 系統寄存器
+  在進入內核映像的異常級中,所有構架中可寫的系統寄存器必須通過軟體
+  在一個更高的異常級別下初始化,以防止在 未知 狀態下運行。
+
+  對於擁有 GICv3 中斷控制器並以 v3 模式運行的系統:
+  - 如果 EL3 存在:
+    ICC_SRE_EL3.Enable (位 3) 必須初始化爲 0b1。
+    ICC_SRE_EL3.SRE (位 0) 必須初始化爲 0b1。
+  - 若內核運行在 EL1:
+    ICC_SRE_EL2.Enable (位 3) 必須初始化爲 0b1。
+    ICC_SRE_EL2.SRE (位 0) 必須初始化爲 0b1。
+  - 設備樹(DT)或 ACPI 表必須描述一個 GICv3 中斷控制器。
+
+  對於擁有 GICv3 中斷控制器並以兼容(v2)模式運行的系統:
+  - 如果 EL3 存在:
+    ICC_SRE_EL3.SRE (位 0) 必須初始化爲 0b0。
+  - 若內核運行在 EL1:
+    ICC_SRE_EL2.SRE (位 0) 必須初始化爲 0b0。
+  - 設備樹(DT)或 ACPI 表必須描述一個 GICv2 中斷控制器。
+
+以上對於 CPU 模式、高速緩存、MMU、架構計時器、一致性、系統寄存器的
+必要條件描述適用於所有 CPU。所有 CPU 必須在同一異常級別跳入內核。
+
+引導裝載程序必須在每個 CPU 處於以下狀態時跳入內核入口:
+
+- 主 CPU 必須直接跳入內核映像的第一條指令。通過此 CPU 傳遞的設備樹
+  數據塊必須在每個 CPU 節點中包含一個 『enable-method』 屬性,所
+  支持的 enable-method 請見下文。
+
+  引導裝載程序必須生成這些設備樹屬性,並在跳入內核入口之前將其插入
+  數據塊。
+
+- enable-method 爲 「spin-table」 的 CPU 必須在它們的 CPU
+  節點中包含一個 『cpu-release-addr』 屬性。這個屬性標識了一個
+  64 位自然對齊且初始化爲零的內存位置。
+
+  這些 CPU 必須在內存保留區(通過設備樹中的 /memreserve/ 域傳遞
+  給內核)中自旋於內核之外,輪詢它們的 cpu-release-addr 位置(必須
+  包含在保留區中)。可通過插入 wfe 指令來降低忙循環開銷,而主 CPU 將
+  發出 sev 指令。當對 cpu-release-addr 所指位置的讀取操作返回非零值
+  時,CPU 必須跳入此值所指向的地址。此值爲一個單獨的 64 位小端值,
+  因此 CPU 須在跳轉前將所讀取的值轉換爲其本身的端模式。
+
+- enable-method 爲 「psci」 的 CPU 保持在內核外(比如,在
+  memory 節點中描述爲內核空間的內存區外,或在通過設備樹 /memreserve/
+  域中描述爲內核保留區的空間中)。內核將會發起在 ARM 文檔(編號
+  ARM DEN 0022A:用於 ARM 上的電源狀態協調接口系統軟體)中描述的
+  CPU_ON 調用來將 CPU 帶入內核。
+
+  *譯者注: ARM DEN 0022A 已更新到 ARM DEN 0022C。
+
+  設備樹必須包含一個 『psci』 節點,請參考以下文檔:
+  Documentation/devicetree/bindings/arm/psci.yaml
+
+
+- 輔助 CPU 通用寄存器設置
+  x0 = 0 (保留,將來可能使用)
+  x1 = 0 (保留,將來可能使用)
+  x2 = 0 (保留,將來可能使用)
+  x3 = 0 (保留,將來可能使用)
+
diff --git a/Documentation/translations/zh_TW/arm64/elf_hwcaps.rst b/Documentation/translations/zh_TW/arm64/elf_hwcaps.rst
new file mode 100644 (file)
index 0000000..3eb1c62
--- /dev/null
@@ -0,0 +1,244 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arm64/elf_hwcaps.rst <elf_hwcaps_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+            Hu Haowen <src.res@email.cn>
+
+================
+ARM64 ELF hwcaps
+================
+
+這篇文檔描述了 arm64 ELF hwcaps 的用法和語義。
+
+
+1. 簡介
+-------
+
+有些硬體或軟體功能僅在某些 CPU 實現上和/或在具體某個內核配置上可用,但
+對於處於 EL0 的用戶空間代碼沒有可用的架構發現機制。內核通過在輔助向量表
+公開一組稱爲 hwcaps 的標誌而把這些功能暴露給用戶空間。
+
+用戶空間軟體可以通過獲取輔助向量的 AT_HWCAP 或 AT_HWCAP2 條目來測試功能,
+並測試是否設置了相關標誌,例如::
+
+       bool floating_point_is_present(void)
+       {
+               unsigned long hwcaps = getauxval(AT_HWCAP);
+               if (hwcaps & HWCAP_FP)
+                       return true;
+
+               return false;
+       }
+
+如果軟體依賴於 hwcap 描述的功能,在嘗試使用該功能前則應檢查相關的 hwcap
+標誌以驗證該功能是否存在。
+
+不能通過其他方式探查這些功能。當一個功能不可用時,嘗試使用它可能導致不可
+預測的行爲,並且無法保證能確切的知道該功能不可用,例如 SIGILL。
+
+
+2. Hwcaps 的說明
+----------------
+
+大多數 hwcaps 旨在說明通過架構 ID 寄存器(處於 EL0 的用戶空間代碼無法訪問)
+描述的功能的存在。這些 hwcap 通過 ID 寄存器欄位定義,並且應根據 ARM 體系
+結構參考手冊(ARM ARM)中定義的欄位來解釋說明。
+
+這些 hwcaps 以下面的形式描述::
+
+    idreg.field == val 表示有某個功能。
+
+當 idreg.field 中有 val 時,hwcaps 表示 ARM ARM 定義的功能是有效的,但是
+並不是說要完全和 val 相等,也不是說 idreg.field 描述的其他功能就是缺失的。
+
+其他 hwcaps 可能表明無法僅由 ID 寄存器描述的功能的存在。這些 hwcaps 可能
+沒有被 ID 寄存器描述,需要參考其他文檔。
+
+
+3. AT_HWCAP 中揭示的 hwcaps
+---------------------------
+
+HWCAP_FP
+    ID_AA64PFR0_EL1.FP == 0b0000 表示有此功能。
+
+HWCAP_ASIMD
+    ID_AA64PFR0_EL1.AdvSIMD == 0b0000 表示有此功能。
+
+HWCAP_EVTSTRM
+    通用計時器頻率配置爲大約100KHz以生成事件。
+
+HWCAP_AES
+    ID_AA64ISAR0_EL1.AES == 0b0001 表示有此功能。
+
+HWCAP_PMULL
+    ID_AA64ISAR0_EL1.AES == 0b0010 表示有此功能。
+
+HWCAP_SHA1
+    ID_AA64ISAR0_EL1.SHA1 == 0b0001 表示有此功能。
+
+HWCAP_SHA2
+    ID_AA64ISAR0_EL1.SHA2 == 0b0001 表示有此功能。
+
+HWCAP_CRC32
+    ID_AA64ISAR0_EL1.CRC32 == 0b0001 表示有此功能。
+
+HWCAP_ATOMICS
+    ID_AA64ISAR0_EL1.Atomic == 0b0010 表示有此功能。
+
+HWCAP_FPHP
+    ID_AA64PFR0_EL1.FP == 0b0001 表示有此功能。
+
+HWCAP_ASIMDHP
+    ID_AA64PFR0_EL1.AdvSIMD == 0b0001 表示有此功能。
+
+HWCAP_CPUID
+    根據 Documentation/arm64/cpu-feature-registers.rst 描述,EL0 可以訪問
+    某些 ID 寄存器。
+
+    這些 ID 寄存器可能表示功能的可用性。
+
+HWCAP_ASIMDRDM
+    ID_AA64ISAR0_EL1.RDM == 0b0001 表示有此功能。
+
+HWCAP_JSCVT
+    ID_AA64ISAR1_EL1.JSCVT == 0b0001 表示有此功能。
+
+HWCAP_FCMA
+    ID_AA64ISAR1_EL1.FCMA == 0b0001 表示有此功能。
+
+HWCAP_LRCPC
+    ID_AA64ISAR1_EL1.LRCPC == 0b0001 表示有此功能。
+
+HWCAP_DCPOP
+    ID_AA64ISAR1_EL1.DPB == 0b0001 表示有此功能。
+
+HWCAP_SHA3
+    ID_AA64ISAR0_EL1.SHA3 == 0b0001 表示有此功能。
+
+HWCAP_SM3
+    ID_AA64ISAR0_EL1.SM3 == 0b0001 表示有此功能。
+
+HWCAP_SM4
+    ID_AA64ISAR0_EL1.SM4 == 0b0001 表示有此功能。
+
+HWCAP_ASIMDDP
+    ID_AA64ISAR0_EL1.DP == 0b0001 表示有此功能。
+
+HWCAP_SHA512
+    ID_AA64ISAR0_EL1.SHA2 == 0b0010 表示有此功能。
+
+HWCAP_SVE
+    ID_AA64PFR0_EL1.SVE == 0b0001 表示有此功能。
+
+HWCAP_ASIMDFHM
+    ID_AA64ISAR0_EL1.FHM == 0b0001 表示有此功能。
+
+HWCAP_DIT
+    ID_AA64PFR0_EL1.DIT == 0b0001 表示有此功能。
+
+HWCAP_USCAT
+    ID_AA64MMFR2_EL1.AT == 0b0001 表示有此功能。
+
+HWCAP_ILRCPC
+    ID_AA64ISAR1_EL1.LRCPC == 0b0010 表示有此功能。
+
+HWCAP_FLAGM
+    ID_AA64ISAR0_EL1.TS == 0b0001 表示有此功能。
+
+HWCAP_SSBS
+    ID_AA64PFR1_EL1.SSBS == 0b0010 表示有此功能。
+
+HWCAP_SB
+    ID_AA64ISAR1_EL1.SB == 0b0001 表示有此功能。
+
+HWCAP_PACA
+    如 Documentation/arm64/pointer-authentication.rst 所描述,
+    ID_AA64ISAR1_EL1.APA == 0b0001 或 ID_AA64ISAR1_EL1.API == 0b0001
+    表示有此功能。
+
+HWCAP_PACG
+    如 Documentation/arm64/pointer-authentication.rst 所描述,
+    ID_AA64ISAR1_EL1.GPA == 0b0001 或 ID_AA64ISAR1_EL1.GPI == 0b0001
+    表示有此功能。
+
+HWCAP2_DCPODP
+
+    ID_AA64ISAR1_EL1.DPB == 0b0010 表示有此功能。
+
+HWCAP2_SVE2
+
+    ID_AA64ZFR0_EL1.SVEVer == 0b0001 表示有此功能。
+
+HWCAP2_SVEAES
+
+    ID_AA64ZFR0_EL1.AES == 0b0001 表示有此功能。
+
+HWCAP2_SVEPMULL
+
+    ID_AA64ZFR0_EL1.AES == 0b0010 表示有此功能。
+
+HWCAP2_SVEBITPERM
+
+    ID_AA64ZFR0_EL1.BitPerm == 0b0001 表示有此功能。
+
+HWCAP2_SVESHA3
+
+    ID_AA64ZFR0_EL1.SHA3 == 0b0001 表示有此功能。
+
+HWCAP2_SVESM4
+
+    ID_AA64ZFR0_EL1.SM4 == 0b0001 表示有此功能。
+
+HWCAP2_FLAGM2
+
+    ID_AA64ISAR0_EL1.TS == 0b0010 表示有此功能。
+
+HWCAP2_FRINT
+
+    ID_AA64ISAR1_EL1.FRINTTS == 0b0001 表示有此功能。
+
+HWCAP2_SVEI8MM
+
+    ID_AA64ZFR0_EL1.I8MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEF32MM
+
+    ID_AA64ZFR0_EL1.F32MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEF64MM
+
+    ID_AA64ZFR0_EL1.F64MM == 0b0001 表示有此功能。
+
+HWCAP2_SVEBF16
+
+    ID_AA64ZFR0_EL1.BF16 == 0b0001 表示有此功能。
+
+HWCAP2_I8MM
+
+    ID_AA64ISAR1_EL1.I8MM == 0b0001 表示有此功能。
+
+HWCAP2_BF16
+
+    ID_AA64ISAR1_EL1.BF16 == 0b0001 表示有此功能。
+
+HWCAP2_DGH
+
+    ID_AA64ISAR1_EL1.DGH == 0b0001 表示有此功能。
+
+HWCAP2_RNG
+
+    ID_AA64ISAR0_EL1.RNDR == 0b0001 表示有此功能。
+
+HWCAP2_BTI
+
+    ID_AA64PFR0_EL1.BT == 0b0001 表示有此功能。
+
+
+4. 未使用的 AT_HWCAP 位
+-----------------------
+
+爲了與用戶空間交互,內核保證 AT_HWCAP 的第62、63位將始終返回0。
+
diff --git a/Documentation/translations/zh_TW/arm64/hugetlbpage.rst b/Documentation/translations/zh_TW/arm64/hugetlbpage.rst
new file mode 100644 (file)
index 0000000..846b500
--- /dev/null
@@ -0,0 +1,49 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arm64/hugetlbpage.rst <hugetlbpage_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+            Hu Haowen <src.res@email.cn>
+
+=====================
+ARM64中的 HugeTLBpage
+=====================
+
+大頁依靠有效利用 TLBs 來提高地址翻譯的性能。這取決於以下
+兩點 -
+
+  - 大頁的大小
+  - TLBs 支持的條目大小
+
+ARM64 接口支持2種大頁方式。
+
+1) pud/pmd 級別的塊映射
+-----------------------
+
+這是常規大頁,他們的 pmd 或 pud 頁面表條目指向一個內存塊。
+不管 TLB 中支持的條目大小如何,塊映射可以減少翻譯大頁地址
+所需遍歷的頁表深度。
+
+2) 使用連續位
+-------------
+
+架構中轉換頁表條目(D4.5.3, ARM DDI 0487C.a)中提供一個連續
+位告訴 MMU 這個條目是一個連續條目集的一員,它可以被緩存在單
+個 TLB 條目中。
+
+在 Linux 中連續位用來增加 pmd 和 pte(最後一級)級別映射的大
+小。受支持的連續頁表條目數量因頁面大小和頁表級別而異。
+
+
+支持以下大頁尺寸配置 -
+
+  ====== ========   ====    ========    ===
+  -      CONT PTE    PMD    CONT PMD    PUD
+  ====== ========   ====    ========    ===
+  4K:         64K     2M         32M     1G
+  16K:         2M    32M          1G
+  64K:         2M   512M         16G
+  ====== ========   ====    ========    ===
+
diff --git a/Documentation/translations/zh_TW/arm64/index.rst b/Documentation/translations/zh_TW/arm64/index.rst
new file mode 100644 (file)
index 0000000..2322783
--- /dev/null
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arm64/index.rst <arm64_index>`
+:Translator: Bailu Lin <bailu.lin@vivo.com>
+             Hu Haowen <src.res@email.cn>
+
+.. _tw_arm64_index:
+
+
+==========
+ARM64 架構
+==========
+
+.. toctree::
+    :maxdepth: 2
+
+    amu
+    hugetlbpage
+    perf
+    elf_hwcaps
+
diff --git a/Documentation/translations/zh_TW/arm64/legacy_instructions.txt b/Documentation/translations/zh_TW/arm64/legacy_instructions.txt
new file mode 100644 (file)
index 0000000..6d4454f
--- /dev/null
@@ -0,0 +1,77 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arm64/legacy_instructions.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Punit Agrawal <punit.agrawal@arm.com>
+            Suzuki K. Poulose <suzuki.poulose@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
+---------------------------------------------------------------------
+Documentation/arm64/legacy_instructions.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+本文翻譯提交時的 Git 檢出點爲: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6
+
+英文版維護者: Punit Agrawal <punit.agrawal@arm.com>
+            Suzuki K. Poulose <suzuki.poulose@arm.com>
+中文版維護者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒  Fu Wei <wefu@redhat.com>
+繁體中文版校譯者:胡皓文  Hu Haowen <src.res@email.cn>
+
+以下爲正文
+---------------------------------------------------------------------
+Linux 內核在 arm64 上的移植提供了一個基礎框架,以支持構架中正在被淘汰或已廢棄指令的模擬執行。
+這個基礎框架的代碼使用未定義指令鉤子(hooks)來支持模擬。如果指令存在,它也允許在硬體中啓用該指令。
+
+模擬模式可通過寫 sysctl 節點(/proc/sys/abi)來控制。
+不同的執行方式及 sysctl 節點的相應值,解釋如下:
+
+* Undef(未定義)
+  值: 0
+  產生未定義指令終止異常。它是那些構架中已廢棄的指令,如 SWP,的默認處理方式。
+
+* Emulate(模擬)
+  值: 1
+  使用軟體模擬方式。爲解決軟體遷移問題,這種模擬指令模式的使用是被跟蹤的,並會發出速率限制警告。
+  它是那些構架中正在被淘汰的指令,如 CP15 barriers(隔離指令),的默認處理方式。
+
+* Hardware Execution(硬體執行)
+  值: 2
+  雖然標記爲正在被淘汰,但一些實現可能提供硬體執行這些指令的使能/禁用操作。
+  使用硬體執行一般會有更好的性能,但將無法收集運行時對正被淘汰指令的使用統計數據。
+
+默認執行模式依賴於指令在構架中狀態。正在被淘汰的指令應該以模擬(Emulate)作爲默認模式,
+而已廢棄的指令必須默認使用未定義(Undef)模式
+
+注意:指令模擬可能無法應對所有情況。更多詳情請參考單獨的指令注釋。
+
+受支持的遺留指令
+-------------
+* SWP{B}
+節點: /proc/sys/abi/swp
+狀態: 已廢棄
+默認執行方式: Undef (0)
+
+* CP15 Barriers
+節點: /proc/sys/abi/cp15_barrier
+狀態: 正被淘汰,不推薦使用
+默認執行方式: Emulate (1)
+
+* SETEND
+節點: /proc/sys/abi/setend
+狀態: 正被淘汰,不推薦使用
+默認執行方式: Emulate (1)*
+註:爲了使能這個特性,系統中的所有 CPU 必須在 EL0 支持混合字節序。
+如果一個新的 CPU (不支持混合字節序) 在使能這個特性後被熱插入系統,
+在應用中可能會出現不可預期的結果。
+
diff --git a/Documentation/translations/zh_TW/arm64/memory.txt b/Documentation/translations/zh_TW/arm64/memory.txt
new file mode 100644 (file)
index 0000000..99c2b78
--- /dev/null
@@ -0,0 +1,119 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arm64/memory.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Catalin Marinas <catalin.marinas@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
+---------------------------------------------------------------------
+Documentation/arm64/memory.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+本文翻譯提交時的 Git 檢出點爲: bc465aa9d045feb0e13b4a8f32cc33c1943f62d6
+
+英文版維護者: Catalin Marinas <catalin.marinas@arm.com>
+中文版維護者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒  Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文  Hu Haowen <src.res@email.cn>
+
+以下爲正文
+---------------------------------------------------------------------
+                    Linux 在 AArch64 中的內存布局
+                    ===========================
+
+作者: Catalin Marinas <catalin.marinas@arm.com>
+
+本文檔描述 AArch64 Linux 內核所使用的虛擬內存布局。此構架可以實現
+頁大小爲 4KB 的 4 級轉換表和頁大小爲 64KB 的 3 級轉換表。
+
+AArch64 Linux 使用 3 級或 4 級轉換表,其頁大小配置爲 4KB,對於用戶和內核
+分別都有 39-bit (512GB) 或 48-bit (256TB) 的虛擬地址空間。
+對於頁大小爲 64KB的配置,僅使用 2 級轉換表,有 42-bit (4TB) 的虛擬地址空間,但內存布局相同。
+
+用戶地址空間的 63:48 位爲 0,而內核地址空間的相應位爲 1。TTBRx 的
+選擇由虛擬地址的 63 位給出。swapper_pg_dir 僅包含內核(全局)映射,
+而用戶 pgd 僅包含用戶(非全局)映射。swapper_pg_dir 地址被寫入
+TTBR1 中,且從不寫入 TTBR0。
+
+
+AArch64 Linux 在頁大小爲 4KB,並使用 3 級轉換表時的內存布局:
+
+起始地址                   結束地址                    大小          用途
+-----------------------------------------------------------------------
+0000000000000000       0000007fffffffff         512GB          用戶空間
+ffffff8000000000       ffffffffffffffff         512GB          內核空間
+
+
+AArch64 Linux 在頁大小爲 4KB,並使用 4 級轉換表時的內存布局:
+
+起始地址                   結束地址                    大小          用途
+-----------------------------------------------------------------------
+0000000000000000       0000ffffffffffff         256TB          用戶空間
+ffff000000000000       ffffffffffffffff         256TB          內核空間
+
+
+AArch64 Linux 在頁大小爲 64KB,並使用 2 級轉換表時的內存布局:
+
+起始地址                   結束地址                    大小          用途
+-----------------------------------------------------------------------
+0000000000000000       000003ffffffffff           4TB          用戶空間
+fffffc0000000000       ffffffffffffffff           4TB          內核空間
+
+
+AArch64 Linux 在頁大小爲 64KB,並使用 3 級轉換表時的內存布局:
+
+起始地址                   結束地址                    大小          用途
+-----------------------------------------------------------------------
+0000000000000000       0000ffffffffffff         256TB          用戶空間
+ffff000000000000       ffffffffffffffff         256TB          內核空間
+
+
+更詳細的內核虛擬內存布局,請參閱內核啓動信息。
+
+
+4KB 頁大小的轉換表查找:
+
++--------+--------+--------+--------+--------+--------+--------+--------+
+|63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
++--------+--------+--------+--------+--------+--------+--------+--------+
+ |                 |         |         |         |         |
+ |                 |         |         |         |         v
+ |                 |         |         |         |   [11:0]  頁內偏移
+ |                 |         |         |         +-> [20:12] L3 索引
+ |                 |         |         +-----------> [29:21] L2 索引
+ |                 |         +---------------------> [38:30] L1 索引
+ |                 +-------------------------------> [47:39] L0 索引
+ +-------------------------------------------------> [63] TTBR0/1
+
+
+64KB 頁大小的轉換表查找:
+
++--------+--------+--------+--------+--------+--------+--------+--------+
+|63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
++--------+--------+--------+--------+--------+--------+--------+--------+
+ |                 |    |               |              |
+ |                 |    |               |              v
+ |                 |    |               |            [15:0]  頁內偏移
+ |                 |    |               +----------> [28:16] L3 索引
+ |                 |    +--------------------------> [41:29] L2 索引
+ |                 +-------------------------------> [47:42] L1 索引
+ +-------------------------------------------------> [63] TTBR0/1
+
+
+當使用 KVM 時, 管理程序(hypervisor)在 EL2 中通過相對內核虛擬地址的
+一個固定偏移來映射內核頁(內核虛擬地址的高 24 位設爲零):
+
+起始地址                   結束地址                    大小          用途
+-----------------------------------------------------------------------
+0000004000000000       0000007fffffffff         256GB          在 HYP 中映射的內核對象
+
diff --git a/Documentation/translations/zh_TW/arm64/perf.rst b/Documentation/translations/zh_TW/arm64/perf.rst
new file mode 100644 (file)
index 0000000..f1ffd55
--- /dev/null
@@ -0,0 +1,88 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/arm64/perf.rst <perf_index>`
+
+Translator: Bailu Lin <bailu.lin@vivo.com>
+            Hu Haowen <src.res@email.cn>
+
+=============
+Perf 事件屬性
+=============
+
+:作者: Andrew Murray <andrew.murray@arm.com>
+:日期: 2019-03-06
+
+exclude_user
+------------
+
+該屬性排除用戶空間。
+
+用戶空間始終運行在 EL0,因此該屬性將排除 EL0。
+
+
+exclude_kernel
+--------------
+
+該屬性排除內核空間。
+
+打開 VHE 時內核運行在 EL2,不打開 VHE 時內核運行在 EL1。客戶機
+內核總是運行在 EL1。
+
+對於宿主機,該屬性排除 EL1 和 VHE 上的 EL2。
+
+對於客戶機,該屬性排除 EL1。請注意客戶機從來不會運行在 EL2。
+
+
+exclude_hv
+----------
+
+該屬性排除虛擬機監控器。
+
+對於 VHE 宿主機該屬性將被忽略,此時我們認爲宿主機內核是虛擬機監
+控器。
+
+對於 non-VHE 宿主機該屬性將排除 EL2,因爲虛擬機監控器運行在 EL2
+的任何代碼主要用於客戶機和宿主機的切換。
+
+對於客戶機該屬性無效。請注意客戶機從來不會運行在 EL2。
+
+
+exclude_host / exclude_guest
+----------------------------
+
+這些屬性分別排除了 KVM 宿主機和客戶機。
+
+KVM 宿主機可能運行在 EL0(用戶空間),EL1(non-VHE 內核)和
+EL2(VHE 內核 或 non-VHE 虛擬機監控器)。
+
+KVM 客戶機可能運行在 EL0(用戶空間)和 EL1(內核)。
+
+由於宿主機和客戶機之間重疊的異常級別,我們不能僅僅依靠 PMU 的硬體異
+常過濾機制-因此我們必須啓用/禁用對於客戶機進入和退出的計數。而這在
+VHE 和 non-VHE 系統上表現不同。
+
+對於 non-VHE 系統的 exclude_host 屬性排除 EL2 - 在進入和退出客戶
+機時,我們會根據 exclude_host 和 exclude_guest 屬性在適當的情況下
+禁用/啓用該事件。
+
+對於 VHE 系統的 exclude_guest 屬性排除 EL1,而對其中的 exclude_host
+屬性同時排除 EL0,EL2。在進入和退出客戶機時,我們會適當地根據
+exclude_host 和 exclude_guest 屬性包括/排除 EL0。
+
+以上聲明也適用於在 not-VHE 客戶機使用這些屬性時,但是請注意客戶機從
+來不會運行在 EL2。
+
+
+準確性
+------
+
+在 non-VHE 宿主機上,我們在 EL2 進入/退出宿主機/客戶機的切換時啓用/
+關閉計數器 -但是在啓用/禁用計數器和進入/退出客戶機之間存在一段延時。
+對於 exclude_host, 我們可以通過過濾 EL2 消除在客戶機進入/退出邊界
+上用於計數客戶機事件的宿主機事件計數器。但是當使用 !exclude_hv 時,
+在客戶機進入/退出有一個小的停電窗口無法捕獲到宿主機的事件。
+
+在 VHE 系統沒有停電窗口。
+
diff --git a/Documentation/translations/zh_TW/arm64/silicon-errata.txt b/Documentation/translations/zh_TW/arm64/silicon-errata.txt
new file mode 100644 (file)
index 0000000..bf20771
--- /dev/null
@@ -0,0 +1,79 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arm64/silicon-errata.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+M:     Will Deacon <will.deacon@arm.com>
+zh_CN: Fu Wei <wefu@redhat.com>
+zh_TW: Hu Haowen <src.res@email.cn>
+C:     1926e54f115725a9248d0c4c65c22acaf94de4c4
+---------------------------------------------------------------------
+Documentation/arm64/silicon-errata.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+英文版維護者: Will Deacon <will.deacon@arm.com>
+中文版維護者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒  Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文  Hu Haowen <src.res@email.cn>
+本文翻譯提交時的 Git 檢出點爲: 1926e54f115725a9248d0c4c65c22acaf94de4c4
+
+以下爲正文
+---------------------------------------------------------------------
+                晶片勘誤和軟體補救措施
+                ==================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2015年11月27日
+
+一個不幸的現實:硬體經常帶有一些所謂的「瑕疵(errata)」,導致其在
+某些特定情況下會違背構架定義的行爲。就基於 ARM 的硬體而言,這些瑕疵
+大體可分爲以下幾類:
+
+  A 類:無可行補救措施的嚴重缺陷。
+  B 類:有可接受的補救措施的重大或嚴重缺陷。
+  C 類:在正常操作中不會顯現的小瑕疵。
+
+更多資訊,請在 infocenter.arm.com (需註冊)中查閱「軟體開發者勘誤
+筆記」(「Software Developers Errata Notice」)文檔。
+
+對於 Linux 而言,B 類缺陷可能需要作業系統的某些特別處理。例如,避免
+一個特殊的代碼序列,或是以一種特定的方式配置處理器。在某種不太常見的
+情況下,爲將 A 類缺陷當作 C 類處理,可能需要用類似的手段。這些手段被
+統稱爲「軟體補救措施」,且僅在少數情況需要(例如,那些需要一個運行在
+非安全異常級的補救措施 *並且* 能被 Linux 觸發的情況)。
+
+對於尚在討論中的可能對未受瑕疵影響的系統產生干擾的軟體補救措施,有一個
+相應的內核配置(Kconfig)選項被加在 「內核特性(Kernel Features)」->
+「基於可選方法框架的 ARM 瑕疵補救措施(ARM errata workarounds via
+the alternatives framework)"。這些選項被默認開啓,若探測到受影響的CPU,
+補丁將在運行時被使用。至於對系統運行影響較小的補救措施,內核配置選項
+並不存在,且代碼以某種規避瑕疵的方式被構造(帶注釋爲宜)。
+
+這種做法對於在任意內核原始碼樹中準確地判斷出哪個瑕疵已被軟體方法所補救
+稍微有點麻煩,所以在 Linux 內核中此文件作爲軟體補救措施的註冊表,
+並將在新的軟體補救措施被提交和向後移植(backported)到穩定內核時被更新。
+
+| 實現者         | 受影響的組件    | 勘誤編號        | 內核配置                |
++----------------+-----------------+-----------------+-------------------------+
+| ARM            | Cortex-A53      | #826319         | ARM64_ERRATUM_826319    |
+| ARM            | Cortex-A53      | #827319         | ARM64_ERRATUM_827319    |
+| ARM            | Cortex-A53      | #824069         | ARM64_ERRATUM_824069    |
+| ARM            | Cortex-A53      | #819472         | ARM64_ERRATUM_819472    |
+| ARM            | Cortex-A53      | #845719         | ARM64_ERRATUM_845719    |
+| ARM            | Cortex-A53      | #843419         | ARM64_ERRATUM_843419    |
+| ARM            | Cortex-A57      | #832075         | ARM64_ERRATUM_832075    |
+| ARM            | Cortex-A57      | #852523         | N/A                     |
+| ARM            | Cortex-A57      | #834220         | ARM64_ERRATUM_834220    |
+|                |                 |                 |                         |
+| Cavium         | ThunderX ITS    | #22375, #24313  | CAVIUM_ERRATUM_22375    |
+| Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154    |
+
diff --git a/Documentation/translations/zh_TW/arm64/tagged-pointers.txt b/Documentation/translations/zh_TW/arm64/tagged-pointers.txt
new file mode 100644 (file)
index 0000000..87f8862
--- /dev/null
@@ -0,0 +1,57 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/arm64/tagged-pointers.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Will Deacon <will.deacon@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
+---------------------------------------------------------------------
+Documentation/arm64/tagged-pointers.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+
+英文版維護者: Will Deacon <will.deacon@arm.com>
+中文版維護者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版翻譯者: 傅煒  Fu Wei <wefu@redhat.com>
+中文版校譯者: 傅煒  Fu Wei <wefu@redhat.com>
+繁體中文版校譯者: 胡皓文  Hu Haowen <src.res@email.cn>
+
+以下爲正文
+---------------------------------------------------------------------
+               Linux 在 AArch64 中帶標記的虛擬地址
+               =================================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2013 年 06 月 12 日
+
+本文檔簡述了在 AArch64 地址轉換系統中提供的帶標記的虛擬地址及其在
+AArch64 Linux 中的潛在用途。
+
+內核提供的地址轉換表配置使通過 TTBR0 完成的虛擬地址轉換(即用戶空間
+映射),其虛擬地址的最高 8 位(63:56)會被轉換硬體所忽略。這種機制
+讓這些位可供應用程式自由使用,其注意事項如下:
+
+       (1) 內核要求所有傳遞到 EL1 的用戶空間地址帶有 0x00 標記。
+           這意味著任何攜帶用戶空間虛擬地址的系統調用(syscall)
+           參數 *必須* 在陷入內核前使它們的最高字節被清零。
+
+       (2) 非零標記在傳遞信號時不被保存。這意味著在應用程式中利用了
+           標記的信號處理函數無法依賴 siginfo_t 的用戶空間虛擬
+           地址所攜帶的包含其內部域信息的標記。此規則的一個例外是
+           當信號是在調試觀察點的異常處理程序中產生的,此時標記的
+           信息將被保存。
+
+       (3) 當使用帶標記的指針時需特別留心,因爲僅對兩個虛擬地址
+           的高字節,C 編譯器很可能無法判斷它們是不同的。
+
+此構架會阻止對帶標記的 PC 指針的利用,因此在異常返回時,其高字節
+將被設置成一個爲 「55」 的擴展符。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/core.rst b/Documentation/translations/zh_TW/cpu-freq/core.rst
new file mode 100644 (file)
index 0000000..3d890c2
--- /dev/null
@@ -0,0 +1,108 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../cpu-freq/core`
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+             Hu Haowen <src.res@email.cn>
+
+.. _tw_core.rst:
+
+
+====================================
+CPUFreq核心和CPUFreq通知器的通用說明
+====================================
+
+作者:
+       - Dominik Brodowski  <linux@brodo.de>
+       - David Kimdon <dwhedon@debian.org>
+       - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+       - Viresh Kumar <viresh.kumar@linaro.org>
+
+.. 目錄:
+
+   1.  CPUFreq核心和接口
+   2.  CPUFreq通知器
+   3.  含有Operating Performance Point (OPP)的CPUFreq表的生成
+
+1. CPUFreq核心和接口
+======================
+
+cpufreq核心代碼位於drivers/cpufreq/cpufreq.c中。這些cpufreq代碼爲CPUFreq架構的驅
+動程序(那些操作硬體切換頻率的代碼)以及 "通知器 "提供了一個標準化的接口。
+這些是設備驅動程序或需要了解策略變化的其它內核部分(如 ACPI 熱量管理)或所有頻率更改(除
+計時代碼外),甚至需要強制確定速度限制的通知器(如 ARM 架構上的 LCD 驅動程序)。
+此外, 內核 "常數" loops_per_jiffy會根據頻率變化而更新。
+
+cpufreq策略的引用計數由 cpufreq_cpu_get 和 cpufreq_cpu_put 來完成,以確保 cpufreq 驅
+動程序被正確地註冊到核心中,並且驅動程序在 cpufreq_put_cpu 被調用之前不會被卸載。這也保證
+了每個CPU核的cpufreq 策略在使用期間不會被釋放。
+
+2. CPUFreq 通知器
+====================
+
+CPUFreq通知器符合標準的內核通知器接口。
+關於通知器的細節請參閱 linux/include/linux/notifier.h。
+
+這裡有兩個不同的CPUfreq通知器 - 策略通知器和轉換通知器。
+
+
+2.1 CPUFreq策略通知器
+----------------------------
+
+當創建或移除策略時,這些都會被通知。
+
+階段是在通知器的第二個參數中指定的。當第一次創建策略時,階段是CPUFREQ_CREATE_POLICY,當
+策略被移除時,階段是CPUFREQ_REMOVE_POLICY。
+
+第三個參數 ``void *pointer`` 指向一個結構體cpufreq_policy,其包括min,max(新策略的下限和
+上限(單位爲kHz))這幾個值。
+
+
+2.2 CPUFreq轉換通知器
+--------------------------------
+
+當CPUfreq驅動切換CPU核心頻率時,策略中的每個在線CPU都會收到兩次通知,這些變化沒有任何外部干
+預。
+
+第二個參數指定階段 - CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE.
+
+第三個參數是一個包含如下值的結構體cpufreq_freqs:
+
+=====  ====================
+cpu    受影響cpu的編號
+old    舊頻率
+new    新頻率
+flags  cpufreq驅動的標誌
+=====  ====================
+
+3. 含有Operating Performance Point (OPP)的CPUFreq表的生成
+==================================================================
+關於OPP的細節請參閱 Documentation/power/opp.rst
+
+dev_pm_opp_init_cpufreq_table -
+       這個功能提供了一個隨時可用的轉換程序,用來將OPP層關於可用頻率的內部信息翻譯成一種容易提供給
+       cpufreq的格式。
+
+       .. Warning::
+
+               不要在中斷上下文中使用此函數。
+
+       例如::
+
+        soc_pm_init()
+        {
+               /* Do things */
+               r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
+               if (!r)
+                       policy->freq_table = freq_table;
+               /* Do other things */
+        }
+
+       .. note::
+
+               該函數只有在CONFIG_PM_OPP之外還啓用了CONFIG_CPU_FREQ時才可用。
+
+dev_pm_opp_free_cpufreq_table
+       釋放dev_pm_opp_init_cpufreq_table分配的表。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst b/Documentation/translations/zh_TW/cpu-freq/cpu-drivers.rst
new file mode 100644 (file)
index 0000000..2bb8197
--- /dev/null
@@ -0,0 +1,256 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../cpu-freq/cpu-drivers`
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+             Hu Haowen <src.res@email.cn>
+
+.. _tw_cpu-drivers.rst:
+
+
+=======================================
+如何實現一個新的CPUFreq處理器驅動程序?
+=======================================
+
+作者:
+
+
+       - Dominik Brodowski  <linux@brodo.de>
+       - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+       - Viresh Kumar <viresh.kumar@linaro.org>
+
+.. Contents
+
+   1.   怎麼做?
+   1.1  初始化
+   1.2  Per-CPU 初始化
+   1.3  驗證
+   1.4  target/target_index 或 setpolicy?
+   1.5  target/target_index
+   1.6  setpolicy
+   1.7  get_intermediate 與 target_intermediate
+   2.   頻率表助手
+
+
+
+1. 怎麼做?
+===========
+
+如此,你剛剛得到了一個全新的CPU/晶片組及其數據手冊,並希望爲這個CPU/晶片組添加cpufreq
+支持?很好,這裡有一些至關重要的提示:
+
+
+1.1 初始化
+----------
+
+首先,在__initcall_level_7 (module_init())或更靠後的函數中檢查這個內核是否
+運行在正確的CPU和正確的晶片組上。如果是,則使用cpufreq_register_driver()向
+CPUfreq核心層註冊一個cpufreq_driver結構體。
+
+結構體cpufreq_driver應該包含什麼成員?
+
+ .name - 驅動的名字。
+
+ .init - 一個指向per-policy初始化函數的指針。
+
+ .verify - 一個指向"verification"函數的指針。
+
+ .setpolicy 或 .fast_switch 或 .target 或 .target_index - 差異見
+ 下文。
+
+並且可選擇
+
+ .flags - cpufreq核的提示。
+
+ .driver_data - cpufreq驅動程序的特定數據。
+
+ .get_intermediate 和 target_intermediate - 用於在改變CPU頻率時切換到穩定
+ 的頻率。
+
+ .get - 返回CPU的當前頻率。
+
+ .bios_limit - 返回HW/BIOS對CPU的最大頻率限制值。
+
+ .exit - 一個指向per-policy清理函數的指針,該函數在cpu熱插拔過程的CPU_POST_DEAD
+ 階段被調用。
+
+ .suspend - 一個指向per-policy暫停函數的指針,該函數在關中斷且在該策略的調節器停止
+ 後被調用。
+
+ .resume - 一個指向per-policy恢復函數的指針,該函數在關中斷且在調節器再一次開始前被
+ 調用。
+
+ .ready - 一個指向per-policy準備函數的指針,該函數在策略完全初始化之後被調用。
+
+ .attr - 一個指向NULL結尾的"struct freq_attr"列表的指針,該函數允許導出值到
+ sysfs。
+
+ .boost_enabled - 如果設置,則啓用提升(boost)頻率。
+
+ .set_boost - 一個指向per-policy函數的指針,該函數用來開啓/關閉提升(boost)頻率功能。
+
+
+1.2 Per-CPU 初始化
+------------------
+
+每當一個新的CPU被註冊到設備模型中,或者在cpufreq驅動註冊自己之後,如果此CPU的cpufreq策
+略不存在,則會調用per-policy的初始化函數cpufreq_driver.init。請注意,.init()和.exit()程序
+只對策略調用一次,而不是對策略管理的每個CPU調用一次。它需要一個 ``struct cpufreq_policy
+*policy`` 作爲參數。現在該怎麼做呢?
+
+如果有必要,請在你的CPU上激活CPUfreq功能支持。
+
+然後,驅動程序必須填寫以下數值:
+
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.min_freq 和     |                                      |
+|policy->cpuinfo.max_freq          | 該CPU支持的最低和最高頻率(kHz)     |
+|                                  |                                      |
+|                                  |                                      |
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.transition_latency |                                      |
+|                                  | CPU在兩個頻率之間切換所需的時間,以  |
+|                                  | 納秒爲單位(如適用,否則指定         |
+|                                  | CPUFREQ_ETERNAL)                    |
++-----------------------------------+--------------------------------------+
+|policy->cur                       | 該CPU當前的工作頻率(如適用)          |
+|                                  |                                      |
++-----------------------------------+--------------------------------------+
+|policy->min,                      |                                      |
+|policy->max,                      |                                      |
+|policy->policy and, if necessary,  |                                     |
+|policy->governor                  | 必須包含該cpu的 「默認策略」。稍後   |
+|                                  | 會用這些值調用                       |
+|                                  | cpufreq_driver.verify and either     |
+|                                  | cpufreq_driver.setpolicy or          |
+|                                  | cpufreq_driver.target/target_index   |
+|                                  |                                      |
++-----------------------------------+--------------------------------------+
+|policy->cpus                      | 用與這個CPU一起做DVFS的(在線+離線)   |
+|                                  | CPU(即與它共享時鐘/電壓軌)的掩碼更新 |
+|                                  | 這個                                 |
+|                                  |                                      |
++-----------------------------------+--------------------------------------+
+
+對於設置其中的一些值(cpuinfo.min[max]_freq, policy->min[max]),頻率表助手可能會有幫
+助。關於它們的更多信息,請參見第2節。
+
+
+1.3 驗證
+--------
+
+當用戶決定設置一個新的策略(由 「policy,governor,min,max組成」)時,必須對這個策略進行驗證,
+以便糾正不兼容的值。爲了驗證這些值,cpufreq_verify_within_limits(``struct cpufreq_policy
+*policy``, ``unsigned int min_freq``, ``unsigned int max_freq``)函數可能會有幫助。
+關於頻率表助手的詳細內容請參見第2節。
+
+您需要確保至少有一個有效頻率(或工作範圍)在 policy->min 和 policy->max 範圍內。如果有必
+要,先增加policy->max,只有在沒有辦法的情況下,才減少policy->min。
+
+
+1.4 target 或 target_index 或 setpolicy 或 fast_switch?
+-------------------------------------------------------
+
+大多數cpufreq驅動甚至大多數cpu頻率升降算法只允許將CPU頻率設置爲預定義的固定值。對於這些,你
+可以使用->target(),->target_index()或->fast_switch()回調。
+
+有些cpufreq功能的處理器可以自己在某些限制之間切換頻率。這些應使用->setpolicy()回調。
+
+
+1.5. target/target_index
+------------------------
+
+target_index調用有兩個參數:``struct cpufreq_policy * policy``和``unsigned int``
+索引(於列出的頻率表)。
+
+當調用這裡時,CPUfreq驅動必須設置新的頻率。實際頻率必須由freq_table[index].frequency決定。
+
+它應該總是在錯誤的情況下恢復到之前的頻率(即policy->restore_freq),即使我們之前切換到中間頻率。
+
+已棄用
+----------
+目標調用有三個參數。``struct cpufreq_policy * policy``, unsigned int target_frequency,
+unsigned int relation.
+
+CPUfreq驅動在調用這裡時必須設置新的頻率。實際的頻率必須使用以下規則來確定。
+
+- 緊跟 "目標頻率"。
+- policy->min <= new_freq <= policy->max (這必須是有效的!!!)
+- 如果 relation==CPUFREQ_REL_L,嘗試選擇一個高於或等於 target_freq 的 new_freq。("L代表
+  最低,但不能低於")
+- 如果 relation==CPUFREQ_REL_H,嘗試選擇一個低於或等於 target_freq 的 new_freq。("H代表
+  最高,但不能高於")
+
+這裡,頻率表助手可能會幫助你--詳見第2節。
+
+1.6. fast_switch
+----------------
+
+這個函數用於從調度器的上下文進行頻率切換。並非所有的驅動都要實現它,因爲不允許在這個回調中睡眠。這
+個回調必須經過高度優化,以儘可能快地進行切換。
+
+這個函數有兩個參數: ``struct cpufreq_policy *policy`` 和 ``unsigned int target_frequency``。
+
+
+1.7 setpolicy
+-------------
+
+setpolicy調用只需要一個``struct cpufreq_policy * policy``作爲參數。需要將處理器內或晶片組內動態頻
+率切換的下限設置爲policy->min,上限設置爲policy->max,如果支持的話,當policy->policy爲
+CPUFREQ_POLICY_PERFORMANCE時選擇面向性能的設置,當CPUFREQ_POLICY_POWERSAVE時選擇面向省電的設置。
+也可以查看drivers/cpufreq/longrun.c中的參考實現。
+
+1.8 get_intermediate 和 target_intermediate
+--------------------------------------------
+
+僅適用於 target_index() 和 CPUFREQ_ASYNC_NOTIFICATION 未設置的驅動。
+
+get_intermediate應該返回一個平台想要切換到的穩定的中間頻率,target_intermediate()應該將CPU設置爲
+該頻率,然後再跳轉到'index'對應的頻率。核心會負責發送通知,驅動不必在target_intermediate()或
+target_index()中處理。
+
+在驅動程序不想因爲某個目標頻率切換到中間頻率的情況下,它們可以從get_intermediate()中返回'0'。在這種情況
+下,核心將直接調用->target_index()。
+
+注意:->target_index()應該在失敗的情況下恢復到policy->restore_freq,因爲core會爲此發送通知。
+
+
+2. 頻率表助手
+=============
+
+由於大多數cpufreq處理器只允許被設置爲幾個特定的頻率,因此,一個帶有一些函數的 「頻率表」可能會輔助處理器驅動
+程序的一些工作。這樣的 "頻率表" 由一個cpufreq_frequency_table條目構成的數組組成,"driver_data" 中包
+含了驅動程序的具體數值,"frequency" 中包含了相應的頻率,並設置了標誌。在表的最後,需要添加一個
+cpufreq_frequency_table條目,頻率設置爲CPUFREQ_TABLE_END。而如果想跳過表中的一個條目,則將頻率設置爲
+CPUFREQ_ENTRY_INVALID。這些條目不需要按照任何特定的順序排序,但如果它們是cpufreq 核心會對它們進行快速的DVFS,
+因爲搜索最佳匹配會更快。
+
+如果策略在其policy->freq_table欄位中包含一個有效的指針,cpufreq表就會被核心自動驗證。
+
+cpufreq_frequency_table_verify()保證至少有一個有效的頻率在policy->min和policy->max範圍內,並且所有其他
+標準都被滿足。這對->verify調用很有幫助。
+
+cpufreq_frequency_table_target()是對應於->target階段的頻率表助手。只要把數值傳遞給這個函數,這個函數就會返
+回包含CPU要設置的頻率的頻率表條目。
+
+以下宏可以作爲cpufreq_frequency_table的疊代器。
+
+cpufreq_for_each_entry(pos, table) - 遍歷頻率表的所有條目。
+
+cpufreq_for_each_valid_entry(pos, table) - 該函數遍歷所有條目,不包括CPUFREQ_ENTRY_INVALID頻率。
+使用參數 "pos"-一個``cpufreq_frequency_table * `` 作爲循環變量,使用參數 "table"-作爲你想疊代
+的``cpufreq_frequency_table * `` 。
+
+例如::
+
+       struct cpufreq_frequency_table *pos, *driver_freq_table;
+
+       cpufreq_for_each_entry(pos, driver_freq_table) {
+               /* Do something with pos */
+               pos->frequency = ...
+       }
+
+如果你需要在driver_freq_table中處理pos的位置,不要減去指針,因爲它的代價相當高。相反,使用宏
+cpufreq_for_each_entry_idx() 和 cpufreq_for_each_valid_entry_idx() 。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst b/Documentation/translations/zh_TW/cpu-freq/cpufreq-stats.rst
new file mode 100644 (file)
index 0000000..d80bfed
--- /dev/null
@@ -0,0 +1,132 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../cpu-freq/cpufreq-stats`
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+             Hu Haowen <src.res@email.cn>
+
+.. _tw_cpufreq-stats.rst:
+
+
+==========================================
+sysfs CPUFreq Stats的一般說明
+==========================================
+
+用戶信息
+
+
+作者: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+
+.. Contents
+
+   1. 簡介
+   2. 提供的統計數據(舉例說明)
+   3. 配置cpufreq-stats
+
+
+1. 簡介
+===============
+
+cpufreq-stats是一個爲每個CPU提供CPU頻率統計的驅動。
+這些統計數據在/sysfs中以一堆只讀接口的形式提供。這個接口(在配置好後)將出現在
+/sysfs(<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/)中cpufreq下的一個單
+獨的目錄中,提供給每個CPU。
+各種統計數據將在此目錄下形成只讀文件。
+
+此驅動是獨立於任何可能運行在你所用CPU上的特定cpufreq_driver而設計的。因此,它將與所有
+cpufreq_driver一起工作。
+
+
+2. 提供的統計數據(舉例說明)
+=====================================
+
+cpufreq stats提供了以下統計數據(在下面詳細解釋)。
+
+-  time_in_state
+-  total_trans
+-  trans_table
+
+所有的統計數據將從統計驅動被載入的時間(或統計被重置的時間)開始,到某一統計數據被讀取的時間爲止。
+顯然,統計驅動不會有任何關於統計驅動載入之前的頻率轉換信息。
+
+::
+
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
+    total 0
+    drwxr-xr-x  2 root root    0 May 14 16:06 .
+    drwxr-xr-x  3 root root    0 May 14 15:58 ..
+    --w-------  1 root root 4096 May 14 16:06 reset
+    -r--r--r--  1 root root 4096 May 14 16:06 time_in_state
+    -r--r--r--  1 root root 4096 May 14 16:06 total_trans
+    -r--r--r--  1 root root 4096 May 14 16:06 trans_table
+
+- **reset**
+
+只寫屬性,可用於重置統計計數器。這對於評估不同調節器下的系統行爲非常有用,且無需重啓。
+
+
+- **time_in_state**
+
+此項給出了這個CPU所支持的每個頻率所花費的時間。cat輸出的每一行都會有"<frequency>
+<time>"對,表示這個CPU在<frequency>上花費了<time>個usertime單位的時間。這裡的
+usertime單位是10mS(類似於/proc中輸出的其他時間)。
+
+::
+
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state
+    3600000 2089
+    3400000 136
+    3200000 34
+    3000000 67
+    2800000 172488
+
+
+- **total_trans**
+
+給出了這個CPU上頻率轉換的總次數。cat的輸出將有一個單一的計數,這就是頻率轉換的總數。
+
+::
+
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans
+    20
+
+- **trans_table**
+
+這將提供所有CPU頻率轉換的細粒度信息。這裡的cat輸出是一個二維矩陣,其中一個條目<i, j>(第
+i行,第j列)代表從Freq_i到Freq_j的轉換次數。Freq_i行和Freq_j列遵循驅動最初提供給cpufreq
+核的頻率表的排序順序,因此可以排序(升序或降序)或不排序。 這裡的輸出也包含了每行每列的實際
+頻率值,以便更好地閱讀。
+
+如果轉換表大於PAGE_SIZE,讀取時將返回一個-EFBIG錯誤。
+
+::
+
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
+    From  :    To
+           :   3600000   3400000   3200000   3000000   2800000
+    3600000:         0         5         0         0         0
+    3400000:         4         0         2         0         0
+    3200000:         0         1         0         2         0
+    3000000:         0         0         1         0         3
+    2800000:         0         0         0         2         0
+
+3. 配置cpufreq-stats
+============================
+
+要在你的內核中配置cpufreq-stats::
+
+       Config Main Menu
+               Power management options (ACPI, APM)  --->
+                       CPU Frequency scaling  --->
+                               [*] CPU Frequency scaling
+                               [*]   CPU frequency translation statistics
+
+
+"CPU Frequency scaling" (CONFIG_CPU_FREQ) 應該被啓用以配置cpufreq-stats。
+
+"CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT)提供了包括
+time_in_state、total_trans和trans_table的統計數據。
+
+一旦啓用了這個選項,並且你的CPU支持cpufrequency,你就可以在/sysfs中看到CPU頻率統計。
+
diff --git a/Documentation/translations/zh_TW/cpu-freq/index.rst b/Documentation/translations/zh_TW/cpu-freq/index.rst
new file mode 100644 (file)
index 0000000..1a8e680
--- /dev/null
@@ -0,0 +1,47 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../cpu-freq/index`
+:Translator: Yanteng Si <siyanteng@loongson.cn>
+             Hu Haowen <src.res@email.cn>
+
+.. _tw_index.rst:
+
+
+=======================================================
+Linux CPUFreq - Linux(TM)內核中的CPU頻率和電壓升降代碼
+=======================================================
+
+Author: Dominik Brodowski  <linux@brodo.de>
+
+      時鐘升降允許你在運行中改變CPU的時鐘速度。這是一個很好的節省電池電量的方法,因爲時
+      鐘速度越低,CPU消耗的電量越少。
+
+
+.. toctree::
+   :maxdepth: 1
+
+   core
+   cpu-drivers
+   cpufreq-stats
+
+郵件列表
+------------
+這裡有一個 CPU 頻率變化的 CVS 提交和通用列表,您可以在這裡報告bug、問題或提交補丁。要發
+布消息,請發送電子郵件到 linux-pm@vger.kernel.org。
+
+連結
+-----
+FTP檔案:
+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
+
+如何訪問CVS倉庫:
+* http://cvs.arm.linux.org.uk/
+
+CPUFreq郵件列表:
+* http://vger.kernel.org/vger-lists.html#linux-pm
+
+SA-1100的時鐘和電壓標度:
+* http://www.lartmaker.nl/projects/scaling
+
diff --git a/Documentation/translations/zh_TW/filesystems/debugfs.rst b/Documentation/translations/zh_TW/filesystems/debugfs.rst
new file mode 100644 (file)
index 0000000..270dd94
--- /dev/null
@@ -0,0 +1,224 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :doc:`../../../filesystems/debugfs`
+
+=======
+Debugfs
+=======
+
+譯者
+::
+
+       中文版維護者:羅楚成 Chucheng Luo <luochucheng@vivo.com>
+       中文版翻譯者:羅楚成 Chucheng Luo <luochucheng@vivo.com>
+       中文版校譯者: 羅楚成 Chucheng Luo <luochucheng@vivo.com>
+       繁體中文版校譯者: 胡皓文 Hu Haowen <src.res@email.cn>
+
+
+
+版權所有2020 羅楚成 <luochucheng@vivo.com>
+版權所有2021 胡皓文 Hu Haowen <src.res@email.cn>
+
+
+Debugfs是內核開發人員在用戶空間獲取信息的簡單方法。與/proc不同,proc只提供進程
+信息。也不像sysfs,具有嚴格的「每個文件一個值「的規則。debugfs根本沒有規則,開發
+人員可以在這裡放置他們想要的任何信息。debugfs文件系統也不能用作穩定的ABI接口。
+從理論上講,debugfs導出文件的時候沒有任何約束。但是[1]實際情況並不總是那麼
+簡單。即使是debugfs接口,也最好根據需要進行設計,並儘量保持接口不變。
+
+
+Debugfs通常使用以下命令安裝::
+
+    mount -t debugfs none /sys/kernel/debug
+
+(或等效的/etc/fstab行)。
+debugfs根目錄默認僅可由root用戶訪問。要更改對文件樹的訪問,請使用「 uid」,「 gid」
+和「 mode」掛載選項。請注意,debugfs API僅按照GPL協議導出到模塊。
+
+使用debugfs的代碼應包含<linux/debugfs.h>。然後,首先是創建至少一個目錄來保存
+一組debugfs文件::
+
+    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
+
+如果成功,此調用將在指定的父目錄下創建一個名爲name的目錄。如果parent參數爲空,
+則會在debugfs根目錄中創建。創建目錄成功時,返回值是一個指向dentry結構體的指針。
+該dentry結構體的指針可用於在目錄中創建文件(以及最後將其清理乾淨)。ERR_PTR
+(-ERROR)返回值表明出錯。如果返回ERR_PTR(-ENODEV),則表明內核是在沒有debugfs
+支持的情況下構建的,並且下述函數都不會起作用。
+
+在debugfs目錄中創建文件的最通用方法是::
+
+    struct dentry *debugfs_create_file(const char *name, umode_t mode,
+                                      struct dentry *parent, void *data,
+                                      const struct file_operations *fops);
+
+在這裡,name是要創建的文件的名稱,mode描述了訪問文件應具有的權限,parent指向
+應該保存文件的目錄,data將存儲在產生的inode結構體的i_private欄位中,而fops是
+一組文件操作函數,這些函數中實現文件操作的具體行爲。至少,read()和/或
+write()操作應提供;其他可以根據需要包括在內。同樣的,返回值將是指向創建文件
+的dentry指針,錯誤時返回ERR_PTR(-ERROR),系統不支持debugfs時返回值爲ERR_PTR
+(-ENODEV)。創建一個初始大小的文件,可以使用以下函數代替::
+
+    struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
+                               struct dentry *parent, void *data,
+                               const struct file_operations *fops,
+                               loff_t file_size);
+
+file_size是初始文件大小。其他參數跟函數debugfs_create_file的相同。
+
+在許多情況下,沒必要自己去創建一組文件操作;對於一些簡單的情況,debugfs代碼提供
+了許多幫助函數。包含單個整數值的文件可以使用以下任何一項創建::
+
+    void debugfs_create_u8(const char *name, umode_t mode,
+                          struct dentry *parent, u8 *value);
+    void debugfs_create_u16(const char *name, umode_t mode,
+                           struct dentry *parent, u16 *value);
+    struct dentry *debugfs_create_u32(const char *name, umode_t mode,
+                                     struct dentry *parent, u32 *value);
+    void debugfs_create_u64(const char *name, umode_t mode,
+                           struct dentry *parent, u64 *value);
+
+這些文件支持讀取和寫入給定值。如果某個文件不支持寫入,只需根據需要設置mode
+參數位。這些文件中的值以十進位表示;如果需要使用十六進位,可以使用以下函數
+替代::
+
+    void debugfs_create_x8(const char *name, umode_t mode,
+                          struct dentry *parent, u8 *value);
+    void debugfs_create_x16(const char *name, umode_t mode,
+                           struct dentry *parent, u16 *value);
+    void debugfs_create_x32(const char *name, umode_t mode,
+                           struct dentry *parent, u32 *value);
+    void debugfs_create_x64(const char *name, umode_t mode,
+                           struct dentry *parent, u64 *value);
+
+這些功能只有在開發人員知道導出值的大小的時候才有用。某些數據類型在不同的架構上
+有不同的寬度,這樣會使情況變得有些複雜。在這種特殊情況下可以使用以下函數::
+
+    void debugfs_create_size_t(const char *name, umode_t mode,
+                              struct dentry *parent, size_t *value);
+
+不出所料,此函數將創建一個debugfs文件來表示類型爲size_t的變量。
+
+同樣地,也有導出無符號長整型變量的函數,分別以十進位和十六進位表示如下::
+
+    struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
+                                       struct dentry *parent,
+                                       unsigned long *value);
+    void debugfs_create_xul(const char *name, umode_t mode,
+                           struct dentry *parent, unsigned long *value);
+
+布爾值可以通過以下方式放置在debugfs中::
+
+    struct dentry *debugfs_create_bool(const char *name, umode_t mode,
+                                      struct dentry *parent, bool *value);
+
+
+讀取結果文件將產生Y(對於非零值)或N,後跟換行符寫入的時候,它只接受大寫或小寫
+值或1或0。任何其他輸入將被忽略。
+
+同樣,atomic_t類型的值也可以放置在debugfs中::
+
+    void debugfs_create_atomic_t(const char *name, umode_t mode,
+                                struct dentry *parent, atomic_t *value)
+
+讀取此文件將獲得atomic_t值,寫入此文件將設置atomic_t值。
+
+另一個選擇是通過以下結構體和函數導出一個任意二進位數據塊::
+
+    struct debugfs_blob_wrapper {
+       void *data;
+       unsigned long size;
+    };
+
+    struct dentry *debugfs_create_blob(const char *name, umode_t mode,
+                                      struct dentry *parent,
+                                      struct debugfs_blob_wrapper *blob);
+
+讀取此文件將返回由指針指向debugfs_blob_wrapper結構體的數據。一些驅動使用「blobs」
+作爲一種返回幾行(靜態)格式化文本的簡單方法。這個函數可用於導出二進位信息,但
+似乎在主線中沒有任何代碼這樣做。請注意,使用debugfs_create_blob()命令創建的
+所有文件是只讀的。
+
+如果您要轉儲一個寄存器塊(在開發過程中經常會這麼做,但是這樣的調試代碼很少上傳
+到主線中。Debugfs提供兩個函數:一個用於創建僅寄存器文件,另一個把一個寄存器塊
+插入一個順序文件中::
+
+    struct debugfs_reg32 {
+       char *name;
+       unsigned long offset;
+    };
+
+    struct debugfs_regset32 {
+       struct debugfs_reg32 *regs;
+       int nregs;
+       void __iomem *base;
+    };
+
+    struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
+                                    struct dentry *parent,
+                                    struct debugfs_regset32 *regset);
+
+    void debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
+                        int nregs, void __iomem *base, char *prefix);
+
+「base」參數可能爲0,但您可能需要使用__stringify構建reg32數組,實際上有許多寄存器
+名稱(宏)是寄存器塊在基址上的字節偏移量。
+
+如果要在debugfs中轉儲u32數組,可以使用以下函數創建文件::
+
+     void debugfs_create_u32_array(const char *name, umode_t mode,
+                       struct dentry *parent,
+                       u32 *array, u32 elements);
+
+「array」參數提供數據,而「elements」參數爲數組中元素的數量。注意:數組創建後,數組
+大小無法更改。
+
+有一個函數來創建與設備相關的seq_file::
+
+   struct dentry *debugfs_create_devm_seqfile(struct device *dev,
+                               const char *name,
+                               struct dentry *parent,
+                               int (*read_fn)(struct seq_file *s,
+                                       void *data));
+
+「dev」參數是與此debugfs文件相關的設備,並且「read_fn」是一個函數指針,這個函數在
+列印seq_file內容的時候被回調。
+
+還有一些其他的面向目錄的函數::
+
+    struct dentry *debugfs_rename(struct dentry *old_dir,
+                                 struct dentry *old_dentry,
+                                 struct dentry *new_dir,
+                                 const char *new_name);
+
+    struct dentry *debugfs_create_symlink(const char *name,
+                                          struct dentry *parent,
+                                          const char *target);
+
+調用debugfs_rename()將爲現有的debugfs文件重命名,可能同時切換目錄。 new_name
+函數調用之前不能存在;返回值爲old_dentry,其中包含更新的信息。可以使用
+debugfs_create_symlink()創建符號連結。
+
+所有debugfs用戶必須考慮的一件事是:
+
+debugfs不會自動清除在其中創建的任何目錄。如果一個模塊在不顯式刪除debugfs目錄的
+情況下卸載模塊,結果將會遺留很多野指針,從而導致系統不穩定。因此,所有debugfs
+用戶-至少是那些可以作爲模塊構建的用戶-必須做模塊卸載的時候準備刪除在此創建的
+所有文件和目錄。一份文件可以通過以下方式刪除::
+
+    void debugfs_remove(struct dentry *dentry);
+
+dentry值可以爲NULL或錯誤值,在這種情況下,不會有任何文件被刪除。
+
+很久以前,內核開發者使用debugfs時需要記錄他們創建的每個dentry指針,以便最後所有
+文件都可以被清理掉。但是,現在debugfs用戶能調用以下函數遞歸清除之前創建的文件::
+
+    void debugfs_remove_recursive(struct dentry *dentry);
+
+如果將對應頂層目錄的dentry傳遞給以上函數,則該目錄下的整個層次結構將會被刪除。
+
+注釋:
+[1] http://lwn.net/Articles/309298/
+
diff --git a/Documentation/translations/zh_TW/filesystems/index.rst b/Documentation/translations/zh_TW/filesystems/index.rst
new file mode 100644 (file)
index 0000000..4e5dde0
--- /dev/null
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/filesystems/index.rst <filesystems_index>`
+:Translator: Wang Wenhu <wenhu.wang@vivo.com>
+             Hu Haowen <src.res@email.cn>
+
+.. _tw_filesystems_index:
+
+========================
+Linux Kernel中的文件系統
+========================
+
+這份正在開發的手冊或許在未來某個輝煌的日子裡以易懂的形式將Linux虛擬\
+文件系統(VFS)層以及基於其上的各種文件系統如何工作呈現給大家。當前\
+可以看到下面的內容。
+
+文件系統
+========
+
+文件系統實現文檔。
+
+.. toctree::
+   :maxdepth: 2
+
+   virtiofs
+   debugfs
+   tmpfs
+
+
diff --git a/Documentation/translations/zh_TW/filesystems/sysfs.txt b/Documentation/translations/zh_TW/filesystems/sysfs.txt
new file mode 100644 (file)
index 0000000..acd677f
--- /dev/null
@@ -0,0 +1,377 @@
+SPDX-License-Identifier: GPL-2.0
+
+Chinese translated version of Documentation/filesystems/sysfs.rst
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Patrick Mochel     <mochel@osdl.org>
+               Mike Murphy <mamurph@cs.clemson.edu>
+Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+---------------------------------------------------------------------
+Documentation/filesystems/sysfs.rst 的中文翻譯
+
+如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
+交流有困難的話,也可以向中文版維護者求助。如果本翻譯更新不及時或者翻
+譯存在問題,請聯繫中文版維護者。
+英文版維護者: Patrick Mochel   <mochel@osdl.org>
+               Mike Murphy <mamurph@cs.clemson.edu>
+中文版維護者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版翻譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+中文版校譯者: 傅煒 Fu Wei <tekkamanninja@gmail.com>
+繁體中文版校譯者:胡皓文 Hu Haowen <src.res@email.cn>
+
+
+以下爲正文
+---------------------------------------------------------------------
+sysfs - 用於導出內核對象(kobject)的文件系統
+
+Patrick Mochel <mochel@osdl.org>
+Mike Murphy <mamurph@cs.clemson.edu>
+
+修訂:    16 August 2011
+原始版本:   10 January 2003
+
+
+sysfs 簡介:
+~~~~~~~~~~
+
+sysfs 是一個最初基於 ramfs 且位於內存的文件系統。它提供導出內核
+數據結構及其屬性,以及它們之間的關聯到用戶空間的方法。
+
+sysfs 始終與 kobject 的底層結構緊密相關。請閱讀
+Documentation/core-api/kobject.rst 文檔以獲得更多關於 kobject 接口的
+信息。
+
+
+使用 sysfs
+~~~~~~~~~~~
+
+只要內核配置中定義了 CONFIG_SYSFS ,sysfs 總是被編譯進內核。你可
+通過以下命令掛載它:
+
+    mount -t sysfs sysfs /sys
+
+
+創建目錄
+~~~~~~~~
+
+任何 kobject 在系統中註冊,就會有一個目錄在 sysfs 中被創建。這個
+目錄是作爲該 kobject 的父對象所在目錄的子目錄創建的,以準確地傳遞
+內核的對象層次到用戶空間。sysfs 中的頂層目錄代表著內核對象層次的
+共同祖先;例如:某些對象屬於某個子系統。
+
+Sysfs 在與其目錄關聯的 kernfs_node 對象中內部保存一個指向實現
+目錄的 kobject 的指針。以前,這個 kobject 指針被 sysfs 直接用於
+kobject 文件打開和關閉的引用計數。而現在的 sysfs 實現中,kobject
+引用計數只能通過 sysfs_schedule_callback() 函數直接修改。
+
+
+屬性
+~~~~
+
+kobject 的屬性可在文件系統中以普通文件的形式導出。Sysfs 爲屬性定義
+了面向文件 I/O 操作的方法,以提供對內核屬性的讀寫。
+
+
+屬性應爲 ASCII 碼文本文件。以一個文件只存儲一個屬性值爲宜。但一個
+文件只包含一個屬性值可能影響效率,所以一個包含相同數據類型的屬性值
+數組也被廣泛地接受。
+
+混合類型、表達多行數據以及一些怪異的數據格式會遭到強烈反對。這樣做是
+很丟臉的,而且其代碼會在未通知作者的情況下被重寫。
+
+
+一個簡單的屬性結構定義如下:
+
+struct attribute {
+        char                    * name;
+        struct module          *owner;
+        umode_t                 mode;
+};
+
+
+int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
+void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
+
+
+一個單獨的屬性結構並不包含讀寫其屬性值的方法。子系統最好爲增刪特定
+對象類型的屬性定義自己的屬性結構體和封裝函數。
+
+例如:驅動程序模型定義的 device_attribute 結構體如下:
+
+struct device_attribute {
+       struct attribute        attr;
+       ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count);
+};
+
+int device_create_file(struct device *, const struct device_attribute *);
+void device_remove_file(struct device *, const struct device_attribute *);
+
+爲了定義設備屬性,同時定義了一下輔助宏:
+
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
+
+例如:聲明
+
+static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
+
+等同於如下代碼:
+
+static struct device_attribute dev_attr_foo = {
+       .attr   = {
+               .name = "foo",
+               .mode = S_IWUSR | S_IRUGO,
+               .show = show_foo,
+               .store = store_foo,
+       },
+};
+
+
+子系統特有的回調函數
+~~~~~~~~~~~~~~~~~~~
+
+當一個子系統定義一個新的屬性類型時,必須實現一系列的 sysfs 操作,
+以幫助讀寫調用實現屬性所有者的顯示和儲存方法。
+
+struct sysfs_ops {
+        ssize_t (*show)(struct kobject *, struct attribute *, char *);
+        ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
+};
+
+[子系統應已經定義了一個 struct kobj_type 結構體作爲這個類型的
+描述符,並在此保存 sysfs_ops 的指針。更多的信息參見 kobject 的
+文檔]
+
+sysfs 會爲這個類型調用適當的方法。當一個文件被讀寫時,這個方法會
+將一般的kobject 和 attribute 結構體指針轉換爲適當的指針類型後
+調用相關聯的函數。
+
+
+示例:
+
+#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
+
+static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
+                             char *buf)
+{
+        struct device_attribute *dev_attr = to_dev_attr(attr);
+        struct device *dev = kobj_to_dev(kobj);
+        ssize_t ret = -EIO;
+
+        if (dev_attr->show)
+                ret = dev_attr->show(dev, dev_attr, buf);
+        if (ret >= (ssize_t)PAGE_SIZE) {
+                printk("dev_attr_show: %pS returned bad count\n",
+                                dev_attr->show);
+        }
+        return ret;
+}
+
+
+
+讀寫屬性數據
+~~~~~~~~~~~~
+
+在聲明屬性時,必須指定 show() 或 store() 方法,以實現屬性的
+讀或寫。這些方法的類型應該和以下的設備屬性定義一樣簡單。
+
+ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
+ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                 const char *buf, size_t count);
+
+也就是說,他們應只以一個處理對象、一個屬性和一個緩衝指針作爲參數。
+
+sysfs 會分配一個大小爲 (PAGE_SIZE) 的緩衝區並傳遞給這個方法。
+Sysfs 將會爲每次讀寫操作調用一次這個方法。這使得這些方法在執行時
+會出現以下的行爲:
+
+- 在讀方面(read(2)),show() 方法應該填充整個緩衝區。回想屬性
+  應只導出了一個屬性值或是一個同類型屬性值的數組,所以這個代價將
+  不會不太高。
+
+  這使得用戶空間可以局部地讀和任意的向前搜索整個文件。如果用戶空間
+  向後搜索到零或使用『0』偏移執行一個pread(2)操作,show()方法將
+  再次被調用,以重新填充緩存。
+
+- 在寫方面(write(2)),sysfs 希望在第一次寫操作時得到整個緩衝區。
+  之後 Sysfs 傳遞整個緩衝區給 store() 方法。
+
+  當要寫 sysfs 文件時,用戶空間進程應首先讀取整個文件,修該想要
+  改變的值,然後回寫整個緩衝區。
+
+  在讀寫屬性值時,屬性方法的執行應操作相同的緩衝區。
+
+註記:
+
+- 寫操作導致的 show() 方法重載,會忽略當前文件位置。
+
+- 緩衝區應總是 PAGE_SIZE 大小。對於i386,這個值爲4096。
+
+- show() 方法應該返回寫入緩衝區的字節數,也就是 scnprintf()的
+  返回值。
+
+- show() 方法在將格式化返回值返回用戶空間的時候,禁止使用snprintf()。
+  如果可以保證不會發生緩衝區溢出,可以使用sprintf(),否則必須使用
+  scnprintf()。
+
+- store() 應返回緩衝區的已用字節數。如果整個緩存都已填滿,只需返回
+  count 參數。
+
+- show() 或 store() 可以返回錯誤值。當得到一個非法值,必須返回一個
+  錯誤值。
+
+- 一個傳遞給方法的對象將會通過 sysfs 調用對象內嵌的引用計數固定在
+  內存中。儘管如此,對象代表的物理實體(如設備)可能已不存在。如有必要,
+  應該實現一個檢測機制。
+
+一個簡單的(未經實驗證實的)設備屬性實現如下:
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
+}
+
+static ssize_t store_name(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+        snprintf(dev->name, sizeof(dev->name), "%.*s",
+                 (int)min(count, sizeof(dev->name) - 1), buf);
+       return count;
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
+
+
+(注意:真正的實現不允許用戶空間設置設備名。)
+
+頂層目錄布局
+~~~~~~~~~~~~
+
+sysfs 目錄的安排顯示了內核數據結構之間的關係。
+
+頂層 sysfs 目錄如下:
+
+block/
+bus/
+class/
+dev/
+devices/
+firmware/
+net/
+fs/
+
+devices/ 包含了一個設備樹的文件系統表示。他直接映射了內部的內核
+設備樹,反映了設備的層次結構。
+
+bus/ 包含了內核中各種總線類型的平面目錄布局。每個總線目錄包含兩個
+子目錄:
+
+       devices/
+       drivers/
+
+devices/ 包含了系統中出現的每個設備的符號連結,他們指向 root/ 下的
+設備目錄。
+
+drivers/ 包含了每個已爲特定總線上的設備而掛載的驅動程序的目錄(這裡
+假定驅動沒有跨越多個總線類型)。
+
+fs/ 包含了一個爲文件系統設立的目錄。現在每個想要導出屬性的文件系統必須
+在 fs/ 下創建自己的層次結構(參見Documentation/filesystems/fuse.rst)。
+
+dev/ 包含兩個子目錄: char/ 和 block/。在這兩個子目錄中,有以
+<major>:<minor> 格式命名的符號連結。這些符號連結指向 sysfs 目錄
+中相應的設備。/sys/dev 提供一個通過一個 stat(2) 操作結果,查找
+設備 sysfs 接口快捷的方法。
+
+更多有關 driver-model 的特性信息可以在 Documentation/driver-api/driver-model/
+中找到。
+
+
+TODO: 完成這一節。
+
+
+當前接口
+~~~~~~~~
+
+以下的接口層普遍存在於當前的sysfs中:
+
+- 設備 (include/linux/device.h)
+----------------------------------
+結構體:
+
+struct device_attribute {
+       struct attribute        attr;
+       ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count);
+};
+
+聲明:
+
+DEVICE_ATTR(_name, _mode, _show, _store);
+
+增/刪屬性:
+
+int device_create_file(struct device *dev, const struct device_attribute * attr);
+void device_remove_file(struct device *dev, const struct device_attribute * attr);
+
+
+- 總線驅動程序 (include/linux/device.h)
+--------------------------------------
+結構體:
+
+struct bus_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct bus_type *, char * buf);
+        ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
+};
+
+聲明:
+
+BUS_ATTR(_name, _mode, _show, _store)
+
+增/刪屬性:
+
+int bus_create_file(struct bus_type *, struct bus_attribute *);
+void bus_remove_file(struct bus_type *, struct bus_attribute *);
+
+
+- 設備驅動程序 (include/linux/device.h)
+-----------------------------------------
+
+結構體:
+
+struct driver_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct device_driver *, char * buf);
+        ssize_t (*store)(struct device_driver *, const char * buf,
+                         size_t count);
+};
+
+聲明:
+
+DRIVER_ATTR(_name, _mode, _show, _store)
+
+增/刪屬性:
+
+int driver_create_file(struct device_driver *, const struct driver_attribute *);
+void driver_remove_file(struct device_driver *, const struct driver_attribute *);
+
+
+文檔
+~~~~
+
+sysfs 目錄結構以及其中包含的屬性定義了一個內核與用戶空間之間的 ABI。
+對於任何 ABI,其自身的穩定和適當的文檔是非常重要的。所有新的 sysfs
+屬性必須在 Documentation/ABI 中有文檔。詳見 Documentation/ABI/README。
+
diff --git a/Documentation/translations/zh_TW/filesystems/tmpfs.rst b/Documentation/translations/zh_TW/filesystems/tmpfs.rst
new file mode 100644 (file)
index 0000000..8d753a3
--- /dev/null
@@ -0,0 +1,148 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: Documentation/filesystems/tmpfs.rst
+
+Translated by Wang Qing <wangqing@vivo.com>
+and Hu Haowen <src.res@email.cn>
+
+=====
+Tmpfs
+=====
+
+Tmpfs是一個將所有文件都保存在虛擬內存中的文件系統。
+
+tmpfs中的所有內容都是臨時的,也就是說沒有任何文件會在硬碟上創建。
+如果卸載tmpfs實例,所有保存在其中的文件都會丟失。
+
+tmpfs將所有文件保存在內核緩存中,隨著文件內容增長或縮小可以將不需要的
+頁面swap出去。它具有最大限制,可以通過「mount -o remount ...」調整。
+
+和ramfs(創建tmpfs的模板)相比,tmpfs包含交換和限制檢查。和tmpfs相似的另
+一個東西是RAM磁碟(/dev/ram*),可以在物理RAM中模擬固定大小的硬碟,並在
+此之上創建一個普通的文件系統。Ramdisks無法swap,因此無法調整它們的大小。
+
+由於tmpfs完全保存於頁面緩存和swap中,因此所有tmpfs頁面將在/proc/meminfo
+中顯示爲「Shmem」,而在free(1)中顯示爲「Shared」。請注意,這些計數還包括
+共享內存(shmem,請參閱ipcs(1))。獲得計數的最可靠方法是使用df(1)和du(1)。
+
+tmpfs具有以下用途:
+
+1) 內核總有一個無法看到的內部掛載,用於共享匿名映射和SYSV共享內存。
+
+   掛載不依賴於CONFIG_TMPFS。如果CONFIG_TMPFS未設置,tmpfs對用戶不可見。
+   但是內部機制始終存在。
+
+2) glibc 2.2及更高版本期望將tmpfs掛載在/dev/shm上以用於POSIX共享內存
+   (shm_open,shm_unlink)。添加內容到/etc/fstab應注意如下:
+
+       tmpfs   /dev/shm        tmpfs   defaults        0 0
+
+   使用時需要記住創建掛載tmpfs的目錄。
+
+   SYSV共享內存無需掛載,內部已默認支持。(在2.3內核版本中,必須掛載
+   tmpfs的前身(shm fs)才能使用SYSV共享內存)
+
+3) 很多人(包括我)都覺的在/tmp和/var/tmp上掛載非常方便,並具有較大的
+   swap分區。目前循環掛載tmpfs可以正常工作,所以大多數發布都應當可以
+   使用mkinitrd通過/tmp訪問/tmp。
+
+4) 也許還有更多我不知道的地方:-)
+
+
+tmpfs有三個用於調整大小的掛載選項:
+
+=========  ===========================================================
+size       tmpfs實例分配的字節數限制。默認值是不swap時物理RAM的一半。
+           如果tmpfs實例過大,機器將死鎖,因爲OOM處理將無法釋放該內存。
+nr_blocks  與size相同,但以PAGE_SIZE爲單位。
+nr_inodes  tmpfs實例的最大inode個數。默認值是物理內存頁數的一半,或者
+           (有高端內存的機器)低端內存RAM的頁數,二者以較低者為準。
+=========  ===========================================================
+
+這些參數接受後綴k,m或g表示千,兆和千兆字節,可以在remount時更改。
+size參數也接受後綴%用來限制tmpfs實例占用物理RAM的百分比:
+未指定size或nr_blocks時,默認值爲size=50%
+
+如果nr_blocks=0(或size=0),block個數將不受限制;如果nr_inodes=0,
+inode個數將不受限制。這樣掛載通常是不明智的,因爲它允許任何具有寫權限的
+用戶通過訪問tmpfs耗盡機器上的所有內存;但同時這樣做也會增強在多個CPU的
+場景下的訪問。
+
+tmpfs具有爲所有文件設置NUMA內存分配策略掛載選項(如果啓用了CONFIG_NUMA),
+可以通過「mount -o remount ...」調整
+
+======================== =========================
+mpol=default             採用進程分配策略
+                         (請參閱 set_mempolicy(2))
+mpol=prefer:Node         傾向從給定的節點分配
+mpol=bind:NodeList       只允許從指定的鍊表分配
+mpol=interleave          傾向於依次從每個節點分配
+mpol=interleave:NodeList 依次從每個節點分配
+mpol=local               優先本地節點分配內存
+======================== =========================
+
+NodeList格式是以逗號分隔的十進位數字表示大小和範圍,最大和最小範圍是用-
+分隔符的十進位數來表示。例如,mpol=bind0-3,5,7,9-15
+
+帶有有效NodeList的內存策略將按指定格式保存,在創建文件時使用。當任務在該
+文件系統上創建文件時,會使用到掛載時的內存策略NodeList選項,如果設置的話,
+由調用任務的cpuset[請參見Documentation/admin-guide/cgroup-v1/cpusets.rst]
+以及下面列出的可選標誌約束。如果NodeLists爲設置爲空集,則文件的內存策略將
+恢復爲「默認」策略。
+
+NUMA內存分配策略有可選標誌,可以用於模式結合。在掛載tmpfs時指定這些可選
+標誌可以在NodeList之前生效。
+Documentation/admin-guide/mm/numa_memory_policy.rst列出所有可用的內存
+分配策略模式標誌及其對內存策略。
+
+::
+
+       =static         相當於       MPOL_F_STATIC_NODES
+       =relative       相當於       MPOL_F_RELATIVE_NODES
+
+例如,mpol=bind=staticNodeList相當於MPOL_BIND|MPOL_F_STATIC_NODES的分配策略
+
+請注意,如果內核不支持NUMA,那麼使用mpol選項掛載tmpfs將會失敗;nodelist指定不
+在線的節點也會失敗。如果您的系統依賴於此,但內核會運行不帶NUMA功能(也許是安全
+revocery內核),或者具有較少的節點在線,建議從自動模式中省略mpol選項掛載選項。
+可以在以後通過「mount -o remount,mpol=Policy:NodeList MountPoint」添加到掛載點。
+
+要指定初始根目錄,可以使用如下掛載選項:
+
+====   ====================
+模式 權限用八進位數字表示
+uid    用戶ID
+gid    組ID
+====   ====================
+
+這些選項對remount沒有任何影響。您可以通過chmod(1),chown(1)和chgrp(1)的更改
+已經掛載的參數。
+
+tmpfs具有選擇32位還是64位inode的掛載選項:
+
+=======   =============
+inode64   使用64位inode
+inode32   使用32位inode
+=======   =============
+
+在32位內核上,默認是inode32,掛載時指定inode64會被拒絕。
+在64位內核上,默認配置是CONFIG_TMPFS_INODE64。inode64避免了單個設備上可能有多個
+具有相同inode編號的文件;比如32位應用程式使用glibc如果長期訪問tmpfs,一旦達到33
+位inode編號,就有EOVERFLOW失敗的危險,無法打開大於2GiB的文件,並返回EINVAL。
+
+所以'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs'將在
+/mytmpfs上掛載tmpfs實例,分配只能由root用戶訪問的10GB RAM/SWAP,可以有10240個
+inode的實例。
+
+
+:作者:
+   Christoph Rohland <cr@sap.com>, 1.12.01
+:更新:
+   Hugh Dickins, 4 June 2007
+:更新:
+   KOSAKI Motohiro, 16 Mar 2010
+:更新:
+   Chris Down, 13 July 2020
+
diff --git a/Documentation/translations/zh_TW/filesystems/virtiofs.rst b/Documentation/translations/zh_TW/filesystems/virtiofs.rst
new file mode 100644 (file)
index 0000000..2b05e84
--- /dev/null
@@ -0,0 +1,61 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_TW.rst
+
+:Original: :ref:`Documentation/filesystems/virtiofs.rst <virtiofs_index>`
+
+譯者
+::
+
+       中文版維護者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+       中文版翻譯者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+       中文版校譯者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+       中文版校譯者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+       繁體中文版校譯者:胡皓文 Hu Haowen <src.res@email.cn>
+
+===========================================
+virtiofs: virtio-fs 主機<->客機共享文件系統
+===========================================
+
+- Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
+
+介紹
+====
+Linux的virtiofs文件系統實現了一個半虛擬化VIRTIO類型「virtio-fs」設備的驅動,通過該\
+類型設備實現客機<->主機文件系統共享。它允許客機掛載一個已經導出到主機的目錄。
+
+客機通常需要訪問主機或者遠程系統上的文件。使用場景包括:在新客機安裝時讓文件對其\
+可見;從主機上的根文件系統啓動;對無狀態或臨時客機提供持久存儲和在客機之間共享目錄。
+
+儘管在某些任務可能通過使用已有的網絡文件系統完成,但是卻需要非常難以自動化的配置\
+步驟,且將存儲網絡暴露給客機。而virtio-fs設備通過提供不經過網絡的文件系統訪問文件\
+的設計方式解決了這些問題。
+
+另外,virto-fs設備發揮了主客機共存的優點提高了性能,並且提供了網絡文件系統所不具備
+的一些語義功能。
+
+用法
+====
+以``myfs``標籤將文件系統掛載到``/mnt``:
+
+.. code-block:: sh
+
+  guest# mount -t virtiofs myfs /mnt
+
+請查閱 https://virtio-fs.gitlab.io/ 了解配置QEMU和virtiofsd守護程序的詳細信息。
+
+內幕
+====
+由於virtio-fs設備將FUSE協議用於文件系統請求,因此Linux的virtiofs文件系統與FUSE文\
+件系統客戶端緊密集成在一起。客機充當FUSE客戶端而主機充當FUSE伺服器,內核與用戶空\
+間之間的/dev/fuse接口由virtio-fs設備接口代替。
+
+FUSE請求被置於虛擬隊列中由主機處理。主機填充緩衝區中的響應部分,而客機處理請求的完成部分。
+
+將/dev/fuse映射到虛擬隊列需要解決/dev/fuse和虛擬隊列之間語義上的差異。每次讀取\
+/dev/fuse設備時,FUSE客戶端都可以選擇要傳輸的請求,從而可以使某些請求優先於其他\
+請求。虛擬隊列有其隊列語義,無法更改已入隊請求的順序。在虛擬隊列已滿的情況下尤
+其關鍵,因爲此時不可能加入高優先級的請求。爲了解決此差異,virtio-fs設備採用「hiprio」\
+(高優先級)虛擬隊列,專門用於有別於普通請求的高優先級請求。
+
+
index c02c4b5..2a28103 100644 (file)
@@ -89,6 +89,12 @@ TODOList:
 大部分信息都是直接從內核原始碼獲取的,並根據需要添加補充材料(或者至少是在
 我們設法添加的時候——可能不是所有的都是有需要的)。
 
+.. toctree::
+   :maxdepth: 2
+
+   cpu-freq/index
+   filesystems/index
+
 TODOList:
 
 * driver-api/index
@@ -97,7 +103,6 @@ TODOList:
 * accounting/index
 * block/index
 * cdrom/index
-* cpu-freq/index
 * ide/index
 * fb/index
 * fpga/index
@@ -123,7 +128,6 @@ TODOList:
 * security/index
 * sound/index
 * crypto/index
-* filesystems/index
 * vm/index
 * bpf/index
 * usb/index
@@ -136,6 +140,11 @@ TODOList:
 體系結構無關文檔
 ----------------
 
+.. toctree::
+   :maxdepth: 2
+
+   arm64/index
+
 TODOList:
 
 * asm-annotations
index ede1875..9798676 100644 (file)
@@ -140,10 +140,6 @@ The direct mapping covers all memory in the system up to the highest
 memory address (this means in some cases it can also include PCI memory
 holes).
 
-vmalloc space is lazily synchronized into the different PML4/PML5 pages of
-the processes using the page fault handler, with init_top_pgt as
-reference.
-
 We map EFI runtime services in the 'efi_pgd' PGD in a 64Gb large virtual
 memory window (this size is arbitrary, it can be raised later if needed).
 The mappings are not part of any other kernel PGD and are only available
index 9af529a..3a9a7cb 100644 (file)
@@ -12633,6 +12633,7 @@ Q:      http://patchwork.linuxtv.org/project/linux-media/list/
 F:     drivers/media/dvb-frontends/mn88473*
 
 MODULE SUPPORT
+M:     Luis Chamberlain <mcgrof@kernel.org>
 M:     Jessica Yu <jeyu@kernel.org>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux.git modules-next
index feaa43b..8b84513 100644 (file)
@@ -24,7 +24,6 @@
                };
        };
 
-       /* see Documentation/devicetree/bindings/opp/opp.txt */
        cpu0_opp_table: opp-table {
                compatible = "operating-points-v2-ti-cpu";
                syscon = <&scm_conf>;
index 20844db..22b3309 100644 (file)
@@ -29,7 +29,6 @@
                };
        };
 
-       /* see Documentation/devicetree/bindings/opp/opp.txt */
        cpu0_opp_table: opp-table {
                compatible = "operating-points-v2-ti-cpu";
                syscon = <&scm_conf>;
index 79c1a75..eaa6ca0 100644 (file)
@@ -107,11 +107,6 @@ struct compat_statfs {
 #define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
 #define COMPAT_MINSIGSTKSZ     2048
 
-static inline void __user *arch_compat_alloc_user_space(long len)
-{
-       return (void __user *)compat_user_stack_pointer() - len;
-}
-
 struct compat_ipc64_perm {
        compat_key_t key;
        __compat_uid32_t uid;
index b5f0862..190b494 100644 (file)
@@ -430,17 +430,6 @@ extern unsigned long __must_check __arch_copy_to_user(void __user *to, const voi
        __actu_ret;                                                     \
 })
 
-extern unsigned long __must_check __arch_copy_in_user(void __user *to, const void __user *from, unsigned long n);
-#define raw_copy_in_user(to, from, n)                                  \
-({                                                                     \
-       unsigned long __aciu_ret;                                       \
-       uaccess_ttbr0_enable();                                         \
-       __aciu_ret = __arch_copy_in_user(__uaccess_mask_ptr(to),        \
-                                   __uaccess_mask_ptr(from), (n));     \
-       uaccess_ttbr0_disable();                                        \
-       __aciu_ret;                                                     \
-})
-
 #define INLINE_COPY_TO_USER
 #define INLINE_COPY_FROM_USER
 
index 4e99e4b..844f6ae 100644 (file)
@@ -649,11 +649,11 @@ __SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch)
 #define __NR_inotify_rm_watch 318
 __SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
 #define __NR_mbind 319
-__SYSCALL(__NR_mbind, compat_sys_mbind)
+__SYSCALL(__NR_mbind, sys_mbind)
 #define __NR_get_mempolicy 320
-__SYSCALL(__NR_get_mempolicy, compat_sys_get_mempolicy)
+__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
 #define __NR_set_mempolicy 321
-__SYSCALL(__NR_set_mempolicy, compat_sys_set_mempolicy)
+__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
 #define __NR_openat 322
 __SYSCALL(__NR_openat, compat_sys_openat)
 #define __NR_mkdirat 323
@@ -699,7 +699,7 @@ __SYSCALL(__NR_tee, sys_tee)
 #define __NR_vmsplice 343
 __SYSCALL(__NR_vmsplice, sys_vmsplice)
 #define __NR_move_pages 344
-__SYSCALL(__NR_move_pages, compat_sys_move_pages)
+__SYSCALL(__NR_move_pages, sys_move_pages)
 #define __NR_getcpu 345
 __SYSCALL(__NR_getcpu, sys_getcpu)
 #define __NR_epoll_pwait 346
@@ -811,7 +811,7 @@ __SYSCALL(__NR_rseq, sys_rseq)
 #define __NR_io_pgetevents 399
 __SYSCALL(__NR_io_pgetevents, compat_sys_io_pgetevents)
 #define __NR_migrate_pages 400
-__SYSCALL(__NR_migrate_pages, compat_sys_migrate_pages)
+__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
 #define __NR_kexec_file_load 401
 __SYSCALL(__NR_kexec_file_load, sys_kexec_file_load)
 /* 402 is unused */
index 6dd56a4..0941180 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 lib-y          := clear_user.o delay.o copy_from_user.o                \
-                  copy_to_user.o copy_in_user.o copy_page.o            \
+                  copy_to_user.o copy_page.o                           \
                   clear_page.o csum.o insn.o memchr.o memcpy.o         \
                   memset.o memcmp.o strcmp.o strncmp.o strlen.o        \
                   strnlen.o strchr.o strrchr.o tishift.o
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
deleted file mode 100644 (file)
index dbea379..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copy from user space to user space
- *
- * Copyright (C) 2012 ARM Ltd.
- */
-
-#include <linux/linkage.h>
-
-#include <asm/asm-uaccess.h>
-#include <asm/assembler.h>
-#include <asm/cache.h>
-
-/*
- * Copy from user space to user space (alignment handled by the hardware)
- *
- * Parameters:
- *     x0 - to
- *     x1 - from
- *     x2 - n
- * Returns:
- *     x0 - bytes not copied
- */
-       .macro ldrb1 reg, ptr, val
-       user_ldst 9998f, ldtrb, \reg, \ptr, \val
-       .endm
-
-       .macro strb1 reg, ptr, val
-       user_ldst 9998f, sttrb, \reg, \ptr, \val
-       .endm
-
-       .macro ldrh1 reg, ptr, val
-       user_ldst 9997f, ldtrh, \reg, \ptr, \val
-       .endm
-
-       .macro strh1 reg, ptr, val
-       user_ldst 9997f, sttrh, \reg, \ptr, \val
-       .endm
-
-       .macro ldr1 reg, ptr, val
-       user_ldst 9997f, ldtr, \reg, \ptr, \val
-       .endm
-
-       .macro str1 reg, ptr, val
-       user_ldst 9997f, sttr, \reg, \ptr, \val
-       .endm
-
-       .macro ldp1 reg1, reg2, ptr, val
-       user_ldp 9997f, \reg1, \reg2, \ptr, \val
-       .endm
-
-       .macro stp1 reg1, reg2, ptr, val
-       user_stp 9997f, \reg1, \reg2, \ptr, \val
-       .endm
-
-end    .req    x5
-srcin  .req    x15
-SYM_FUNC_START(__arch_copy_in_user)
-       add     end, x0, x2
-       mov     srcin, x1
-#include "copy_template.S"
-       mov     x0, #0
-       ret
-SYM_FUNC_END(__arch_copy_in_user)
-EXPORT_SYMBOL(__arch_copy_in_user)
-
-       .section .fixup,"ax"
-       .align  2
-9997:  cmp     dst, dstin
-       b.ne    9998f
-       // Before being absolutely sure we couldn't copy anything, try harder
-USER(9998f, ldtrb tmp1w, [srcin])
-USER(9998f, sttrb tmp1w, [dst])
-       add     dst, dst, #1
-9998:  sub     x0, end, dst                    // bytes not copied
-       ret
-       .previous
index a4e40e5..a1c5978 100644 (file)
@@ -1 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-y                  += kernel/
+obj-y                  += mm/
+obj-$(CONFIG_PCI)      += pci/
+obj-y                  += boot/dts/
index 6d4af39..9adc6b6 100644 (file)
@@ -50,17 +50,12 @@ KBUILD_CFLAGS += -ffixed-r31 $(CPUFLAGS-y) $(CPUFLAGS-1) $(CPUFLAGS-2)
 
 head-y := arch/microblaze/kernel/head.o
 libs-y += arch/microblaze/lib/
-core-y += arch/microblaze/kernel/
-core-y += arch/microblaze/mm/
-core-$(CONFIG_PCI) += arch/microblaze/pci/
 
 boot := arch/microblaze/boot
 
 # Are we making a simpleImage.<boardname> target? If so, crack out the boardname
 DTB:=$(subst simpleImage.,,$(filter simpleImage.%, $(MAKECMDGOALS)))
 
-core-y += $(boot)/dts/
-
 export DTB
 
 all: linux.bin
index 600d018..0a515cd 100644 (file)
@@ -154,8 +154,6 @@ FEXPORT(__raw_copy_from_user)
 EXPORT_SYMBOL(__raw_copy_from_user)
 FEXPORT(__raw_copy_to_user)
 EXPORT_SYMBOL(__raw_copy_to_user)
-FEXPORT(__raw_copy_in_user)
-EXPORT_SYMBOL(__raw_copy_in_user)
        /*
         * Note: dst & src may be unaligned, len may be 0
         * Temps
index 53f015a..bbb3bc5 100644 (file)
@@ -96,14 +96,6 @@ struct compat_statfs {
 
 #define COMPAT_OFF_T_MAX       0x7fffffff
 
-static inline void __user *arch_compat_alloc_user_space(long len)
-{
-       struct pt_regs *regs = (struct pt_regs *)
-               ((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1;
-
-       return (void __user *) (regs->regs[29] - len);
-}
-
 struct compat_ipc64_perm {
        compat_key_t key;
        __compat_uid32_t uid;
index 783fecc..f8f74f9 100644 (file)
@@ -428,7 +428,6 @@ do {                                                                        \
 
 extern size_t __raw_copy_from_user(void *__to, const void *__from, size_t __n);
 extern size_t __raw_copy_to_user(void *__to, const void *__from, size_t __n);
-extern size_t __raw_copy_in_user(void *__to, const void *__from, size_t __n);
 
 static inline unsigned long
 raw_copy_from_user(void *to, const void __user *from, unsigned long n)
@@ -480,31 +479,6 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
 #define INLINE_COPY_FROM_USER
 #define INLINE_COPY_TO_USER
 
-static inline unsigned long
-raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
-{
-       register void __user *__cu_to_r __asm__("$4");
-       register const void __user *__cu_from_r __asm__("$5");
-       register long __cu_len_r __asm__("$6");
-
-       __cu_to_r = to;
-       __cu_from_r = from;
-       __cu_len_r = n;
-
-       __asm__ __volatile__(
-               ".set\tnoreorder\n\t"
-               __MODULE_JAL(__raw_copy_in_user)
-               ".set\tnoat\n\t"
-               __UA_ADDU "\t$1, %1, %2\n\t"
-               ".set\tat\n\t"
-               ".set\treorder"
-               : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)
-               :
-               : "$8", "$9", "$10", "$11", "$12", "$14", "$15", "$24", "$31",
-                 DADDI_SCRATCH, "memory");
-       return __cu_len_r;
-}
-
 extern __kernel_size_t __bzero(void __user *addr, __kernel_size_t size);
 
 /*
index 56c8d3c..70e32de 100644 (file)
 228    n32     clock_nanosleep                 sys_clock_nanosleep_time32
 229    n32     tgkill                          sys_tgkill
 230    n32     utimes                          sys_utimes_time32
-231    n32     mbind                           compat_sys_mbind
-232    n32     get_mempolicy                   compat_sys_get_mempolicy
-233    n32     set_mempolicy                   compat_sys_set_mempolicy
+231    n32     mbind                           sys_mbind
+232    n32     get_mempolicy                   sys_get_mempolicy
+233    n32     set_mempolicy                   sys_set_mempolicy
 234    n32     mq_open                         compat_sys_mq_open
 235    n32     mq_unlink                       sys_mq_unlink
 236    n32     mq_timedsend                    sys_mq_timedsend_time32
 247    n32     inotify_init                    sys_inotify_init
 248    n32     inotify_add_watch               sys_inotify_add_watch
 249    n32     inotify_rm_watch                sys_inotify_rm_watch
-250    n32     migrate_pages                   compat_sys_migrate_pages
+250    n32     migrate_pages                   sys_migrate_pages
 251    n32     openat                          sys_openat
 252    n32     mkdirat                         sys_mkdirat
 253    n32     mknodat                         sys_mknodat
 268    n32     sync_file_range                 sys_sync_file_range
 269    n32     tee                             sys_tee
 270    n32     vmsplice                        sys_vmsplice
-271    n32     move_pages                      compat_sys_move_pages
+271    n32     move_pages                      sys_move_pages
 272    n32     set_robust_list                 compat_sys_set_robust_list
 273    n32     get_robust_list                 compat_sys_get_robust_list
 274    n32     kexec_load                      compat_sys_kexec_load
index 201237f..a61c35e 100644 (file)
 265    o32     clock_nanosleep                 sys_clock_nanosleep_time32
 266    o32     tgkill                          sys_tgkill
 267    o32     utimes                          sys_utimes_time32
-268    o32     mbind                           sys_mbind                       compat_sys_mbind
-269    o32     get_mempolicy                   sys_get_mempolicy               compat_sys_get_mempolicy
-270    o32     set_mempolicy                   sys_set_mempolicy               compat_sys_set_mempolicy
+268    o32     mbind                           sys_mbind
+269    o32     get_mempolicy                   sys_get_mempolicy
+270    o32     set_mempolicy                   sys_set_mempolicy
 271    o32     mq_open                         sys_mq_open                     compat_sys_mq_open
 272    o32     mq_unlink                       sys_mq_unlink
 273    o32     mq_timedsend                    sys_mq_timedsend_time32
 284    o32     inotify_init                    sys_inotify_init
 285    o32     inotify_add_watch               sys_inotify_add_watch
 286    o32     inotify_rm_watch                sys_inotify_rm_watch
-287    o32     migrate_pages                   sys_migrate_pages               compat_sys_migrate_pages
+287    o32     migrate_pages                   sys_migrate_pages
 288    o32     openat                          sys_openat                      compat_sys_openat
 289    o32     mkdirat                         sys_mkdirat
 290    o32     mknodat                         sys_mknodat
 305    o32     sync_file_range                 sys_sync_file_range             sys32_sync_file_range
 306    o32     tee                             sys_tee
 307    o32     vmsplice                        sys_vmsplice
-308    o32     move_pages                      sys_move_pages                  compat_sys_move_pages
+308    o32     move_pages                      sys_move_pages
 309    o32     set_robust_list                 sys_set_robust_list             compat_sys_set_robust_list
 310    o32     get_robust_list                 sys_get_robust_list             compat_sys_get_robust_list
 311    o32     kexec_load                      sys_kexec_load                  compat_sys_kexec_load
index e19fb98..277c322 100644 (file)
@@ -666,8 +666,6 @@ FEXPORT(__raw_copy_from_user)
 EXPORT_SYMBOL(__raw_copy_from_user)
 FEXPORT(__raw_copy_to_user)
 EXPORT_SYMBOL(__raw_copy_to_user)
-FEXPORT(__raw_copy_in_user)
-EXPORT_SYMBOL(__raw_copy_in_user)
 #endif
        /* Legacy Mode, user <-> user */
        __BUILD_COPY_USER LEGACY_MODE USEROP USEROP
@@ -703,13 +701,4 @@ EXPORT_SYMBOL(__raw_copy_to_user)
 __BUILD_COPY_USER EVA_MODE KERNELOP USEROP
 END(__raw_copy_to_user)
 
-/*
- * __copy_in_user (EVA)
- */
-
-LEAF(__raw_copy_in_user)
-EXPORT_SYMBOL(__raw_copy_in_user)
-__BUILD_COPY_USER EVA_MODE USEROP USEROP
-END(__raw_copy_in_user)
-
 #endif
index b5d90e8..c04f5a6 100644 (file)
@@ -163,12 +163,6 @@ struct compat_shmid64_ds {
 #define COMPAT_ELF_NGREG 80
 typedef compat_ulong_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
 
-static __inline__ void __user *arch_compat_alloc_user_space(long len)
-{
-       struct pt_regs *regs = &current->thread.regs;
-       return (void __user *)regs->gr[30];
-}
-
 static inline int __is_compat_task(struct task_struct *t)
 {
        return test_tsk_thread_flag(t, TIF_32BIT);
index ed2cd4f..7c13314 100644 (file)
@@ -215,8 +215,6 @@ unsigned long __must_check raw_copy_to_user(void __user *dst, const void *src,
                                            unsigned long len);
 unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src,
                                            unsigned long len);
-unsigned long __must_check raw_copy_in_user(void __user *dst, const void __user *src,
-                                           unsigned long len);
 #define INLINE_COPY_TO_USER
 #define INLINE_COPY_FROM_USER
 
index 0bf854b..bf751e0 100644 (file)
 258    32      clock_nanosleep         sys_clock_nanosleep_time32
 258    64      clock_nanosleep         sys_clock_nanosleep
 259    common  tgkill                  sys_tgkill
-260    common  mbind                   sys_mbind                       compat_sys_mbind
-261    common  get_mempolicy           sys_get_mempolicy               compat_sys_get_mempolicy
-262    common  set_mempolicy           sys_set_mempolicy               compat_sys_set_mempolicy
+260    common  mbind                   sys_mbind
+261    common  get_mempolicy           sys_get_mempolicy
+262    common  set_mempolicy           sys_set_mempolicy
 # 263 was vserver
 264    common  add_key                 sys_add_key
 265    common  request_key             sys_request_key
 292    64      sync_file_range         sys_sync_file_range
 293    common  tee                     sys_tee
 294    common  vmsplice                sys_vmsplice
-295    common  move_pages              sys_move_pages                  compat_sys_move_pages
+295    common  move_pages              sys_move_pages
 296    common  getcpu                  sys_getcpu
 297    common  epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
 298    common  statfs64                sys_statfs64                    compat_sys_statfs64
index 4b75388..ea70a0e 100644 (file)
@@ -38,14 +38,6 @@ unsigned long raw_copy_from_user(void *dst, const void __user *src,
 }
 EXPORT_SYMBOL(raw_copy_from_user);
 
-unsigned long raw_copy_in_user(void __user *dst, const void __user *src, unsigned long len)
-{
-       mtsp(get_user_space(), 1);
-       mtsp(get_user_space(), 2);
-       return pa_memcpy((void __force *)dst, (void __force *)src, len);
-}
-
-
 void * memcpy(void * dst,const void *src, size_t count)
 {
        mtsp(get_kernel_space(), 1);
@@ -54,7 +46,6 @@ void * memcpy(void * dst,const void *src, size_t count)
        return dst;
 }
 
-EXPORT_SYMBOL(raw_copy_in_user);
 EXPORT_SYMBOL(memcpy);
 
 bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
index e33dcf1..7afc96f 100644 (file)
@@ -83,22 +83,6 @@ struct compat_statfs {
 
 #define COMPAT_OFF_T_MAX       0x7fffffff
 
-static inline void __user *arch_compat_alloc_user_space(long len)
-{
-       struct pt_regs *regs = current->thread.regs;
-       unsigned long usp = regs->gpr[1];
-
-       /*
-        * We can't access below the stack pointer in the 32bit ABI and
-        * can access 288 bytes in the 64bit big-endian ABI,
-        * or 512 bytes with the new ELFv2 little-endian ABI.
-        */
-       if (!is_32bit_task())
-               usp -= USER_REDZONE_SIZE;
-
-       return (void __user *) (usp - len);
-}
-
 /*
  * ipc64_perm is actually 32/64bit clean but since the compat layer refers to
  * it we may as well define it.
index 29b55e2..7bef917 100644 (file)
 256    64      sys_debug_setcontext            sys_ni_syscall
 256    spu     sys_debug_setcontext            sys_ni_syscall
 # 257 reserved for vserver
-258    nospu   migrate_pages                   sys_migrate_pages               compat_sys_migrate_pages
-259    nospu   mbind                           sys_mbind                       compat_sys_mbind
-260    nospu   get_mempolicy                   sys_get_mempolicy               compat_sys_get_mempolicy
-261    nospu   set_mempolicy                   sys_set_mempolicy               compat_sys_set_mempolicy
+258    nospu   migrate_pages                   sys_migrate_pages
+259    nospu   mbind                           sys_mbind
+260    nospu   get_mempolicy                   sys_get_mempolicy
+261    nospu   set_mempolicy                   sys_set_mempolicy
 262    nospu   mq_open                         sys_mq_open                     compat_sys_mq_open
 263    nospu   mq_unlink                       sys_mq_unlink
 264    32      mq_timedsend                    sys_mq_timedsend_time32
 298    common  faccessat                       sys_faccessat
 299    common  get_robust_list                 sys_get_robust_list             compat_sys_get_robust_list
 300    common  set_robust_list                 sys_set_robust_list             compat_sys_set_robust_list
-301    common  move_pages                      sys_move_pages                  compat_sys_move_pages
+301    common  move_pages                      sys_move_pages
 302    common  getcpu                          sys_getcpu
 303    nospu   epoll_pwait                     sys_epoll_pwait                 compat_sys_epoll_pwait
 304    32      utimensat                       sys_utimensat_time32
index 8d49505..cdc7ae7 100644 (file)
@@ -176,16 +176,6 @@ static inline int is_compat_task(void)
        return test_thread_flag(TIF_31BIT);
 }
 
-static inline void __user *arch_compat_alloc_user_space(long len)
-{
-       unsigned long stack;
-
-       stack = KSTK_ESP(current);
-       if (is_compat_task())
-               stack &= 0x7fffffffUL;
-       return (void __user *) (stack - len);
-}
-
 #endif
 
 struct compat_ipc64_perm {
index 9ed9aa3..ce550d0 100644 (file)
@@ -227,9 +227,6 @@ static inline int __get_user_fn(void *x, const void __user *ptr, unsigned long s
        __get_user(x, ptr);                                     \
 })
 
-unsigned long __must_check
-raw_copy_in_user(void __user *to, const void __user *from, unsigned long n);
-
 /*
  * Copy a null terminated string from userspace.
  */
index aa9d68b..df5261e 100644 (file)
 265  common    statfs64                sys_statfs64                    compat_sys_statfs64
 266  common    fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
 267  common    remap_file_pages        sys_remap_file_pages            sys_remap_file_pages
-268  common    mbind                   sys_mbind                       compat_sys_mbind
-269  common    get_mempolicy           sys_get_mempolicy               compat_sys_get_mempolicy
-270  common    set_mempolicy           sys_set_mempolicy               compat_sys_set_mempolicy
+268  common    mbind                   sys_mbind                       sys_mbind
+269  common    get_mempolicy           sys_get_mempolicy               sys_get_mempolicy
+270  common    set_mempolicy           sys_set_mempolicy               sys_set_mempolicy
 271  common    mq_open                 sys_mq_open                     compat_sys_mq_open
 272  common    mq_unlink               sys_mq_unlink                   sys_mq_unlink
 273  common    mq_timedsend            sys_mq_timedsend                sys_mq_timedsend_time32
 284  common    inotify_init            sys_inotify_init                sys_inotify_init
 285  common    inotify_add_watch       sys_inotify_add_watch           sys_inotify_add_watch
 286  common    inotify_rm_watch        sys_inotify_rm_watch            sys_inotify_rm_watch
-287  common    migrate_pages           sys_migrate_pages               compat_sys_migrate_pages
+287  common    migrate_pages           sys_migrate_pages               sys_migrate_pages
 288  common    openat                  sys_openat                      compat_sys_openat
 289  common    mkdirat                 sys_mkdirat                     sys_mkdirat
 290  common    mknodat                 sys_mknodat                     sys_mknodat
 307  common    sync_file_range         sys_sync_file_range             compat_sys_s390_sync_file_range
 308  common    tee                     sys_tee                         sys_tee
 309  common    vmsplice                sys_vmsplice                    sys_vmsplice
-310  common    move_pages              sys_move_pages                  compat_sys_move_pages
+310  common    move_pages              sys_move_pages                  sys_move_pages
 311  common    getcpu                  sys_getcpu                      sys_getcpu
 312  common    epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
 313  common    utimes                  sys_utimes                      sys_utimes_time32
index 94ca99b..a596e69 100644 (file)
@@ -204,69 +204,6 @@ unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long
 }
 EXPORT_SYMBOL(raw_copy_to_user);
 
-static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
-                                              unsigned long size)
-{
-       unsigned long tmp1, tmp2;
-
-       tmp1 = -4096UL;
-       /* FIXME: copy with reduced length. */
-       asm volatile(
-               "   lgr   0,%[spec]\n"
-               "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
-               "   jz    2f\n"
-               "1: algr  %0,%3\n"
-               "   slgr  %1,%3\n"
-               "   slgr  %2,%3\n"
-               "   j     0b\n"
-               "2:slgr  %0,%0\n"
-               "3: \n"
-               EX_TABLE(0b,3b)
-               : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
-               : [spec] "d" (0x810081UL)
-               : "cc", "memory", "0");
-       return size;
-}
-
-static inline unsigned long copy_in_user_mvc(void __user *to, const void __user *from,
-                                            unsigned long size)
-{
-       unsigned long tmp1;
-
-       asm volatile(
-               "   sacf  256\n"
-               "   aghi  %0,-1\n"
-               "   jo    5f\n"
-               "   bras  %3,3f\n"
-               "0: aghi  %0,257\n"
-               "1: mvc   0(1,%1),0(%2)\n"
-               "   la    %1,1(%1)\n"
-               "   la    %2,1(%2)\n"
-               "   aghi  %0,-1\n"
-               "   jnz   1b\n"
-               "   j     5f\n"
-               "2: mvc   0(256,%1),0(%2)\n"
-               "   la    %1,256(%1)\n"
-               "   la    %2,256(%2)\n"
-               "3: aghi  %0,-256\n"
-               "   jnm   2b\n"
-               "4: ex    %0,1b-0b(%3)\n"
-               "5: slgr  %0,%0\n"
-               "6: sacf  768\n"
-               EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
-               : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
-               : : "cc", "memory");
-       return size;
-}
-
-unsigned long raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
-{
-       if (copy_with_mvcos())
-               return copy_in_user_mvcos(to, from, n);
-       return copy_in_user_mvc(to, from, n);
-}
-EXPORT_SYMBOL(raw_copy_in_user);
-
 static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
 {
        unsigned long tmp1, tmp2;
index 8b63410..bd949fc 100644 (file)
@@ -116,25 +116,6 @@ struct compat_statfs {
 
 #define COMPAT_OFF_T_MAX       0x7fffffff
 
-#ifdef CONFIG_COMPAT
-static inline void __user *arch_compat_alloc_user_space(long len)
-{
-       struct pt_regs *regs = current_thread_info()->kregs;
-       unsigned long usp = regs->u_regs[UREG_I6];
-
-       if (test_thread_64bit_stack(usp))
-               usp += STACK_BIAS;
-
-       if (test_thread_flag(TIF_32BIT))
-               usp &= 0xffffffffUL;
-
-       usp -= len;
-       usp &= ~0x7UL;
-
-       return (void __user *) usp;
-}
-#endif
-
 struct compat_ipc64_perm {
        compat_key_t key;
        __compat_uid32_t uid;
index 093849b..d1cc410 100644 (file)
@@ -455,7 +455,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
 
        distance = fp - psp;
        rval = (csp - distance);
-       if (copy_in_user((void __user *) rval, (void __user *) psp, distance))
+       if (raw_copy_in_user((void __user *)rval, (void __user *)psp, distance))
                rval = 0;
        else if (!stack_64bit) {
                if (put_user(((u32)csp),
index 4276b9e..6cc124a 100644 (file)
@@ -435,9 +435,9 @@ static int setup_frame32(struct ksignal *ksig, struct pt_regs *regs,
                              (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
 
        if (!wsaved) {
-               err |= copy_in_user((u32 __user *)sf,
-                                   (u32 __user *)(regs->u_regs[UREG_FP]),
-                                   sizeof(struct reg_window32));
+               err |= raw_copy_in_user((u32 __user *)sf,
+                                       (u32 __user *)(regs->u_regs[UREG_FP]),
+                                       sizeof(struct reg_window32));
        } else {
                struct reg_window *rp;
 
@@ -567,9 +567,9 @@ static int setup_rt_frame32(struct ksignal *ksig, struct pt_regs *regs,
        err |= put_compat_sigset(&sf->mask, oldset, sizeof(compat_sigset_t));
 
        if (!wsaved) {
-               err |= copy_in_user((u32 __user *)sf,
-                                   (u32 __user *)(regs->u_regs[UREG_FP]),
-                                   sizeof(struct reg_window32));
+               err |= raw_copy_in_user((u32 __user *)sf,
+                                       (u32 __user *)(regs->u_regs[UREG_FP]),
+                                       sizeof(struct reg_window32));
        } else {
                struct reg_window *rp;
 
index cea23cf..2a78d2a 100644 (file)
@@ -406,10 +406,10 @@ setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)
        err |= copy_to_user(&sf->mask, sigmask_to_save(), sizeof(sigset_t));
 
        if (!wsaved) {
-               err |= copy_in_user((u64 __user *)sf,
-                                   (u64 __user *)(regs->u_regs[UREG_FP] +
-                                                  STACK_BIAS),
-                                   sizeof(struct reg_window));
+               err |= raw_copy_in_user((u64 __user *)sf,
+                                       (u64 __user *)(regs->u_regs[UREG_FP] +
+                                          STACK_BIAS),
+                                       sizeof(struct reg_window));
        } else {
                struct reg_window *rp;
 
index 7893104..c37764d 100644 (file)
 299    common  unshare                 sys_unshare
 300    common  set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
 301    common  get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
-302    common  migrate_pages           sys_migrate_pages               compat_sys_migrate_pages
-303    common  mbind                   sys_mbind                       compat_sys_mbind
-304    common  get_mempolicy           sys_get_mempolicy               compat_sys_get_mempolicy
-305    common  set_mempolicy           sys_set_mempolicy               compat_sys_set_mempolicy
+302    common  migrate_pages           sys_migrate_pages
+303    common  mbind                   sys_mbind
+304    common  get_mempolicy           sys_get_mempolicy
+305    common  set_mempolicy           sys_set_mempolicy
 306    common  kexec_load              sys_kexec_load                  compat_sys_kexec_load
-307    common  move_pages              sys_move_pages                  compat_sys_move_pages
+307    common  move_pages              sys_move_pages
 308    common  getcpu                  sys_getcpu
 309    common  epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
 310    32      utimensat               sys_utimensat_time32
index 61f18b7..960a021 100644 (file)
 272    i386    fadvise64_64            sys_ia32_fadvise64_64
 273    i386    vserver
 274    i386    mbind                   sys_mbind
-275    i386    get_mempolicy           sys_get_mempolicy               compat_sys_get_mempolicy
+275    i386    get_mempolicy           sys_get_mempolicy
 276    i386    set_mempolicy           sys_set_mempolicy
 277    i386    mq_open                 sys_mq_open                     compat_sys_mq_open
 278    i386    mq_unlink               sys_mq_unlink
 314    i386    sync_file_range         sys_ia32_sync_file_range
 315    i386    tee                     sys_tee
 316    i386    vmsplice                sys_vmsplice
-317    i386    move_pages              sys_move_pages                  compat_sys_move_pages
+317    i386    move_pages              sys_move_pages
 318    i386    getcpu                  sys_getcpu
 319    i386    epoll_pwait             sys_epoll_pwait
 320    i386    utimensat               sys_utimensat_time32
index 807b6a1..18b5500 100644 (file)
 530    x32     set_robust_list         compat_sys_set_robust_list
 531    x32     get_robust_list         compat_sys_get_robust_list
 532    x32     vmsplice                sys_vmsplice
-533    x32     move_pages              compat_sys_move_pages
+533    x32     move_pages              sys_move_pages
 534    x32     preadv                  compat_sys_preadv64
 535    x32     pwritev                 compat_sys_pwritev64
 536    x32     rt_tgsigqueueinfo       compat_sys_rt_tgsigqueueinfo
index 4ae01cd..7516e41 100644 (file)
@@ -156,19 +156,6 @@ struct compat_shmid64_ds {
        (!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
 #endif
 
-static inline void __user *arch_compat_alloc_user_space(long len)
-{
-       compat_uptr_t sp = task_pt_regs(current)->sp;
-
-       /*
-        * -128 for the x32 ABI redzone.  For IA32, it is not strictly
-        * necessary, but not harmful.
-        */
-       sp -= 128;
-
-       return (void __user *)round_down(sp - len, 16);
-}
-
 static inline bool in_x32_syscall(void)
 {
 #ifdef CONFIG_X86_X32_ABI
index e7265a5..45697e0 100644 (file)
@@ -58,13 +58,6 @@ raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
        return copy_user_generic((__force void *)dst, src, size);
 }
 
-static __always_inline __must_check
-unsigned long raw_copy_in_user(void __user *dst, const void __user *src, unsigned long size)
-{
-       return copy_user_generic((__force void *)dst,
-                                (__force void *)src, size);
-}
-
 extern long __copy_user_nocache(void *dst, const void __user *src,
                                unsigned size, int zerorest);
 
index 3a30846..bd92b54 100644 (file)
@@ -449,25 +449,30 @@ int acpi_s2idle_prepare_late(void)
        if (pm_debug_messages_on)
                lpi_check_constraints();
 
-       if (lps0_dsm_func_mask_microsoft > 0) {
+       /* Screen off */
+       if (lps0_dsm_func_mask > 0)
+               acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
+                                       ACPI_LPS0_SCREEN_OFF_AMD :
+                                       ACPI_LPS0_SCREEN_OFF,
+                                       lps0_dsm_func_mask, lps0_dsm_guid);
+
+       if (lps0_dsm_func_mask_microsoft > 0)
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
                                lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
-                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+
+       /* LPS0 entry */
+       if (lps0_dsm_func_mask > 0)
+               acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
+                                       ACPI_LPS0_ENTRY_AMD :
+                                       ACPI_LPS0_ENTRY,
+                                       lps0_dsm_func_mask, lps0_dsm_guid);
+       if (lps0_dsm_func_mask_microsoft > 0) {
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
                                lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
-       } else if (acpi_s2idle_vendor_amd()) {
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF_AMD,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
-       } else {
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
+               /* modern standby entry */
+               acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
+                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
        }
-
        return 0;
 }
 
@@ -476,24 +481,30 @@ void acpi_s2idle_restore_early(void)
        if (!lps0_device_handle || sleep_no_lps0)
                return;
 
-       if (lps0_dsm_func_mask_microsoft > 0) {
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
-                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+       /* Modern standby exit */
+       if (lps0_dsm_func_mask_microsoft > 0)
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
                                lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
-                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
-       } else if (acpi_s2idle_vendor_amd()) {
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT_AMD,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
-       } else {
+
+       /* LPS0 exit */
+       if (lps0_dsm_func_mask > 0)
+               acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
+                                       ACPI_LPS0_EXIT_AMD :
+                                       ACPI_LPS0_EXIT,
+                                       lps0_dsm_func_mask, lps0_dsm_guid);
+       if (lps0_dsm_func_mask_microsoft > 0)
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
+                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+
+       /* Screen on */
+       if (lps0_dsm_func_mask_microsoft > 0)
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
-                               lps0_dsm_func_mask, lps0_dsm_guid);
-       }
+                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+       if (lps0_dsm_func_mask > 0)
+               acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
+                                       ACPI_LPS0_SCREEN_ON_AMD :
+                                       ACPI_LPS0_SCREEN_ON,
+                                       lps0_dsm_func_mask, lps0_dsm_guid);
 }
 
 static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
index 921312a..4340766 100644 (file)
@@ -149,6 +149,7 @@ void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
 }
 
 DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
+EXPORT_PER_CPU_SYMBOL_GPL(cpu_scale);
 
 void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity)
 {
@@ -165,6 +166,7 @@ void topology_set_thermal_pressure(const struct cpumask *cpus,
        for_each_cpu(cpu, cpus)
                WRITE_ONCE(per_cpu(thermal_pressure, cpu), th_pressure);
 }
+EXPORT_SYMBOL_GPL(topology_set_thermal_pressure);
 
 static ssize_t cpu_capacity_show(struct device *dev,
                                 struct device_attribute *attr,
index a5c5f70..954749a 100644 (file)
@@ -133,6 +133,18 @@ config ARM_MEDIATEK_CPUFREQ
        help
          This adds the CPUFreq driver support for MediaTek SoCs.
 
+config ARM_MEDIATEK_CPUFREQ_HW
+       tristate "MediaTek CPUFreq HW driver"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       default m
+       help
+         Support for the CPUFreq HW driver.
+         Some MediaTek chipsets have a HW engine to offload the steps
+         necessary for changing the frequency of the CPUs. Firmware loaded
+         in this engine exposes a programming interface to the OS.
+         The driver implements the cpufreq interface for this HW engine.
+         Say Y if you want to support CPUFreq HW.
+
 config ARM_OMAP2PLUS_CPUFREQ
        bool "TI OMAP2+"
        depends on ARCH_OMAP2PLUS
index 27d3bd7..48ee585 100644 (file)
@@ -56,6 +56,7 @@ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)               += imx6q-cpufreq.o
 obj-$(CONFIG_ARM_IMX_CPUFREQ_DT)       += imx-cpufreq-dt.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)     += kirkwood-cpufreq.o
 obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ)     += mediatek-cpufreq.o
+obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ_HW)  += mediatek-cpufreq-hw.o
 obj-$(CONFIG_MACH_MVEBU_V7)            += mvebu-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)    += omap-cpufreq.o
 obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)       += pxa2xx-cpufreq.o
index b496128..28467d8 100644 (file)
@@ -889,6 +889,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->fast_switch_possible = !acpi_pstate_strict &&
                !(policy_is_shared(policy) && policy->shared_type != CPUFREQ_SHARED_TYPE_ANY);
 
+       if (perf->states[0].core_frequency * 1000 != freq_table[0].frequency)
+               pr_warn(FW_WARN "P-state 0 is not max freq\n");
+
        return result;
 
 err_unreg:
@@ -918,16 +921,6 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static void acpi_cpufreq_cpu_ready(struct cpufreq_policy *policy)
-{
-       struct acpi_processor_performance *perf = per_cpu_ptr(acpi_perf_data,
-                                                             policy->cpu);
-       unsigned int freq = policy->freq_table[0].frequency;
-
-       if (perf->states[0].core_frequency * 1000 != freq)
-               pr_warn(FW_WARN "P-state 0 is not max freq\n");
-}
-
 static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
 {
        struct acpi_cpufreq_data *data = policy->driver_data;
@@ -955,7 +948,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
        .bios_limit     = acpi_processor_get_bios_limit,
        .init           = acpi_cpufreq_cpu_init,
        .exit           = acpi_cpufreq_cpu_exit,
-       .ready          = acpi_cpufreq_cpu_ready,
        .resume         = acpi_cpufreq_resume,
        .name           = "acpi-cpufreq",
        .attr           = acpi_cpufreq_attr,
index 231e585..ca1d103 100644 (file)
@@ -137,11 +137,15 @@ static const struct of_device_id blocklist[] __initconst = {
        { .compatible = "qcom,apq8096", },
        { .compatible = "qcom,msm8996", },
        { .compatible = "qcom,qcs404", },
+       { .compatible = "qcom,sa8155p" },
        { .compatible = "qcom,sc7180", },
        { .compatible = "qcom,sc7280", },
        { .compatible = "qcom,sc8180x", },
        { .compatible = "qcom,sdm845", },
+       { .compatible = "qcom,sm6350", },
        { .compatible = "qcom,sm8150", },
+       { .compatible = "qcom,sm8250", },
+       { .compatible = "qcom,sm8350", },
 
        { .compatible = "st,stih407", },
        { .compatible = "st,stih410", },
index ece5286..8fcaba5 100644 (file)
@@ -143,8 +143,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
                cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs;
        }
 
-       dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
-
        return 0;
 
 out_clk_put:
@@ -184,6 +182,7 @@ static struct cpufreq_driver dt_cpufreq_driver = {
        .exit = cpufreq_exit,
        .online = cpufreq_online,
        .offline = cpufreq_offline,
+       .register_em = cpufreq_register_em_with_opp,
        .name = "cpufreq-dt",
        .attr = cpufreq_dt_attr,
        .suspend = cpufreq_generic_suspend,
index 06c526d..5782b15 100644 (file)
@@ -1491,6 +1491,19 @@ static int cpufreq_online(unsigned int cpu)
                write_lock_irqsave(&cpufreq_driver_lock, flags);
                list_add(&policy->policy_list, &cpufreq_policy_list);
                write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+               /*
+                * Register with the energy model before
+                * sched_cpufreq_governor_change() is called, which will result
+                * in rebuilding of the sched domains, which should only be done
+                * once the energy model is properly initialized for the policy
+                * first.
+                *
+                * Also, this should be called before the policy is registered
+                * with cooling framework.
+                */
+               if (cpufreq_driver->register_em)
+                       cpufreq_driver->register_em(policy);
        }
 
        ret = cpufreq_init_policy(policy);
@@ -1504,10 +1517,6 @@ static int cpufreq_online(unsigned int cpu)
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
 
-       /* Callback for handling stuff after policy is ready */
-       if (cpufreq_driver->ready)
-               cpufreq_driver->ready(policy);
-
        if (cpufreq_thermal_control_enabled(cpufreq_driver))
                policy->cdev = of_cpufreq_cooling_register(policy);
 
index 5bf5fc7..90beb26 100644 (file)
@@ -192,7 +192,6 @@ static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
        policy->clk = clks[ARM].clk;
        cpufreq_generic_init(policy, freq_table, transition_latency);
        policy->suspend_freq = max_freq;
-       dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
 
        return 0;
 }
@@ -204,6 +203,7 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
        .target_index = imx6q_set_target,
        .get = cpufreq_generic_get,
        .init = imx6q_cpufreq_init,
+       .register_em = cpufreq_register_em_with_opp,
        .name = "imx6q-cpufreq",
        .attr = cpufreq_generic_attr,
        .suspend = cpufreq_generic_suspend,
index b4ffe6c..2d83a9f 100644 (file)
@@ -32,7 +32,6 @@
 #include <asm/cpu_device_id.h>
 #include <asm/cpufeature.h>
 #include <asm/intel-family.h>
-#include "../drivers/thermal/intel/thermal_interrupt.h"
 
 #define INTEL_PSTATE_SAMPLING_INTERVAL (10 * NSEC_PER_MSEC)
 
@@ -220,7 +219,6 @@ struct global_params {
  * @sched_flags:       Store scheduler flags for possible cross CPU update
  * @hwp_boost_min:     Last HWP boosted min performance
  * @suspended:         Whether or not the driver has been suspended.
- * @hwp_notify_work:   workqueue for HWP notifications.
  *
  * This structure stores per CPU instance data for all CPUs.
  */
@@ -259,7 +257,6 @@ struct cpudata {
        unsigned int sched_flags;
        u32 hwp_boost_min;
        bool suspended;
-       struct delayed_work hwp_notify_work;
 };
 
 static struct cpudata **all_cpu_data;
@@ -1628,40 +1625,6 @@ static void intel_pstate_sysfs_hide_hwp_dynamic_boost(void)
 
 /************************** sysfs end ************************/
 
-static void intel_pstate_notify_work(struct work_struct *work)
-{
-       mutex_lock(&intel_pstate_driver_lock);
-       cpufreq_update_policy(smp_processor_id());
-       wrmsrl(MSR_HWP_STATUS, 0);
-       mutex_unlock(&intel_pstate_driver_lock);
-}
-
-void notify_hwp_interrupt(void)
-{
-       unsigned int this_cpu = smp_processor_id();
-       struct cpudata *cpudata;
-       u64 value;
-
-       if (!hwp_active || !boot_cpu_has(X86_FEATURE_HWP_NOTIFY))
-               return;
-
-       rdmsrl(MSR_HWP_STATUS, value);
-       if (!(value & 0x01))
-               return;
-
-       cpudata = all_cpu_data[this_cpu];
-       schedule_delayed_work_on(this_cpu, &cpudata->hwp_notify_work, msecs_to_jiffies(10));
-}
-
-static void intel_pstate_enable_hwp_interrupt(struct cpudata *cpudata)
-{
-       /* Enable HWP notification interrupt for guaranteed performance change */
-       if (boot_cpu_has(X86_FEATURE_HWP_NOTIFY)) {
-               INIT_DELAYED_WORK(&cpudata->hwp_notify_work, intel_pstate_notify_work);
-               wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x01);
-       }
-}
-
 static void intel_pstate_hwp_enable(struct cpudata *cpudata)
 {
        /* First disable HWP notification interrupt as we don't process them */
@@ -1671,8 +1634,6 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata)
        wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
        if (cpudata->epp_default == -EINVAL)
                cpudata->epp_default = intel_pstate_get_epp(cpudata, 0);
-
-       intel_pstate_enable_hwp_interrupt(cpudata);
 }
 
 static int atom_get_min_pstate(void)
diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c
new file mode 100644 (file)
index 0000000..0cf18dd
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cpufreq.h>
+#include <linux/energy_model.h>
+#include <linux/init.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+
+#define LUT_MAX_ENTRIES                        32U
+#define LUT_FREQ                       GENMASK(11, 0)
+#define LUT_ROW_SIZE                   0x4
+#define CPUFREQ_HW_STATUS              BIT(0)
+#define SVS_HW_STATUS                  BIT(1)
+#define POLL_USEC                      1000
+#define TIMEOUT_USEC                   300000
+
+enum {
+       REG_FREQ_LUT_TABLE,
+       REG_FREQ_ENABLE,
+       REG_FREQ_PERF_STATE,
+       REG_FREQ_HW_STATE,
+       REG_EM_POWER_TBL,
+       REG_FREQ_LATENCY,
+
+       REG_ARRAY_SIZE,
+};
+
+struct mtk_cpufreq_data {
+       struct cpufreq_frequency_table *table;
+       void __iomem *reg_bases[REG_ARRAY_SIZE];
+       int nr_opp;
+};
+
+static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = {
+       [REG_FREQ_LUT_TABLE]    = 0x0,
+       [REG_FREQ_ENABLE]       = 0x84,
+       [REG_FREQ_PERF_STATE]   = 0x88,
+       [REG_FREQ_HW_STATE]     = 0x8c,
+       [REG_EM_POWER_TBL]      = 0x90,
+       [REG_FREQ_LATENCY]      = 0x110,
+};
+
+static int __maybe_unused
+mtk_cpufreq_get_cpu_power(unsigned long *mW,
+                         unsigned long *KHz, struct device *cpu_dev)
+{
+       struct mtk_cpufreq_data *data;
+       struct cpufreq_policy *policy;
+       int i;
+
+       policy = cpufreq_cpu_get_raw(cpu_dev->id);
+       if (!policy)
+               return 0;
+
+       data = policy->driver_data;
+
+       for (i = 0; i < data->nr_opp; i++) {
+               if (data->table[i].frequency < *KHz)
+                       break;
+       }
+       i--;
+
+       *KHz = data->table[i].frequency;
+       *mW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] +
+                           i * LUT_ROW_SIZE) / 1000;
+
+       return 0;
+}
+
+static int mtk_cpufreq_hw_target_index(struct cpufreq_policy *policy,
+                                      unsigned int index)
+{
+       struct mtk_cpufreq_data *data = policy->driver_data;
+
+       writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]);
+
+       return 0;
+}
+
+static unsigned int mtk_cpufreq_hw_get(unsigned int cpu)
+{
+       struct mtk_cpufreq_data *data;
+       struct cpufreq_policy *policy;
+       unsigned int index;
+
+       policy = cpufreq_cpu_get_raw(cpu);
+       if (!policy)
+               return 0;
+
+       data = policy->driver_data;
+
+       index = readl_relaxed(data->reg_bases[REG_FREQ_PERF_STATE]);
+       index = min(index, LUT_MAX_ENTRIES - 1);
+
+       return data->table[index].frequency;
+}
+
+static unsigned int mtk_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
+                                              unsigned int target_freq)
+{
+       struct mtk_cpufreq_data *data = policy->driver_data;
+       unsigned int index;
+
+       index = cpufreq_table_find_index_dl(policy, target_freq);
+
+       writel_relaxed(index, data->reg_bases[REG_FREQ_PERF_STATE]);
+
+       return policy->freq_table[index].frequency;
+}
+
+static int mtk_cpu_create_freq_table(struct platform_device *pdev,
+                                    struct mtk_cpufreq_data *data)
+{
+       struct device *dev = &pdev->dev;
+       u32 temp, i, freq, prev_freq = 0;
+       void __iomem *base_table;
+
+       data->table = devm_kcalloc(dev, LUT_MAX_ENTRIES + 1,
+                                  sizeof(*data->table), GFP_KERNEL);
+       if (!data->table)
+               return -ENOMEM;
+
+       base_table = data->reg_bases[REG_FREQ_LUT_TABLE];
+
+       for (i = 0; i < LUT_MAX_ENTRIES; i++) {
+               temp = readl_relaxed(base_table + (i * LUT_ROW_SIZE));
+               freq = FIELD_GET(LUT_FREQ, temp) * 1000;
+
+               if (freq == prev_freq)
+                       break;
+
+               data->table[i].frequency = freq;
+
+               dev_dbg(dev, "index=%d freq=%d\n", i, data->table[i].frequency);
+
+               prev_freq = freq;
+       }
+
+       data->table[i].frequency = CPUFREQ_TABLE_END;
+       data->nr_opp = i;
+
+       return 0;
+}
+
+static int mtk_cpu_resources_init(struct platform_device *pdev,
+                                 struct cpufreq_policy *policy,
+                                 const u16 *offsets)
+{
+       struct mtk_cpufreq_data *data;
+       struct device *dev = &pdev->dev;
+       void __iomem *base;
+       int ret, i;
+       int index;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       index = of_perf_domain_get_sharing_cpumask(policy->cpu, "performance-domains",
+                                                  "#performance-domain-cells",
+                                                  policy->cpus);
+       if (index < 0)
+               return index;
+
+       base = devm_platform_ioremap_resource(pdev, index);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       for (i = REG_FREQ_LUT_TABLE; i < REG_ARRAY_SIZE; i++)
+               data->reg_bases[i] = base + offsets[i];
+
+       ret = mtk_cpu_create_freq_table(pdev, data);
+       if (ret) {
+               dev_info(dev, "Domain-%d failed to create freq table\n", index);
+               return ret;
+       }
+
+       policy->freq_table = data->table;
+       policy->driver_data = data;
+
+       return 0;
+}
+
+static int mtk_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
+{
+       struct platform_device *pdev = cpufreq_get_driver_data();
+       int sig, pwr_hw = CPUFREQ_HW_STATUS | SVS_HW_STATUS;
+       struct mtk_cpufreq_data *data;
+       unsigned int latency;
+       int ret;
+
+       /* Get the bases of cpufreq for domains */
+       ret = mtk_cpu_resources_init(pdev, policy, platform_get_drvdata(pdev));
+       if (ret) {
+               dev_info(&pdev->dev, "CPUFreq resource init failed\n");
+               return ret;
+       }
+
+       data = policy->driver_data;
+
+       latency = readl_relaxed(data->reg_bases[REG_FREQ_LATENCY]) * 1000;
+       if (!latency)
+               latency = CPUFREQ_ETERNAL;
+
+       policy->cpuinfo.transition_latency = latency;
+       policy->fast_switch_possible = true;
+
+       /* HW should be in enabled state to proceed now */
+       writel_relaxed(0x1, data->reg_bases[REG_FREQ_ENABLE]);
+       if (readl_poll_timeout(data->reg_bases[REG_FREQ_HW_STATE], sig,
+                              (sig & pwr_hw) == pwr_hw, POLL_USEC,
+                              TIMEOUT_USEC)) {
+               if (!(sig & CPUFREQ_HW_STATUS)) {
+                       pr_info("cpufreq hardware of CPU%d is not enabled\n",
+                               policy->cpu);
+                       return -ENODEV;
+               }
+
+               pr_info("SVS of CPU%d is not enabled\n", policy->cpu);
+       }
+
+       return 0;
+}
+
+static int mtk_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
+{
+       struct mtk_cpufreq_data *data = policy->driver_data;
+
+       /* HW should be in paused state now */
+       writel_relaxed(0x0, data->reg_bases[REG_FREQ_ENABLE]);
+
+       return 0;
+}
+
+static void mtk_cpufreq_register_em(struct cpufreq_policy *policy)
+{
+       struct em_data_callback em_cb = EM_DATA_CB(mtk_cpufreq_get_cpu_power);
+       struct mtk_cpufreq_data *data = policy->driver_data;
+
+       em_dev_register_perf_domain(get_cpu_device(policy->cpu), data->nr_opp,
+                                   &em_cb, policy->cpus, true);
+}
+
+static struct cpufreq_driver cpufreq_mtk_hw_driver = {
+       .flags          = CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                         CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
+                         CPUFREQ_IS_COOLING_DEV,
+       .verify         = cpufreq_generic_frequency_table_verify,
+       .target_index   = mtk_cpufreq_hw_target_index,
+       .get            = mtk_cpufreq_hw_get,
+       .init           = mtk_cpufreq_hw_cpu_init,
+       .exit           = mtk_cpufreq_hw_cpu_exit,
+       .register_em    = mtk_cpufreq_register_em,
+       .fast_switch    = mtk_cpufreq_hw_fast_switch,
+       .name           = "mtk-cpufreq-hw",
+       .attr           = cpufreq_generic_attr,
+};
+
+static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev)
+{
+       const void *data;
+       int ret;
+
+       data = of_device_get_match_data(&pdev->dev);
+       if (!data)
+               return -EINVAL;
+
+       platform_set_drvdata(pdev, (void *) data);
+       cpufreq_mtk_hw_driver.driver_data = pdev;
+
+       ret = cpufreq_register_driver(&cpufreq_mtk_hw_driver);
+       if (ret)
+               dev_err(&pdev->dev, "CPUFreq HW driver failed to register\n");
+
+       return ret;
+}
+
+static int mtk_cpufreq_hw_driver_remove(struct platform_device *pdev)
+{
+       return cpufreq_unregister_driver(&cpufreq_mtk_hw_driver);
+}
+
+static const struct of_device_id mtk_cpufreq_hw_match[] = {
+       { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_offsets },
+       {}
+};
+
+static struct platform_driver mtk_cpufreq_hw_driver = {
+       .probe = mtk_cpufreq_hw_driver_probe,
+       .remove = mtk_cpufreq_hw_driver_remove,
+       .driver = {
+               .name = "mtk-cpufreq-hw",
+               .of_match_table = mtk_cpufreq_hw_match,
+       },
+};
+module_platform_driver(mtk_cpufreq_hw_driver);
+
+MODULE_AUTHOR("Hector Yuan <hector.yuan@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek cpufreq-hw driver");
+MODULE_LICENSE("GPL v2");
index 87019d5..8661638 100644 (file)
@@ -448,8 +448,6 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy)
        policy->driver_data = info;
        policy->clk = info->cpu_clk;
 
-       dev_pm_opp_of_register_em(info->cpu_dev, policy->cpus);
-
        return 0;
 }
 
@@ -471,6 +469,7 @@ static struct cpufreq_driver mtk_cpufreq_driver = {
        .get = cpufreq_generic_get,
        .init = mtk_cpufreq_init,
        .exit = mtk_cpufreq_exit,
+       .register_em = cpufreq_register_em_with_opp,
        .name = "mtk-cpufreq",
        .attr = cpufreq_generic_attr,
 };
index e035ee2..1b50df0 100644 (file)
@@ -131,7 +131,6 @@ static int omap_cpu_init(struct cpufreq_policy *policy)
 
        /* FIXME: what's the actual transition time? */
        cpufreq_generic_init(policy, freq_table, 300 * 1000);
-       dev_pm_opp_of_register_em(mpu_dev, policy->cpus);
 
        return 0;
 }
@@ -150,6 +149,7 @@ static struct cpufreq_driver omap_driver = {
        .get            = cpufreq_generic_get,
        .init           = omap_cpu_init,
        .exit           = omap_cpu_exit,
+       .register_em    = cpufreq_register_em_with_opp,
        .name           = "omap",
        .attr           = cpufreq_generic_attr,
 };
index f86859b..a2be0df 100644 (file)
@@ -7,12 +7,14 @@
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 #include <linux/interconnect.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/pm_opp.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 
 #define LUT_MAX_ENTRIES                        40U
 #define LUT_SRC                                GENMASK(31, 30)
 #define CLK_HW_DIV                     2
 #define LUT_TURBO_IND                  1
 
+#define HZ_PER_KHZ                     1000
+
 struct qcom_cpufreq_soc_data {
        u32 reg_enable;
        u32 reg_freq_lut;
        u32 reg_volt_lut;
+       u32 reg_current_vote;
        u32 reg_perf_state;
        u8 lut_row_size;
 };
@@ -34,6 +39,16 @@ struct qcom_cpufreq_data {
        void __iomem *base;
        struct resource *res;
        const struct qcom_cpufreq_soc_data *soc_data;
+
+       /*
+        * Mutex to synchronize between de-init sequence and re-starting LMh
+        * polling/interrupts
+        */
+       struct mutex throttle_lock;
+       int throttle_irq;
+       bool cancel_throttle;
+       struct delayed_work throttle_work;
+       struct cpufreq_policy *policy;
 };
 
 static unsigned long cpu_hw_rate, xo_rate;
@@ -251,10 +266,92 @@ static void qcom_get_related_cpus(int index, struct cpumask *m)
        }
 }
 
+static unsigned int qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
+{
+       unsigned int val = readl_relaxed(data->base + data->soc_data->reg_current_vote);
+
+       return (val & 0x3FF) * 19200;
+}
+
+static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
+{
+       unsigned long max_capacity, capacity, freq_hz, throttled_freq;
+       struct cpufreq_policy *policy = data->policy;
+       int cpu = cpumask_first(policy->cpus);
+       struct device *dev = get_cpu_device(cpu);
+       struct dev_pm_opp *opp;
+       unsigned int freq;
+
+       /*
+        * Get the h/w throttled frequency, normalize it using the
+        * registered opp table and use it to calculate thermal pressure.
+        */
+       freq = qcom_lmh_get_throttle_freq(data);
+       freq_hz = freq * HZ_PER_KHZ;
+
+       opp = dev_pm_opp_find_freq_floor(dev, &freq_hz);
+       if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE)
+               dev_pm_opp_find_freq_ceil(dev, &freq_hz);
+
+       throttled_freq = freq_hz / HZ_PER_KHZ;
+
+       /* Update thermal pressure */
+
+       max_capacity = arch_scale_cpu_capacity(cpu);
+       capacity = mult_frac(max_capacity, throttled_freq, policy->cpuinfo.max_freq);
+
+       /* Don't pass boost capacity to scheduler */
+       if (capacity > max_capacity)
+               capacity = max_capacity;
+
+       arch_set_thermal_pressure(policy->cpus, max_capacity - capacity);
+
+       /*
+        * In the unlikely case policy is unregistered do not enable
+        * polling or h/w interrupt
+        */
+       mutex_lock(&data->throttle_lock);
+       if (data->cancel_throttle)
+               goto out;
+
+       /*
+        * If h/w throttled frequency is higher than what cpufreq has requested
+        * for, then stop polling and switch back to interrupt mechanism.
+        */
+       if (throttled_freq >= qcom_cpufreq_hw_get(cpu))
+               enable_irq(data->throttle_irq);
+       else
+               mod_delayed_work(system_highpri_wq, &data->throttle_work,
+                                msecs_to_jiffies(10));
+
+out:
+       mutex_unlock(&data->throttle_lock);
+}
+
+static void qcom_lmh_dcvs_poll(struct work_struct *work)
+{
+       struct qcom_cpufreq_data *data;
+
+       data = container_of(work, struct qcom_cpufreq_data, throttle_work.work);
+       qcom_lmh_dcvs_notify(data);
+}
+
+static irqreturn_t qcom_lmh_dcvs_handle_irq(int irq, void *data)
+{
+       struct qcom_cpufreq_data *c_data = data;
+
+       /* Disable interrupt and enable polling */
+       disable_irq_nosync(c_data->throttle_irq);
+       qcom_lmh_dcvs_notify(c_data);
+
+       return 0;
+}
+
 static const struct qcom_cpufreq_soc_data qcom_soc_data = {
        .reg_enable = 0x0,
        .reg_freq_lut = 0x110,
        .reg_volt_lut = 0x114,
+       .reg_current_vote = 0x704,
        .reg_perf_state = 0x920,
        .lut_row_size = 32,
 };
@@ -274,6 +371,51 @@ static const struct of_device_id qcom_cpufreq_hw_match[] = {
 };
 MODULE_DEVICE_TABLE(of, qcom_cpufreq_hw_match);
 
+static int qcom_cpufreq_hw_lmh_init(struct cpufreq_policy *policy, int index)
+{
+       struct qcom_cpufreq_data *data = policy->driver_data;
+       struct platform_device *pdev = cpufreq_get_driver_data();
+       char irq_name[15];
+       int ret;
+
+       /*
+        * Look for LMh interrupt. If no interrupt line is specified /
+        * if there is an error, allow cpufreq to be enabled as usual.
+        */
+       data->throttle_irq = platform_get_irq(pdev, index);
+       if (data->throttle_irq <= 0)
+               return data->throttle_irq == -EPROBE_DEFER ? -EPROBE_DEFER : 0;
+
+       data->cancel_throttle = false;
+       data->policy = policy;
+
+       mutex_init(&data->throttle_lock);
+       INIT_DEFERRABLE_WORK(&data->throttle_work, qcom_lmh_dcvs_poll);
+
+       snprintf(irq_name, sizeof(irq_name), "dcvsh-irq-%u", policy->cpu);
+       ret = request_threaded_irq(data->throttle_irq, NULL, qcom_lmh_dcvs_handle_irq,
+                                  IRQF_ONESHOT, irq_name, data);
+       if (ret) {
+               dev_err(&pdev->dev, "Error registering %s: %d\n", irq_name, ret);
+               return 0;
+       }
+
+       return 0;
+}
+
+static void qcom_cpufreq_hw_lmh_exit(struct qcom_cpufreq_data *data)
+{
+       if (data->throttle_irq <= 0)
+               return;
+
+       mutex_lock(&data->throttle_lock);
+       data->cancel_throttle = true;
+       mutex_unlock(&data->throttle_lock);
+
+       cancel_delayed_work_sync(&data->throttle_work);
+       free_irq(data->throttle_irq, data);
+}
+
 static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
 {
        struct platform_device *pdev = cpufreq_get_driver_data();
@@ -348,6 +490,7 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
        }
 
        policy->driver_data = data;
+       policy->dvfs_possible_from_any_cpu = true;
 
        ret = qcom_cpufreq_hw_read_lut(cpu_dev, policy);
        if (ret) {
@@ -362,14 +505,16 @@ static int qcom_cpufreq_hw_cpu_init(struct cpufreq_policy *policy)
                goto error;
        }
 
-       dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
-
        if (policy_has_boost_freq(policy)) {
                ret = cpufreq_enable_boost_support();
                if (ret)
                        dev_warn(cpu_dev, "failed to enable boost: %d\n", ret);
        }
 
+       ret = qcom_cpufreq_hw_lmh_init(policy, index);
+       if (ret)
+               goto error;
+
        return 0;
 error:
        kfree(data);
@@ -389,6 +534,7 @@ static int qcom_cpufreq_hw_cpu_exit(struct cpufreq_policy *policy)
 
        dev_pm_opp_remove_all_dynamic(cpu_dev);
        dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
+       qcom_cpufreq_hw_lmh_exit(data);
        kfree(policy->freq_table);
        kfree(data);
        iounmap(base);
@@ -412,6 +558,7 @@ static struct cpufreq_driver cpufreq_qcom_hw_driver = {
        .get            = qcom_cpufreq_hw_get,
        .init           = qcom_cpufreq_hw_cpu_init,
        .exit           = qcom_cpufreq_hw_cpu_exit,
+       .register_em    = cpufreq_register_em_with_opp,
        .fast_switch    = qcom_cpufreq_hw_fast_switch,
        .name           = "qcom-cpufreq-hw",
        .attr           = qcom_cpufreq_hw_attr,
index 75f818d..1e0cd4d 100644 (file)
@@ -22,7 +22,9 @@
 
 struct scmi_data {
        int domain_id;
+       int nr_opp;
        struct device *cpu_dev;
+       cpumask_var_t opp_shared_cpus;
 };
 
 static struct scmi_protocol_handle *ph;
@@ -123,9 +125,6 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
        struct device *cpu_dev;
        struct scmi_data *priv;
        struct cpufreq_frequency_table *freq_table;
-       struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
-       cpumask_var_t opp_shared_cpus;
-       bool power_scale_mw;
 
        cpu_dev = get_cpu_device(policy->cpu);
        if (!cpu_dev) {
@@ -133,9 +132,15 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
                return -ENODEV;
        }
 
-       if (!zalloc_cpumask_var(&opp_shared_cpus, GFP_KERNEL))
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
                return -ENOMEM;
 
+       if (!zalloc_cpumask_var(&priv->opp_shared_cpus, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto out_free_priv;
+       }
+
        /* Obtain CPUs that share SCMI performance controls */
        ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus);
        if (ret) {
@@ -148,14 +153,14 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
         * The OPP 'sharing cpus' info may come from DT through an empty opp
         * table and opp-shared.
         */
-       ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, opp_shared_cpus);
-       if (ret || !cpumask_weight(opp_shared_cpus)) {
+       ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->opp_shared_cpus);
+       if (ret || !cpumask_weight(priv->opp_shared_cpus)) {
                /*
                 * Either opp-table is not set or no opp-shared was found.
                 * Use the CPU mask from SCMI to designate CPUs sharing an OPP
                 * table.
                 */
-               cpumask_copy(opp_shared_cpus, policy->cpus);
+               cpumask_copy(priv->opp_shared_cpus, policy->cpus);
        }
 
         /*
@@ -180,7 +185,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
                        goto out_free_opp;
                }
 
-               ret = dev_pm_opp_set_sharing_cpus(cpu_dev, opp_shared_cpus);
+               ret = dev_pm_opp_set_sharing_cpus(cpu_dev, priv->opp_shared_cpus);
                if (ret) {
                        dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
                                __func__, ret);
@@ -188,21 +193,13 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
                        goto out_free_opp;
                }
 
-               power_scale_mw = perf_ops->power_scale_mw_get(ph);
-               em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb,
-                                           opp_shared_cpus, power_scale_mw);
-       }
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               ret = -ENOMEM;
-               goto out_free_opp;
+               priv->nr_opp = nr_opp;
        }
 
        ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
        if (ret) {
                dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
-               goto out_free_priv;
+               goto out_free_opp;
        }
 
        priv->cpu_dev = cpu_dev;
@@ -223,17 +220,16 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
        policy->fast_switch_possible =
                perf_ops->fast_switch_possible(ph, cpu_dev);
 
-       free_cpumask_var(opp_shared_cpus);
        return 0;
 
-out_free_priv:
-       kfree(priv);
-
 out_free_opp:
        dev_pm_opp_remove_all_dynamic(cpu_dev);
 
 out_free_cpumask:
-       free_cpumask_var(opp_shared_cpus);
+       free_cpumask_var(priv->opp_shared_cpus);
+
+out_free_priv:
+       kfree(priv);
 
        return ret;
 }
@@ -244,11 +240,33 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
 
        dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
        dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
+       free_cpumask_var(priv->opp_shared_cpus);
        kfree(priv);
 
        return 0;
 }
 
+static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
+{
+       struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
+       bool power_scale_mw = perf_ops->power_scale_mw_get(ph);
+       struct scmi_data *priv = policy->driver_data;
+
+       /*
+        * This callback will be called for each policy, but we don't need to
+        * register with EM every time. Despite not being part of the same
+        * policy, some CPUs may still share their perf-domains, and a CPU from
+        * another policy may already have registered with EM on behalf of CPUs
+        * of this policy.
+        */
+       if (!priv->nr_opp)
+               return;
+
+       em_dev_register_perf_domain(get_cpu_device(policy->cpu), priv->nr_opp,
+                                   &em_cb, priv->opp_shared_cpus,
+                                   power_scale_mw);
+}
+
 static struct cpufreq_driver scmi_cpufreq_driver = {
        .name   = "scmi",
        .flags  = CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
@@ -261,6 +279,7 @@ static struct cpufreq_driver scmi_cpufreq_driver = {
        .get    = scmi_cpufreq_get_rate,
        .init   = scmi_cpufreq_init,
        .exit   = scmi_cpufreq_exit,
+       .register_em    = scmi_cpufreq_register_em,
 };
 
 static int scmi_cpufreq_probe(struct scmi_device *sdev)
index d6a698a..bda3e7d 100644 (file)
@@ -163,8 +163,6 @@ static int scpi_cpufreq_init(struct cpufreq_policy *policy)
 
        policy->fast_switch_possible = false;
 
-       dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
-
        return 0;
 
 out_free_cpufreq_table:
@@ -200,6 +198,7 @@ static struct cpufreq_driver scpi_cpufreq_driver = {
        .init   = scpi_cpufreq_init,
        .exit   = scpi_cpufreq_exit,
        .target_index   = scpi_cpufreq_set_target,
+       .register_em    = cpufreq_register_em_with_opp,
 };
 
 static int scpi_cpufreq_probe(struct platform_device *pdev)
index 1a251e6..b870423 100644 (file)
@@ -145,16 +145,6 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static void sh_cpufreq_cpu_ready(struct cpufreq_policy *policy)
-{
-       struct device *dev = get_cpu_device(policy->cpu);
-
-       dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, "
-              "Maximum %u.%03u MHz.\n",
-              policy->min / 1000, policy->min % 1000,
-              policy->max / 1000, policy->max % 1000);
-}
-
 static struct cpufreq_driver sh_cpufreq_driver = {
        .name           = "sh",
        .flags          = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
@@ -163,7 +153,6 @@ static struct cpufreq_driver sh_cpufreq_driver = {
        .verify         = sh_cpufreq_verify,
        .init           = sh_cpufreq_cpu_init,
        .exit           = sh_cpufreq_cpu_exit,
-       .ready          = sh_cpufreq_cpu_ready,
        .attr           = cpufreq_generic_attr,
 };
 
index 51dfa9a..284b6bd 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
-#include <linux/cpu_cooling.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -47,7 +46,6 @@ static bool bL_switching_enabled;
 #define ACTUAL_FREQ(cluster, freq)  ((cluster == A7_CLUSTER) ? freq << 1 : freq)
 #define VIRT_FREQ(cluster, freq)    ((cluster == A7_CLUSTER) ? freq >> 1 : freq)
 
-static struct thermal_cooling_device *cdev[MAX_CLUSTERS];
 static struct clk *clk[MAX_CLUSTERS];
 static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1];
 static atomic_t cluster_usage[MAX_CLUSTERS + 1];
@@ -442,8 +440,6 @@ static int ve_spc_cpufreq_init(struct cpufreq_policy *policy)
        policy->freq_table = freq_table[cur_cluster];
        policy->cpuinfo.transition_latency = 1000000; /* 1 ms */
 
-       dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
-
        if (is_bL_switching_enabled())
                per_cpu(cpu_last_req_freq, policy->cpu) =
                                                clk_get_cpu_rate(policy->cpu);
@@ -457,11 +453,6 @@ static int ve_spc_cpufreq_exit(struct cpufreq_policy *policy)
        struct device *cpu_dev;
        int cur_cluster = cpu_to_cluster(policy->cpu);
 
-       if (cur_cluster < MAX_CLUSTERS) {
-               cpufreq_cooling_unregister(cdev[cur_cluster]);
-               cdev[cur_cluster] = NULL;
-       }
-
        cpu_dev = get_cpu_device(policy->cpu);
        if (!cpu_dev) {
                pr_err("%s: failed to get cpu%d device\n", __func__,
@@ -473,17 +464,6 @@ static int ve_spc_cpufreq_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
-static void ve_spc_cpufreq_ready(struct cpufreq_policy *policy)
-{
-       int cur_cluster = cpu_to_cluster(policy->cpu);
-
-       /* Do not register a cpu_cooling device if we are in IKS mode */
-       if (cur_cluster >= MAX_CLUSTERS)
-               return;
-
-       cdev[cur_cluster] = of_cpufreq_cooling_register(policy);
-}
-
 static struct cpufreq_driver ve_spc_cpufreq_driver = {
        .name                   = "vexpress-spc",
        .flags                  = CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
@@ -493,7 +473,7 @@ static struct cpufreq_driver ve_spc_cpufreq_driver = {
        .get                    = ve_spc_cpufreq_get_rate,
        .init                   = ve_spc_cpufreq_init,
        .exit                   = ve_spc_cpufreq_exit,
-       .ready                  = ve_spc_cpufreq_ready,
+       .register_em            = cpufreq_register_em_with_opp,
        .attr                   = cpufreq_generic_attr,
 };
 
@@ -553,6 +533,9 @@ static int ve_spc_cpufreq_probe(struct platform_device *pdev)
        for (i = 0; i < MAX_CLUSTERS; i++)
                mutex_init(&cluster_lock[i]);
 
+       if (!is_bL_switching_enabled())
+               ve_spc_cpufreq_driver.flags |= CPUFREQ_IS_COOLING_DEV;
+
        ret = cpufreq_register_driver(&ve_spc_cpufreq_driver);
        if (ret) {
                pr_info("%s: Failed registering platform driver: %s, err: %d\n",
index e3fcdfe..a5987e5 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/msi.h>
 #include <linux/pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/pci-ecam.h>
 #include <linux/srcu.h>
 #include <linux/rculist.h>
@@ -447,6 +448,56 @@ static struct pci_ops vmd_ops = {
        .write          = vmd_pci_write,
 };
 
+#ifdef CONFIG_ACPI
+static struct acpi_device *vmd_acpi_find_companion(struct pci_dev *pci_dev)
+{
+       struct pci_host_bridge *bridge;
+       u32 busnr, addr;
+
+       if (pci_dev->bus->ops != &vmd_ops)
+               return NULL;
+
+       bridge = pci_find_host_bridge(pci_dev->bus);
+       busnr = pci_dev->bus->number - bridge->bus->number;
+       /*
+        * The address computation below is only applicable to relative bus
+        * numbers below 32.
+        */
+       if (busnr > 31)
+               return NULL;
+
+       addr = (busnr << 24) | ((u32)pci_dev->devfn << 16) | 0x8000FFFFU;
+
+       dev_dbg(&pci_dev->dev, "Looking for ACPI companion (address 0x%x)\n",
+               addr);
+
+       return acpi_find_child_device(ACPI_COMPANION(bridge->dev.parent), addr,
+                                     false);
+}
+
+static bool hook_installed;
+
+static void vmd_acpi_begin(void)
+{
+       if (pci_acpi_set_companion_lookup_hook(vmd_acpi_find_companion))
+               return;
+
+       hook_installed = true;
+}
+
+static void vmd_acpi_end(void)
+{
+       if (!hook_installed)
+               return;
+
+       pci_acpi_clear_companion_lookup_hook();
+       hook_installed = false;
+}
+#else
+static inline void vmd_acpi_begin(void) { }
+static inline void vmd_acpi_end(void) { }
+#endif /* CONFIG_ACPI */
+
 static void vmd_attach_resources(struct vmd_dev *vmd)
 {
        vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1];
@@ -747,6 +798,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
        if (vmd->irq_domain)
                dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
 
+       vmd_acpi_begin();
+
        pci_scan_child_bus(vmd->bus);
        pci_assign_unassigned_bus_resources(vmd->bus);
 
@@ -760,6 +813,8 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
 
        pci_bus_add_devices(vmd->bus);
 
+       vmd_acpi_end();
+
        WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj,
                               "domain"), "Can't create symlink to domain\n");
        return 0;
index e01d53f..afa50b4 100644 (file)
@@ -23,6 +23,7 @@ struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus)
 
        return to_pci_host_bridge(root_bus->bridge);
 }
+EXPORT_SYMBOL_GPL(pci_find_host_bridge);
 
 struct device *pci_get_host_bridge_device(struct pci_dev *dev)
 {
index fe286c8..a1b1e2a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pci-acpi.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_qos.h>
+#include <linux/rwsem.h>
 #include "pci.h"
 
 /*
@@ -1178,6 +1179,69 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
 }
 
 /* ACPI bus type */
+
+
+static DECLARE_RWSEM(pci_acpi_companion_lookup_sem);
+static struct acpi_device *(*pci_acpi_find_companion_hook)(struct pci_dev *);
+
+/**
+ * pci_acpi_set_companion_lookup_hook - Set ACPI companion lookup callback.
+ * @func: ACPI companion lookup callback pointer or NULL.
+ *
+ * Set a special ACPI companion lookup callback for PCI devices whose companion
+ * objects in the ACPI namespace have _ADR with non-standard bus-device-function
+ * encodings.
+ *
+ * Return 0 on success or a negative error code on failure (in which case no
+ * changes are made).
+ *
+ * The caller is responsible for the appropriate ordering of the invocations of
+ * this function with respect to the enumeration of the PCI devices needing the
+ * callback installed by it.
+ */
+int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *))
+{
+       int ret;
+
+       if (!func)
+               return -EINVAL;
+
+       down_write(&pci_acpi_companion_lookup_sem);
+
+       if (pci_acpi_find_companion_hook) {
+               ret = -EBUSY;
+       } else {
+               pci_acpi_find_companion_hook = func;
+               ret = 0;
+       }
+
+       up_write(&pci_acpi_companion_lookup_sem);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pci_acpi_set_companion_lookup_hook);
+
+/**
+ * pci_acpi_clear_companion_lookup_hook - Clear ACPI companion lookup callback.
+ *
+ * Clear the special ACPI companion lookup callback previously set by
+ * pci_acpi_set_companion_lookup_hook().  Block until the last running instance
+ * of the callback returns before clearing it.
+ *
+ * The caller is responsible for the appropriate ordering of the invocations of
+ * this function with respect to the enumeration of the PCI devices needing the
+ * callback cleared by it.
+ */
+void pci_acpi_clear_companion_lookup_hook(void)
+{
+       down_write(&pci_acpi_companion_lookup_sem);
+
+       pci_acpi_find_companion_hook = NULL;
+
+       up_write(&pci_acpi_companion_lookup_sem);
+}
+EXPORT_SYMBOL_GPL(pci_acpi_clear_companion_lookup_hook);
+
 static struct acpi_device *acpi_pci_find_companion(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -1185,6 +1249,16 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
        bool check_children;
        u64 addr;
 
+       down_read(&pci_acpi_companion_lookup_sem);
+
+       adev = pci_acpi_find_companion_hook ?
+               pci_acpi_find_companion_hook(pci_dev) : NULL;
+
+       up_read(&pci_acpi_companion_lookup_sem);
+
+       if (adev)
+               return adev;
+
        check_children = pci_is_bridge(pci_dev);
        /* Please ref to ACPI spec for the syntax of _ADR */
        addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
index 41baccb..f901d2e 100644 (file)
@@ -20,7 +20,7 @@ obj-$(CONFIG_CROS_EC_CHARDEV)         += cros_ec_chardev.o
 obj-$(CONFIG_CROS_EC_LIGHTBAR)         += cros_ec_lightbar.o
 obj-$(CONFIG_CROS_EC_VBC)              += cros_ec_vbc.o
 obj-$(CONFIG_CROS_EC_DEBUGFS)          += cros_ec_debugfs.o
-cros-ec-sensorhub-objs                 := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o
+cros-ec-sensorhub-objs                 := cros_ec_sensorhub.o cros_ec_sensorhub_ring.o cros_ec_trace.o
 obj-$(CONFIG_CROS_EC_SENSORHUB)                += cros-ec-sensorhub.o
 obj-$(CONFIG_CROS_EC_SYSFS)            += cros_ec_sysfs.o
 obj-$(CONFIG_CROS_USBPD_LOGGER)                += cros_usbpd_logger.o
index aa7f7aa..a7404d6 100644 (file)
@@ -279,6 +279,15 @@ static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
        msg->insize = sizeof(struct ec_response_get_protocol_info);
 
        ret = send_command(ec_dev, msg);
+       /*
+        * Send command once again when timeout occurred.
+        * Fingerprint MCU (FPMCU) is restarted during system boot which
+        * introduces small window in which FPMCU won't respond for any
+        * messages sent by kernel. There is no need to wait before next
+        * attempt because we waited at least EC_MSG_DEADLINE_MS.
+        */
+       if (ret == -ETIMEDOUT)
+               ret = send_command(ec_dev, msg);
 
        if (ret < 0) {
                dev_dbg(ec_dev->dev,
index 8921f24..98e3708 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/sort.h>
 #include <linux/slab.h>
 
+#include "cros_ec_trace.h"
+
 /* Precision of fixed point for the m values from the filter */
 #define M_PRECISION BIT(23)
 
@@ -291,6 +293,7 @@ cros_ec_sensor_ring_ts_filter_update(struct cros_ec_sensors_ts_filter_state
                state->median_m = 0;
                state->median_error = 0;
        }
+       trace_cros_ec_sensorhub_filter(state, dx, dy);
 }
 
 /**
@@ -427,6 +430,11 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub,
                        if (new_timestamp - *current_timestamp > 0)
                                *current_timestamp = new_timestamp;
                }
+               trace_cros_ec_sensorhub_timestamp(in->timestamp,
+                                                 fifo_info->timestamp,
+                                                 fifo_timestamp,
+                                                 *current_timestamp,
+                                                 now);
        }
 
        if (in->flags & MOTIONSENSE_SENSOR_FLAG_ODR) {
@@ -460,6 +468,12 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub,
 
        /* Regular sample */
        out->sensor_id = in->sensor_num;
+       trace_cros_ec_sensorhub_data(in->sensor_num,
+                                    fifo_info->timestamp,
+                                    fifo_timestamp,
+                                    *current_timestamp,
+                                    now);
+
        if (*current_timestamp - now > 0) {
                /*
                 * This fix is needed to overcome the timestamp filter putting
index f744b21..7e7cfc9 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/platform_data/cros_ec_commands.h>
 #include <linux/platform_data/cros_ec_proto.h>
+#include <linux/platform_data/cros_ec_sensorhub.h>
 
 #include <linux/tracepoint.h>
 
@@ -70,6 +71,99 @@ TRACE_EVENT(cros_ec_request_done,
                  __entry->retval)
 );
 
+TRACE_EVENT(cros_ec_sensorhub_timestamp,
+           TP_PROTO(u32 ec_sample_timestamp, u32 ec_fifo_timestamp, s64 fifo_timestamp,
+                    s64 current_timestamp, s64 current_time),
+       TP_ARGS(ec_sample_timestamp, ec_fifo_timestamp, fifo_timestamp, current_timestamp,
+               current_time),
+       TP_STRUCT__entry(
+               __field(u32, ec_sample_timestamp)
+               __field(u32, ec_fifo_timestamp)
+               __field(s64, fifo_timestamp)
+               __field(s64, current_timestamp)
+               __field(s64, current_time)
+               __field(s64, delta)
+       ),
+       TP_fast_assign(
+               __entry->ec_sample_timestamp = ec_sample_timestamp;
+               __entry->ec_fifo_timestamp = ec_fifo_timestamp;
+               __entry->fifo_timestamp = fifo_timestamp;
+               __entry->current_timestamp = current_timestamp;
+               __entry->current_time = current_time;
+               __entry->delta = current_timestamp - current_time;
+       ),
+       TP_printk("ec_ts: %9u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld",
+                 __entry->ec_sample_timestamp,
+               __entry->ec_fifo_timestamp,
+               __entry->fifo_timestamp,
+               __entry->current_timestamp,
+               __entry->current_time,
+               __entry->delta
+       )
+);
+
+TRACE_EVENT(cros_ec_sensorhub_data,
+           TP_PROTO(u32 ec_sensor_num, u32 ec_fifo_timestamp, s64 fifo_timestamp,
+                    s64 current_timestamp, s64 current_time),
+       TP_ARGS(ec_sensor_num, ec_fifo_timestamp, fifo_timestamp, current_timestamp, current_time),
+       TP_STRUCT__entry(
+               __field(u32, ec_sensor_num)
+               __field(u32, ec_fifo_timestamp)
+               __field(s64, fifo_timestamp)
+               __field(s64, current_timestamp)
+               __field(s64, current_time)
+               __field(s64, delta)
+       ),
+       TP_fast_assign(
+               __entry->ec_sensor_num = ec_sensor_num;
+               __entry->ec_fifo_timestamp = ec_fifo_timestamp;
+               __entry->fifo_timestamp = fifo_timestamp;
+               __entry->current_timestamp = current_timestamp;
+               __entry->current_time = current_time;
+               __entry->delta = current_timestamp - current_time;
+       ),
+       TP_printk("ec_num: %4u, ec_fifo_ts: %9u, fifo_ts: %12lld, curr_ts: %12lld, curr_time: %12lld, delta %12lld",
+                 __entry->ec_sensor_num,
+               __entry->ec_fifo_timestamp,
+               __entry->fifo_timestamp,
+               __entry->current_timestamp,
+               __entry->current_time,
+               __entry->delta
+       )
+);
+
+TRACE_EVENT(cros_ec_sensorhub_filter,
+           TP_PROTO(struct cros_ec_sensors_ts_filter_state *state, s64 dx, s64 dy),
+       TP_ARGS(state, dx, dy),
+       TP_STRUCT__entry(
+               __field(s64, dx)
+               __field(s64, dy)
+               __field(s64, median_m)
+               __field(s64, median_error)
+               __field(s64, history_len)
+               __field(s64, x)
+               __field(s64, y)
+       ),
+       TP_fast_assign(
+               __entry->dx = dx;
+               __entry->dy = dy;
+               __entry->median_m = state->median_m;
+               __entry->median_error = state->median_error;
+               __entry->history_len = state->history_len;
+               __entry->x = state->x_offset;
+               __entry->y = state->y_offset;
+       ),
+       TP_printk("dx: %12lld. dy: %12lld median_m: %12lld median_error: %12lld len: %lld x: %12lld y: %12lld",
+                 __entry->dx,
+               __entry->dy,
+               __entry->median_m,
+               __entry->median_error,
+               __entry->history_len,
+               __entry->x,
+               __entry->y
+       )
+);
+
 
 #endif /* _CROS_EC_TRACE_H_ */
 
index 27c068c..262a891 100644 (file)
@@ -1054,24 +1054,6 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
        return 0;
 }
 
-/* Check the EC feature flags to see if TYPEC_* features are supported. */
-static int cros_typec_feature_supported(struct cros_typec_data *typec, enum ec_feature_code feature)
-{
-       struct ec_response_get_features resp = {};
-       int ret;
-
-       ret = cros_typec_ec_command(typec, 0, EC_CMD_GET_FEATURES, NULL, 0,
-                                   &resp, sizeof(resp));
-       if (ret < 0) {
-               dev_warn(typec->dev,
-                        "Failed to get features, assuming typec feature=%d unsupported.\n",
-                        feature);
-               return 0;
-       }
-
-       return resp.flags[feature / 32] & EC_FEATURE_MASK_1(feature);
-}
-
 static void cros_typec_port_work(struct work_struct *work)
 {
        struct cros_typec_data *typec = container_of(work, struct cros_typec_data, port_work);
@@ -1113,6 +1095,7 @@ MODULE_DEVICE_TABLE(of, cros_typec_of_match);
 
 static int cros_typec_probe(struct platform_device *pdev)
 {
+       struct cros_ec_dev *ec_dev = NULL;
        struct device *dev = &pdev->dev;
        struct cros_typec_data *typec;
        struct ec_response_usb_pd_ports resp;
@@ -1132,10 +1115,10 @@ static int cros_typec_probe(struct platform_device *pdev)
                return ret;
        }
 
-       typec->typec_cmd_supported = !!cros_typec_feature_supported(typec,
-                                       EC_FEATURE_TYPEC_CMD);
-       typec->needs_mux_ack = !!cros_typec_feature_supported(typec,
-                                       EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
+       ec_dev = dev_get_drvdata(&typec->ec->ec->dev);
+       typec->typec_cmd_supported = !!cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD);
+       typec->needs_mux_ack = !!cros_ec_check_features(ec_dev,
+                                                       EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
 
        ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
                                    &resp, sizeof(resp));
index 7e7a897..99b80b5 100644 (file)
@@ -1281,8 +1281,8 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
        dout("write_end file %p inode %p page %p %d~%d (%d)\n", file,
             inode, page, (int)pos, (int)copied, (int)len);
 
-       /* zero the stale part of the page if we did a short copy */
        if (!PageUptodate(page)) {
+               /* just return that nothing was copied on a short copy */
                if (copied < len) {
                        copied = 0;
                        goto out;
index 1409d61..058ea2a 100644 (file)
@@ -26,12 +26,6 @@ void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci);
 void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp);
 void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci);
 
-int ceph_readpage_from_fscache(struct inode *inode, struct page *page);
-int ceph_readpages_from_fscache(struct inode *inode,
-                               struct address_space *mapping,
-                               struct list_head *pages,
-                               unsigned *nr_pages);
-
 static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci)
 {
        ci->fscache = NULL;
index 39db97f..6c0e52f 100644 (file)
@@ -703,29 +703,12 @@ void ceph_add_cap(struct inode *inode,
                 */
                struct ceph_snap_realm *realm = ceph_lookup_snap_realm(mdsc,
                                                               realmino);
-               if (realm) {
-                       struct ceph_snap_realm *oldrealm = ci->i_snap_realm;
-                       if (oldrealm) {
-                               spin_lock(&oldrealm->inodes_with_caps_lock);
-                               list_del_init(&ci->i_snap_realm_item);
-                               spin_unlock(&oldrealm->inodes_with_caps_lock);
-                       }
-
-                       spin_lock(&realm->inodes_with_caps_lock);
-                       list_add(&ci->i_snap_realm_item,
-                                &realm->inodes_with_caps);
-                       ci->i_snap_realm = realm;
-                       if (realm->ino == ci->i_vino.ino)
-                               realm->inode = inode;
-                       spin_unlock(&realm->inodes_with_caps_lock);
-
-                       if (oldrealm)
-                               ceph_put_snap_realm(mdsc, oldrealm);
-               } else {
-                       pr_err("ceph_add_cap: couldn't find snap realm %llx\n",
-                              realmino);
-                       WARN_ON(!realm);
-               }
+               if (realm)
+                       ceph_change_snap_realm(inode, realm);
+               else
+                       WARN(1, "%s: couldn't find snap realm 0x%llx (ino 0x%llx oldrealm 0x%llx)\n",
+                            __func__, realmino, ci->i_vino.ino,
+                            ci->i_snap_realm ? ci->i_snap_realm->ino : 0);
        }
 
        __check_cap_issue(ci, cap, issued);
@@ -1112,20 +1095,6 @@ int ceph_is_any_caps(struct inode *inode)
        return ret;
 }
 
-static void drop_inode_snap_realm(struct ceph_inode_info *ci)
-{
-       struct ceph_snap_realm *realm = ci->i_snap_realm;
-       spin_lock(&realm->inodes_with_caps_lock);
-       list_del_init(&ci->i_snap_realm_item);
-       ci->i_snap_realm_counter++;
-       ci->i_snap_realm = NULL;
-       if (realm->ino == ci->i_vino.ino)
-               realm->inode = NULL;
-       spin_unlock(&realm->inodes_with_caps_lock);
-       ceph_put_snap_realm(ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc,
-                           realm);
-}
-
 /*
  * Remove a cap.  Take steps to deal with a racing iterate_session_caps.
  *
@@ -1145,17 +1114,16 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)
                return;
        }
 
+       lockdep_assert_held(&ci->i_ceph_lock);
+
        dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
 
        mdsc = ceph_inode_to_client(&ci->vfs_inode)->mdsc;
 
        /* remove from inode's cap rbtree, and clear auth cap */
        rb_erase(&cap->ci_node, &ci->i_caps);
-       if (ci->i_auth_cap == cap) {
-               WARN_ON_ONCE(!list_empty(&ci->i_dirty_item) &&
-                            !mdsc->fsc->blocklisted);
+       if (ci->i_auth_cap == cap)
                ci->i_auth_cap = NULL;
-       }
 
        /* remove from session list */
        spin_lock(&session->s_cap_lock);
@@ -1201,12 +1169,34 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release)
                 * keep i_snap_realm.
                 */
                if (ci->i_wr_ref == 0 && ci->i_snap_realm)
-                       drop_inode_snap_realm(ci);
+                       ceph_change_snap_realm(&ci->vfs_inode, NULL);
 
                __cap_delay_cancel(mdsc, ci);
        }
 }
 
+void ceph_remove_cap(struct ceph_cap *cap, bool queue_release)
+{
+       struct ceph_inode_info *ci = cap->ci;
+       struct ceph_fs_client *fsc;
+
+       /* 'ci' being NULL means the remove have already occurred */
+       if (!ci) {
+               dout("%s: cap inode is NULL\n", __func__);
+               return;
+       }
+
+       lockdep_assert_held(&ci->i_ceph_lock);
+
+       fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
+       WARN_ON_ONCE(ci->i_auth_cap == cap &&
+                    !list_empty(&ci->i_dirty_item) &&
+                    !fsc->blocklisted &&
+                    READ_ONCE(fsc->mount_state) != CEPH_MOUNT_SHUTDOWN);
+
+       __ceph_remove_cap(cap, queue_release);
+}
+
 struct cap_msg_args {
        struct ceph_mds_session *session;
        u64                     ino, cid, follows;
@@ -1335,7 +1325,7 @@ void __ceph_remove_caps(struct ceph_inode_info *ci)
        while (p) {
                struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
                p = rb_next(p);
-               __ceph_remove_cap(cap, true);
+               ceph_remove_cap(cap, true);
        }
        spin_unlock(&ci->i_ceph_lock);
 }
@@ -1746,6 +1736,9 @@ struct ceph_cap_flush *ceph_alloc_cap_flush(void)
        struct ceph_cap_flush *cf;
 
        cf = kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL);
+       if (!cf)
+               return NULL;
+
        cf->is_capsnap = false;
        return cf;
 }
@@ -1856,6 +1849,8 @@ static u64 __mark_caps_flushing(struct inode *inode,
  * try to invalidate mapping pages without blocking.
  */
 static int try_nonblocking_invalidate(struct inode *inode)
+       __releases(ci->i_ceph_lock)
+       __acquires(ci->i_ceph_lock)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
        u32 invalidating_gen = ci->i_rdcache_gen;
@@ -2219,6 +2214,7 @@ static int caps_are_flushed(struct inode *inode, u64 flush_tid)
  */
 static int unsafe_request_wait(struct inode *inode)
 {
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_mds_request *req1 = NULL, *req2 = NULL;
        int ret, err = 0;
@@ -2238,6 +2234,81 @@ static int unsafe_request_wait(struct inode *inode)
        }
        spin_unlock(&ci->i_unsafe_lock);
 
+       /*
+        * Trigger to flush the journal logs in all the relevant MDSes
+        * manually, or in the worst case we must wait at most 5 seconds
+        * to wait the journal logs to be flushed by the MDSes periodically.
+        */
+       if (req1 || req2) {
+               struct ceph_mds_session **sessions = NULL;
+               struct ceph_mds_session *s;
+               struct ceph_mds_request *req;
+               unsigned int max;
+               int i;
+
+               /*
+                * The mdsc->max_sessions is unlikely to be changed
+                * mostly, here we will retry it by reallocating the
+                * sessions arrary memory to get rid of the mdsc->mutex
+                * lock.
+                */
+retry:
+               max = mdsc->max_sessions;
+               sessions = krealloc(sessions, max * sizeof(s), __GFP_ZERO);
+               if (!sessions)
+                       return -ENOMEM;
+
+               spin_lock(&ci->i_unsafe_lock);
+               if (req1) {
+                       list_for_each_entry(req, &ci->i_unsafe_dirops,
+                                           r_unsafe_dir_item) {
+                               s = req->r_session;
+                               if (unlikely(s->s_mds > max)) {
+                                       spin_unlock(&ci->i_unsafe_lock);
+                                       goto retry;
+                               }
+                               if (!sessions[s->s_mds]) {
+                                       s = ceph_get_mds_session(s);
+                                       sessions[s->s_mds] = s;
+                               }
+                       }
+               }
+               if (req2) {
+                       list_for_each_entry(req, &ci->i_unsafe_iops,
+                                           r_unsafe_target_item) {
+                               s = req->r_session;
+                               if (unlikely(s->s_mds > max)) {
+                                       spin_unlock(&ci->i_unsafe_lock);
+                                       goto retry;
+                               }
+                               if (!sessions[s->s_mds]) {
+                                       s = ceph_get_mds_session(s);
+                                       sessions[s->s_mds] = s;
+                               }
+                       }
+               }
+               spin_unlock(&ci->i_unsafe_lock);
+
+               /* the auth MDS */
+               spin_lock(&ci->i_ceph_lock);
+               if (ci->i_auth_cap) {
+                     s = ci->i_auth_cap->session;
+                     if (!sessions[s->s_mds])
+                             sessions[s->s_mds] = ceph_get_mds_session(s);
+               }
+               spin_unlock(&ci->i_ceph_lock);
+
+               /* send flush mdlog request to MDSes */
+               for (i = 0; i < max; i++) {
+                       s = sessions[i];
+                       if (s) {
+                               send_flush_mdlog(s);
+                               ceph_put_mds_session(s);
+                       }
+               }
+               kfree(sessions);
+       }
+
        dout("unsafe_request_wait %p wait on tid %llu %llu\n",
             inode, req1 ? req1->r_tid : 0ULL, req2 ? req2->r_tid : 0ULL);
        if (req1) {
@@ -3008,7 +3079,7 @@ static void __ceph_put_cap_refs(struct ceph_inode_info *ci, int had,
                        }
                        /* see comment in __ceph_remove_cap() */
                        if (!__ceph_is_any_real_caps(ci) && ci->i_snap_realm)
-                               drop_inode_snap_realm(ci);
+                               ceph_change_snap_realm(inode, NULL);
                }
        }
        if (check_flushsnaps && __ceph_have_pending_cap_snap(ci)) {
@@ -3114,7 +3185,16 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
                                break;
                        }
                }
-               BUG_ON(!found);
+
+               if (!found) {
+                       /*
+                        * The capsnap should already be removed when removing
+                        * auth cap in the case of a forced unmount.
+                        */
+                       WARN_ON_ONCE(ci->i_auth_cap);
+                       goto unlock;
+               }
+
                capsnap->dirty_pages -= nr;
                if (capsnap->dirty_pages == 0) {
                        complete_capsnap = true;
@@ -3136,6 +3216,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
                     complete_capsnap ? " (complete capsnap)" : "");
        }
 
+unlock:
        spin_unlock(&ci->i_ceph_lock);
 
        if (last) {
@@ -3606,6 +3687,43 @@ out:
                iput(inode);
 }
 
+void __ceph_remove_capsnap(struct inode *inode, struct ceph_cap_snap *capsnap,
+                          bool *wake_ci, bool *wake_mdsc)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
+       bool ret;
+
+       lockdep_assert_held(&ci->i_ceph_lock);
+
+       dout("removing capsnap %p, inode %p ci %p\n", capsnap, inode, ci);
+
+       list_del_init(&capsnap->ci_item);
+       ret = __detach_cap_flush_from_ci(ci, &capsnap->cap_flush);
+       if (wake_ci)
+               *wake_ci = ret;
+
+       spin_lock(&mdsc->cap_dirty_lock);
+       if (list_empty(&ci->i_cap_flush_list))
+               list_del_init(&ci->i_flushing_item);
+
+       ret = __detach_cap_flush_from_mdsc(mdsc, &capsnap->cap_flush);
+       if (wake_mdsc)
+               *wake_mdsc = ret;
+       spin_unlock(&mdsc->cap_dirty_lock);
+}
+
+void ceph_remove_capsnap(struct inode *inode, struct ceph_cap_snap *capsnap,
+                        bool *wake_ci, bool *wake_mdsc)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       lockdep_assert_held(&ci->i_ceph_lock);
+
+       WARN_ON_ONCE(capsnap->dirty_pages || capsnap->writing);
+       __ceph_remove_capsnap(inode, capsnap, wake_ci, wake_mdsc);
+}
+
 /*
  * Handle FLUSHSNAP_ACK.  MDS has flushed snap data to disk and we can
  * throw away our cap_snap.
@@ -3643,23 +3761,10 @@ static void handle_cap_flushsnap_ack(struct inode *inode, u64 flush_tid,
                             capsnap, capsnap->follows);
                }
        }
-       if (flushed) {
-               WARN_ON(capsnap->dirty_pages || capsnap->writing);
-               dout(" removing %p cap_snap %p follows %lld\n",
-                    inode, capsnap, follows);
-               list_del(&capsnap->ci_item);
-               wake_ci |= __detach_cap_flush_from_ci(ci, &capsnap->cap_flush);
-
-               spin_lock(&mdsc->cap_dirty_lock);
-
-               if (list_empty(&ci->i_cap_flush_list))
-                       list_del_init(&ci->i_flushing_item);
-
-               wake_mdsc |= __detach_cap_flush_from_mdsc(mdsc,
-                                                         &capsnap->cap_flush);
-               spin_unlock(&mdsc->cap_dirty_lock);
-       }
+       if (flushed)
+               ceph_remove_capsnap(inode, capsnap, &wake_ci, &wake_mdsc);
        spin_unlock(&ci->i_ceph_lock);
+
        if (flushed) {
                ceph_put_snap_context(capsnap->context);
                ceph_put_cap_snap(capsnap);
@@ -3743,7 +3848,7 @@ retry:
                goto out_unlock;
 
        if (target < 0) {
-               __ceph_remove_cap(cap, false);
+               ceph_remove_cap(cap, false);
                goto out_unlock;
        }
 
@@ -3778,7 +3883,7 @@ retry:
                                change_auth_cap_ses(ci, tcap->session);
                        }
                }
-               __ceph_remove_cap(cap, false);
+               ceph_remove_cap(cap, false);
                goto out_unlock;
        } else if (tsession) {
                /* add placeholder for the export tagert */
@@ -3795,7 +3900,7 @@ retry:
                        spin_unlock(&mdsc->cap_dirty_lock);
                }
 
-               __ceph_remove_cap(cap, false);
+               ceph_remove_cap(cap, false);
                goto out_unlock;
        }
 
@@ -3906,7 +4011,7 @@ retry:
                                        ocap->mseq, mds, le32_to_cpu(ph->seq),
                                        le32_to_cpu(ph->mseq));
                }
-               __ceph_remove_cap(ocap, (ph->flags & CEPH_CAP_FLAG_RELEASE));
+               ceph_remove_cap(ocap, (ph->flags & CEPH_CAP_FLAG_RELEASE));
        }
 
        *old_issued = issued;
@@ -4134,8 +4239,9 @@ void ceph_handle_caps(struct ceph_mds_session *session,
 done:
        mutex_unlock(&session->s_mutex);
 done_unlocked:
-       ceph_put_string(extra_info.pool_ns);
        iput(inode);
+out:
+       ceph_put_string(extra_info.pool_ns);
        return;
 
 flush_cap_releases:
@@ -4150,7 +4256,7 @@ flush_cap_releases:
 bad:
        pr_err("ceph_handle_caps: corrupt message\n");
        ceph_msg_dump(msg);
-       return;
+       goto out;
 }
 
 /*
@@ -4225,33 +4331,9 @@ static void flush_dirty_session_caps(struct ceph_mds_session *s)
        dout("flush_dirty_caps done\n");
 }
 
-static void iterate_sessions(struct ceph_mds_client *mdsc,
-                            void (*cb)(struct ceph_mds_session *))
-{
-       int mds;
-
-       mutex_lock(&mdsc->mutex);
-       for (mds = 0; mds < mdsc->max_sessions; ++mds) {
-               struct ceph_mds_session *s;
-
-               if (!mdsc->sessions[mds])
-                       continue;
-
-               s = ceph_get_mds_session(mdsc->sessions[mds]);
-               if (!s)
-                       continue;
-
-               mutex_unlock(&mdsc->mutex);
-               cb(s);
-               ceph_put_mds_session(s);
-               mutex_lock(&mdsc->mutex);
-       }
-       mutex_unlock(&mdsc->mutex);
-}
-
 void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
 {
-       iterate_sessions(mdsc, flush_dirty_session_caps);
+       ceph_mdsc_iterate_sessions(mdsc, flush_dirty_session_caps, true);
 }
 
 void __ceph_touch_fmode(struct ceph_inode_info *ci,
index e1d605a..d16fd2d 100644 (file)
@@ -1722,32 +1722,26 @@ retry_snap:
                goto out;
        }
 
-       err = file_remove_privs(file);
-       if (err)
+       down_read(&osdc->lock);
+       map_flags = osdc->osdmap->flags;
+       pool_flags = ceph_pg_pool_flags(osdc->osdmap, ci->i_layout.pool_id);
+       up_read(&osdc->lock);
+       if ((map_flags & CEPH_OSDMAP_FULL) ||
+           (pool_flags & CEPH_POOL_FLAG_FULL)) {
+               err = -ENOSPC;
                goto out;
+       }
 
-       err = file_update_time(file);
+       err = file_remove_privs(file);
        if (err)
                goto out;
 
-       inode_inc_iversion_raw(inode);
-
        if (ci->i_inline_version != CEPH_INLINE_NONE) {
                err = ceph_uninline_data(file, NULL);
                if (err < 0)
                        goto out;
        }
 
-       down_read(&osdc->lock);
-       map_flags = osdc->osdmap->flags;
-       pool_flags = ceph_pg_pool_flags(osdc->osdmap, ci->i_layout.pool_id);
-       up_read(&osdc->lock);
-       if ((map_flags & CEPH_OSDMAP_FULL) ||
-           (pool_flags & CEPH_POOL_FLAG_FULL)) {
-               err = -ENOSPC;
-               goto out;
-       }
-
        dout("aio_write %p %llx.%llx %llu~%zd getting caps. i_size %llu\n",
             inode, ceph_vinop(inode), pos, count, i_size_read(inode));
        if (fi->fmode & CEPH_FILE_MODE_LAZY)
@@ -1759,6 +1753,12 @@ retry_snap:
        if (err < 0)
                goto out;
 
+       err = file_update_time(file);
+       if (err)
+               goto out_caps;
+
+       inode_inc_iversion_raw(inode);
+
        dout("aio_write %p %llx.%llx %llu~%zd got cap refs on %s\n",
             inode, ceph_vinop(inode), pos, count, ceph_cap_string(got));
 
@@ -1842,6 +1842,8 @@ retry_snap:
        }
 
        goto out_unlocked;
+out_caps:
+       ceph_put_cap_refs(ci, got);
 out:
        if (direct_lock)
                ceph_end_io_direct(inode);
index 1bd2cc0..2df1e12 100644 (file)
@@ -581,16 +581,9 @@ void ceph_evict_inode(struct inode *inode)
         */
        if (ci->i_snap_realm) {
                if (ceph_snap(inode) == CEPH_NOSNAP) {
-                       struct ceph_snap_realm *realm = ci->i_snap_realm;
                        dout(" dropping residual ref to snap realm %p\n",
-                            realm);
-                       spin_lock(&realm->inodes_with_caps_lock);
-                       list_del_init(&ci->i_snap_realm_item);
-                       ci->i_snap_realm = NULL;
-                       if (realm->ino == ci->i_vino.ino)
-                               realm->inode = NULL;
-                       spin_unlock(&realm->inodes_with_caps_lock);
-                       ceph_put_snap_realm(mdsc, realm);
+                            ci->i_snap_realm);
+                       ceph_change_snap_realm(inode, NULL);
                } else {
                        ceph_put_snapid_map(mdsc, ci->i_snapid_map);
                        ci->i_snap_realm = NULL;
index 0b69aec..7cad180 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/ratelimit.h>
 #include <linux/bits.h>
 #include <linux/ktime.h>
+#include <linux/bitmap.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -652,14 +653,9 @@ const char *ceph_session_state_name(int s)
 
 struct ceph_mds_session *ceph_get_mds_session(struct ceph_mds_session *s)
 {
-       if (refcount_inc_not_zero(&s->s_ref)) {
-               dout("mdsc get_session %p %d -> %d\n", s,
-                    refcount_read(&s->s_ref)-1, refcount_read(&s->s_ref));
+       if (refcount_inc_not_zero(&s->s_ref))
                return s;
-       } else {
-               dout("mdsc get_session %p 0 -- FAIL\n", s);
-               return NULL;
-       }
+       return NULL;
 }
 
 void ceph_put_mds_session(struct ceph_mds_session *s)
@@ -667,8 +663,6 @@ void ceph_put_mds_session(struct ceph_mds_session *s)
        if (IS_ERR_OR_NULL(s))
                return;
 
-       dout("mdsc put_session %p %d -> %d\n", s,
-            refcount_read(&s->s_ref), refcount_read(&s->s_ref)-1);
        if (refcount_dec_and_test(&s->s_ref)) {
                if (s->s_auth.authorizer)
                        ceph_auth_destroy_authorizer(s->s_auth.authorizer);
@@ -743,8 +737,6 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        s->s_mdsc = mdsc;
        s->s_mds = mds;
        s->s_state = CEPH_MDS_SESSION_NEW;
-       s->s_ttl = 0;
-       s->s_seq = 0;
        mutex_init(&s->s_mutex);
 
        ceph_con_init(&s->s_con, s, &mds_con_ops, &mdsc->fsc->client->msgr);
@@ -753,17 +745,11 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        s->s_cap_ttl = jiffies - 1;
 
        spin_lock_init(&s->s_cap_lock);
-       s->s_renew_requested = 0;
-       s->s_renew_seq = 0;
        INIT_LIST_HEAD(&s->s_caps);
-       s->s_nr_caps = 0;
        refcount_set(&s->s_ref, 1);
        INIT_LIST_HEAD(&s->s_waiting);
        INIT_LIST_HEAD(&s->s_unsafe);
        xa_init(&s->s_delegated_inos);
-       s->s_num_cap_releases = 0;
-       s->s_cap_reconnect = 0;
-       s->s_cap_iterator = NULL;
        INIT_LIST_HEAD(&s->s_cap_releases);
        INIT_WORK(&s->s_cap_release_work, ceph_cap_release_work);
 
@@ -811,6 +797,33 @@ static void put_request_session(struct ceph_mds_request *req)
        }
 }
 
+void ceph_mdsc_iterate_sessions(struct ceph_mds_client *mdsc,
+                               void (*cb)(struct ceph_mds_session *),
+                               bool check_state)
+{
+       int mds;
+
+       mutex_lock(&mdsc->mutex);
+       for (mds = 0; mds < mdsc->max_sessions; ++mds) {
+               struct ceph_mds_session *s;
+
+               s = __ceph_lookup_mds_session(mdsc, mds);
+               if (!s)
+                       continue;
+
+               if (check_state && !check_session_state(s)) {
+                       ceph_put_mds_session(s);
+                       continue;
+               }
+
+               mutex_unlock(&mdsc->mutex);
+               cb(s);
+               ceph_put_mds_session(s);
+               mutex_lock(&mdsc->mutex);
+       }
+       mutex_unlock(&mdsc->mutex);
+}
+
 void ceph_mdsc_release_request(struct kref *kref)
 {
        struct ceph_mds_request *req = container_of(kref,
@@ -1155,7 +1168,7 @@ random:
 /*
  * session messages
  */
-static struct ceph_msg *create_session_msg(u32 op, u64 seq)
+struct ceph_msg *ceph_create_session_msg(u32 op, u64 seq)
 {
        struct ceph_msg *msg;
        struct ceph_mds_session_head *h;
@@ -1163,7 +1176,8 @@ static struct ceph_msg *create_session_msg(u32 op, u64 seq)
        msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h), GFP_NOFS,
                           false);
        if (!msg) {
-               pr_err("create_session_msg ENOMEM creating msg\n");
+               pr_err("ENOMEM creating session %s msg\n",
+                      ceph_session_op_name(op));
                return NULL;
        }
        h = msg->front.iov_base;
@@ -1294,7 +1308,7 @@ static struct ceph_msg *create_session_open_msg(struct ceph_mds_client *mdsc, u6
        msg = ceph_msg_new(CEPH_MSG_CLIENT_SESSION, sizeof(*h) + extra_bytes,
                           GFP_NOFS, false);
        if (!msg) {
-               pr_err("create_session_msg ENOMEM creating msg\n");
+               pr_err("ENOMEM creating session open msg\n");
                return ERR_PTR(-ENOMEM);
        }
        p = msg->front.iov_base;
@@ -1583,14 +1597,39 @@ out:
        return ret;
 }
 
+static int remove_capsnaps(struct ceph_mds_client *mdsc, struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_cap_snap *capsnap;
+       int capsnap_release = 0;
+
+       lockdep_assert_held(&ci->i_ceph_lock);
+
+       dout("removing capsnaps, ci is %p, inode is %p\n", ci, inode);
+
+       while (!list_empty(&ci->i_cap_snaps)) {
+               capsnap = list_first_entry(&ci->i_cap_snaps,
+                                          struct ceph_cap_snap, ci_item);
+               __ceph_remove_capsnap(inode, capsnap, NULL, NULL);
+               ceph_put_snap_context(capsnap->context);
+               ceph_put_cap_snap(capsnap);
+               capsnap_release++;
+       }
+       wake_up_all(&ci->i_cap_wq);
+       wake_up_all(&mdsc->cap_flushing_wq);
+       return capsnap_release;
+}
+
 static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
                                  void *arg)
 {
        struct ceph_fs_client *fsc = (struct ceph_fs_client *)arg;
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        LIST_HEAD(to_remove);
        bool dirty_dropped = false;
        bool invalidate = false;
+       int capsnap_release = 0;
 
        dout("removing cap %p, ci is %p, inode is %p\n",
             cap, ci, &ci->vfs_inode);
@@ -1598,7 +1637,6 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
        __ceph_remove_cap(cap, false);
        if (!ci->i_auth_cap) {
                struct ceph_cap_flush *cf;
-               struct ceph_mds_client *mdsc = fsc->mdsc;
 
                if (READ_ONCE(fsc->mount_state) >= CEPH_MOUNT_SHUTDOWN) {
                        if (inode->i_data.nrpages > 0)
@@ -1662,6 +1700,9 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
                        list_add(&ci->i_prealloc_cap_flush->i_list, &to_remove);
                        ci->i_prealloc_cap_flush = NULL;
                }
+
+               if (!list_empty(&ci->i_cap_snaps))
+                       capsnap_release = remove_capsnaps(mdsc, inode);
        }
        spin_unlock(&ci->i_ceph_lock);
        while (!list_empty(&to_remove)) {
@@ -1678,6 +1719,8 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
                ceph_queue_invalidate(inode);
        if (dirty_dropped)
                iput(inode);
+       while (capsnap_release--)
+               iput(inode);
        return 0;
 }
 
@@ -1803,8 +1846,8 @@ static int send_renew_caps(struct ceph_mds_client *mdsc,
 
        dout("send_renew_caps to mds%d (%s)\n", session->s_mds,
                ceph_mds_state_name(state));
-       msg = create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS,
-                                ++session->s_renew_seq);
+       msg = ceph_create_session_msg(CEPH_SESSION_REQUEST_RENEWCAPS,
+                                     ++session->s_renew_seq);
        if (!msg)
                return -ENOMEM;
        ceph_con_send(&session->s_con, msg);
@@ -1818,7 +1861,7 @@ static int send_flushmsg_ack(struct ceph_mds_client *mdsc,
 
        dout("send_flushmsg_ack to mds%d (%s)s seq %lld\n",
             session->s_mds, ceph_session_state_name(session->s_state), seq);
-       msg = create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq);
+       msg = ceph_create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq);
        if (!msg)
                return -ENOMEM;
        ceph_con_send(&session->s_con, msg);
@@ -1870,7 +1913,8 @@ static int request_close_session(struct ceph_mds_session *session)
        dout("request_close_session mds%d state %s seq %lld\n",
             session->s_mds, ceph_session_state_name(session->s_state),
             session->s_seq);
-       msg = create_session_msg(CEPH_SESSION_REQUEST_CLOSE, session->s_seq);
+       msg = ceph_create_session_msg(CEPH_SESSION_REQUEST_CLOSE,
+                                     session->s_seq);
        if (!msg)
                return -ENOMEM;
        ceph_con_send(&session->s_con, msg);
@@ -1965,7 +2009,7 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
 
        if (oissued) {
                /* we aren't the only cap.. just remove us */
-               __ceph_remove_cap(cap, true);
+               ceph_remove_cap(cap, true);
                (*remaining)--;
        } else {
                struct dentry *dentry;
@@ -4150,13 +4194,21 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                          struct ceph_mdsmap *newmap,
                          struct ceph_mdsmap *oldmap)
 {
-       int i;
+       int i, j, err;
        int oldstate, newstate;
        struct ceph_mds_session *s;
+       unsigned long targets[DIV_ROUND_UP(CEPH_MAX_MDS, sizeof(unsigned long))] = {0};
 
        dout("check_new_map new %u old %u\n",
             newmap->m_epoch, oldmap->m_epoch);
 
+       if (newmap->m_info) {
+               for (i = 0; i < newmap->possible_max_rank; i++) {
+                       for (j = 0; j < newmap->m_info[i].num_export_targets; j++)
+                               set_bit(newmap->m_info[i].export_targets[j], targets);
+               }
+       }
+
        for (i = 0; i < oldmap->possible_max_rank && i < mdsc->max_sessions; i++) {
                if (!mdsc->sessions[i])
                        continue;
@@ -4210,6 +4262,7 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                if (s->s_state == CEPH_MDS_SESSION_RESTARTING &&
                    newstate >= CEPH_MDS_STATE_RECONNECT) {
                        mutex_unlock(&mdsc->mutex);
+                       clear_bit(i, targets);
                        send_mds_reconnect(mdsc, s);
                        mutex_lock(&mdsc->mutex);
                }
@@ -4232,6 +4285,51 @@ static void check_new_map(struct ceph_mds_client *mdsc,
                }
        }
 
+       /*
+        * Only open and reconnect sessions that don't exist yet.
+        */
+       for (i = 0; i < newmap->possible_max_rank; i++) {
+               /*
+                * In case the import MDS is crashed just after
+                * the EImportStart journal is flushed, so when
+                * a standby MDS takes over it and is replaying
+                * the EImportStart journal the new MDS daemon
+                * will wait the client to reconnect it, but the
+                * client may never register/open the session yet.
+                *
+                * Will try to reconnect that MDS daemon if the
+                * rank number is in the export targets array and
+                * is the up:reconnect state.
+                */
+               newstate = ceph_mdsmap_get_state(newmap, i);
+               if (!test_bit(i, targets) || newstate != CEPH_MDS_STATE_RECONNECT)
+                       continue;
+
+               /*
+                * The session maybe registered and opened by some
+                * requests which were choosing random MDSes during
+                * the mdsc->mutex's unlock/lock gap below in rare
+                * case. But the related MDS daemon will just queue
+                * that requests and be still waiting for the client's
+                * reconnection request in up:reconnect state.
+                */
+               s = __ceph_lookup_mds_session(mdsc, i);
+               if (likely(!s)) {
+                       s = __open_export_target_session(mdsc, i);
+                       if (IS_ERR(s)) {
+                               err = PTR_ERR(s);
+                               pr_err("failed to open export target session, err %d\n",
+                                      err);
+                               continue;
+                       }
+               }
+               dout("send reconnect to export target mds.%d\n", i);
+               mutex_unlock(&mdsc->mutex);
+               send_mds_reconnect(mdsc, s);
+               ceph_put_mds_session(s);
+               mutex_lock(&mdsc->mutex);
+       }
+
        for (i = 0; i < newmap->possible_max_rank && i < mdsc->max_sessions; i++) {
                s = mdsc->sessions[i];
                if (!s)
@@ -4409,24 +4507,12 @@ void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
 }
 
 /*
- * lock unlock sessions, to wait ongoing session activities
+ * lock unlock the session, to wait ongoing session activities
  */
-static void lock_unlock_sessions(struct ceph_mds_client *mdsc)
+static void lock_unlock_session(struct ceph_mds_session *s)
 {
-       int i;
-
-       mutex_lock(&mdsc->mutex);
-       for (i = 0; i < mdsc->max_sessions; i++) {
-               struct ceph_mds_session *s = __ceph_lookup_mds_session(mdsc, i);
-               if (!s)
-                       continue;
-               mutex_unlock(&mdsc->mutex);
-               mutex_lock(&s->s_mutex);
-               mutex_unlock(&s->s_mutex);
-               ceph_put_mds_session(s);
-               mutex_lock(&mdsc->mutex);
-       }
-       mutex_unlock(&mdsc->mutex);
+       mutex_lock(&s->s_mutex);
+       mutex_unlock(&s->s_mutex);
 }
 
 static void maybe_recover_session(struct ceph_mds_client *mdsc)
@@ -4448,6 +4534,8 @@ static void maybe_recover_session(struct ceph_mds_client *mdsc)
 
 bool check_session_state(struct ceph_mds_session *s)
 {
+       struct ceph_fs_client *fsc = s->s_mdsc->fsc;
+
        switch (s->s_state) {
        case CEPH_MDS_SESSION_OPEN:
                if (s->s_ttl && time_after(jiffies, s->s_ttl)) {
@@ -4456,8 +4544,9 @@ bool check_session_state(struct ceph_mds_session *s)
                }
                break;
        case CEPH_MDS_SESSION_CLOSING:
-               /* Should never reach this when we're unmounting */
-               WARN_ON_ONCE(s->s_ttl);
+               /* Should never reach this when not force unmounting */
+               WARN_ON_ONCE(s->s_ttl &&
+                            READ_ONCE(fsc->mount_state) != CEPH_MOUNT_SHUTDOWN);
                fallthrough;
        case CEPH_MDS_SESSION_NEW:
        case CEPH_MDS_SESSION_RESTARTING:
@@ -4584,21 +4673,12 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        init_completion(&mdsc->safe_umount_waiters);
        init_waitqueue_head(&mdsc->session_close_wq);
        INIT_LIST_HEAD(&mdsc->waiting_for_map);
-       mdsc->sessions = NULL;
-       atomic_set(&mdsc->num_sessions, 0);
-       mdsc->max_sessions = 0;
-       mdsc->stopping = 0;
-       atomic64_set(&mdsc->quotarealms_count, 0);
        mdsc->quotarealms_inodes = RB_ROOT;
        mutex_init(&mdsc->quotarealms_inodes_mutex);
-       mdsc->last_snap_seq = 0;
        init_rwsem(&mdsc->snap_rwsem);
        mdsc->snap_realms = RB_ROOT;
        INIT_LIST_HEAD(&mdsc->snap_empty);
-       mdsc->num_snap_realms = 0;
        spin_lock_init(&mdsc->snap_empty_lock);
-       mdsc->last_tid = 0;
-       mdsc->oldest_tid = 0;
        mdsc->request_tree = RB_ROOT;
        INIT_DELAYED_WORK(&mdsc->delayed_work, delayed_work);
        mdsc->last_renew_caps = jiffies;
@@ -4610,11 +4690,9 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        mdsc->last_cap_flush_tid = 1;
        INIT_LIST_HEAD(&mdsc->cap_flush_list);
        INIT_LIST_HEAD(&mdsc->cap_dirty_migrating);
-       mdsc->num_cap_flushing = 0;
        spin_lock_init(&mdsc->cap_dirty_lock);
        init_waitqueue_head(&mdsc->cap_flushing_wq);
        INIT_WORK(&mdsc->cap_reclaim_work, ceph_cap_reclaim_work);
-       atomic_set(&mdsc->cap_reclaim_pending, 0);
        err = ceph_metric_init(&mdsc->metric);
        if (err)
                goto err_mdsmap;
@@ -4676,6 +4754,30 @@ static void wait_requests(struct ceph_mds_client *mdsc)
        dout("wait_requests done\n");
 }
 
+void send_flush_mdlog(struct ceph_mds_session *s)
+{
+       struct ceph_msg *msg;
+
+       /*
+        * Pre-luminous MDS crashes when it sees an unknown session request
+        */
+       if (!CEPH_HAVE_FEATURE(s->s_con.peer_features, SERVER_LUMINOUS))
+               return;
+
+       mutex_lock(&s->s_mutex);
+       dout("request mdlog flush to mds%d (%s)s seq %lld\n", s->s_mds,
+            ceph_session_state_name(s->s_state), s->s_seq);
+       msg = ceph_create_session_msg(CEPH_SESSION_REQUEST_FLUSH_MDLOG,
+                                     s->s_seq);
+       if (!msg) {
+               pr_err("failed to request mdlog flush to mds%d (%s) seq %lld\n",
+                      s->s_mds, ceph_session_state_name(s->s_state), s->s_seq);
+       } else {
+               ceph_con_send(&s->s_con, msg);
+       }
+       mutex_unlock(&s->s_mutex);
+}
+
 /*
  * called before mount is ro, and before dentries are torn down.
  * (hmm, does this still race with new lookups?)
@@ -4685,7 +4787,8 @@ void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc)
        dout("pre_umount\n");
        mdsc->stopping = 1;
 
-       lock_unlock_sessions(mdsc);
+       ceph_mdsc_iterate_sessions(mdsc, send_flush_mdlog, true);
+       ceph_mdsc_iterate_sessions(mdsc, lock_unlock_session, false);
        ceph_flush_dirty_caps(mdsc);
        wait_requests(mdsc);
 
@@ -4912,7 +5015,6 @@ void ceph_mdsc_destroy(struct ceph_fs_client *fsc)
 
        ceph_metric_destroy(&mdsc->metric);
 
-       flush_delayed_work(&mdsc->metric.delayed_work);
        fsc->mdsc = NULL;
        kfree(mdsc);
        dout("mdsc_destroy %p done\n", mdsc);
index 20e42d8..97c7f7b 100644 (file)
@@ -522,6 +522,11 @@ static inline void ceph_mdsc_put_request(struct ceph_mds_request *req)
        kref_put(&req->r_kref, ceph_mdsc_release_request);
 }
 
+extern void send_flush_mdlog(struct ceph_mds_session *s);
+extern void ceph_mdsc_iterate_sessions(struct ceph_mds_client *mdsc,
+                                      void (*cb)(struct ceph_mds_session *),
+                                      bool check_state);
+extern struct ceph_msg *ceph_create_session_msg(u32 op, u64 seq);
 extern void __ceph_queue_cap_release(struct ceph_mds_session *session,
                                    struct ceph_cap *cap);
 extern void ceph_flush_cap_releases(struct ceph_mds_client *mdsc,
index 3c444b9..61d67cb 100644 (file)
@@ -122,6 +122,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end, bool msgr2)
        int err;
        u8 mdsmap_v;
        u16 mdsmap_ev;
+       u32 target;
 
        m = kzalloc(sizeof(*m), GFP_NOFS);
        if (!m)
@@ -260,9 +261,14 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end, bool msgr2)
                                                       sizeof(u32), GFP_NOFS);
                        if (!info->export_targets)
                                goto nomem;
-                       for (j = 0; j < num_export_targets; j++)
-                               info->export_targets[j] =
-                                      ceph_decode_32(&pexport_targets);
+                       for (j = 0; j < num_export_targets; j++) {
+                               target = ceph_decode_32(&pexport_targets);
+                               if (target >= m->possible_max_rank) {
+                                       err = -EIO;
+                                       goto corrupt;
+                               }
+                               info->export_targets[j] = target;
+                       }
                } else {
                        info->export_targets = NULL;
                }
index 5ac151e..04d5df2 100644 (file)
@@ -302,6 +302,8 @@ void ceph_metric_destroy(struct ceph_client_metric *m)
        if (!m)
                return;
 
+       cancel_delayed_work_sync(&m->delayed_work);
+
        percpu_counter_destroy(&m->total_inodes);
        percpu_counter_destroy(&m->opened_inodes);
        percpu_counter_destroy(&m->i_caps_mis);
@@ -309,8 +311,6 @@ void ceph_metric_destroy(struct ceph_client_metric *m)
        percpu_counter_destroy(&m->d_lease_mis);
        percpu_counter_destroy(&m->d_lease_hit);
 
-       cancel_delayed_work_sync(&m->delayed_work);
-
        ceph_put_mds_session(m->session);
 }
 
index 15105f9..b41e672 100644 (file)
@@ -849,6 +849,43 @@ static void flush_snaps(struct ceph_mds_client *mdsc)
        dout("flush_snaps done\n");
 }
 
+/**
+ * ceph_change_snap_realm - change the snap_realm for an inode
+ * @inode: inode to move to new snap realm
+ * @realm: new realm to move inode into (may be NULL)
+ *
+ * Detach an inode from its old snaprealm (if any) and attach it to
+ * the new snaprealm (if any). The old snap realm reference held by
+ * the inode is put. If realm is non-NULL, then the caller's reference
+ * to it is taken over by the inode.
+ */
+void ceph_change_snap_realm(struct inode *inode, struct ceph_snap_realm *realm)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
+       struct ceph_snap_realm *oldrealm = ci->i_snap_realm;
+
+       lockdep_assert_held(&ci->i_ceph_lock);
+
+       if (oldrealm) {
+               spin_lock(&oldrealm->inodes_with_caps_lock);
+               list_del_init(&ci->i_snap_realm_item);
+               if (oldrealm->ino == ci->i_vino.ino)
+                       oldrealm->inode = NULL;
+               spin_unlock(&oldrealm->inodes_with_caps_lock);
+               ceph_put_snap_realm(mdsc, oldrealm);
+       }
+
+       ci->i_snap_realm = realm;
+
+       if (realm) {
+               spin_lock(&realm->inodes_with_caps_lock);
+               list_add(&ci->i_snap_realm_item, &realm->inodes_with_caps);
+               if (realm->ino == ci->i_vino.ino)
+                       realm->inode = inode;
+               spin_unlock(&realm->inodes_with_caps_lock);
+       }
+}
 
 /*
  * Handle a snap notification from the MDS.
@@ -935,7 +972,6 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
                        };
                        struct inode *inode = ceph_find_inode(sb, vino);
                        struct ceph_inode_info *ci;
-                       struct ceph_snap_realm *oldrealm;
 
                        if (!inode)
                                continue;
@@ -960,27 +996,10 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
                        }
                        dout(" will move %p to split realm %llx %p\n",
                             inode, realm->ino, realm);
-                       /*
-                        * Move the inode to the new realm
-                        */
-                       oldrealm = ci->i_snap_realm;
-                       spin_lock(&oldrealm->inodes_with_caps_lock);
-                       list_del_init(&ci->i_snap_realm_item);
-                       spin_unlock(&oldrealm->inodes_with_caps_lock);
-
-                       spin_lock(&realm->inodes_with_caps_lock);
-                       list_add(&ci->i_snap_realm_item,
-                                &realm->inodes_with_caps);
-                       ci->i_snap_realm = realm;
-                       if (realm->ino == ci->i_vino.ino)
-                                realm->inode = inode;
-                       spin_unlock(&realm->inodes_with_caps_lock);
-
-                       spin_unlock(&ci->i_ceph_lock);
 
                        ceph_get_snap_realm(mdsc, realm);
-                       ceph_put_snap_realm(mdsc, oldrealm);
-
+                       ceph_change_snap_realm(inode, realm);
+                       spin_unlock(&ci->i_ceph_lock);
                        iput(inode);
                        continue;
 
index 4a79f36..573bb95 100644 (file)
@@ -46,6 +46,7 @@ const char *ceph_session_op_name(int op)
        case CEPH_SESSION_FLUSHMSG_ACK: return "flushmsg_ack";
        case CEPH_SESSION_FORCE_RO: return "force_ro";
        case CEPH_SESSION_REJECT: return "reject";
+       case CEPH_SESSION_REQUEST_FLUSH_MDLOG: return "flush_mdlog";
        }
        return "???";
 }
index c30258f..a40eb14 100644 (file)
@@ -418,7 +418,6 @@ struct ceph_inode_info {
                struct ceph_snap_realm *i_snap_realm; /* snap realm (if caps) */
                struct ceph_snapid_map *i_snapid_map; /* snapid -> dev_t */
        };
-       int i_snap_realm_counter; /* snap realm (if caps) */
        struct list_head i_snap_realm_item;
        struct list_head i_snap_flush_item;
        struct timespec64 i_btime;
@@ -929,6 +928,7 @@ extern void ceph_put_snap_realm(struct ceph_mds_client *mdsc,
 extern int ceph_update_snap_trace(struct ceph_mds_client *m,
                                  void *p, void *e, bool deletion,
                                  struct ceph_snap_realm **realm_ret);
+void ceph_change_snap_realm(struct inode *inode, struct ceph_snap_realm *realm);
 extern void ceph_handle_snap(struct ceph_mds_client *mdsc,
                             struct ceph_mds_session *session,
                             struct ceph_msg *msg);
@@ -1138,6 +1138,7 @@ extern void ceph_add_cap(struct inode *inode,
                         unsigned cap, unsigned seq, u64 realmino, int flags,
                         struct ceph_cap **new_cap);
 extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release);
+extern void ceph_remove_cap(struct ceph_cap *cap, bool queue_release);
 extern void __ceph_remove_caps(struct ceph_inode_info *ci);
 extern void ceph_put_cap(struct ceph_mds_client *mdsc,
                         struct ceph_cap *cap);
@@ -1163,6 +1164,12 @@ extern void ceph_put_cap_refs_no_check_caps(struct ceph_inode_info *ci,
                                            int had);
 extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
                                       struct ceph_snap_context *snapc);
+extern void __ceph_remove_capsnap(struct inode *inode,
+                                 struct ceph_cap_snap *capsnap,
+                                 bool *wake_ci, bool *wake_mdsc);
+extern void ceph_remove_capsnap(struct inode *inode,
+                               struct ceph_cap_snap *capsnap,
+                               bool *wake_ci, bool *wake_mdsc);
 extern void ceph_flush_snaps(struct ceph_inode_info *ci,
                             struct ceph_mds_session **psession);
 extern bool __ceph_should_report_size(struct ceph_inode_info *ci);
index 1242db8..159a1ff 100644 (file)
@@ -340,6 +340,18 @@ static ssize_t ceph_vxattrcb_caps(struct ceph_inode_info *ci, char *val,
                              ceph_cap_string(issued), issued);
 }
 
+static ssize_t ceph_vxattrcb_auth_mds(struct ceph_inode_info *ci,
+                                      char *val, size_t size)
+{
+       int ret;
+
+       spin_lock(&ci->i_ceph_lock);
+       ret = ceph_fmt_xattr(val, size, "%d",
+                            ci->i_auth_cap ? ci->i_auth_cap->session->s_mds : -1);
+       spin_unlock(&ci->i_ceph_lock);
+       return ret;
+}
+
 #define CEPH_XATTR_NAME(_type, _name)  XATTR_CEPH_PREFIX #_type "." #_name
 #define CEPH_XATTR_NAME2(_type, _name, _name2) \
        XATTR_CEPH_PREFIX #_type "." #_name "." #_name2
@@ -473,6 +485,13 @@ static struct ceph_vxattr ceph_common_vxattrs[] = {
                .exists_cb = NULL,
                .flags = VXATTR_FLAG_READONLY,
        },
+       {
+               .name = "ceph.auth_mds",
+               .name_size = sizeof("ceph.auth_mds"),
+               .getxattr_cb = ceph_vxattrcb_auth_mds,
+               .exists_cb = NULL,
+               .flags = VXATTR_FLAG_READONLY,
+       },
        { .name = NULL, 0 }     /* Required table terminator */
 };
 
index e41a811..bc2699f 100644 (file)
@@ -299,6 +299,7 @@ enum {
        CEPH_SESSION_FLUSHMSG_ACK,
        CEPH_SESSION_FORCE_RO,
        CEPH_SESSION_REJECT,
+       CEPH_SESSION_REQUEST_FLUSH_MDLOG,
 };
 
 extern const char *ceph_session_op_name(int op);
index 8e0598c..1c758b0 100644 (file)
@@ -395,14 +395,6 @@ struct compat_kexec_segment;
 struct compat_mq_attr;
 struct compat_msgbuf;
 
-#define BITS_PER_COMPAT_LONG    (8*sizeof(compat_long_t))
-
-#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
-
-long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
-                      unsigned long bitmap_size);
-long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
-                      unsigned long bitmap_size);
 void copy_siginfo_to_external32(struct compat_siginfo *to,
                const struct kernel_siginfo *from);
 int copy_siginfo_from_user32(kernel_siginfo_t *to,
@@ -519,8 +511,6 @@ extern long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 
 struct epoll_event;    /* fortunately, this one is fixed-layout */
 
-extern void __user *compat_alloc_user_space(unsigned long len);
-
 int compat_restore_altstack(const compat_stack_t __user *uss);
 int __compat_save_altstack(compat_stack_t __user *, unsigned long);
 #define unsafe_compat_save_altstack(uss, sp, label) do { \
@@ -807,26 +797,6 @@ asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr
 /* mm/fadvise.c: No generic prototype for fadvise64_64 */
 
 /* mm/, CONFIG_MMU only */
-asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
-                                compat_ulong_t mode,
-                                compat_ulong_t __user *nmask,
-                                compat_ulong_t maxnode, compat_ulong_t flags);
-asmlinkage long compat_sys_get_mempolicy(int __user *policy,
-                                        compat_ulong_t __user *nmask,
-                                        compat_ulong_t maxnode,
-                                        compat_ulong_t addr,
-                                        compat_ulong_t flags);
-asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
-                                        compat_ulong_t maxnode);
-asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
-               compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes,
-               const compat_ulong_t __user *new_nodes);
-asmlinkage long compat_sys_move_pages(pid_t pid, compat_ulong_t nr_pages,
-                                     __u32 __user *pages,
-                                     const int __user *nodes,
-                                     int __user *status,
-                                     int flags);
-
 asmlinkage long compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid,
                                        compat_pid_t pid, int sig,
                                        struct compat_siginfo __user *uinfo);
@@ -976,6 +946,15 @@ static inline bool in_compat_syscall(void) { return false; }
 
 #endif /* CONFIG_COMPAT */
 
+#define BITS_PER_COMPAT_LONG    (8*sizeof(compat_long_t))
+
+#define BITS_TO_COMPAT_LONGS(bits) DIV_ROUND_UP(bits, BITS_PER_COMPAT_LONG)
+
+long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
+                      unsigned long bitmap_size);
+long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
+                      unsigned long bitmap_size);
+
 /*
  * Some legacy ABIs like the i386 one use less than natural alignment for 64-bit
  * types, and will need special compat treatment for that.  Most architectures
index 9fd7194..ff88bb3 100644 (file)
@@ -9,10 +9,14 @@
 #define _LINUX_CPUFREQ_H
 
 #include <linux/clk.h>
+#include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/completion.h>
 #include <linux/kobject.h>
 #include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
 #include <linux/pm_qos.h>
 #include <linux/spinlock.h>
 #include <linux/sysfs.h>
@@ -365,14 +369,17 @@ struct cpufreq_driver {
        int             (*suspend)(struct cpufreq_policy *policy);
        int             (*resume)(struct cpufreq_policy *policy);
 
-       /* Will be called after the driver is fully initialized */
-       void            (*ready)(struct cpufreq_policy *policy);
-
        struct freq_attr **attr;
 
        /* platform specific boost support code */
        bool            boost_enabled;
        int             (*set_boost)(struct cpufreq_policy *policy, int state);
+
+       /*
+        * Set by drivers that want to register with the energy model after the
+        * policy is properly initialized, but before the governor is started.
+        */
+       void            (*register_em)(struct cpufreq_policy *policy);
 };
 
 /* flags */
@@ -995,6 +1002,55 @@ static inline int cpufreq_table_count_valid_entries(const struct cpufreq_policy
 
        return count;
 }
+
+static inline int parse_perf_domain(int cpu, const char *list_name,
+                                   const char *cell_name)
+{
+       struct device_node *cpu_np;
+       struct of_phandle_args args;
+       int ret;
+
+       cpu_np = of_cpu_device_node_get(cpu);
+       if (!cpu_np)
+               return -ENODEV;
+
+       ret = of_parse_phandle_with_args(cpu_np, list_name, cell_name, 0,
+                                        &args);
+       if (ret < 0)
+               return ret;
+
+       of_node_put(cpu_np);
+
+       return args.args[0];
+}
+
+static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_name,
+                                                    const char *cell_name, struct cpumask *cpumask)
+{
+       int target_idx;
+       int cpu, ret;
+
+       ret = parse_perf_domain(pcpu, list_name, cell_name);
+       if (ret < 0)
+               return ret;
+
+       target_idx = ret;
+       cpumask_set_cpu(pcpu, cpumask);
+
+       for_each_possible_cpu(cpu) {
+               if (cpu == pcpu)
+                       continue;
+
+               ret = parse_perf_domain(pcpu, list_name, cell_name);
+               if (ret < 0)
+                       continue;
+
+               if (target_idx == ret)
+                       cpumask_set_cpu(cpu, cpumask);
+       }
+
+       return target_idx;
+}
 #else
 static inline int cpufreq_boost_trigger_state(int state)
 {
@@ -1014,6 +1070,12 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy)
 {
        return false;
 }
+
+static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_name,
+                                                    const char *cell_name, struct cpumask *cpumask)
+{
+       return -EOPNOTSUPP;
+}
 #endif
 
 #if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
@@ -1035,7 +1097,6 @@ void arch_set_freq_scale(const struct cpumask *cpus,
 {
 }
 #endif
-
 /* the following are really really optional */
 extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
 extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
@@ -1046,4 +1107,10 @@ unsigned int cpufreq_generic_get(unsigned int cpu);
 void cpufreq_generic_init(struct cpufreq_policy *policy,
                struct cpufreq_frequency_table *table,
                unsigned int transition_latency);
+
+static inline void cpufreq_register_em_with_opp(struct cpufreq_policy *policy)
+{
+       dev_pm_opp_of_register_em(get_cpu_device(policy->cpu),
+                                 policy->related_cpus);
+}
 #endif /* _LINUX_CPUFREQ_H */
index 5ba475c..f16de39 100644 (file)
@@ -122,6 +122,9 @@ static inline void pci_acpi_add_edr_notifier(struct pci_dev *pdev) { }
 static inline void pci_acpi_remove_edr_notifier(struct pci_dev *pdev) { }
 #endif /* CONFIG_PCIE_EDR */
 
+int pci_acpi_set_companion_lookup_hook(struct acpi_device *(*func)(struct pci_dev *));
+void pci_acpi_clear_companion_lookup_hook(void);
+
 #else  /* CONFIG_ACPI */
 static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
 static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
index c05e903..ac03940 100644 (file)
@@ -200,16 +200,6 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
                n = _copy_to_user(to, from, n);
        return n;
 }
-#ifdef CONFIG_COMPAT
-static __always_inline unsigned long __must_check
-copy_in_user(void __user *to, const void __user *from, unsigned long n)
-{
-       might_fault();
-       if (access_ok(to, n) && access_ok(from, n))
-               n = raw_copy_in_user(to, from, n);
-       return n;
-}
-#endif
 
 #ifndef copy_mc_to_kernel
 /*
index 14c8fe8..1c5fb86 100644 (file)
@@ -673,15 +673,15 @@ __SYSCALL(__NR_madvise, sys_madvise)
 #define __NR_remap_file_pages 234
 __SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
 #define __NR_mbind 235
-__SC_COMP(__NR_mbind, sys_mbind, compat_sys_mbind)
+__SYSCALL(__NR_mbind, sys_mbind)
 #define __NR_get_mempolicy 236
-__SC_COMP(__NR_get_mempolicy, sys_get_mempolicy, compat_sys_get_mempolicy)
+__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
 #define __NR_set_mempolicy 237
-__SC_COMP(__NR_set_mempolicy, sys_set_mempolicy, compat_sys_set_mempolicy)
+__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
 #define __NR_migrate_pages 238
-__SC_COMP(__NR_migrate_pages, sys_migrate_pages, compat_sys_migrate_pages)
+__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
 #define __NR_move_pages 239
-__SC_COMP(__NR_move_pages, sys_move_pages, compat_sys_move_pages)
+__SYSCALL(__NR_move_pages, sys_move_pages)
 #endif
 
 #define __NR_rt_tgsigqueueinfo 240
index 05adfd6..5555198 100644 (file)
@@ -269,24 +269,3 @@ get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat)
        return 0;
 }
 EXPORT_SYMBOL_GPL(get_compat_sigset);
-
-/*
- * Allocate user-space memory for the duration of a single system call,
- * in order to marshall parameters inside a compat thunk.
- */
-void __user *compat_alloc_user_space(unsigned long len)
-{
-       void __user *ptr;
-
-       /* If len would occupy more than half of the entire compat space... */
-       if (unlikely(len > (((compat_uptr_t)~0) >> 1)))
-               return NULL;
-
-       ptr = arch_compat_alloc_user_space(len);
-
-       if (unlikely(!access_ok(ptr, len)))
-               return NULL;
-
-       return ptr;
-}
-EXPORT_SYMBOL_GPL(compat_alloc_user_space);
index c82c6c0..b5e40f0 100644 (file)
 
 #include "kexec_internal.h"
 
-static int copy_user_segment_list(struct kimage *image,
-                                 unsigned long nr_segments,
-                                 struct kexec_segment __user *segments)
-{
-       int ret;
-       size_t segment_bytes;
-
-       /* Read in the segments */
-       image->nr_segments = nr_segments;
-       segment_bytes = nr_segments * sizeof(*segments);
-       ret = copy_from_user(image->segment, segments, segment_bytes);
-       if (ret)
-               ret = -EFAULT;
-
-       return ret;
-}
-
 static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
                             unsigned long nr_segments,
-                            struct kexec_segment __user *segments,
+                            struct kexec_segment *segments,
                             unsigned long flags)
 {
        int ret;
@@ -58,10 +41,8 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
                return -ENOMEM;
 
        image->start = entry;
-
-       ret = copy_user_segment_list(image, nr_segments, segments);
-       if (ret)
-               goto out_free_image;
+       image->nr_segments = nr_segments;
+       memcpy(image->segment, segments, nr_segments * sizeof(*segments));
 
        if (kexec_on_panic) {
                /* Enable special crash kernel control page alloc policy. */
@@ -104,12 +85,23 @@ out_free_image:
 }
 
 static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
-               struct kexec_segment __user *segments, unsigned long flags)
+               struct kexec_segment *segments, unsigned long flags)
 {
        struct kimage **dest_image, *image;
        unsigned long i;
        int ret;
 
+       /*
+        * Because we write directly to the reserved memory region when loading
+        * crash kernels we need a mutex here to prevent multiple crash kernels
+        * from attempting to load simultaneously, and to prevent a crash kernel
+        * from loading over the top of a in use crash kernel.
+        *
+        * KISS: always take the mutex.
+        */
+       if (!mutex_trylock(&kexec_mutex))
+               return -EBUSY;
+
        if (flags & KEXEC_ON_CRASH) {
                dest_image = &kexec_crash_image;
                if (kexec_crash_image)
@@ -121,7 +113,8 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
        if (nr_segments == 0) {
                /* Uninstall image */
                kimage_free(xchg(dest_image, NULL));
-               return 0;
+               ret = 0;
+               goto out_unlock;
        }
        if (flags & KEXEC_ON_CRASH) {
                /*
@@ -134,7 +127,7 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
 
        ret = kimage_alloc_init(&image, entry, nr_segments, segments, flags);
        if (ret)
-               return ret;
+               goto out_unlock;
 
        if (flags & KEXEC_PRESERVE_CONTEXT)
                image->preserve_context = 1;
@@ -171,6 +164,8 @@ out:
                arch_kexec_protect_crashkres();
 
        kimage_free(image);
+out_unlock:
+       mutex_unlock(&kexec_mutex);
        return ret;
 }
 
@@ -236,7 +231,8 @@ static inline int kexec_load_check(unsigned long nr_segments,
 SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
                struct kexec_segment __user *, segments, unsigned long, flags)
 {
-       int result;
+       struct kexec_segment *ksegments;
+       unsigned long result;
 
        result = kexec_load_check(nr_segments, flags);
        if (result)
@@ -247,20 +243,12 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
                ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT))
                return -EINVAL;
 
-       /* Because we write directly to the reserved memory
-        * region when loading crash kernels we need a mutex here to
-        * prevent multiple crash  kernels from attempting to load
-        * simultaneously, and to prevent a crash kernel from loading
-        * over the top of a in use crash kernel.
-        *
-        * KISS: always take the mutex.
-        */
-       if (!mutex_trylock(&kexec_mutex))
-               return -EBUSY;
+       ksegments = memdup_user(segments, nr_segments * sizeof(ksegments[0]));
+       if (IS_ERR(ksegments))
+               return PTR_ERR(ksegments);
 
-       result = do_kexec_load(entry, nr_segments, segments, flags);
-
-       mutex_unlock(&kexec_mutex);
+       result = do_kexec_load(entry, nr_segments, ksegments, flags);
+       kfree(ksegments);
 
        return result;
 }
@@ -272,7 +260,7 @@ COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry,
                       compat_ulong_t, flags)
 {
        struct compat_kexec_segment in;
-       struct kexec_segment out, __user *ksegments;
+       struct kexec_segment *ksegments;
        unsigned long i, result;
 
        result = kexec_load_check(nr_segments, flags);
@@ -285,37 +273,26 @@ COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry,
        if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT)
                return -EINVAL;
 
-       ksegments = compat_alloc_user_space(nr_segments * sizeof(out));
+       ksegments = kmalloc_array(nr_segments, sizeof(ksegments[0]),
+                       GFP_KERNEL);
+       if (!ksegments)
+               return -ENOMEM;
+
        for (i = 0; i < nr_segments; i++) {
                result = copy_from_user(&in, &segments[i], sizeof(in));
                if (result)
-                       return -EFAULT;
+                       goto fail;
 
-               out.buf   = compat_ptr(in.buf);
-               out.bufsz = in.bufsz;
-               out.mem   = in.mem;
-               out.memsz = in.memsz;
-
-               result = copy_to_user(&ksegments[i], &out, sizeof(out));
-               if (result)
-                       return -EFAULT;
+               ksegments[i].buf   = compat_ptr(in.buf);
+               ksegments[i].bufsz = in.bufsz;
+               ksegments[i].mem   = in.mem;
+               ksegments[i].memsz = in.memsz;
        }
 
-       /* Because we write directly to the reserved memory
-        * region when loading crash kernels we need a mutex here to
-        * prevent multiple crash  kernels from attempting to load
-        * simultaneously, and to prevent a crash kernel from loading
-        * over the top of a in use crash kernel.
-        *
-        * KISS: always take the mutex.
-        */
-       if (!mutex_trylock(&kexec_mutex))
-               return -EBUSY;
-
        result = do_kexec_load(entry, nr_segments, ksegments, flags);
 
-       mutex_unlock(&kexec_mutex);
-
+fail:
+       kfree(ksegments);
        return result;
 }
 #endif
index 64578ad..f43d89d 100644 (file)
@@ -292,15 +292,10 @@ COND_SYSCALL(process_madvise);
 COND_SYSCALL(process_mrelease);
 COND_SYSCALL(remap_file_pages);
 COND_SYSCALL(mbind);
-COND_SYSCALL_COMPAT(mbind);
 COND_SYSCALL(get_mempolicy);
-COND_SYSCALL_COMPAT(get_mempolicy);
 COND_SYSCALL(set_mempolicy);
-COND_SYSCALL_COMPAT(set_mempolicy);
 COND_SYSCALL(migrate_pages);
-COND_SYSCALL_COMPAT(migrate_pages);
 COND_SYSCALL(move_pages);
-COND_SYSCALL_COMPAT(move_pages);
 
 COND_SYSCALL(perf_event_open);
 COND_SYSCALL(accept4);
index b44f547..1592b08 100644 (file)
@@ -1362,16 +1362,33 @@ mpol_out:
 /*
  * User space interface with variable sized bitmaps for nodelists.
  */
+static int get_bitmap(unsigned long *mask, const unsigned long __user *nmask,
+                     unsigned long maxnode)
+{
+       unsigned long nlongs = BITS_TO_LONGS(maxnode);
+       int ret;
+
+       if (in_compat_syscall())
+               ret = compat_get_bitmap(mask,
+                                       (const compat_ulong_t __user *)nmask,
+                                       maxnode);
+       else
+               ret = copy_from_user(mask, nmask,
+                                    nlongs * sizeof(unsigned long));
+
+       if (ret)
+               return -EFAULT;
+
+       if (maxnode % BITS_PER_LONG)
+               mask[nlongs - 1] &= (1UL << (maxnode % BITS_PER_LONG)) - 1;
+
+       return 0;
+}
 
 /* Copy a node mask from user space. */
 static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
                     unsigned long maxnode)
 {
-       unsigned long k;
-       unsigned long t;
-       unsigned long nlongs;
-       unsigned long endmask;
-
        --maxnode;
        nodes_clear(*nodes);
        if (maxnode == 0 || !nmask)
@@ -1379,49 +1396,29 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask,
        if (maxnode > PAGE_SIZE*BITS_PER_BYTE)
                return -EINVAL;
 
-       nlongs = BITS_TO_LONGS(maxnode);
-       if ((maxnode % BITS_PER_LONG) == 0)
-               endmask = ~0UL;
-       else
-               endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1;
-
        /*
         * When the user specified more nodes than supported just check
-        * if the non supported part is all zero.
-        *
-        * If maxnode have more longs than MAX_NUMNODES, check
-        * the bits in that area first. And then go through to
-        * check the rest bits which equal or bigger than MAX_NUMNODES.
-        * Otherwise, just check bits [MAX_NUMNODES, maxnode).
+        * if the non supported part is all zero, one word at a time,
+        * starting at the end.
         */
-       if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) {
-               for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) {
-                       if (get_user(t, nmask + k))
-                               return -EFAULT;
-                       if (k == nlongs - 1) {
-                               if (t & endmask)
-                                       return -EINVAL;
-                       } else if (t)
-                               return -EINVAL;
-               }
-               nlongs = BITS_TO_LONGS(MAX_NUMNODES);
-               endmask = ~0UL;
-       }
-
-       if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) {
-               unsigned long valid_mask = endmask;
+       while (maxnode > MAX_NUMNODES) {
+               unsigned long bits = min_t(unsigned long, maxnode, BITS_PER_LONG);
+               unsigned long t;
 
-               valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1);
-               if (get_user(t, nmask + nlongs - 1))
+               if (get_bitmap(&t, &nmask[maxnode / BITS_PER_LONG], bits))
                        return -EFAULT;
-               if (t & valid_mask)
+
+               if (maxnode - bits >= MAX_NUMNODES) {
+                       maxnode -= bits;
+               } else {
+                       maxnode = MAX_NUMNODES;
+                       t &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1);
+               }
+               if (t)
                        return -EINVAL;
        }
 
-       if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long)))
-               return -EFAULT;
-       nodes_addr(*nodes)[nlongs-1] &= endmask;
-       return 0;
+       return get_bitmap(nodes_addr(*nodes), nmask, maxnode);
 }
 
 /* Copy a kernel node mask to user space */
@@ -1430,6 +1427,10 @@ static int copy_nodes_to_user(unsigned long __user *mask, unsigned long maxnode,
 {
        unsigned long copy = ALIGN(maxnode-1, 64) / 8;
        unsigned int nbytes = BITS_TO_LONGS(nr_node_ids) * sizeof(long);
+       bool compat = in_compat_syscall();
+
+       if (compat)
+               nbytes = BITS_TO_COMPAT_LONGS(nr_node_ids) * sizeof(compat_long_t);
 
        if (copy > nbytes) {
                if (copy > PAGE_SIZE)
@@ -1437,7 +1438,13 @@ static int copy_nodes_to_user(unsigned long __user *mask, unsigned long maxnode,
                if (clear_user((char __user *)mask + nbytes, copy - nbytes))
                        return -EFAULT;
                copy = nbytes;
+               maxnode = nr_node_ids;
        }
+
+       if (compat)
+               return compat_put_bitmap((compat_ulong_t __user *)mask,
+                                        nodes_addr(*nodes), maxnode);
+
        return copy_to_user(mask, nodes_addr(*nodes), copy) ? -EFAULT : 0;
 }
 
@@ -1642,116 +1649,6 @@ SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
        return kernel_get_mempolicy(policy, nmask, maxnode, addr, flags);
 }
 
-#ifdef CONFIG_COMPAT
-
-COMPAT_SYSCALL_DEFINE5(get_mempolicy, int __user *, policy,
-                      compat_ulong_t __user *, nmask,
-                      compat_ulong_t, maxnode,
-                      compat_ulong_t, addr, compat_ulong_t, flags)
-{
-       long err;
-       unsigned long __user *nm = NULL;
-       unsigned long nr_bits, alloc_size;
-       DECLARE_BITMAP(bm, MAX_NUMNODES);
-
-       nr_bits = min_t(unsigned long, maxnode-1, nr_node_ids);
-       alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
-
-       if (nmask)
-               nm = compat_alloc_user_space(alloc_size);
-
-       err = kernel_get_mempolicy(policy, nm, nr_bits+1, addr, flags);
-
-       if (!err && nmask) {
-               unsigned long copy_size;
-               copy_size = min_t(unsigned long, sizeof(bm), alloc_size);
-               err = copy_from_user(bm, nm, copy_size);
-               /* ensure entire bitmap is zeroed */
-               err |= clear_user(nmask, ALIGN(maxnode-1, 8) / 8);
-               err |= compat_put_bitmap(nmask, bm, nr_bits);
-       }
-
-       return err;
-}
-
-COMPAT_SYSCALL_DEFINE3(set_mempolicy, int, mode, compat_ulong_t __user *, nmask,
-                      compat_ulong_t, maxnode)
-{
-       unsigned long __user *nm = NULL;
-       unsigned long nr_bits, alloc_size;
-       DECLARE_BITMAP(bm, MAX_NUMNODES);
-
-       nr_bits = min_t(unsigned long, maxnode-1, MAX_NUMNODES);
-       alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
-
-       if (nmask) {
-               if (compat_get_bitmap(bm, nmask, nr_bits))
-                       return -EFAULT;
-               nm = compat_alloc_user_space(alloc_size);
-               if (copy_to_user(nm, bm, alloc_size))
-                       return -EFAULT;
-       }
-
-       return kernel_set_mempolicy(mode, nm, nr_bits+1);
-}
-
-COMPAT_SYSCALL_DEFINE6(mbind, compat_ulong_t, start, compat_ulong_t, len,
-                      compat_ulong_t, mode, compat_ulong_t __user *, nmask,
-                      compat_ulong_t, maxnode, compat_ulong_t, flags)
-{
-       unsigned long __user *nm = NULL;
-       unsigned long nr_bits, alloc_size;
-       nodemask_t bm;
-
-       nr_bits = min_t(unsigned long, maxnode-1, MAX_NUMNODES);
-       alloc_size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
-
-       if (nmask) {
-               if (compat_get_bitmap(nodes_addr(bm), nmask, nr_bits))
-                       return -EFAULT;
-               nm = compat_alloc_user_space(alloc_size);
-               if (copy_to_user(nm, nodes_addr(bm), alloc_size))
-                       return -EFAULT;
-       }
-
-       return kernel_mbind(start, len, mode, nm, nr_bits+1, flags);
-}
-
-COMPAT_SYSCALL_DEFINE4(migrate_pages, compat_pid_t, pid,
-                      compat_ulong_t, maxnode,
-                      const compat_ulong_t __user *, old_nodes,
-                      const compat_ulong_t __user *, new_nodes)
-{
-       unsigned long __user *old = NULL;
-       unsigned long __user *new = NULL;
-       nodemask_t tmp_mask;
-       unsigned long nr_bits;
-       unsigned long size;
-
-       nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES);
-       size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
-       if (old_nodes) {
-               if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits))
-                       return -EFAULT;
-               old = compat_alloc_user_space(new_nodes ? size * 2 : size);
-               if (new_nodes)
-                       new = old + size / sizeof(unsigned long);
-               if (copy_to_user(old, nodes_addr(tmp_mask), size))
-                       return -EFAULT;
-       }
-       if (new_nodes) {
-               if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits))
-                       return -EFAULT;
-               if (new == NULL)
-                       new = compat_alloc_user_space(size);
-               if (copy_to_user(new, nodes_addr(tmp_mask), size))
-                       return -EFAULT;
-       }
-       return kernel_migrate_pages(pid, nr_bits + 1, old, new);
-}
-
-#endif /* CONFIG_COMPAT */
-
 bool vma_migratable(struct vm_area_struct *vma)
 {
        if (vma->vm_flags & (VM_IO | VM_PFNMAP))
index a0aeb3f..a6a7743 100644 (file)
@@ -960,7 +960,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
                                int force, enum migrate_mode mode)
 {
        int rc = -EAGAIN;
-       int page_was_mapped = 0;
+       bool page_was_mapped = false;
        struct anon_vma *anon_vma = NULL;
        bool is_lru = !__PageMovable(page);
 
@@ -1008,7 +1008,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        }
 
        /*
-        * By try_to_unmap(), page->mapcount goes down to 0 here. In this case,
+        * By try_to_migrate(), page->mapcount goes down to 0 here. In this case,
         * we cannot notice that anon_vma is freed while we migrates a page.
         * This get_anon_vma() delays freeing anon_vma pointer until the end
         * of migration. File cache pages are no problem because of page_lock()
@@ -1063,7 +1063,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
                VM_BUG_ON_PAGE(PageAnon(page) && !PageKsm(page) && !anon_vma,
                                page);
                try_to_migrate(page, 0);
-               page_was_mapped = 1;
+               page_was_mapped = true;
        }
 
        if (!page_mapped(page))
@@ -1900,6 +1900,23 @@ set_status:
        mmap_read_unlock(mm);
 }
 
+static int get_compat_pages_array(const void __user *chunk_pages[],
+                                 const void __user * __user *pages,
+                                 unsigned long chunk_nr)
+{
+       compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
+       compat_uptr_t p;
+       int i;
+
+       for (i = 0; i < chunk_nr; i++) {
+               if (get_user(p, pages32 + i))
+                       return -EFAULT;
+               chunk_pages[i] = compat_ptr(p);
+       }
+
+       return 0;
+}
+
 /*
  * Determine the nodes of a user array of pages and store it in
  * a user array of status.
@@ -1919,8 +1936,15 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
                if (chunk_nr > DO_PAGES_STAT_CHUNK_NR)
                        chunk_nr = DO_PAGES_STAT_CHUNK_NR;
 
-               if (copy_from_user(chunk_pages, pages, chunk_nr * sizeof(*chunk_pages)))
-                       break;
+               if (in_compat_syscall()) {
+                       if (get_compat_pages_array(chunk_pages, pages,
+                                                  chunk_nr))
+                               break;
+               } else {
+                       if (copy_from_user(chunk_pages, pages,
+                                     chunk_nr * sizeof(*chunk_pages)))
+                               break;
+               }
 
                do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
 
@@ -2023,28 +2047,6 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
        return kernel_move_pages(pid, nr_pages, pages, nodes, status, flags);
 }
 
-#ifdef CONFIG_COMPAT
-COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
-                      compat_uptr_t __user *, pages32,
-                      const int __user *, nodes,
-                      int __user *, status,
-                      int, flags)
-{
-       const void __user * __user *pages;
-       int i;
-
-       pages = compat_alloc_user_space(nr_pages * sizeof(void *));
-       for (i = 0; i < nr_pages; i++) {
-               compat_uptr_t p;
-
-               if (get_user(p, pages32 + i) ||
-                       put_user(compat_ptr(p), pages + i))
-                       return -EFAULT;
-       }
-       return kernel_move_pages(pid, nr_pages, pages, nodes, status, flags);
-}
-#endif /* CONFIG_COMPAT */
-
 #ifdef CONFIG_NUMA_BALANCING
 /*
  * Returns true if this is a safe migration target node for misplaced NUMA
@@ -2107,6 +2109,7 @@ out:
 static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
 {
        int page_lru;
+       int nr_pages = thp_nr_pages(page);
 
        VM_BUG_ON_PAGE(compound_order(page) && !PageTransHuge(page), page);
 
@@ -2115,7 +2118,7 @@ static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
                return 0;
 
        /* Avoid migrating to a node that is nearly full */
-       if (!migrate_balanced_pgdat(pgdat, compound_nr(page)))
+       if (!migrate_balanced_pgdat(pgdat, nr_pages))
                return 0;
 
        if (isolate_lru_page(page))
@@ -2123,7 +2126,7 @@ static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
 
        page_lru = page_is_file_lru(page);
        mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON + page_lru,
-                               thp_nr_pages(page));
+                           nr_pages);
 
        /*
         * Isolating the page has taken another reference, so the
index 0885a34..8ce2620 100644 (file)
@@ -319,6 +319,16 @@ void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
        long x;
        long t;
 
+       /*
+        * Accurate vmstat updates require a RMW. On !PREEMPT_RT kernels,
+        * atomicity is provided by IRQs being disabled -- either explicitly
+        * or via local_lock_irq. On PREEMPT_RT, local_lock_irq only disables
+        * CPU migrations and preemption potentially corrupts a counter so
+        * disable preemption.
+        */
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_disable();
+
        x = delta + __this_cpu_read(*p);
 
        t = __this_cpu_read(pcp->stat_threshold);
@@ -328,6 +338,9 @@ void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
                x = 0;
        }
        __this_cpu_write(*p, x);
+
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_enable();
 }
 EXPORT_SYMBOL(__mod_zone_page_state);
 
@@ -350,6 +363,10 @@ void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
                delta >>= PAGE_SHIFT;
        }
 
+       /* See __mod_node_page_state */
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_disable();
+
        x = delta + __this_cpu_read(*p);
 
        t = __this_cpu_read(pcp->stat_threshold);
@@ -359,6 +376,9 @@ void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item,
                x = 0;
        }
        __this_cpu_write(*p, x);
+
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_enable();
 }
 EXPORT_SYMBOL(__mod_node_page_state);
 
@@ -391,6 +411,10 @@ void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
        s8 __percpu *p = pcp->vm_stat_diff + item;
        s8 v, t;
 
+       /* See __mod_node_page_state */
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_disable();
+
        v = __this_cpu_inc_return(*p);
        t = __this_cpu_read(pcp->stat_threshold);
        if (unlikely(v > t)) {
@@ -399,6 +423,9 @@ void __inc_zone_state(struct zone *zone, enum zone_stat_item item)
                zone_page_state_add(v + overstep, zone, item);
                __this_cpu_write(*p, -overstep);
        }
+
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_enable();
 }
 
 void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
@@ -409,6 +436,10 @@ void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
 
        VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
 
+       /* See __mod_node_page_state */
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_disable();
+
        v = __this_cpu_inc_return(*p);
        t = __this_cpu_read(pcp->stat_threshold);
        if (unlikely(v > t)) {
@@ -417,6 +448,9 @@ void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item)
                node_page_state_add(v + overstep, pgdat, item);
                __this_cpu_write(*p, -overstep);
        }
+
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_enable();
 }
 
 void __inc_zone_page_state(struct page *page, enum zone_stat_item item)
@@ -437,6 +471,10 @@ void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
        s8 __percpu *p = pcp->vm_stat_diff + item;
        s8 v, t;
 
+       /* See __mod_node_page_state */
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_disable();
+
        v = __this_cpu_dec_return(*p);
        t = __this_cpu_read(pcp->stat_threshold);
        if (unlikely(v < - t)) {
@@ -445,6 +483,9 @@ void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
                zone_page_state_add(v - overstep, zone, item);
                __this_cpu_write(*p, overstep);
        }
+
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_enable();
 }
 
 void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
@@ -455,6 +496,10 @@ void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
 
        VM_WARN_ON_ONCE(vmstat_item_in_bytes(item));
 
+       /* See __mod_node_page_state */
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_disable();
+
        v = __this_cpu_dec_return(*p);
        t = __this_cpu_read(pcp->stat_threshold);
        if (unlikely(v < - t)) {
@@ -463,6 +508,9 @@ void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item)
                node_page_state_add(v - overstep, pgdat, item);
                __this_cpu_write(*p, overstep);
        }
+
+       if (IS_ENABLED(CONFIG_PREEMPT_RT))
+               preempt_enable();
 }
 
 void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
index b7b958f..213f12e 100644 (file)
@@ -30,6 +30,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/9p.h>
 
+#define DEFAULT_MSIZE (128 * 1024)
+
 /*
   * Client Option Parsing (code inspired by NFS code)
   *  - a little lazy - parse all client options
@@ -65,7 +67,7 @@ EXPORT_SYMBOL(p9_is_proto_dotu);
 
 int p9_show_client_options(struct seq_file *m, struct p9_client *clnt)
 {
-       if (clnt->msize != 8192)
+       if (clnt->msize != DEFAULT_MSIZE)
                seq_printf(m, ",msize=%u", clnt->msize);
        seq_printf(m, ",trans=%s", clnt->trans_mod->name);
 
@@ -139,7 +141,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
        int ret = 0;
 
        clnt->proto_version = p9_proto_2000L;
-       clnt->msize = 8192;
+       clnt->msize = DEFAULT_MSIZE;
 
        if (!opts)
                return 0;
index f4dd045..007bbcc 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/syscalls.h> /* killme */
 
 #define P9_PORT 564
-#define MAX_SOCK_BUF (64*1024)
+#define MAX_SOCK_BUF (1024*1024)
 #define MAXPOLLWADDR   2
 
 static struct p9_trans_module p9_tcp_trans;
index 2bbd7dc..490a4c9 100644 (file)
@@ -610,7 +610,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
        chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
        if (!chan->vc_wq) {
                err = -ENOMEM;
-               goto out_free_tag;
+               goto out_remove_file;
        }
        init_waitqueue_head(chan->vc_wq);
        chan->ring_bufs_avail = 1;
@@ -628,6 +628,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)
 
        return 0;
 
+out_remove_file:
+       sysfs_remove_file(&vdev->dev.kobj, &dev_attr_mount_tag.attr);
 out_free_tag:
        kfree(tag);
 out_free_vq:
index f4fea28..3ec1a51 100644 (file)
@@ -138,7 +138,7 @@ static bool p9_xen_write_todo(struct xen_9pfs_dataring *ring, RING_IDX size)
 
 static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
 {
-       struct xen_9pfs_front_priv *priv = NULL;
+       struct xen_9pfs_front_priv *priv;
        RING_IDX cons, prod, masked_cons, masked_prod;
        unsigned long flags;
        u32 size = p9_req->tc.size;
@@ -151,7 +151,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
                        break;
        }
        read_unlock(&xen_9pfs_lock);
-       if (!priv || priv->client != client)
+       if (list_entry_is_head(priv, &xen_9pfs_devs, list))
                return -EINVAL;
 
        num = p9_req->tc.tag % priv->num_rings;
index 9de41e7..3e776e3 100644 (file)
@@ -194,6 +194,8 @@ static void rsi_request(struct cache_detail *cd,
        qword_addhex(bpp, blen, rsii->in_handle.data, rsii->in_handle.len);
        qword_addhex(bpp, blen, rsii->in_token.data, rsii->in_token.len);
        (*bpp)[-1] = '\n';
+       WARN_ONCE(*blen < 0,
+                 "RPCSEC/GSS credential too large - please use gssproxy\n");
 }
 
 static int rsi_parse(struct cache_detail *cd,
index 1a2c1c4..5964180 100644 (file)
@@ -803,7 +803,7 @@ static int cache_request(struct cache_detail *detail,
 
        detail->cache_request(detail, crq->item, &bp, &len);
        if (len < 0)
-               return -EAGAIN;
+               return -E2BIG;
        return PAGE_SIZE - len;
 }
 
index e1153cb..6316bd2 100644 (file)
@@ -663,7 +663,7 @@ static int svc_alloc_arg(struct svc_rqst *rqstp)
 {
        struct svc_serv *serv = rqstp->rq_server;
        struct xdr_buf *arg = &rqstp->rq_arg;
-       unsigned long pages, filled;
+       unsigned long pages, filled, ret;
 
        pagevec_init(&rqstp->rq_pvec);
 
@@ -675,11 +675,12 @@ static int svc_alloc_arg(struct svc_rqst *rqstp)
                pages = RPCSVC_MAXPAGES;
        }
 
-       for (;;) {
-               filled = alloc_pages_bulk_array(GFP_KERNEL, pages,
-                                               rqstp->rq_pages);
-               if (filled == pages)
-                       break;
+       for (filled = 0; filled < pages; filled = ret) {
+               ret = alloc_pages_bulk_array(GFP_KERNEL, pages,
+                                            rqstp->rq_pages);
+               if (ret > filled)
+                       /* Made progress, don't sleep yet */
+                       continue;
 
                set_current_state(TASK_INTERRUPTIBLE);
                if (signalled() || kthread_should_stop()) {
index 04c5685..1d0e1e4 100644 (file)
@@ -24,6 +24,7 @@ SECTIONS {
        __kcrctab               0 : { *(SORT(___kcrctab+*)) }
        __kcrctab_gpl           0 : { *(SORT(___kcrctab_gpl+*)) }
 
+       .ctors                  0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
        .init_array             0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
 
        __jump_table            0 : ALIGN(8) { KEEP(*(__jump_table)) }