diff --git a/.travis.yml b/.travis.yml
index 23e81f65..56592e40 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,7 @@ addons:
apt:
- gcc-aarch64-linux-gnu
script:
-- git config --global user.name "홍길동"
+- git config --global user.name "abc"
- git config --global user.email "support@webisfree.com"
- yes | git clone https://github.com/roynatech2544/Samsung_Device_A20e_Kernel.git -b Kernel_4.4.177
- cd Samsung_Device_A20e_Kernel
@@ -18,5 +18,5 @@ script:
- cp arch/arm64/boot/Image out
- cp arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dtbo out
- cp arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dts out
-- zip -r Kernel out
-- curl --upload-file Kernel.zip https://transfer.sh/Kernel.zip
+- zip -r Kernel_$TRAVIS_BUILD_NUMBER out
+- curl --upload-file Kernel_$TRAVIS_BUILD_NUMBER.zip https://transfer.sh/Kernel.zip
diff --git a/README b/README
deleted file mode 100755
index 70935dd3..00000000
--- a/README
+++ /dev/null
@@ -1,406 +0,0 @@
-[](https://travis-ci.com/roynatech2544/Samsung_Device_A20e_Kernel)
-
-Linux kernel release 4.x
-
-These are the release notes for Linux version 4. Read them carefully,
-as they tell you what this is all about, explain how to install the
-kernel, and what to do if something goes wrong.
-
-WHAT IS LINUX?
-
- Linux is a clone of the operating system Unix, written from scratch by
- Linus Torvalds with assistance from a loosely-knit team of hackers across
- the Net. It aims towards POSIX and Single UNIX Specification compliance.
-
- It has all the features you would expect in a modern fully-fledged Unix,
- including true multitasking, virtual memory, shared libraries, demand
- loading, shared copy-on-write executables, proper memory management,
- and multistack networking including IPv4 and IPv6.
-
- It is distributed under the GNU General Public License - see the
- accompanying COPYING file for more details.
-
-ON WHAT HARDWARE DOES IT RUN?
-
- Although originally developed first for 32-bit x86-based PCs (386 or higher),
- today Linux also runs on (at least) the Compaq Alpha AXP, Sun SPARC and
- UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, Hitachi SuperH, Cell,
- IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD x86-64, AXIS CRIS,
- Xtensa, Tilera TILE, AVR32, ARC and Renesas M32R architectures.
-
- Linux is easily portable to most general-purpose 32- or 64-bit architectures
- as long as they have a paged memory management unit (PMMU) and a port of the
- GNU C compiler (gcc) (part of The GNU Compiler Collection, GCC). Linux has
- also been ported to a number of architectures without a PMMU, although
- functionality is then obviously somewhat limited.
- Linux has also been ported to itself. You can now run the kernel as a
- userspace application - this is called UserMode Linux (UML).
-
-DOCUMENTATION:
-
- - There is a lot of documentation available both in electronic form on
- the Internet and in books, both Linux-specific and pertaining to
- general UNIX questions. I'd recommend looking into the documentation
- subdirectories on any Linux FTP site for the LDP (Linux Documentation
- Project) books. This README is not meant to be documentation on the
- system: there are much better sources available.
-
- - There are various README files in the Documentation/ subdirectory:
- these typically contain kernel-specific installation notes for some
- drivers for example. See Documentation/00-INDEX for a list of what
- is contained in each file. Please read the Changes file, as it
- contains information about the problems, which may result by upgrading
- your kernel.
-
- - The Documentation/DocBook/ subdirectory contains several guides for
- kernel developers and users. These guides can be rendered in a
- number of formats: PostScript (.ps), PDF, HTML, & man-pages, among others.
- After installation, "make psdocs", "make pdfdocs", "make htmldocs",
- or "make mandocs" will render the documentation in the requested format.
-
-INSTALLING the kernel source:
-
- - If you install the full sources, put the kernel tarball in a
- directory where you have permissions (eg. your home directory) and
- unpack it:
-
- xz -cd linux-4.X.tar.xz | tar xvf -
-
- Replace "X" with the version number of the latest kernel.
-
- Do NOT use the /usr/src/linux area! This area has a (usually
- incomplete) set of kernel headers that are used by the library header
- files. They should match the library, and not get messed up by
- whatever the kernel-du-jour happens to be.
-
- - You can also upgrade between 4.x releases by patching. Patches are
- distributed in the xz format. To install by patching, get all the
- newer patch files, enter the top level directory of the kernel source
- (linux-4.X) and execute:
-
- xz -cd ../patch-4.x.xz | patch -p1
-
- Replace "x" for all versions bigger than the version "X" of your current
- source tree, _in_order_, and you should be ok. You may want to remove
- the backup files (some-file-name~ or some-file-name.orig), and make sure
- that there are no failed patches (some-file-name# or some-file-name.rej).
- If there are, either you or I have made a mistake.
-
- Unlike patches for the 4.x kernels, patches for the 4.x.y kernels
- (also known as the -stable kernels) are not incremental but instead apply
- directly to the base 4.x kernel. For example, if your base kernel is 4.0
- and you want to apply the 4.0.3 patch, you must not first apply the 4.0.1
- and 4.0.2 patches. Similarly, if you are running kernel version 4.0.2 and
- want to jump to 4.0.3, you must first reverse the 4.0.2 patch (that is,
- patch -R) _before_ applying the 4.0.3 patch. You can read more on this in
- Documentation/applying-patches.txt
-
- Alternatively, the script patch-kernel can be used to automate this
- process. It determines the current kernel version and applies any
- patches found.
-
- linux/scripts/patch-kernel linux
-
- The first argument in the command above is the location of the
- kernel source. Patches are applied from the current directory, but
- an alternative directory can be specified as the second argument.
-
- - Make sure you have no stale .o files and dependencies lying around:
-
- cd linux
- make mrproper
-
- You should now have the sources correctly installed.
-
-SOFTWARE REQUIREMENTS
-
- Compiling and running the 4.x kernels requires up-to-date
- versions of various software packages. Consult
- Documentation/Changes for the minimum version numbers required
- and how to get updates for these packages. Beware that using
- excessively old versions of these packages can cause indirect
- errors that are very difficult to track down, so don't assume that
- you can just update packages when obvious problems arise during
- build or operation.
-
-BUILD directory for the kernel:
-
- When compiling the kernel, all output files will per default be
- stored together with the kernel source code.
- Using the option "make O=output/dir" allow you to specify an alternate
- place for the output files (including .config).
- Example:
-
- kernel source code: /usr/src/linux-4.X
- build directory: /home/name/build/kernel
-
- To configure and build the kernel, use:
-
- cd /usr/src/linux-4.X
- make O=/home/name/build/kernel menuconfig
- make O=/home/name/build/kernel
- sudo make O=/home/name/build/kernel modules_install install
-
- Please note: If the 'O=output/dir' option is used, then it must be
- used for all invocations of make.
-
-CONFIGURING the kernel:
-
- Do not skip this step even if you are only upgrading one minor
- version. New configuration options are added in each release, and
- odd problems will turn up if the configuration files are not set up
- as expected. If you want to carry your existing configuration to a
- new version with minimal work, use "make oldconfig", which will
- only ask you for the answers to new questions.
-
- - Alternative configuration commands are:
-
- "make config" Plain text interface.
-
- "make menuconfig" Text based color menus, radiolists & dialogs.
-
- "make nconfig" Enhanced text based color menus.
-
- "make xconfig" X windows (Qt) based configuration tool.
-
- "make gconfig" X windows (GTK+) based configuration tool.
-
- "make oldconfig" Default all questions based on the contents of
- your existing ./.config file and asking about
- new config symbols.
-
- "make silentoldconfig"
- Like above, but avoids cluttering the screen
- with questions already answered.
- Additionally updates the dependencies.
-
- "make olddefconfig"
- Like above, but sets new symbols to their default
- values without prompting.
-
- "make defconfig" Create a ./.config file by using the default
- symbol values from either arch/$ARCH/defconfig
- or arch/$ARCH/configs/${PLATFORM}_defconfig,
- depending on the architecture.
-
- "make ${PLATFORM}_defconfig"
- Create a ./.config file by using the default
- symbol values from
- arch/$ARCH/configs/${PLATFORM}_defconfig.
- Use "make help" to get a list of all available
- platforms of your architecture.
-
- "make allyesconfig"
- Create a ./.config file by setting symbol
- values to 'y' as much as possible.
-
- "make allmodconfig"
- Create a ./.config file by setting symbol
- values to 'm' as much as possible.
-
- "make allnoconfig" Create a ./.config file by setting symbol
- values to 'n' as much as possible.
-
- "make randconfig" Create a ./.config file by setting symbol
- values to random values.
-
- "make localmodconfig" Create a config based on current config and
- loaded modules (lsmod). Disables any module
- option that is not needed for the loaded modules.
-
- To create a localmodconfig for another machine,
- store the lsmod of that machine into a file
- and pass it in as a LSMOD parameter.
-
- target$ lsmod > /tmp/mylsmod
- target$ scp /tmp/mylsmod host:/tmp
-
- host$ make LSMOD=/tmp/mylsmod localmodconfig
-
- The above also works when cross compiling.
-
- "make localyesconfig" Similar to localmodconfig, except it will convert
- all module options to built in (=y) options.
-
- You can find more information on using the Linux kernel config tools
- in Documentation/kbuild/kconfig.txt.
-
- - NOTES on "make config":
-
- - Having unnecessary drivers will make the kernel bigger, and can
- under some circumstances lead to problems: probing for a
- nonexistent controller card may confuse your other controllers
-
- - Compiling the kernel with "Processor type" set higher than 386
- will result in a kernel that does NOT work on a 386. The
- kernel will detect this on bootup, and give up.
-
- - A kernel with math-emulation compiled in will still use the
- coprocessor if one is present: the math emulation will just
- never get used in that case. The kernel will be slightly larger,
- but will work on different machines regardless of whether they
- have a math coprocessor or not.
-
- - The "kernel hacking" configuration details usually result in a
- bigger or slower kernel (or both), and can even make the kernel
- less stable by configuring some routines to actively try to
- break bad code to find kernel problems (kmalloc()). Thus you
- should probably answer 'n' to the questions for "development",
- "experimental", or "debugging" features.
-
-COMPILING the kernel:
-
- - Make sure you have at least gcc 3.2 available.
- For more information, refer to Documentation/Changes.
-
- Please note that you can still run a.out user programs with this kernel.
-
- - Do a "make" to create a compressed kernel image. It is also
- possible to do "make install" if you have lilo installed to suit the
- kernel makefiles, but you may want to check your particular lilo setup first.
-
- To do the actual install, you have to be root, but none of the normal
- build should require that. Don't take the name of root in vain.
-
- - If you configured any of the parts of the kernel as `modules', you
- will also have to do "make modules_install".
-
- - Verbose kernel compile/build output:
-
- Normally, the kernel build system runs in a fairly quiet mode (but not
- totally silent). However, sometimes you or other kernel developers need
- to see compile, link, or other commands exactly as they are executed.
- For this, use "verbose" build mode. This is done by inserting
- "V=1" in the "make" command. E.g.:
-
- make V=1 all
-
- To have the build system also tell the reason for the rebuild of each
- target, use "V=2". The default is "V=0".
-
- - Keep a backup kernel handy in case something goes wrong. This is
- especially true for the development releases, since each new release
- contains new code which has not been debugged. Make sure you keep a
- backup of the modules corresponding to that kernel, as well. If you
- are installing a new kernel with the same version number as your
- working kernel, make a backup of your modules directory before you
- do a "make modules_install".
-
- Alternatively, before compiling, use the kernel config option
- "LOCALVERSION" to append a unique suffix to the regular kernel version.
- LOCALVERSION can be set in the "General Setup" menu.
-
- - In order to boot your new kernel, you'll need to copy the kernel
- image (e.g. .../linux/arch/i386/boot/bzImage after compilation)
- to the place where your regular bootable kernel is found.
-
- - Booting a kernel directly from a floppy without the assistance of a
- bootloader such as LILO, is no longer supported.
-
- If you boot Linux from the hard drive, chances are you use LILO, which
- uses the kernel image as specified in the file /etc/lilo.conf. The
- kernel image file is usually /vmlinuz, /boot/vmlinuz, /bzImage or
- /boot/bzImage. To use the new kernel, save a copy of the old image
- and copy the new image over the old one. Then, you MUST RERUN LILO
- to update the loading map!! If you don't, you won't be able to boot
- the new kernel image.
-
- Reinstalling LILO is usually a matter of running /sbin/lilo.
- You may wish to edit /etc/lilo.conf to specify an entry for your
- old kernel image (say, /vmlinux.old) in case the new one does not
- work. See the LILO docs for more information.
-
- After reinstalling LILO, you should be all set. Shutdown the system,
- reboot, and enjoy!
-
- If you ever need to change the default root device, video mode,
- ramdisk size, etc. in the kernel image, use the 'rdev' program (or
- alternatively the LILO boot options when appropriate). No need to
- recompile the kernel to change these parameters.
-
- - Reboot with the new kernel and enjoy.
-
-IF SOMETHING GOES WRONG:
-
- - If you have problems that seem to be due to kernel bugs, please check
- the file MAINTAINERS to see if there is a particular person associated
- with the part of the kernel that you are having trouble with. If there
- isn't anyone listed there, then the second best thing is to mail
- them to me (torvalds@linux-foundation.org), and possibly to any other
- relevant mailing-list or to the newsgroup.
-
- - In all bug-reports, *please* tell what kernel you are talking about,
- how to duplicate the problem, and what your setup is (use your common
- sense). If the problem is new, tell me so, and if the problem is
- old, please try to tell me when you first noticed it.
-
- - If the bug results in a message like
-
- unable to handle kernel paging request at address C0000010
- Oops: 0002
- EIP: 0010:XXXXXXXX
- eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx
- esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx
- ds: xxxx es: xxxx fs: xxxx gs: xxxx
- Pid: xx, process nr: xx
- xx xx xx xx xx xx xx xx xx xx
-
- or similar kernel debugging information on your screen or in your
- system log, please duplicate it *exactly*. The dump may look
- incomprehensible to you, but it does contain information that may
- help debugging the problem. The text above the dump is also
- important: it tells something about why the kernel dumped code (in
- the above example, it's due to a bad kernel pointer). More information
- on making sense of the dump is in Documentation/oops-tracing.txt
-
- - If you compiled the kernel with CONFIG_KALLSYMS you can send the dump
- as is, otherwise you will have to use the "ksymoops" program to make
- sense of the dump (but compiling with CONFIG_KALLSYMS is usually preferred).
- This utility can be downloaded from
- ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops/ .
- Alternatively, you can do the dump lookup by hand:
-
- - In debugging dumps like the above, it helps enormously if you can
- look up what the EIP value means. The hex value as such doesn't help
- me or anybody else very much: it will depend on your particular
- kernel setup. What you should do is take the hex value from the EIP
- line (ignore the "0010:"), and look it up in the kernel namelist to
- see which kernel function contains the offending address.
-
- To find out the kernel function name, you'll need to find the system
- binary associated with the kernel that exhibited the symptom. This is
- the file 'linux/vmlinux'. To extract the namelist and match it against
- the EIP from the kernel crash, do:
-
- nm vmlinux | sort | less
-
- This will give you a list of kernel addresses sorted in ascending
- order, from which it is simple to find the function that contains the
- offending address. Note that the address given by the kernel
- debugging messages will not necessarily match exactly with the
- function addresses (in fact, that is very unlikely), so you can't
- just 'grep' the list: the list will, however, give you the starting
- point of each kernel function, so by looking for the function that
- has a starting address lower than the one you are searching for but
- is followed by a function with a higher address you will find the one
- you want. In fact, it may be a good idea to include a bit of
- "context" in your problem report, giving a few lines around the
- interesting one.
-
- If you for some reason cannot do the above (you have a pre-compiled
- kernel image or similar), telling me as much about your setup as
- possible will help. Please read the REPORTING-BUGS document for details.
-
- - Alternatively, you can use gdb on a running kernel. (read-only; i.e. you
- cannot change values or set break points.) To do this, first compile the
- kernel with -g; edit arch/i386/Makefile appropriately, then do a "make
- clean". You'll also need to enable CONFIG_PROC_FS (via "make config").
-
- After you've rebooted with the new kernel, do "gdb vmlinux /proc/kcore".
- You can now use all the usual gdb commands. The command to look up the
- point where your system crashed is "l *0xXXXXXXXX". (Replace the XXXes
- with the EIP value.)
-
- gdb'ing a non-running kernel currently fails because gdb (wrongly)
- disregards the starting offset for which the kernel is compiled.
-
diff --git a/README.md b/README.md
new file mode 100755
index 00000000..ee8a56aa
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# SM-A202K/F Kernel Source
+[](https://travis-ci.com/roynatech2544/Samsung_Device_A20e_Kernel)
+Modified Kernel Source for A20e running exynos7885 CPU chipset
diff --git a/arch/arm64/boot/Image b/arch/arm64/boot/Image
deleted file mode 100755
index 3dac7ed1..00000000
Binary files a/arch/arm64/boot/Image and /dev/null differ
diff --git a/arch/arm64/boot/Image.gz b/arch/arm64/boot/Image.gz
deleted file mode 100644
index 36d48eac..00000000
Binary files a/arch/arm64/boot/Image.gz and /dev/null differ
diff --git a/arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dtbo b/arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dtbo
deleted file mode 100644
index ffacea1c..00000000
Binary files a/arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dtbo and /dev/null differ
diff --git a/arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dts b/arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dts
deleted file mode 100755
index f4406fb1..00000000
--- a/arch/arm64/boot/dts/exynos/dtbo/exynos7884B-a20e_kor_ktt_00.dts
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * SAMSUNG EXYNOS7884B board device tree source
-
- *
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/dts-v1/;
-/plugin/;
-
-#include "exynos7884B-a20e_common.dtsi"
-#include "exynos7884B-a20e_kor_ktt_gpio_00.dtsi"
-#include "exynos7884B-a20e_fingerprint_00.dtsi"
-#include "exynos7884B-a20e_kor-tdmb-00.dtsi"
-
-/ {
- compatible = "samsung,A20E KOR KTT 00", "samsung,EXYNOS7884B";
-
- dtbo-hw_rev = <0>;
- dtbo-hw_rev_end = <255>;
-
-
- fragment@model {
- target-path = "/";
- __overlay__ {
- #address-cells = <2>;
- #size-cells = <1>;
-
- model = "Samsung A20E KOR KTT 00 board based on EXYNOS7884B";
-
- fm@14840000 {
- /delete-property/ elna_gpio;
- elna_gpio = <&gpg0 2 0x1>; /* FM_LNA_EN */
- num-trfon-freq = <56>;
- val-trfon-freq = <87500 87600 88300 88400 89000 89100 89800 89900
- 90600 90700 91300 91400 92100 92200 92900 93000 93600 93700
- 94400 94500 95200 95300 96700 96800 97500 97600 98300 98400 99000 99800 99900 99100
- 100000 100600 100700 101300 101400 101500 101600 102100 102200 102900 103000 103600
- 103700 104000 104400 104500 105200 105300 105900 106000 106700 106800 107500 107600 >;
- spur-trfon-freq = <1536>;
- };
-
- }; /* end of __overlay__ */
- }; /* end of fragment */
-}; /* end of root */
-
-&pinctrl_0 { //11CB0000
- nfc_clk: nfc-clk {
- samsung,pins = "gpq0-0";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- };
-
- nfc_int: nfc-int {
- samsung,pins = "gpa1-0";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- };
-};
-
-&pinctrl_2 { //13430000
- sd2_bus1: sd2-bus-width1 {
- samsung,pins = "gpf4-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <1>;
- };
-
- sd2_bus4: sd2-bus-width4 {
- samsung,pins = "gpf4-3", "gpf4-4", "gpf4-5";
- samsung,pin-function = <2>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <1>;
- };
-};
-
-&pinctrl_3 { //139B0000
- nfc_pvdd_en: nfc_pvdd_en {
- samsung,pins = "gpp6-4";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-val = <0>;
- samsung,pin-con-pdn = <3>;
- samsung,pin-pud-pdn = <0>;
- };
-
- nfc_firm: nfc_firm {
- samsung,pins = "gpp3-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-val = <0>;
- samsung,pin-con-pdn = <3>;
- samsung,pin-pud-pdn = <0>;
- };
-
- nfc_pd: nfc_pd {
- samsung,pins = "gpp2-2";
- samsung,pin-function = <2>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- samsung,pin-con-pdn = <3>;
- samsung,pin-pud-pdn = <0>;
- };
-
- nfc_clk_req: nfc_clk_req {
- samsung,pins = "gpp2-3";
- samsung,pin-function = <2>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
- samsung,pin-con-pdn = <3>;
- samsung,pin-pud-pdn = <0>;
- };
-};
-
-&hsi2c_5 {
- status = "okay";
- clock-frequency = <400000>; /* 400 kHz */
- sec-nfc@27{
- compatible = "sec-nfc";
- reg = <0x27>;
-
- interrupt-parent = <&gpa1>;
- interrupts = <0 0 0>;
-
- sec-nfc,nfc_pd = <&gpp2 2 0x2>;
- sec-nfc,firm-gpio = <&gpp3 2 1>;
- sec-nfc,irq-gpio = <&gpa1 0 0>;
- sec-nfc,nfc_clkreq = <&gpp2 3 0x2>;
- sec-nfc,pvdd_en = <&gpp6 4 1>;
- clkctrl-reg = <0x11C8600C>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&nfc_pd &nfc_firm &nfc_int &nfc_clk &nfc_pvdd_en &nfc_clk_req>;
- };
-};
diff --git a/arch/arm64/configs/exynos7885-a20ektt_defconfig b/arch/arm64/configs/exynos7885-a20ektt_defconfig
index f05c6757..3646a35f 100755
--- a/arch/arm64/configs/exynos7885-a20ektt_defconfig
+++ b/arch/arm64/configs/exynos7885-a20ektt_defconfig
@@ -44,11 +44,13 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_CROSS_COMPILE="aarch64-linux-gnu-"
# CONFIG_COMPILE_TEST is not set
CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="(none)"
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_CROSS_MEMORY_ATTACH=y
CONFIG_FHANDLE=y
# CONFIG_USELIB is not set
@@ -58,7 +60,6 @@ CONFIG_AUDITSYSCALL=y
CONFIG_AUDIT_WATCH=y
CONFIG_AUDIT_TREE=y
-#
# IRQ subsystem
#
CONFIG_GENERIC_IRQ_PROBE=y
@@ -118,35 +119,43 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=19
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
CONFIG_CGROUPS=y
-CONFIG_CGROUP_DEBUG=y
+# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
-# CONFIG_CGROUP_PIDS is not set
+CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_CGROUP_CPUACCT=y
+# CONFIG_CGROUP_SCHEDTUNE is not set
CONFIG_PAGE_COUNTER=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_SWAP_ENABLED=y
CONFIG_MEMCG_FORCE_USE_VM_SWAPPINESS=y
-# CONFIG_MEMCG_KMEM is not set
-CONFIG_CGROUP_PERF=y
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_CFS_BANDWIDTH=y
CONFIG_RT_GROUP_SCHED=y
-CONFIG_BLK_CGROUP=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SOCK_CGROUP_DATA=y
# CONFIG_CHECKPOINT_RESTORE is not set
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
# CONFIG_SCHED_AUTOGROUP is not set
-# CONFIG_SCHED_TUNE is not set
-# CONFIG_DEFAULT_USE_ENERGY_AWARE is not set
+CONFIG_SCHED_TUNE=y
+CONFIG_SCHED_EHMP=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
+CONFIG_SCHED_USE_FLUID_RT=y
# CONFIG_SYSFS_DEPRECATED is not set
# CONFIG_RELAY is not set
CONFIG_BLK_DEV_INITRD=y
@@ -157,8 +166,8 @@ CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
-# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
CONFIG_HAVE_UID16=y
@@ -171,7 +180,9 @@ CONFIG_MULTIUSER=y
CONFIG_SYSFS_SYSCALL=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
-CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set
+CONFIG_KALLSYMS_BASE_RELATIVE=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
@@ -181,73 +192,16 @@ CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
-# CONFIG_BPF_SYSCALL is not set
+CONFIG_BPF_SYSCALL=y
CONFIG_SHMEM=y
CONFIG_AIO=y
CONFIG_ADVISE_SYSCALLS=y
# CONFIG_USERFAULTFD is not set
+CONFIG_PCI_QUIRKS=y
CONFIG_MEMBARRIER=y
CONFIG_EMBEDDED=y
CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_PERF_USE_VMALLOC=y
-
-#
-# Kernel Performance Events And Counters
-#
-CONFIG_PERF_EVENTS=y
-# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
-# CONFIG_COMPAT_BRK is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-# CONFIG_SLOB is not set
-CONFIG_SLUB_CPU_PARTIAL=y
-# CONFIG_SYSTEM_DATA_VERIFICATION is not set
-CONFIG_PROFILING=y
-CONFIG_TRACEPOINTS=y
-# CONFIG_JUMP_LABEL is not set
-# CONFIG_UPROBES is not set
-# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
-CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
-CONFIG_HAVE_ARCH_TRACEHOOK=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DMA_CONTIGUOUS=y
-CONFIG_GENERIC_SMP_IDLE_THREAD=y
-CONFIG_GENERIC_IDLE_POLL_SETUP=y
-CONFIG_HAVE_CLK=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_HW_BREAKPOINT=y
-CONFIG_HAVE_PERF_REGS=y
-CONFIG_HAVE_PERF_USER_STACK_DUMP=y
-CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_RCU_TABLE_FREE=y
-CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
-CONFIG_HAVE_CMPXCHG_LOCAL=y
-CONFIG_HAVE_CMPXCHG_DOUBLE=y
-CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
-CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
-CONFIG_SECCOMP_FILTER=y
-CONFIG_HAVE_CC_STACKPROTECTOR=y
-CONFIG_CC_STACKPROTECTOR=y
-CONFIG_CC_STACKPROTECTOR_NONE=y
-# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
-CONFIG_CC_STACKPROTECTOR_STRONG=y
-CONFIG_HAVE_CONTEXT_TRACKING=y
-CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
-CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
-CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
-CONFIG_HAVE_ARCH_HUGE_VMAP=y
-CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
-CONFIG_MODULES_USE_ELF_RELA=y
-CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
-CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
-CONFIG_ARCH_MMAP_RND_BITS=18
-CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
-CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11
-CONFIG_CLONE_BACKWARDS=y
-CONFIG_OLD_SIGSUSPEND3=y
-CONFIG_COMPAT_OLD_SIGACTION=y
+
#
# GCOV-based kernel profiling
@@ -309,7 +263,7 @@ CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_NOOP is not set
# CONFIG_DEFAULT_IOSCHED was "cfq"
-CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_ASN1=y
CONFIG_UNINLINE_SPIN_UNLOCK=y
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
@@ -341,32 +295,47 @@ CONFIG_OLAF_SUPPORT=y
#
# Samsung Exynos
#
-CONFIG_ARCH_EXYNOS=y
-# CONFIG_SOC_EXYNOS7872 is not set
-# CONFIG_SOC_EMULATOR7872 is not set
CONFIG_SOC_EXYNOS7885=y
-# CONFIG_SOC_EXYNOS7885_ANDROID_VERSION_O is not set
-CONFIG_SOC_EXYNOS7885_ANDROID_VERSION_P=y
-# CONFIG_SOC_EXYNOS7885_ANDROID_VERSION_Q is not set
-# CONFIG_SOC_EXYNOS7885_ANDROID_VERSION_Q_MR is not set
-# CONFIG_SOC_EXYNOS7885_ANDROID_VERSION_P_MR is not set
-# CONFIG_SOC_EXYNOS7884 is not set
-# CONFIG_SOC_EXYNOS7883 is not set
CONFIG_SOC_EXYNOS7884A=y
CONFIG_ARCH_EXYNOS7=y
-# CONFIG_SOC_EXYNOS8890 is not set
-# CONFIG_SOC_EXYNOS8895 is not set
-# CONFIG_SOC_EMULATOR8895 is not set
-# CONFIG_ARCH_EXYNOS8 is not set
+CONFIG_SOC_EXYNOS7885_ANDROID_VERSION_P=y
+# CONFIG_EXYNOS_DTBTOOL
+# CONFIG_EXYNOS_DTBH_PLATFORM_CODE
+# CONFIG_EXYNOS_DTBH_SUBTYPE_CODE
+# CONFIG_EXYNOS_DTBH_PAGE_SIZE=2048
# CONFIG_ZONE_MOVABLE is not set
+
#
# Bus support
#
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
-# CONFIG_PCI_DOMAINS_GENERIC is not set
-# CONFIG_PCI_SYSCALL is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
+CONFIG_PCIEASPM=y
+# CONFIG_PCIEASPM_DEBUG is not set
+CONFIG_PCIEASPM_DEFAULT=y
+# CONFIG_PCIEASPM_POWERSAVE is not set
+# CONFIG_PCIEASPM_PERFORMANCE is not set
+CONFIG_PCIE_PME=y
+# CONFIG_PCIE_DPC is not set
+# CONFIG_PCIE_PTM is not set
+CONFIG_PCI_BUS_ADDR_T_64BIT=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_PRI is not set
+# CONFIG_PCI_PASID is not set
+# CONFIG_HOTPLUG_PCI is not set
+
#
# Kernel Features
@@ -495,30 +464,27 @@ CONFIG_SETEND_EMULATION=y
# ARMv8.1 architectural features
#
# CONFIG_ARM64_HW_AFDBM is not set
-CONFIG_ARM64_PAN=y
+# CONFIG_ARM64_PAN is not set
# CONFIG_ARM64_LSE_ATOMICS is not set
-CONFIG_ARM64_UAO=y
-CONFIG_ARM64_MODULE_CMODEL_LARGE=y
-CONFIG_ARM64_MODULE_PLTS=y
-CONFIG_RELOCATABLE=y
-CONFIG_RANDOMIZE_BASE=y
-CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
+# CONFIG_ARM64_VHE is not set
+
#
# Boot options
#
CONFIG_CMDLINE=""
# CONFIG_EFI is not set
-CONFIG_TIMA=y
-CONFIG_TIMA_LKMAUTH=y
-CONFIG_TIMA_LKM_BLOCK=y
+# CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE is not set
+CONFIG_LOD_SEC=y
+# CONFIG_TIMA is not set
+# CONFIG_TIMA_LKMAUTH is not set
+# CONFIG_TIMA_LKM_BLOCK is not set
# CONFIG_TIMA_LKMAUTH_CODE_PROT is not set
CONFIG_UH=y
-CONFIG_UH_RKP=y
-CONFIG_RKP_KDP=y
-CONFIG_RKP_NS_PROT=y
-CONFIG_RKP_DMAP_PROT=y
-# CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE is not set
+CONFIG_UH_DEBUG=y
+# CONFIG_UH_RKP is not set
+# CONFIG_UH_INFORM is not set
+
#
# Userspace binary formats
@@ -539,6 +505,7 @@ CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
# CONFIG_SUSPEND_SKIP_SYNC is not set
CONFIG_WAKELOCK=y
+# CONFIG_HIBERNATION is not set
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_PM_AUTOSLEEP=y
@@ -558,8 +525,12 @@ CONFIG_PM_GENERIC_DOMAINS=y
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
CONFIG_PM_GENERIC_DOMAINS_OF=y
CONFIG_CPU_PM=y
+# CONFIG_FOTA_LIMIT is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+
#
# CPU Power Management
#
@@ -584,26 +555,27 @@ CONFIG_ARM64_EXYNOS_CPUIDLE=y
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
-# CONFIG_CPU_FREQ_SCHEDUTIL_PERFSTAT_TRIGGER is not set
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_STAT=y
# CONFIG_CPU_FREQ_STAT_DETAILS is not set
-CONFIG_CPU_FREQ_TIMES=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y
+# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
-CONFIG_CPU_INDEX_QOS_CLUSTER0=0
-CONFIG_CPU_INDEX_QOS_CLUSTER1=6
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
-# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set
+# CONFIG_CPU_FREQ_GOV_SCHED is not set
+# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_FREQVAR_TUNE=y
+
#
# CPU frequency scaling drivers
@@ -3913,32 +3885,37 @@ CONFIG_STAGING=y
# Android
#
CONFIG_ASHMEM=y
-CONFIG_ANDROID_TIMED_OUTPUT=y
-CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y
-CONFIG_SYNC=y
-CONFIG_SW_SYNC=y
-CONFIG_SW_SYNC_USER=y
+# CONFIG_ANDROID_VSOC is not set
CONFIG_ANDROID_INTF_ALARM_DEV=y
-# CONFIG_SAMSUNG_FREECESS is not set
+CONFIG_SAMSUNG_FREECESS=y
CONFIG_ION=y
-# CONFIG_ION_TEST is not set
+CONFIG_ION_TEST=y
# CONFIG_ION_DUMMY is not set
+# CONFIG_ION_OF is not set
CONFIG_ION_EXYNOS=y
-CONFIG_ION_EXYNOS_STAT_LOG=y
+# CONFIG_ION_EXYNOS_STAT_LOG is not set
+CONFIG_ION_RBIN_HEAP=y
# CONFIG_ION_EXYNOS_OF is not set
+CONFIG_ANDROID_SWITCH=y
+# CONFIG_FIQ_DEBUGGER is not set
+# CONFIG_FIQ_WATCHDOG is not set
# CONFIG_STAGING_BOARD is not set
-# CONFIG_WIMAX_GDM72XX is not set
# CONFIG_LTE_GDM724X is not set
-# CONFIG_LUSTRE_FS is not set
-# CONFIG_DGAP is not set
+# CONFIG_LNET is not set
+# CONFIG_DGNC is not set
# CONFIG_GS_FPGABOOT is not set
# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
# CONFIG_FB_TFT is not set
# CONFIG_FSL_MC_BUS is not set
-# CONFIG_WILC1000_DRIVER is not set
+# CONFIG_WILC1000_SDIO is not set
+# CONFIG_WILC1000_SPI is not set
# CONFIG_MOST is not set
+# CONFIG_KS7010 is not set
+# CONFIG_GREYBUS is not set
+CONFIG_SEC_EXT=y
+
#
# Samsung TN Features
@@ -4022,7 +3999,7 @@ CONFIG_SEC_ABC=y
#
# Samsung ABC Hub Options
#
-# CONFIG_SEC_ABC_HUB is not set
+CONFIG_SEC_ABC_HUB=y
#
# Samsung ABC Hub Connect Detect Options
@@ -4488,17 +4465,15 @@ CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"
# FPGA Configuration Support
#
# CONFIG_FPGA is not set
-CONFIG_EXYNOS_BTS=y
-CONFIG_EXYNOS7885_BTS=y
-# CONFIG_EXYNOS7885_BTS_VM is not set
+# CONFIG_TEE is not set
CONFIG_TRACE=y
CONFIG_EXYNOS_ITMON=y
-CONFIG_EXYNOS_ITMON_THRESHOLD_CPU=3
CONFIG_EXYNOS_SNAPSHOT=y
CONFIG_EXYNOS_SNAPSHOT_CALLSTACK=4
CONFIG_EXYNOS_SNAPSHOT_IRQ_EXIT=y
CONFIG_EXYNOS_SNAPSHOT_IRQ_EXIT_THRESHOLD=0
# CONFIG_EXYNOS_SNAPSHOT_IRQ_DISABLED is not set
+# CONFIG_EXYNOS_SNAPSHOT_SPINLOCK is not set
CONFIG_EXYNOS_SNAPSHOT_CLK=y
CONFIG_EXYNOS_SNAPSHOT_PMU=y
CONFIG_EXYNOS_SNAPSHOT_FREQ=y
@@ -4508,21 +4483,27 @@ CONFIG_EXYNOS_SNAPSHOT_HRTIMER=y
CONFIG_EXYNOS_SNAPSHOT_REGULATOR=y
CONFIG_EXYNOS_SNAPSHOT_ACPM=y
CONFIG_EXYNOS_SNAPSHOT_THERMAL=y
-# CONFIG_EXYNOS_SNAPSHOT_I2C is not set
-# CONFIG_EXYNOS_SNAPSHOT_SPI is not set
-CONFIG_EXYNOS_SNAPSHOT_PSTORE=y
-CONFIG_EXYNOS_SNAPSHOT_HOOK_LOGGER=y
+CONFIG_EXYNOS_SNAPSHOT_UART=y
+CONFIG_EXYNOS_SNAPSHOT_I2C=y
+CONFIG_EXYNOS_SNAPSHOT_SPI=y
+# CONFIG_EXYNOS_SNAPSHOT_LOGGING_HVC_CALL is not set
CONFIG_EXYNOS_SNAPSHOT_PANIC_REBOOT=y
CONFIG_EXYNOS_SNAPSHOT_WATCHDOG_RESET=y
CONFIG_EXYNOS_SNAPSHOT_CRASH_KEY=y
-CONFIG_EXYNOS_SNAPSHOT_SFRDUMP=y
# CONFIG_EXYNOS_SNAPSHOT_MINIMIZED_MODE is not set
-# CONFIG_EXYNOS_CORESIGHT is not set
+CONFIG_EXYNOS_CORESIGHT=y
+CONFIG_EXYNOS_CORESIGHT_PC_INFO=y
+CONFIG_PC_ITERATION=5
+# CONFIG_EXYNOS_CORESIGHT_MAINTAIN_DBG_REG is not set
+CONFIG_EXYNOS_CONSOLE_DEBUGGER=y
+CONFIG_EXYNOS_CONSOLE_DEBUGGER_INTERFACE=y
# CONFIG_EXYNOS_CORESIGHT_ETM is not set
-# CONFIG_EXYNOS_CORESIGHT_STM is not set
-# CONFIG_EXYNOS_CONSOLE_DEBUGGER is not set
-# CONFIG_TRUSTONIC_TEE is not set
-# CONFIG_VISION_SUPPORT is not set
+CONFIG_VISION_SUPPORT=y
+CONFIG_EXYNOS_IVA=y
+CONFIG_IVA_VER=20
+CONFIG_EXYNOS_SCORE=y
+CONFIG_EXYNOS_SCORE_V2=y
+
#
# USB PD configs
@@ -4647,8 +4628,6 @@ CONFIG_SEC_VIB=y
# CONFIG_MOTOR_S2MU004 is not set
# CONFIG_MOTOR_S2MU106 is not set
# CONFIG_ISA1000 is not set
-CONFIG_FIVE_TEE_DRIVER=y
-CONFIG_FIVE_USE_TZDEV=y
# CONFIG_TEE_DRIVER_DEBUG is not set
# CONFIG_FIVE_EARLY_LOAD_TRUSTED_APP is not set
CONFIG_ICD=y
@@ -4680,9 +4659,7 @@ CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
CONFIG_EXT4_FS_ENCRYPTION=y
-CONFIG_EXT4_PRIVATE_ENCRYPTION=y
# CONFIG_EXT4_DEBUG is not set
-CONFIG_EXT4CRYPT_SDP=y
CONFIG_JBD2=y
# CONFIG_JBD2_DEBUG is not set
CONFIG_FS_MBCACHE=y
@@ -4693,22 +4670,19 @@ CONFIG_FS_MBCACHE=y
# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
# CONFIG_NILFS2_FS is not set
-CONFIG_F2FS_FS=y
-CONFIG_F2FS_STAT_FS=y
-CONFIG_F2FS_FS_XATTR=y
-CONFIG_F2FS_FS_POSIX_ACL=y
-CONFIG_F2FS_FS_SECURITY=y
-CONFIG_F2FS_STRICT_BUG_ON=y
-CONFIG_F2FS_FS_ENCRYPTION=y
-# CONFIG_F2FS_FAULT_INJECTION is not set
+# CONFIG_F2FS_FS is not set
# CONFIG_FS_DAX is not set
CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+# CONFIG_EXPORTFS_BLOCK_OPS is not set
CONFIG_FILE_LOCKING=y
+CONFIG_MANDATORY_FILE_LOCKING=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY_USER=y
CONFIG_FANOTIFY=y
+CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_PRINT_QUOTA_WARNING=y
@@ -4940,7 +4914,6 @@ CONFIG_HAVE_ARCH_KASAN=y
#
CONFIG_LOCKUP_DETECTOR=y
CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU=y
-CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
@@ -4949,10 +4922,11 @@ CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+# CONFIG_WQ_WATCHDOG is not set
# CONFIG_PANIC_ON_OOPS is not set
CONFIG_PANIC_ON_OOPS_VALUE=0
CONFIG_PANIC_TIMEOUT=5
-CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHED_INFO=y
# CONFIG_PANIC_ON_RT_THROTTLING is not set
CONFIG_SCHEDSTATS=y
@@ -4990,13 +4964,17 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_PROVE_RCU is not set
# CONFIG_SPARSE_RCU_POINTER is not set
# CONFIG_TORTURE_TEST is not set
+# CONFIG_RCU_PERF_TEST is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=21
# CONFIG_RCU_TRACE is not set
# CONFIG_RCU_EQS_DEBUG is not set
+# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
@@ -5011,26 +4989,8 @@ CONFIG_GPU_TRACEPOINTS=y
CONFIG_CONTEXT_SWITCH_TRACER=y
CONFIG_TRACING=y
CONFIG_TRACING_SUPPORT=y
-CONFIG_FTRACE=y
-# CONFIG_FUNCTION_TRACER is not set
-# CONFIG_PREEMPTIRQ_EVENTS is not set
-# CONFIG_IRQSOFF_TRACER is not set
-# CONFIG_PREEMPT_TRACER is not set
-# CONFIG_SCHED_TRACER is not set
-CONFIG_ENABLE_DEFAULT_TRACERS=y
-# CONFIG_FTRACE_SYSCALLS is not set
-# CONFIG_TRACER_SNAPSHOT is not set
-CONFIG_BRANCH_PROFILE_NONE=y
-# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
-# CONFIG_PROFILE_ALL_BRANCHES is not set
-# CONFIG_STACK_TRACER is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_PROBE_EVENTS is not set
-# CONFIG_TRACEPOINT_BENCHMARK is not set
-# CONFIG_RING_BUFFER_BENCHMARK is not set
-# CONFIG_RING_BUFFER_STARTUP_TEST is not set
-# CONFIG_TRACE_ENUM_MAP_FILE is not set
-CONFIG_TRACING_EVENTS_GPIO=y
+# CONFIG_FTRACE is not set
+
#
# Runtime Testing
@@ -5041,7 +5001,7 @@ CONFIG_TRACING_EVENTS_GPIO=y
# CONFIG_RBTREE_TEST is not set
# CONFIG_INTERVAL_TREE_TEST is not set
# CONFIG_PERCPU_TEST is not set
-# CONFIG_ATOMIC64_SELFTEST is not set
+CONFIG_ATOMIC64_SELFTEST=y
# CONFIG_TEST_HEXDUMP is not set
# CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_KSTRTOX is not set
@@ -5068,21 +5028,18 @@ CONFIG_STRICT_DEVMEM=y
#
# Samsung Rooting Restriction Feature
#
-CONFIG_SEC_RESTRICT_ROOTING=y
-CONFIG_SEC_RESTRICT_SETUID=y
-CONFIG_SEC_RESTRICT_FORK=y
-CONFIG_SEC_RESTRICT_ROOTING_LOG=y
+# CONFIG_SEC_RESTRICT_ROOTING is not set
# CONFIG_CORESIGHT is not set
+
#
# Security options
#
CONFIG_KEYS=y
-CONFIG_KEYS_COMPAT=y
# CONFIG_PERSISTENT_KEYRINGS is not set
# CONFIG_BIG_KEYS is not set
CONFIG_ENCRYPTED_KEYS=y
-CONFIG_KEYS_SUPPORT_STLOG=y
+# CONFIG_KEY_DH_OPERATIONS is not set
# CONFIG_SECURITY_DMESG_RESTRICT is not set
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
@@ -5095,55 +5052,55 @@ CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y
CONFIG_HARDENED_USERCOPY=y
# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set
+# CONFIG_NO_SDP_BASE is not set
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
-# CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE was 1
CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
CONFIG_SECURITY_SELINUX_DISABLE=y
CONFIG_SECURITY_SELINUX_DEVELOP=y
CONFIG_SECURITY_SELINUX_AVC_STATS=y
-# CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE was 0
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
-# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
CONFIG_SECURITY_SMACK=y
+# CONFIG_SECURITY_SMACK_BRINGUP is not set
+# CONFIG_SECURITY_SMACK_NETFILTER is not set
+# CONFIG_SECURITY_SMACK_APPEND_SIGNALS is not set
CONFIG_SECURITY_TOMOYO=y
+CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY=2048
+CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG=1024
+# CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER is not set
+CONFIG_SECURITY_TOMOYO_POLICY_LOADER="/sbin/tomoyo-init"
+CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER="/sbin/init"
CONFIG_SECURITY_APPARMOR=y
+CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
+# CONFIG_SECURITY_APPARMOR_STATS is not set
+CONFIG_SECURITY_APPARMOR_UNCONFINED_INIT=y
+CONFIG_SECURITY_APPARMOR_HASH=y
+CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y
+# CONFIG_SECURITY_LOADPIN is not set
CONFIG_SECURITY_YAMA=y
-# CONFIG_MST_LDO is not set
-# CONFIG_MST_SUPPORT_GPIO is not set
-# CONFIG_MST_NONSECURE is not set
-# CONFIG_MST_IF_PMIC is not set
-# CONFIG_MFC_CHARGER is not set
-# CONFIG_MST_TEEGRIS is not set
-# CONFIG_MST_LPM_CONTROL is not set
+CONFIG_MST_LDO=y
+CONFIG_MFC_CHARGER=y
CONFIG_INTEGRITY=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_INTEGRITY_AUDIT=y
# CONFIG_IMA is not set
CONFIG_EVM=y
-CONFIG_TZ_ICCC=y
-CONFIG_FIVE=y
-# CONFIG_FIVE_DEBUG is not set
-CONFIG_FIVE_CERT_USER="x509_five_user.der"
-CONFIG_FIVE_DEFAULT_HASH_SHA1=y
-# CONFIG_FIVE_DEFAULT_HASH_SHA256 is not set
-# CONFIG_FIVE_DEFAULT_HASH_SHA512 is not set
-CONFIG_FIVE_DEFAULT_HASH="sha1"
-CONFIG_SECURITY_DEFEX=y
+CONFIG_EVM_ATTR_FSUUID=y
+# CONFIG_EVM_EXTRA_SMACK_XATTRS is not set
+# CONFIG_TZ_ICCC is not set
+# CONFIG_SECURITY_DEFEX is not set
# CONFIG_DEFEX_KERNEL_ONLY is not set
CONFIG_SECURITY_DSMS=y
-CONFIG_PROCA=y
-# CONFIG_GAF_V3 is not set
-# CONFIG_GAF_V4 is not set
-# CONFIG_GAF_V5 is not set
-CONFIG_GAF_V6=y
# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_APPARMOR=y
# CONFIG_DEFAULT_SECURITY_DAC is not set
-CONFIG_DEFAULT_SECURITY="selinux"
-# CONFIG_SDP_ENHANCED is not set
+CONFIG_DEFAULT_SECURITY="apparmor"
CONFIG_CRYPTO=y
+
#
# Crypto core or helper
#
@@ -5275,18 +5232,23 @@ CONFIG_CRYPTO_JITTERENTROPY=y
# CONFIG_CRYPTO_USER_API_RNG is not set
# CONFIG_CRYPTO_USER_API_AEAD is not set
CONFIG_CRYPTO_HASH_INFO=y
+# CONFIG_CRYPTO_POST_DEFERRED_INIT is not set
+CONFIG_CRYPTO_POST_LATE_INIT_SYNC=y
+# CONFIG_CRYPTO_POST_LATE_INIT is not set
CONFIG_CRYPTO_HW=y
# CONFIG_CRYPTO_DEV_S5P is not set
# CONFIG_CRYPTO_DEV_CCP is not set
CONFIG_EXYNOS_SMU=y
CONFIG_EXYNOS_FMP=y
-# CONFIG_EXYNOS_FMP_FIPS is not set
+CONFIG_EXYNOS_FMP_FIPS=y
+CONFIG_NODE_FOR_SELFTEST_FAIL=y
+# CONFIG_PANIC_FOR_SELFTEST_FAIL is not set
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
-CONFIG_PUBLIC_KEY_ALGO_RSA=y
CONFIG_X509_CERTIFICATE_PARSER=y
# CONFIG_PKCS7_MESSAGE_PARSER is not set
+
#
# Certificates for signature checking
#
@@ -5300,9 +5262,10 @@ CONFIG_CRYPTO_AES_ARM64_CE=y
# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set
-# CONFIG_CRYPTO_CRC32_ARM64 is not set
+CONFIG_CRYPTO_CRC32_ARM64=y
CONFIG_BINARY_PRINTF=y
+
#
# Library routines
#
@@ -5315,7 +5278,7 @@ CONFIG_GENERIC_NET_UTILS=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_IO=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
-# CONFIG_CRC_CCITT is not set
+CONFIG_CRC_CCITT=y
CONFIG_CRC16=y
# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
@@ -5328,6 +5291,7 @@ CONFIG_CRC32_SLICEBY8=y
# CONFIG_CRC7 is not set
CONFIG_LIBCRC32C=y
# CONFIG_CRC8 is not set
+CONFIG_XXHASH=y
CONFIG_AUDIT_GENERIC=y
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
CONFIG_AUDIT_COMPAT_GENERIC=y
@@ -5338,6 +5302,8 @@ CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_LZ4_COMPRESS=y
CONFIG_LZ4_DECOMPRESS=y
+CONFIG_ZSTD_COMPRESS=y
+CONFIG_ZSTD_DECOMPRESS=y
CONFIG_XZ_DEC=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
@@ -5363,72 +5329,20 @@ CONFIG_TEXTSEARCH_BM=y
CONFIG_TEXTSEARCH_FSM=y
CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAS_DMA=y
CONFIG_CPU_RMAP=y
CONFIG_DQL=y
CONFIG_NLATTR=y
-CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_CLZ_TAB=y
# CONFIG_CORDIC is not set
# CONFIG_DDR is not set
+# CONFIG_IRQ_POLL is not set
CONFIG_MPILIB=y
CONFIG_SIGNATURE=y
CONFIG_LIBFDT=y
CONFIG_OID_REGISTRY=y
# CONFIG_SG_SPLIT is not set
+CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_SG_CHAIN=y
-# CONFIG_FPSIMD_CORRUPTION_DETECT is not set
-CONFIG_CGROUP_MEM_RES_CTLR=y
-CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
-CONFIG_CGROUP_MEM_RES_CTLR_KMEM=y
-CONFIG_RTC_DRV_CMOS=y
-CONFIG_IPC_NS=y
-CONFIG_DEBUG_RODATA=y
-CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
-CONFIG_VT_CONSOLE=y
-CONFIG_DEFAULT_SECURITY_APPARMOR=y
-CONFIG_SECURITY_APPARMOR_HASH=y
-CONFIG_SECURITY_APPARMOR_UNCONFINED_INIT=y
-CONFIG_SECURITY_YAMA_STACKED=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_NETFILTER_TPROXY=y
-CONFIG_NETFILTER_XT_TARGET_LED=y
-CONFIG_IP6_NF_QUEUE=y
-CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
-CONFIG_SUSPEND_TIME=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-# CONFIG_CGROUP_SCHEDTUNE is not set
-# CONFIG_NETPRIO_CGROUP is not set
-# CONFIG_USB_CONFIGFS_QCRNDIS is not set
-# CONFIG_USB_CONFIGFS_F_GSI is not set
-# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
-# CONFIG_DEFAULT_SECURITY_YAMA is not set
-# CONFIG_DEFAULT_SECURITY_SMACK is not set
-# CONFIG_SECURITY_APPARMOR_STATS is not set
-# CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER is not set
-# CONFIG_BT_HCIBTUSB is not set
-# CONFIG_BT_HCIBTSDIO is not set
-# CONFIG_BT_HCIUART is not set
-# CONFIG_BT_HCIBCM203X is not set
-# CONFIG_BT_HCIBPA10X is not set
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIVHCI is not set
-# CONFIG_BT_MRVL is not set
-# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
-# CONFIG_ARM_UNWIND is not set
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-# CONFIG_SPEAKUP is not set
-# CONFIG_CIFS_UPCALL is not set
-# CONFIG_CIFS_DFS_UPCALL is not set
-CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
-CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY=2048
-CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG=1024
-CONFIG_SECURITY_TOMOYO_POLICY_LOADER="/sbin/tomoyo-init"
-CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER="/sbin/init"
-CONFIG_EVM_HMAC_VERSION=2
+CONFIG_SBITMAP=y
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
old mode 100755
new mode 100644
index d4e96cc1..499c8362
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -1,369 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
/*
- *
* drivers/staging/android/ion/ion.c
*
* Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
*
*/
-#include
+#include
+#include
#include
+#include
#include
+#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
-#include
#include
#include
+#include
#include
-#include
+#include
#include
+#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "ion.h"
-#include
-#include
-
+#include
+#include
+#include
+#include
#define CREATE_TRACE_POINTS
-#include "ion_priv.h"
-#include "compat_ion.h"
-
-/**
- * struct ion_device - the metadata of the ion device node
- * @dev: the actual misc device
- * @buffers: an rb tree of all the existing buffers
- * @buffer_lock: lock protecting the tree of buffers
- * @lock: rwsem protecting the tree of heaps and clients
- * @heaps: list of all the heaps in the system
- * @user_clients: list of all the clients created from userspace
- */
-struct ion_device {
- struct miscdevice dev;
- struct rb_root buffers;
- struct mutex buffer_lock;
- struct rw_semaphore lock;
- struct plist_head heaps;
- long (*custom_ioctl)(struct ion_client *client, unsigned int cmd,
- unsigned long arg);
- struct rb_root clients;
- struct dentry *debug_root;
- struct dentry *heaps_debug_root;
- struct dentry *clients_debug_root;
-
-#ifdef CONFIG_ION_EXYNOS_STAT_LOG
- /* event log */
- struct dentry *buffer_debug_file;
- struct dentry *event_debug_file;
- struct ion_eventlog eventlog[ION_EVENT_LOG_MAX];
- atomic_t event_idx;
-#endif
-};
-
-/**
- * struct ion_client - a process/hw block local address space
- * @node: node in the tree of all clients
- * @dev: backpointer to ion device
- * @handles: an rb tree of all the handles in this client
- * @idr: an idr space for allocating handle ids
- * @lock: lock protecting the tree of handles
- * @name: used for debugging
- * @display_name: used for debugging (unique version of @name)
- * @display_serial: used for debugging (to make display_name unique)
- * @task: used for debugging
- *
- * A client represents a list of buffers this client may access.
- * The mutex stored here is used to protect both handles tree
- * as well as the handles themselves, and should be held while modifying either.
- */
-struct ion_client {
- struct rb_node node;
- struct ion_device *dev;
- struct rb_root handles;
- struct idr idr;
- struct mutex lock;
- const char *name;
- char *display_name;
- int display_serial;
- struct task_struct *task;
- pid_t pid;
- struct dentry *debug_root;
-};
-
-/**
- * ion_handle - a client local reference to a buffer
- * @ref: reference count
- * @client: back pointer to the client the buffer resides in
- * @buffer: pointer to the buffer
- * @node: node in the client's handle rbtree
- * @kmap_cnt: count of times this client has mapped to kernel
- * @id: client-unique id allocated by client->idr
- *
- * Modifications to node, map_cnt or mapping should be protected by the
- * lock in the client. Other fields are never changed after initialization.
- */
-struct ion_handle {
- struct kref ref;
- struct ion_client *client;
- struct ion_buffer *buffer;
- struct rb_node node;
- unsigned int kmap_cnt;
- int id;
-};
-
-struct ion_device *g_idev;
+#include
+#include
-static inline struct page *ion_buffer_page(struct page *page)
-{
- return (struct page *)((unsigned long)page & ~(1UL));
-}
-
-static inline bool ion_buffer_page_is_dirty(struct page *page)
-{
- return !!((unsigned long)page & 1UL);
-}
-
-static inline void ion_buffer_page_dirty(struct page **page)
-{
- *page = (struct page *)((unsigned long)(*page) | 1UL);
-}
+#include "ion.h"
+#include "ion_secure_util.h"
-static inline void ion_buffer_page_clean(struct page **page)
-{
- *page = (struct page *)((unsigned long)(*page) & ~(1UL));
-}
+static struct ion_device *internal_dev;
-void ion_debug_heap_usage_show(struct ion_heap *heap)
+int ion_walk_heaps(int heap_id, enum ion_heap_type type, void *data,
+ int (*f)(struct ion_heap *heap, void *data))
{
- struct scatterlist *sg;
- struct sg_table *table;
- struct rb_node *n;
- struct page *page;
- struct ion_device *dev = heap->dev;
- int i;
- ion_phys_addr_t paddr;
-
- /* show the usage for only contiguous buffer */
- if ((heap->type != ION_HEAP_TYPE_CARVEOUT)
- && (heap->type != ION_HEAP_TYPE_DMA))
- return;
-
- pr_err("[HEAP %16s (id %4d) DETAIL USAGE]\n", heap->name, heap->id);
-
- mutex_lock(&dev->buffer_lock);
- for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
- struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
- node);
- if (buffer->heap->id != heap->id)
+ int ret_val = 0;
+ struct ion_heap *heap;
+ struct ion_device *dev = internal_dev;
+ /*
+ * traverse the list of heaps available in this system
+ * and find the heap that is specified.
+ */
+ down_write(&dev->lock);
+ plist_for_each_entry(heap, &dev->heaps, node) {
+ if (ION_HEAP(heap->id) != heap_id ||
+ type != heap->type)
continue;
- table = buffer->sg_table;
- for_each_sg(table->sgl, sg, table->nents, i) {
- page = sg_page(sg);
- paddr = PFN_PHYS(page_to_pfn(page));
- pr_err("[%16lx--%16lx] %16zu\n",
- paddr, paddr + sg->length, buffer->size);
- }
- }
- mutex_unlock(&dev->buffer_lock);
-}
-
-#ifdef CONFIG_ION_EXYNOS_STAT_LOG
-static inline void ION_EVENT_ALLOC(struct ion_buffer *buffer, ktime_t begin)
-{
- struct ion_device *dev = buffer->dev;
- int idx = atomic_inc_return(&dev->event_idx);
- struct ion_eventlog *log = &dev->eventlog[idx % ION_EVENT_LOG_MAX];
- struct ion_event_alloc *data = &log->data.alloc;
-
- log->type = ION_EVENT_TYPE_ALLOC;
- log->begin = begin;
- log->done = ktime_get();
- data->id = buffer;
- data->size = buffer->size;
- data->flags = buffer->flags;
- strlcpy(data->heapname, buffer->heap->name, sizeof(data->heapname));
-}
-
-static inline void ION_EVENT_FREE(struct ion_buffer *buffer, ktime_t begin)
-{
- struct ion_device *dev = buffer->dev;
- int idx = atomic_inc_return(&dev->event_idx) % ION_EVENT_LOG_MAX;
- struct ion_eventlog *log = &dev->eventlog[idx];
- struct ion_event_free *data = &log->data.free;
-
- log->type = ION_EVENT_TYPE_FREE;
- log->begin = begin;
- log->done = ktime_get();
- data->id = buffer;
- data->size = buffer->size;
- data->shrinker = (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE);
- strlcpy(data->heapname, buffer->heap->name, sizeof(data->heapname));
-}
-
-static inline void ION_EVENT_MMAP(struct ion_buffer *buffer, ktime_t begin)
-{
- struct ion_device *dev = buffer->dev;
- int idx = atomic_inc_return(&dev->event_idx) % ION_EVENT_LOG_MAX;
- struct ion_eventlog *log = &dev->eventlog[idx];
- struct ion_event_mmap *data = &log->data.mmap;
-
- log->type = ION_EVENT_TYPE_MMAP;
- log->begin = begin;
- log->done = ktime_get();
- data->id = buffer;
- data->size = buffer->size;
- strlcpy(data->heapname, buffer->heap->name, sizeof(data->heapname));
-}
-
-void ION_EVENT_SHRINK(struct ion_device *dev, size_t size)
-{
- int idx = atomic_inc_return(&dev->event_idx) % ION_EVENT_LOG_MAX;
- struct ion_eventlog *log = &dev->eventlog[idx];
-
- log->type = ION_EVENT_TYPE_SHRINK;
- log->begin = ktime_get();
- log->done = ktime_set(0, 0);
- log->data.shrink.size = size;
-}
-
-void ION_EVENT_CLEAR(struct ion_buffer *buffer, ktime_t begin)
-{
- struct ion_device *dev = buffer->dev;
- int idx = atomic_inc_return(&dev->event_idx) % ION_EVENT_LOG_MAX;
- struct ion_eventlog *log = &dev->eventlog[idx];
- struct ion_event_clear *data = &log->data.clear;
-
- log->type = ION_EVENT_TYPE_CLEAR;
- log->begin = begin;
- log->done = ktime_get();
- data->id = buffer;
- data->size = buffer->size;
- data->flags = buffer->flags;
- strlcpy(data->heapname, buffer->heap->name, sizeof(data->heapname));
-}
-
-static struct ion_task *ion_buffer_task_lookup(struct ion_buffer *buffer,
- struct device *master)
-{
- bool found = false;
- struct ion_task *task;
-
- list_for_each_entry(task, &buffer->master_list, list) {
- if (task->master == master) {
- found = true;
- break;
- }
- }
-
- return found ? task : NULL;
-}
-
-static void ion_buffer_set_task_info(struct ion_buffer *buffer)
-{
- INIT_LIST_HEAD(&buffer->master_list);
- get_task_comm(buffer->task_comm, current->group_leader);
- get_task_comm(buffer->thread_comm, current);
- buffer->pid = task_pid_nr(current->group_leader);
- buffer->tid = task_pid_nr(current);
-}
-
-static void ion_buffer_task_add(struct ion_buffer *buffer,
- struct device *master)
-{
- struct ion_task *task;
-
- task = ion_buffer_task_lookup(buffer, master);
- if (!task) {
- task = kzalloc(sizeof(*task), GFP_KERNEL);
- if (task) {
- task->master = master;
- kref_init(&task->ref);
- list_add_tail(&task->list, &buffer->master_list);
- }
- } else {
- kref_get(&task->ref);
- }
-}
-
-static void ion_buffer_task_add_lock(struct ion_buffer *buffer,
- struct device *master)
-{
- mutex_lock(&buffer->lock);
- ion_buffer_task_add(buffer, master);
- mutex_unlock(&buffer->lock);
-}
-
-static void __ion_buffer_task_remove(struct kref *kref)
-{
- struct ion_task *task = container_of(kref, struct ion_task, ref);
-
- list_del(&task->list);
- kfree(task);
-}
-
-static void ion_buffer_task_remove(struct ion_buffer *buffer,
- struct device *master)
-{
- struct ion_task *task, *tmp;
-
- list_for_each_entry_safe(task, tmp, &buffer->master_list, list) {
- if (task->master == master) {
- kref_put(&task->ref, __ion_buffer_task_remove);
- break;
- }
+ ret_val = f(heap, data);
+ break;
}
+ up_write(&dev->lock);
+ return ret_val;
}
+EXPORT_SYMBOL(ion_walk_heaps);
-static void ion_buffer_task_remove_lock(struct ion_buffer *buffer,
- struct device *master)
-{
- mutex_lock(&buffer->lock);
- ion_buffer_task_remove(buffer, master);
- mutex_unlock(&buffer->lock);
-}
-
-static void ion_buffer_task_remove_all(struct ion_buffer *buffer)
+bool ion_buffer_cached(struct ion_buffer *buffer)
{
- struct ion_task *task, *tmp;
-
- mutex_lock(&buffer->lock);
- list_for_each_entry_safe(task, tmp, &buffer->master_list, list) {
- list_del(&task->list);
- kfree(task);
- }
- mutex_unlock(&buffer->lock);
+ return !!(buffer->flags & ION_FLAG_CACHED);
}
-#else
-#define ION_EVENT_ALLOC(buffer, begin) do { } while (0)
-#define ION_EVENT_FREE(buffer, begin) do { } while (0)
-#define ION_EVENT_MMAP(buffer, begin) do { } while (0)
-#define ion_buffer_set_task_info(buffer) do { } while (0)
-#define ion_buffer_task_add(buffer, master) do { } while (0)
-#define ion_buffer_task_add_lock(buffer, master) do { } while (0)
-#define ion_buffer_task_remove(buffer, master) do { } while (0)
-#define ion_buffer_task_remove_lock(buffer, master) do { } while (0)
-#define ion_buffer_task_remove_all(buffer) do { } while (0)
-#endif
/* this function should only be called while dev->lock is held */
static void ion_buffer_add(struct ion_device *dev,
@@ -372,6 +78,7 @@ static void ion_buffer_add(struct ion_device *dev,
struct rb_node **p = &dev->buffers.rb_node;
struct rb_node *parent = NULL;
struct ion_buffer *entry;
+ struct task_struct *task;
while (*p) {
parent = *p;
@@ -386,99 +93,81 @@ static void ion_buffer_add(struct ion_device *dev,
BUG();
}
}
+ task = current;
+ get_task_comm(buffer->task_comm, task->group_leader);
+ get_task_comm(buffer->thread_comm, task);
+ buffer->pid = task_pid_nr(task->group_leader);
+ buffer->tid = task_pid_nr(task);
rb_link_node(&buffer->node, parent, p);
rb_insert_color(&buffer->node, &dev->buffers);
-
- ion_buffer_set_task_info(buffer);
- ion_buffer_task_add(buffer, dev->dev.this_device);
}
+static void ion_debug_heap_usage_show(struct ion_heap *heap);
+
/* this function should only be called while dev->lock is held */
static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
- struct ion_device *dev,
- unsigned long len,
- unsigned long align,
- unsigned long flags)
+ struct ion_device *dev,
+ unsigned long len,
+ unsigned long flags)
{
struct ion_buffer *buffer;
struct sg_table *table;
- struct scatterlist *sg;
- int i, ret;
+ int ret;
long nr_alloc_cur, nr_alloc_peak;
- buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL);
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
buffer->heap = heap;
buffer->flags = flags;
+ buffer->dev = dev;
buffer->size = len;
- kref_init(&buffer->ref);
- ret = heap->ops->allocate(heap, buffer, len, align, flags);
+ ret = heap->ops->allocate(heap, buffer, len, flags);
if (ret) {
if (!(heap->flags & ION_HEAP_FLAG_DEFER_FREE))
goto err2;
+ if (ret == -EINTR)
+ goto err2;
+
ion_heap_freelist_drain(heap, 0);
- ret = heap->ops->allocate(heap, buffer, len, align,
- flags);
+ ret = heap->ops->allocate(heap, buffer, len, flags);
if (ret)
goto err2;
}
- buffer->dev = dev;
-
- table = heap->ops->map_dma(heap, buffer);
- if (WARN_ONCE(table == NULL,
- "heap->ops->map_dma should return ERR_PTR on error"))
- table = ERR_PTR(-EINVAL);
- if (IS_ERR(table)) {
+ if (!buffer->sg_table) {
+ WARN_ONCE(1, "This heap needs to set the sgtable");
ret = -EINVAL;
goto err1;
}
- buffer->sg_table = table;
- if (ion_buffer_fault_user_mappings(buffer)) {
- int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
- struct scatterlist *sg;
- int i, j, k = 0;
+ table = buffer->sg_table;
+ INIT_LIST_HEAD(&buffer->attachments);
+ INIT_LIST_HEAD(&buffer->vmas);
+ mutex_init(&buffer->lock);
- buffer->pages = vmalloc(sizeof(struct page *) * num_pages);
- if (!buffer->pages) {
- ret = -ENOMEM;
- goto err;
- }
+ if (IS_ENABLED(CONFIG_ION_FORCE_DMA_SYNC)) {
+ int i;
+ struct scatterlist *sg;
+ /*
+ * this will set up dma addresses for the sglist -- it is not
+ * technically correct as per the dma api -- a specific
+ * device isn't really taking ownership here. However, in
+ * practice on our systems the only dma_address space is
+ * physical addresses.
+ */
for_each_sg(table->sgl, sg, table->nents, i) {
- struct page *page = sg_page(sg);
-
- for (j = 0; j < sg->length / PAGE_SIZE; j++)
- buffer->pages[k++] = page++;
+ sg_dma_address(sg) = sg_phys(sg);
+ sg_dma_len(sg) = sg->length;
}
}
- buffer->dev = dev;
- buffer->size = len;
- INIT_LIST_HEAD(&buffer->vmas);
- INIT_LIST_HEAD(&buffer->iovas);
- mutex_init(&buffer->lock);
- /*
- * this will set up dma addresses for the sglist -- it is not
- * technically correct as per the dma api -- a specific
- * device isn't really taking ownership here. However, in practice on
- * our systems the only dma_address space is physical addresses.
- * Additionally, we can't afford the overhead of invalidating every
- * allocation via dma_map_sg. The implicit contract here is that
- * memory coming from the heaps is ready for dma, ie if it has a
- * cached mapping that mapping has been invalidated
- */
- for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) {
- sg_dma_address(sg) = sg_phys(sg);
- sg_dma_len(sg) = sg->length;
- }
mutex_lock(&dev->buffer_lock);
ion_buffer_add(dev, buffer);
mutex_unlock(&dev->buffer_lock);
@@ -488,776 +177,257 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
atomic_long_set(&heap->total_allocated_peak, nr_alloc_cur);
return buffer;
-err:
- heap->ops->unmap_dma(heap, buffer);
err1:
heap->ops->free(buffer);
err2:
kfree(buffer);
+ ion_debug_heap_usage_show(heap);
return ERR_PTR(ret);
}
void ion_buffer_destroy(struct ion_buffer *buffer)
{
- struct ion_iovm_map *iovm_map;
- struct ion_iovm_map *tmp;
-
- ION_EVENT_BEGIN();
- trace_ion_free_start((unsigned long) buffer, buffer->size,
- buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE);
-
- if (WARN_ON(buffer->kmap_cnt > 0))
+ if (buffer->kmap_cnt > 0) {
+ pr_warn_ratelimited("ION client likely missing a call to dma_buf_kunmap or dma_buf_vunmap\n");
buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
-
- list_for_each_entry_safe(iovm_map, tmp, &buffer->iovas, list) {
- iovmm_unmap(iovm_map->dev, iovm_map->iova);
- list_del(&iovm_map->list);
- kfree(iovm_map);
}
-
- atomic_long_sub(buffer->size, &buffer->heap->total_allocated);
- buffer->heap->ops->unmap_dma(buffer->heap, buffer);
buffer->heap->ops->free(buffer);
- vfree(buffer->pages);
-
- ion_buffer_task_remove_all(buffer);
- ION_EVENT_FREE(buffer, ION_EVENT_DONE());
- trace_ion_free_end((unsigned long) buffer, buffer->size,
- buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE);
kfree(buffer);
}
-static void _ion_buffer_destroy(struct kref *kref)
+static void _ion_buffer_destroy(struct ion_buffer *buffer)
{
- struct ion_buffer *buffer = container_of(kref, struct ion_buffer, ref);
struct ion_heap *heap = buffer->heap;
struct ion_device *dev = buffer->dev;
+ msm_dma_buf_freed(buffer);
+
mutex_lock(&dev->buffer_lock);
rb_erase(&buffer->node, &dev->buffers);
mutex_unlock(&dev->buffer_lock);
+ atomic_long_sub(buffer->size, &buffer->heap->total_allocated);
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
ion_heap_freelist_add(heap, buffer);
else
ion_buffer_destroy(buffer);
}
-static void ion_buffer_get(struct ion_buffer *buffer)
+static void *ion_buffer_kmap_get(struct ion_buffer *buffer)
{
- kref_get(&buffer->ref);
-}
+ void *vaddr;
-static int ion_buffer_put(struct ion_buffer *buffer)
-{
- return kref_put(&buffer->ref, _ion_buffer_destroy);
+ if (buffer->kmap_cnt) {
+ buffer->kmap_cnt++;
+ return buffer->vaddr;
+ }
+ vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer);
+ if (WARN_ONCE(!vaddr,
+ "heap->ops->map_kernel should return ERR_PTR on error"))
+ return ERR_PTR(-EINVAL);
+ if (IS_ERR(vaddr))
+ return vaddr;
+ buffer->vaddr = vaddr;
+ buffer->kmap_cnt++;
+ return vaddr;
}
-static void ion_buffer_add_to_handle(struct ion_buffer *buffer)
+static void ion_buffer_kmap_put(struct ion_buffer *buffer)
{
- mutex_lock(&buffer->lock);
- if (buffer->handle_count == 0)
- atomic_long_add(buffer->size, &buffer->heap->total_handles);
+ if (buffer->kmap_cnt == 0) {
+ pr_warn_ratelimited("ION client likely missing a call to dma_buf_kmap or dma_buf_vmap, pid:%d\n",
+ current->pid);
+ return;
+ }
- buffer->handle_count++;
- mutex_unlock(&buffer->lock);
+ buffer->kmap_cnt--;
+ if (!buffer->kmap_cnt) {
+ buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
+ buffer->vaddr = NULL;
+ }
}
-static void ion_buffer_remove_from_handle(struct ion_buffer *buffer)
+static struct sg_table *dup_sg_table(struct sg_table *table)
{
- /*
- * when a buffer is removed from a handle, if it is not in
- * any other handles, copy the taskcomm and the pid of the
- * process it's being removed from into the buffer. At this
- * point there will be no way to track what processes this buffer is
- * being used by, it only exists as a dma_buf file descriptor.
- * The taskcomm and pid can provide a debug hint as to where this fd
- * is in the system
- */
- mutex_lock(&buffer->lock);
- buffer->handle_count--;
- BUG_ON(buffer->handle_count < 0);
- if (!buffer->handle_count) {
- struct task_struct *task;
-
- task = current->group_leader;
- get_task_comm(buffer->task_comm, task);
- buffer->pid = task_pid_nr(task);
+ struct sg_table *new_table;
+ int ret, i;
+ struct scatterlist *sg, *new_sg;
+
+ new_table = kzalloc(sizeof(*new_table), GFP_KERNEL);
+ if (!new_table)
+ return ERR_PTR(-ENOMEM);
+
+ ret = sg_alloc_table(new_table, table->nents, GFP_KERNEL);
+ if (ret) {
+ kfree(new_table);
+ return ERR_PTR(-ENOMEM);
}
- atomic_long_sub(buffer->size, &buffer->heap->total_handles);
- mutex_unlock(&buffer->lock);
+
+ new_sg = new_table->sgl;
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ memcpy(new_sg, sg, sizeof(*sg));
+ sg_dma_address(new_sg) = 0;
+ sg_dma_len(new_sg) = 0;
+ new_sg = sg_next(new_sg);
+ }
+
+ return new_table;
}
-static bool ion_handle_validate(struct ion_client *client,
- struct ion_handle *handle)
+static void free_duped_table(struct sg_table *table)
{
- WARN_ON(!mutex_is_locked(&client->lock));
- return idr_find(&client->idr, handle->id) == handle;
+ sg_free_table(table);
+ kfree(table);
}
-static struct ion_handle *ion_handle_create(struct ion_client *client,
- struct ion_buffer *buffer)
+struct ion_dma_buf_attachment {
+ struct device *dev;
+ struct sg_table *table;
+ struct list_head list;
+ bool dma_mapped;
+};
+
+static int ion_dma_buf_attach(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attachment)
{
- struct ion_handle *handle;
+ struct ion_dma_buf_attachment *a;
+ struct sg_table *table;
+ struct ion_buffer *buffer = dmabuf->priv;
- handle = kzalloc(sizeof(struct ion_handle), GFP_KERNEL);
- if (!handle)
- return ERR_PTR(-ENOMEM);
- kref_init(&handle->ref);
- RB_CLEAR_NODE(&handle->node);
- handle->client = client;
- ion_buffer_get(buffer);
- ion_buffer_add_to_handle(buffer);
- handle->buffer = buffer;
-
- return handle;
-}
+ a = kzalloc(sizeof(*a), GFP_KERNEL);
+ if (!a)
+ return -ENOMEM;
+
+ table = dup_sg_table(buffer->sg_table);
+ if (IS_ERR(table)) {
+ kfree(a);
+ return -ENOMEM;
+ }
-static void ion_handle_kmap_put(struct ion_handle *);
+ a->table = table;
+ a->dev = attachment->dev;
+ a->dma_mapped = false;
+ INIT_LIST_HEAD(&a->list);
-static void ion_handle_destroy(struct kref *kref)
-{
- struct ion_handle *handle = container_of(kref, struct ion_handle, ref);
- struct ion_client *client = handle->client;
- struct ion_buffer *buffer = handle->buffer;
+ attachment->priv = a;
mutex_lock(&buffer->lock);
- while (handle->kmap_cnt)
- ion_handle_kmap_put(handle);
+ list_add(&a->list, &buffer->attachments);
mutex_unlock(&buffer->lock);
- idr_remove(&client->idr, handle->id);
- if (!RB_EMPTY_NODE(&handle->node))
- rb_erase(&handle->node, &client->handles);
-
- ion_buffer_remove_from_handle(buffer);
- ion_buffer_put(buffer);
-
- kfree(handle);
+ return 0;
}
-struct ion_buffer *ion_handle_buffer(struct ion_handle *handle)
+static void ion_dma_buf_detatch(struct dma_buf *dmabuf,
+ struct dma_buf_attachment *attachment)
{
- return handle->buffer;
-}
+ struct ion_dma_buf_attachment *a = attachment->priv;
+ struct ion_buffer *buffer = dmabuf->priv;
-static void ion_handle_get(struct ion_handle *handle)
-{
- kref_get(&handle->ref);
-}
+ mutex_lock(&buffer->lock);
+ list_del(&a->list);
+ mutex_unlock(&buffer->lock);
+ free_duped_table(a->table);
-/* Must hold the client lock */
-static struct ion_handle *ion_handle_get_check_overflow(
- struct ion_handle *handle)
-{
- if (atomic_read(&handle->ref.refcount) + 1 == 0)
- return ERR_PTR(-EOVERFLOW);
- ion_handle_get(handle);
- return handle;
+ kfree(a);
}
-static int ion_handle_put_nolock(struct ion_handle *handle)
+static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction direction)
{
- int ret;
-
- ret = kref_put(&handle->ref, ion_handle_destroy);
+ struct ion_dma_buf_attachment *a = attachment->priv;
+ struct sg_table *table;
+ int count, map_attrs;
+ struct ion_buffer *buffer = attachment->dmabuf->priv;
- return ret;
-}
+ table = a->table;
-int ion_handle_put(struct ion_handle *handle)
-{
- struct ion_client *client = handle->client;
- bool valid_handle;
- int ret;
+ map_attrs = attachment->dma_map_attrs;
+ if (!(buffer->flags & ION_FLAG_CACHED) ||
+ !hlos_accessible_buffer(buffer))
+ map_attrs |= DMA_ATTR_SKIP_CPU_SYNC;
- mutex_lock(&client->lock);
- valid_handle = ion_handle_validate(client, handle);
+ mutex_lock(&buffer->lock);
+ if (map_attrs & DMA_ATTR_SKIP_CPU_SYNC)
+ trace_ion_dma_map_cmo_skip(attachment->dev,
+ attachment->dmabuf->name,
+ ion_buffer_cached(buffer),
+ hlos_accessible_buffer(buffer),
+ attachment->dma_map_attrs,
+ direction);
+ else
+ trace_ion_dma_map_cmo_apply(attachment->dev,
+ attachment->dmabuf->name,
+ ion_buffer_cached(buffer),
+ hlos_accessible_buffer(buffer),
+ attachment->dma_map_attrs,
+ direction);
+
+ if (map_attrs & DMA_ATTR_DELAYED_UNMAP) {
+ count = msm_dma_map_sg_attrs(attachment->dev, table->sgl,
+ table->nents, direction,
+ attachment->dmabuf, map_attrs);
+ } else {
+ count = dma_map_sg_attrs(attachment->dev, table->sgl,
+ table->nents, direction,
+ map_attrs);
+ }
- if (!valid_handle) {
- WARN(1, "%s: invalid handle passed to free.\n", __func__);
- mutex_unlock(&client->lock);
- return -EINVAL;
+ if (count <= 0) {
+ mutex_unlock(&buffer->lock);
+ return ERR_PTR(-ENOMEM);
}
- ret = ion_handle_put_nolock(handle);
- mutex_unlock(&client->lock);
- return ret;
+ a->dma_mapped = true;
+ mutex_unlock(&buffer->lock);
+ return table;
}
-static struct ion_handle *ion_handle_lookup(struct ion_client *client,
- struct ion_buffer *buffer)
+static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *table,
+ enum dma_data_direction direction)
{
- struct rb_node *n = client->handles.rb_node;
+ int map_attrs;
+ struct ion_buffer *buffer = attachment->dmabuf->priv;
+ struct ion_dma_buf_attachment *a = attachment->priv;
- while (n) {
- struct ion_handle *entry = rb_entry(n, struct ion_handle, node);
+ map_attrs = attachment->dma_map_attrs;
+ if (!(buffer->flags & ION_FLAG_CACHED) ||
+ !hlos_accessible_buffer(buffer))
+ map_attrs |= DMA_ATTR_SKIP_CPU_SYNC;
- if (buffer < entry->buffer)
- n = n->rb_left;
- else if (buffer > entry->buffer)
- n = n->rb_right;
- else
- return entry;
- }
- return ERR_PTR(-EINVAL);
+ mutex_lock(&buffer->lock);
+ if (map_attrs & DMA_ATTR_SKIP_CPU_SYNC)
+ trace_ion_dma_unmap_cmo_skip(attachment->dev,
+ attachment->dmabuf->name,
+ ion_buffer_cached(buffer),
+ hlos_accessible_buffer(buffer),
+ attachment->dma_map_attrs,
+ direction);
+ else
+ trace_ion_dma_unmap_cmo_apply(attachment->dev,
+ attachment->dmabuf->name,
+ ion_buffer_cached(buffer),
+ hlos_accessible_buffer(buffer),
+ attachment->dma_map_attrs,
+ direction);
+
+ if (map_attrs & DMA_ATTR_DELAYED_UNMAP)
+ msm_dma_unmap_sg_attrs(attachment->dev, table->sgl,
+ table->nents, direction,
+ attachment->dmabuf,
+ map_attrs);
+ else
+ dma_unmap_sg_attrs(attachment->dev, table->sgl, table->nents,
+ direction, map_attrs);
+ a->dma_mapped = false;
+ mutex_unlock(&buffer->lock);
}
-static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
- int id)
+void ion_pages_sync_for_device(struct device *dev, struct page *page,
+ size_t size, enum dma_data_direction dir)
{
- struct ion_handle *handle;
-
- handle = idr_find(&client->idr, id);
- if (handle)
- return ion_handle_get_check_overflow(handle);
-
- return ERR_PTR(-EINVAL);
-}
-
-static int ion_handle_add(struct ion_client *client, struct ion_handle *handle)
-{
- int id;
- struct rb_node **p = &client->handles.rb_node;
- struct rb_node *parent = NULL;
- struct ion_handle *entry;
-
- id = idr_alloc(&client->idr, handle, 1, 0, GFP_KERNEL);
- if (id < 0) {
- pr_err("%s: Fail to get bad id (ret %d)\n", __func__, id);
- return id;
- }
-
- handle->id = id;
-
- while (*p) {
- parent = *p;
- entry = rb_entry(parent, struct ion_handle, node);
-
- if (handle->buffer < entry->buffer)
- p = &(*p)->rb_left;
- else if (handle->buffer > entry->buffer)
- p = &(*p)->rb_right;
- else
- WARN(1, "%s: buffer already found.", __func__);
- }
-
- rb_link_node(&handle->node, parent, p);
- rb_insert_color(&handle->node, &client->handles);
-
- return 0;
-}
-
-unsigned int ion_parse_heap_id(unsigned int heap_id_mask, unsigned int flags);
-
-static struct ion_handle *__ion_alloc(struct ion_client *client, size_t len,
- size_t align, unsigned int heap_id_mask,
- unsigned int flags, bool grab_handle)
-{
- struct ion_handle *handle;
- struct ion_device *dev = client->dev;
- struct ion_buffer *buffer = NULL;
- struct ion_heap *heap;
- int ret;
-
- ION_EVENT_BEGIN();
- trace_ion_alloc_start(client->name, 0, len, align, heap_id_mask, flags);
-
- pr_debug("%s: len %zu align %zu heap_id_mask %u flags %x\n", __func__,
- len, align, heap_id_mask, flags);
- /*
- * traverse the list of heaps available in this system in priority
- * order. If the heap type is supported by the client, and matches the
- * request of the caller allocate from it. Repeat until allocate has
- * succeeded or all heaps have been tried
- */
- len = PAGE_ALIGN(len);
- if (WARN_ON(!len)) {
- trace_ion_alloc_fail(client->name, EINVAL, len,
- align, heap_id_mask, flags);
- return ERR_PTR(-EINVAL);
- }
-
- heap_id_mask = ion_parse_heap_id(heap_id_mask, flags);
- if (heap_id_mask == 0) {
- trace_ion_alloc_fail(client->name, EINVAL, len,
- align, heap_id_mask, flags);
- return ERR_PTR(-EINVAL);
- }
-
- down_read(&dev->lock);
- plist_for_each_entry(heap, &dev->heaps, node) {
- /* if the caller didn't specify this heap id */
- if (!((1 << heap->id) & heap_id_mask))
- continue;
- buffer = ion_buffer_create(heap, dev, len, align, flags);
- if (!IS_ERR(buffer))
- break;
- }
- up_read(&dev->lock);
-
- if (buffer == NULL) {
- trace_ion_alloc_fail(client->name, ENODEV, len,
- align, heap_id_mask, flags);
- return ERR_PTR(-ENODEV);
- }
-
- if (IS_ERR(buffer)) {
- trace_ion_alloc_fail(client->name, PTR_ERR(buffer),
- len, align, heap_id_mask, flags);
- return ERR_CAST(buffer);
- }
-
- handle = ion_handle_create(client, buffer);
-
- /*
- * ion_buffer_create will create a buffer with a ref_cnt of 1,
- * and ion_handle_create will take a second reference, drop one here
- */
- ion_buffer_put(buffer);
-
- if (IS_ERR(handle)) {
- trace_ion_alloc_fail(client->name, (unsigned long) buffer,
- len, align, heap_id_mask, flags);
- return handle;
- }
-
- mutex_lock(&client->lock);
- if (grab_handle)
- ion_handle_get(handle);
- ret = ion_handle_add(client, handle);
- mutex_unlock(&client->lock);
- if (ret) {
- ion_handle_put(handle);
- handle = ERR_PTR(ret);
- trace_ion_alloc_fail(client->name, (unsigned long ) buffer,
- len, align, heap_id_mask, flags);
- }
-
- ION_EVENT_ALLOC(buffer, ION_EVENT_DONE());
- trace_ion_alloc_end(client->name, (unsigned long) buffer,
- len, align, heap_id_mask, flags);
-
- return handle;
-}
-
-struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
- size_t align, unsigned int heap_id_mask,
- unsigned int flags)
-{
- return __ion_alloc(client, len, align, heap_id_mask, flags, false);
-}
-EXPORT_SYMBOL(ion_alloc);
-
-static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle)
-{
- bool valid_handle;
-
- BUG_ON(client != handle->client);
-
- valid_handle = ion_handle_validate(client, handle);
-
- if (!valid_handle) {
- WARN(1, "%s: invalid handle passed to free.\n", __func__);
- return;
- }
- ion_handle_put_nolock(handle);
-}
-
-void ion_free(struct ion_client *client, struct ion_handle *handle)
-{
- BUG_ON(client != handle->client);
-
- mutex_lock(&client->lock);
- ion_free_nolock(client, handle);
- mutex_unlock(&client->lock);
-}
-EXPORT_SYMBOL(ion_free);
-
-int ion_phys(struct ion_client *client, struct ion_handle *handle,
- ion_phys_addr_t *addr, size_t *len)
-{
- struct ion_buffer *buffer;
- int ret;
-
- mutex_lock(&client->lock);
- if (!ion_handle_validate(client, handle)) {
- mutex_unlock(&client->lock);
- return -EINVAL;
- }
-
- buffer = handle->buffer;
-
- if (!buffer->heap->ops->phys) {
- pr_err("%s: ion_phys is not implemented by this heap (name=%s, type=%d).\n",
- __func__, buffer->heap->name, buffer->heap->type);
- mutex_unlock(&client->lock);
- return -ENODEV;
- }
- mutex_unlock(&client->lock);
- ret = buffer->heap->ops->phys(buffer->heap, buffer, addr, len);
- return ret;
-}
-EXPORT_SYMBOL(ion_phys);
-
-static void *ion_buffer_kmap_get(struct ion_buffer *buffer)
-{
- void *vaddr;
-
- if (buffer->kmap_cnt) {
- buffer->kmap_cnt++;
- return buffer->vaddr;
- }
- vaddr = buffer->heap->ops->map_kernel(buffer->heap, buffer);
- if (WARN_ONCE(vaddr == NULL,
- "heap->ops->map_kernel should return ERR_PTR on error"))
- return ERR_PTR(-EINVAL);
- if (IS_ERR(vaddr))
- return vaddr;
- buffer->vaddr = vaddr;
- buffer->kmap_cnt++;
-
- return vaddr;
-}
-
-static void *ion_handle_kmap_get(struct ion_handle *handle)
-{
- struct ion_buffer *buffer = handle->buffer;
- void *vaddr;
-
- if (handle->kmap_cnt) {
- handle->kmap_cnt++;
- return buffer->vaddr;
- }
- vaddr = ion_buffer_kmap_get(buffer);
- if (IS_ERR(vaddr))
- return vaddr;
- handle->kmap_cnt++;
- return vaddr;
-}
-
-static void ion_buffer_kmap_put(struct ion_buffer *buffer)
-{
- buffer->kmap_cnt--;
- if (!buffer->kmap_cnt) {
- buffer->heap->ops->unmap_kernel(buffer->heap, buffer);
- buffer->vaddr = NULL;
- }
-}
-
-static void ion_handle_kmap_put(struct ion_handle *handle)
-{
- struct ion_buffer *buffer = handle->buffer;
-
- if (!handle->kmap_cnt) {
- WARN(1, "%s: Double unmap detected! bailing...\n", __func__);
- return;
- }
- handle->kmap_cnt--;
- if (!handle->kmap_cnt)
- ion_buffer_kmap_put(buffer);
-}
-
-void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle)
-{
- struct ion_buffer *buffer;
- void *vaddr;
-
- mutex_lock(&client->lock);
- if (!ion_handle_validate(client, handle)) {
- pr_err("%s: invalid handle passed to map_kernel.\n",
- __func__);
- mutex_unlock(&client->lock);
- return ERR_PTR(-EINVAL);
- }
-
- buffer = handle->buffer;
-
- if (!handle->buffer->heap->ops->map_kernel) {
- pr_err("%s: map_kernel is not implemented by this heap.\n",
- __func__);
- mutex_unlock(&client->lock);
- return ERR_PTR(-ENODEV);
- }
-
- mutex_lock(&buffer->lock);
- vaddr = ion_handle_kmap_get(handle);
- mutex_unlock(&buffer->lock);
- mutex_unlock(&client->lock);
- return vaddr;
-}
-EXPORT_SYMBOL(ion_map_kernel);
-
-void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
-{
- struct ion_buffer *buffer;
-
- mutex_lock(&client->lock);
- buffer = handle->buffer;
- mutex_lock(&buffer->lock);
- ion_handle_kmap_put(handle);
- mutex_unlock(&buffer->lock);
- mutex_unlock(&client->lock);
-}
-EXPORT_SYMBOL(ion_unmap_kernel);
-
-static int ion_debug_client_show(struct seq_file *s, void *unused)
-{
- struct ion_client *client = s->private;
- struct rb_node *n;
- size_t sizes[ION_NUM_HEAP_IDS] = {0};
- size_t sizes_pss[ION_NUM_HEAP_IDS] = {0};
- const char *names[ION_NUM_HEAP_IDS] = {NULL};
- int i;
-
- down_read(&g_idev->lock);
-
- /* check validity of the client */
- for (n = rb_first(&g_idev->clients); n; n = rb_next(n)) {
- struct ion_client *c = rb_entry(n, struct ion_client, node);
- if (client == c)
- break;
- }
-
- if (IS_ERR_OR_NULL(n)) {
- pr_err("%s: invalid client %p\n", __func__, client);
- up_read(&g_idev->lock);
- return -EINVAL;
- }
-
- seq_printf(s, "%16.s %4.s %16.s %4.s %10.s %8.s %9.s\n",
- "task", "pid", "thread", "tid", "size", "# procs", "flag");
- seq_printf(s, "----------------------------------------------"
- "--------------------------------------------\n");
-
- mutex_lock(&client->lock);
- for (n = rb_first(&client->handles); n; n = rb_next(n)) {
- struct ion_handle *handle = rb_entry(n, struct ion_handle,
- node);
- struct ion_buffer *buffer = handle->buffer;
- unsigned int id = buffer->heap->id;
-
- if (!names[id])
- names[id] = buffer->heap->name;
- sizes[id] += buffer->size;
- sizes_pss[id] += (buffer->size / buffer->handle_count);
- seq_printf(s, "%16.s %4u %16.s %4u %10zu %8d %9lx\n",
- buffer->task_comm, buffer->pid,
- buffer->thread_comm, buffer->tid, buffer->size,
- buffer->handle_count, buffer->flags);
- }
- mutex_unlock(&client->lock);
- up_read(&g_idev->lock);
-
- seq_printf(s, "----------------------------------------------"
- "--------------------------------------------\n");
- seq_printf(s, "%16.16s: %16.16s %18.18s\n", "heap_name",
- "size_in_bytes", "size_in_bytes(pss)");
- for (i = 0; i < ION_NUM_HEAP_IDS; i++) {
- if (!names[i])
- continue;
- seq_printf(s, "%16.16s: %16zu %18zu\n",
- names[i], sizes[i], sizes_pss[i]);
- }
- return 0;
-}
-
-static int ion_debug_client_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ion_debug_client_show, inode->i_private);
-}
-
-static const struct file_operations debug_client_fops = {
- .open = ion_debug_client_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int ion_get_client_serial(const struct rb_root *root,
- const unsigned char *name)
-{
- int serial = -1;
- struct rb_node *node;
-
- for (node = rb_first(root); node; node = rb_next(node)) {
- struct ion_client *client = rb_entry(node, struct ion_client,
- node);
-
- if (strcmp(client->name, name))
- continue;
- serial = max(serial, client->display_serial);
- }
- return serial + 1;
-}
-
-struct ion_client *ion_client_create(struct ion_device *dev,
- const char *name)
-{
- struct ion_client *client;
- struct task_struct *task;
- struct rb_node **p;
- struct rb_node *parent = NULL;
- struct ion_client *entry;
- pid_t pid;
-
- if (!name) {
- pr_err("%s: Name cannot be null\n", __func__);
- return ERR_PTR(-EINVAL);
- }
-
- get_task_struct(current->group_leader);
- task_lock(current->group_leader);
- pid = task_pid_nr(current->group_leader);
- /*
- * don't bother to store task struct for kernel threads,
- * they can't be killed anyway
- */
- if (current->group_leader->flags & PF_KTHREAD) {
- put_task_struct(current->group_leader);
- task = NULL;
- } else {
- task = current->group_leader;
- }
- task_unlock(current->group_leader);
-
- client = kzalloc(sizeof(struct ion_client), GFP_KERNEL);
- if (!client)
- goto err_put_task_struct;
-
- client->dev = dev;
- client->handles = RB_ROOT;
- idr_init(&client->idr);
- mutex_init(&client->lock);
- client->task = task;
- client->pid = pid;
- client->name = kstrdup(name, GFP_KERNEL);
- if (!client->name)
- goto err_free_client;
-
- down_write(&dev->lock);
- client->display_serial = ion_get_client_serial(&dev->clients, name);
- client->display_name = kasprintf(
- GFP_KERNEL, "%s-%d", name, client->display_serial);
- if (!client->display_name) {
- up_write(&dev->lock);
- goto err_free_client_name;
- }
- p = &dev->clients.rb_node;
- while (*p) {
- parent = *p;
- entry = rb_entry(parent, struct ion_client, node);
-
- if (client < entry)
- p = &(*p)->rb_left;
- else if (client > entry)
- p = &(*p)->rb_right;
- }
- rb_link_node(&client->node, parent, p);
- rb_insert_color(&client->node, &dev->clients);
-
- client->debug_root = debugfs_create_file(client->display_name, 0664,
- dev->clients_debug_root,
- client, &debug_client_fops);
- if (!client->debug_root) {
- char buf[256], *path;
-
- path = dentry_path(dev->clients_debug_root, buf, 256);
- pr_err("Failed to create client debugfs at %s/%s\n",
- path, client->display_name);
- }
-
- up_write(&dev->lock);
-
- return client;
-
-err_free_client_name:
- kfree(client->name);
-err_free_client:
- kfree(client);
-err_put_task_struct:
- if (task)
- put_task_struct(current->group_leader);
- return ERR_PTR(-ENOMEM);
-}
-EXPORT_SYMBOL(ion_client_create);
-
-void ion_client_destroy(struct ion_client *client)
-{
- struct ion_device *dev = client->dev;
- struct rb_node *n;
-
- mutex_lock(&client->lock);
- while ((n = rb_first(&client->handles))) {
- struct ion_handle *handle = rb_entry(n, struct ion_handle,
- node);
- ion_handle_destroy(&handle->ref);
- }
-
- mutex_unlock(&client->lock);
- idr_destroy(&client->idr);
-
- down_write(&dev->lock);
- if (client->task)
- put_task_struct(client->task);
- rb_erase(&client->node, &dev->clients);
- debugfs_remove_recursive(client->debug_root);
- up_write(&dev->lock);
-
- kfree(client->display_name);
- kfree(client->name);
- kfree(client);
-}
-EXPORT_SYMBOL(ion_client_destroy);
-
-struct sg_table *ion_sg_table(struct ion_client *client,
- struct ion_handle *handle)
-{
- struct ion_buffer *buffer;
- struct sg_table *table;
-
- mutex_lock(&client->lock);
- if (!ion_handle_validate(client, handle)) {
- pr_err("%s: invalid handle passed to map_dma.\n",
- __func__);
- mutex_unlock(&client->lock);
- return ERR_PTR(-EINVAL);
- }
- buffer = handle->buffer;
- table = buffer->sg_table;
- mutex_unlock(&client->lock);
- return table;
-}
-EXPORT_SYMBOL(ion_sg_table);
-
-static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
- struct device *dev,
- enum dma_data_direction direction);
-
-static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
- enum dma_data_direction direction)
-{
- struct dma_buf *dmabuf = attachment->dmabuf;
- struct ion_buffer *buffer = dmabuf->priv;
-
- ion_buffer_sync_for_device(buffer, attachment->dev, direction);
-
- ion_buffer_task_add_lock(buffer, attachment->dev);
-
- return buffer->sg_table;
-}
-
-static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment,
- struct sg_table *table,
- enum dma_data_direction direction)
-{
- ion_buffer_task_remove_lock(attachment->dmabuf->priv, attachment->dev);
-}
-
-void ion_pages_sync_for_device(struct device *dev, struct page *page,
- size_t size, enum dma_data_direction dir)
-{
- struct scatterlist sg;
+ struct scatterlist sg;
sg_init_table(&sg, 1);
sg_set_page(&sg, page, size, 0);
@@ -1270,69 +440,12 @@ void ion_pages_sync_for_device(struct device *dev, struct page *page,
dma_sync_sg_for_device(dev, &sg, 1, dir);
}
-struct ion_vma_list {
- struct list_head list;
- struct vm_area_struct *vma;
-};
-
-static void ion_buffer_sync_for_device(struct ion_buffer *buffer,
- struct device *dev,
- enum dma_data_direction dir)
-{
- struct ion_vma_list *vma_list;
- int pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
- int i;
-
- if (!ion_buffer_cached(buffer))
- return;
-
- if (!ion_buffer_fault_user_mappings(buffer))
- return;
-
- mutex_lock(&buffer->lock);
- for (i = 0; i < pages; i++) {
- struct page *page = buffer->pages[i];
-
- if (ion_buffer_page_is_dirty(page))
- ion_pages_sync_for_device(dev, ion_buffer_page(page),
- PAGE_SIZE, dir);
-
- ion_buffer_page_clean(buffer->pages + i);
- }
- list_for_each_entry(vma_list, &buffer->vmas, list) {
- struct vm_area_struct *vma = vma_list->vma;
-
- zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start,
- NULL);
- }
- mutex_unlock(&buffer->lock);
-}
-
-static int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
- struct ion_buffer *buffer = vma->vm_private_data;
- unsigned long pfn;
- int ret;
-
- mutex_lock(&buffer->lock);
- ion_buffer_page_dirty(buffer->pages + vmf->pgoff);
- BUG_ON(!buffer->pages || !buffer->pages[vmf->pgoff]);
-
- pfn = page_to_pfn(ion_buffer_page(buffer->pages[vmf->pgoff]));
- ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
- mutex_unlock(&buffer->lock);
- if (ret)
- return VM_FAULT_ERROR;
-
- return VM_FAULT_NOPAGE;
-}
-
static void ion_vm_open(struct vm_area_struct *vma)
{
struct ion_buffer *buffer = vma->vm_private_data;
struct ion_vma_list *vma_list;
- vma_list = kmalloc(sizeof(struct ion_vma_list), GFP_KERNEL);
+ vma_list = kmalloc(sizeof(*vma_list), GFP_KERNEL);
if (!vma_list)
return;
vma_list->vma = vma;
@@ -1360,7 +473,6 @@ static void ion_vm_close(struct vm_area_struct *vma)
static const struct vm_operations_struct ion_vma_ops = {
.open = ion_vm_open,
.close = ion_vm_close,
- .fault = ion_vm_fault,
};
static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
@@ -1368,51 +480,19 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
struct ion_buffer *buffer = dmabuf->priv;
int ret = 0;
- ION_EVENT_BEGIN();
-
- if (buffer->flags & ION_FLAG_NOZEROED) {
- pr_err("%s: mmap non-zeroed buffer to user is prohibited!\n",
- __func__);
- return -EINVAL;
- }
-
- if (buffer->flags & ION_FLAG_PROTECTED) {
- pr_err("%s: mmap protected buffer to user is prohibited!\n",
- __func__);
- return -EPERM;
- }
-
- if ((((vma->vm_pgoff << PAGE_SHIFT) >= buffer->size)) ||
- ((vma->vm_end - vma->vm_start) >
- (buffer->size - (vma->vm_pgoff << PAGE_SHIFT)))) {
- pr_err("%s: trying to map outside of buffer.\n", __func__);
- return -EINVAL;
- }
-
if (!buffer->heap->ops->map_user) {
pr_err("%s: this heap does not define a method for mapping to userspace\n",
- __func__);
+ __func__);
return -EINVAL;
}
- trace_ion_mmap_start((unsigned long) buffer, buffer->size,
- !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
-
- if (ion_buffer_fault_user_mappings(buffer)) {
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND |
- VM_DONTDUMP;
- vma->vm_private_data = buffer;
- vma->vm_ops = &ion_vma_ops;
- ion_vm_open(vma);
- ION_EVENT_MMAP(buffer, ION_EVENT_DONE());
- trace_ion_mmap_end((unsigned long) buffer, buffer->size,
- !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
- return 0;
- }
-
if (!(buffer->flags & ION_FLAG_CACHED))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ vma->vm_private_data = buffer;
+ vma->vm_ops = &ion_vma_ops;
+ ion_vm_open(vma);
+
mutex_lock(&buffer->lock);
/* now map it to userspace */
ret = buffer->heap->ops->map_user(buffer->heap, buffer, vma);
@@ -1422,10 +502,6 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
pr_err("%s: failure mapping buffer to userspace\n",
__func__);
- ION_EVENT_MMAP(buffer, ION_EVENT_DONE());
- trace_ion_mmap_end((unsigned long) buffer, buffer->size,
- !(buffer->flags & ION_FLAG_CACHED_NEEDS_SYNC));
-
return ret;
}
@@ -1433,625 +509,806 @@ static void ion_dma_buf_release(struct dma_buf *dmabuf)
{
struct ion_buffer *buffer = dmabuf->priv;
- ion_buffer_put(buffer);
+ _ion_buffer_destroy(buffer);
+ kfree(dmabuf->exp_name);
}
static void *ion_dma_buf_vmap(struct dma_buf *dmabuf)
{
struct ion_buffer *buffer = dmabuf->priv;
- void *vaddr;
+ void *vaddr = ERR_PTR(-EINVAL);
- if (!buffer->heap->ops->map_kernel) {
- pr_err("%s: map kernel is not implemented by this heap.\n",
- __func__);
- return ERR_PTR(-ENODEV);
+ if (buffer->heap->ops->map_kernel) {
+ mutex_lock(&buffer->lock);
+ vaddr = ion_buffer_kmap_get(buffer);
+ mutex_unlock(&buffer->lock);
+ } else {
+ pr_warn_ratelimited("heap %s doesn't support map_kernel\n",
+ buffer->heap->name);
}
- mutex_lock(&buffer->lock);
- vaddr = ion_buffer_kmap_get(buffer);
- mutex_unlock(&buffer->lock);
-
return vaddr;
}
-static void ion_dma_buf_vunmap(struct dma_buf *dmabuf, void *ptr)
+static void ion_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
{
struct ion_buffer *buffer = dmabuf->priv;
- mutex_lock(&buffer->lock);
- ion_buffer_kmap_put(buffer);
- mutex_unlock(&buffer->lock);
+ if (buffer->heap->ops->map_kernel) {
+ mutex_lock(&buffer->lock);
+ ion_buffer_kmap_put(buffer);
+ mutex_unlock(&buffer->lock);
+ }
+}
+
+static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
+{
+ /*
+ * TODO: Once clients remove their hacks where they assume kmap(ed)
+ * addresses are virtually contiguous implement this properly
+ */
+ void *vaddr = ion_dma_buf_vmap(dmabuf);
+
+ if (IS_ERR(vaddr))
+ return vaddr;
+
+ return vaddr + offset * PAGE_SIZE;
+}
+
+static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
+ void *ptr)
+{
+ /*
+ * TODO: Once clients remove their hacks where they assume kmap(ed)
+ * addresses are virtually contiguous implement this properly
+ */
+ ion_dma_buf_vunmap(dmabuf, ptr);
+}
+
+static int ion_sgl_sync_range(struct device *dev, struct scatterlist *sgl,
+ unsigned int nents, unsigned long offset,
+ unsigned long length,
+ enum dma_data_direction dir, bool for_cpu)
+{
+ int i;
+ struct scatterlist *sg;
+ unsigned int len = 0;
+ dma_addr_t sg_dma_addr;
+
+ for_each_sg(sgl, sg, nents, i) {
+ if (sg_dma_len(sg) == 0)
+ break;
+
+ if (i > 0) {
+ pr_warn_ratelimited("Partial cmo only supported with 1 segment\n"
+ "is dma_set_max_seg_size being set on dev:%s\n",
+ dev_name(dev));
+ return -EINVAL;
+ }
+ }
+
+ for_each_sg(sgl, sg, nents, i) {
+ unsigned int sg_offset, sg_left, size = 0;
+
+ if (i == 0)
+ sg_dma_addr = sg_dma_address(sg);
+
+ len += sg->length;
+ if (len <= offset) {
+ sg_dma_addr += sg->length;
+ continue;
+ }
+
+ sg_left = len - offset;
+ sg_offset = sg->length - sg_left;
+
+ size = (length < sg_left) ? length : sg_left;
+ if (for_cpu)
+ dma_sync_single_range_for_cpu(dev, sg_dma_addr,
+ sg_offset, size, dir);
+ else
+ dma_sync_single_range_for_device(dev, sg_dma_addr,
+ sg_offset, size, dir);
+
+ offset += size;
+ length -= size;
+ sg_dma_addr += sg->length;
+
+ if (length == 0)
+ break;
+ }
+
+ return 0;
}
-static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
+static int ion_sgl_sync_mapped(struct device *dev, struct scatterlist *sgl,
+ unsigned int nents, struct list_head *vmas,
+ enum dma_data_direction dir, bool for_cpu)
{
- struct ion_buffer *buffer = dmabuf->priv;
+ struct ion_vma_list *vma_list;
+ int ret = 0;
- return buffer->vaddr + offset * PAGE_SIZE;
-}
+ list_for_each_entry(vma_list, vmas, list) {
+ struct vm_area_struct *vma = vma_list->vma;
-static void ion_dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long offset,
- void *ptr)
-{
+ ret = ion_sgl_sync_range(dev, sgl, nents,
+ vma->vm_pgoff * PAGE_SIZE,
+ vma->vm_end - vma->vm_start, dir,
+ for_cpu);
+ if (ret)
+ break;
+ }
+
+ return ret;
}
-static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, size_t start,
- size_t len,
- enum dma_data_direction direction)
+static int __ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+ enum dma_data_direction direction,
+ bool sync_only_mapped)
{
struct ion_buffer *buffer = dmabuf->priv;
- void *vaddr;
+ struct ion_dma_buf_attachment *a;
+ int ret = 0;
- if (!buffer->heap->ops->map_kernel) {
- pr_err("%s: map kernel is not implemented by this heap.\n",
- __func__);
- return -ENODEV;
+ if (!hlos_accessible_buffer(buffer)) {
+ trace_ion_begin_cpu_access_cmo_skip(NULL, dmabuf->name,
+ ion_buffer_cached(buffer),
+ false, direction,
+ sync_only_mapped);
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (!(buffer->flags & ION_FLAG_CACHED)) {
+ trace_ion_begin_cpu_access_cmo_skip(NULL, dmabuf->name, false,
+ true, direction,
+ sync_only_mapped);
+ goto out;
}
mutex_lock(&buffer->lock);
- vaddr = ion_buffer_kmap_get(buffer);
- mutex_unlock(&buffer->lock);
- return PTR_ERR_OR_ZERO(vaddr);
-}
-static void ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, size_t start,
- size_t len,
- enum dma_data_direction direction)
-{
- struct ion_buffer *buffer = dmabuf->priv;
+ if (IS_ENABLED(CONFIG_ION_FORCE_DMA_SYNC)) {
+ struct device *dev = buffer->heap->priv;
+ struct sg_table *table = buffer->sg_table;
- mutex_lock(&buffer->lock);
- ion_buffer_kmap_put(buffer);
- mutex_unlock(&buffer->lock);
-}
+ if (sync_only_mapped)
+ ret = ion_sgl_sync_mapped(dev, table->sgl,
+ table->nents, &buffer->vmas,
+ direction, true);
+ else
+ dma_sync_sg_for_cpu(dev, table->sgl,
+ table->nents, direction);
+
+ if (!ret)
+ trace_ion_begin_cpu_access_cmo_apply(dev, dmabuf->name,
+ true, true,
+ direction,
+ sync_only_mapped);
+ else
+ trace_ion_begin_cpu_access_cmo_skip(dev, dmabuf->name,
+ true, true,
+ direction,
+ sync_only_mapped);
+ mutex_unlock(&buffer->lock);
+ goto out;
+ }
-static void ion_dma_buf_set_privflag(struct dma_buf *dmabuf)
-{
- struct ion_buffer *buffer = dmabuf->priv;
+ list_for_each_entry(a, &buffer->attachments, list) {
+ int tmp = 0;
- mutex_lock(&buffer->lock);
- buffer->private_flags |= ION_PRIV_FLAG_NEED_TO_FLUSH;
+ if (!a->dma_mapped) {
+ trace_ion_begin_cpu_access_notmapped(a->dev,
+ dmabuf->name,
+ true, true,
+ direction,
+ sync_only_mapped);
+ continue;
+ }
+
+ if (sync_only_mapped)
+ tmp = ion_sgl_sync_mapped(a->dev, a->table->sgl,
+ a->table->nents,
+ &buffer->vmas,
+ direction, true);
+ else
+ dma_sync_sg_for_cpu(a->dev, a->table->sgl,
+ a->table->nents, direction);
+
+ if (!tmp) {
+ trace_ion_begin_cpu_access_cmo_apply(a->dev,
+ dmabuf->name,
+ true, true,
+ direction,
+ sync_only_mapped);
+ } else {
+ trace_ion_begin_cpu_access_cmo_skip(a->dev,
+ dmabuf->name, true,
+ true, direction,
+ sync_only_mapped);
+ ret = tmp;
+ }
+
+ }
mutex_unlock(&buffer->lock);
+out:
+ return ret;
}
-static bool ion_dma_buf_get_privflag(struct dma_buf *dmabuf, bool clear)
+static int __ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
+ enum dma_data_direction direction,
+ bool sync_only_mapped)
{
struct ion_buffer *buffer = dmabuf->priv;
- bool ret;
-
- mutex_lock(&buffer->lock);
- ret = !!(buffer->private_flags & ION_PRIV_FLAG_NEED_TO_FLUSH);
- if (clear)
- buffer->private_flags &= ~ION_PRIV_FLAG_NEED_TO_FLUSH;
- mutex_unlock(&buffer->lock);
+ struct ion_dma_buf_attachment *a;
+ int ret = 0;
- return ret;
-}
+ if (!hlos_accessible_buffer(buffer)) {
+ trace_ion_end_cpu_access_cmo_skip(NULL, dmabuf->name,
+ ion_buffer_cached(buffer),
+ false, direction,
+ sync_only_mapped);
+ ret = -EPERM;
+ goto out;
+ }
-static struct dma_buf_ops dma_buf_ops = {
- .map_dma_buf = ion_map_dma_buf,
- .unmap_dma_buf = ion_unmap_dma_buf,
- .mmap = ion_mmap,
- .release = ion_dma_buf_release,
- .begin_cpu_access = ion_dma_buf_begin_cpu_access,
- .end_cpu_access = ion_dma_buf_end_cpu_access,
- .kmap_atomic = ion_dma_buf_kmap,
- .kunmap_atomic = ion_dma_buf_kunmap,
- .kmap = ion_dma_buf_kmap,
- .kunmap = ion_dma_buf_kunmap,
- .vmap = ion_dma_buf_vmap,
- .vunmap = ion_dma_buf_vunmap,
- .set_privflag = ion_dma_buf_set_privflag,
- .get_privflag = ion_dma_buf_get_privflag,
-};
+ if (!(buffer->flags & ION_FLAG_CACHED)) {
+ trace_ion_end_cpu_access_cmo_skip(NULL, dmabuf->name, false,
+ true, direction,
+ sync_only_mapped);
+ goto out;
+ }
-static struct dma_buf *__ion_share_dma_buf(struct ion_client *client,
- struct ion_handle *handle,
- bool lock_client)
-{
- DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
- struct ion_buffer *buffer;
- struct dma_buf *dmabuf;
- bool valid_handle;
-
- if (lock_client)
- mutex_lock(&client->lock);
- valid_handle = ion_handle_validate(client, handle);
- if (!valid_handle) {
- WARN(1, "%s: invalid handle passed to share.\n", __func__);
- if (lock_client)
- mutex_unlock(&client->lock);
- return ERR_PTR(-EINVAL);
+ mutex_lock(&buffer->lock);
+ if (IS_ENABLED(CONFIG_ION_FORCE_DMA_SYNC)) {
+ struct device *dev = buffer->heap->priv;
+ struct sg_table *table = buffer->sg_table;
+
+ if (sync_only_mapped)
+ ret = ion_sgl_sync_mapped(dev, table->sgl,
+ table->nents, &buffer->vmas,
+ direction, false);
+ else
+ dma_sync_sg_for_device(dev, table->sgl,
+ table->nents, direction);
+
+ if (!ret)
+ trace_ion_end_cpu_access_cmo_apply(dev, dmabuf->name,
+ true, true,
+ direction,
+ sync_only_mapped);
+ else
+ trace_ion_end_cpu_access_cmo_skip(dev, dmabuf->name,
+ true, true, direction,
+ sync_only_mapped);
+ mutex_unlock(&buffer->lock);
+ goto out;
}
- buffer = handle->buffer;
- ion_buffer_get(buffer);
- if (lock_client)
- mutex_unlock(&client->lock);
- exp_info.ops = &dma_buf_ops;
- exp_info.size = buffer->size;
- exp_info.flags = O_RDWR;
- exp_info.priv = buffer;
+ list_for_each_entry(a, &buffer->attachments, list) {
+ int tmp = 0;
- dmabuf = dma_buf_export(&exp_info);
- if (IS_ERR(dmabuf)) {
- ion_buffer_put(buffer);
- return dmabuf;
+ if (!a->dma_mapped) {
+ trace_ion_end_cpu_access_notmapped(a->dev,
+ dmabuf->name,
+ true, true,
+ direction,
+ sync_only_mapped);
+ continue;
+ }
+
+ if (sync_only_mapped)
+ tmp = ion_sgl_sync_mapped(a->dev, a->table->sgl,
+ a->table->nents,
+ &buffer->vmas, direction,
+ false);
+ else
+ dma_sync_sg_for_device(a->dev, a->table->sgl,
+ a->table->nents, direction);
+
+ if (!tmp) {
+ trace_ion_end_cpu_access_cmo_apply(a->dev, dmabuf->name,
+ true, true,
+ direction,
+ sync_only_mapped);
+ } else {
+ trace_ion_end_cpu_access_cmo_skip(a->dev, dmabuf->name,
+ true, true, direction,
+ sync_only_mapped);
+ ret = tmp;
+ }
}
+ mutex_unlock(&buffer->lock);
- return dmabuf;
+out:
+ return ret;
}
-struct dma_buf *ion_share_dma_buf(struct ion_client *client,
- struct ion_handle *handle)
+static int ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
+ enum dma_data_direction direction)
{
- return __ion_share_dma_buf(client, handle, true);
+ return __ion_dma_buf_begin_cpu_access(dmabuf, direction, false);
}
-EXPORT_SYMBOL(ion_share_dma_buf);
-static int __ion_share_dma_buf_fd(struct ion_client *client,
- struct ion_handle *handle, bool lock_client)
+static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
+ enum dma_data_direction direction)
{
- struct dma_buf *dmabuf;
- int fd;
-
- dmabuf = __ion_share_dma_buf(client, handle, lock_client);
- if (IS_ERR(dmabuf))
- return PTR_ERR(dmabuf);
-
- fd = dma_buf_fd(dmabuf, O_CLOEXEC);
- if (fd < 0)
- dma_buf_put(dmabuf);
-
- return fd;
+ return __ion_dma_buf_end_cpu_access(dmabuf, direction, false);
}
-int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle)
+static int ion_dma_buf_begin_cpu_access_umapped(struct dma_buf *dmabuf,
+ enum dma_data_direction dir)
{
- return __ion_share_dma_buf_fd(client, handle, true);
+ return __ion_dma_buf_begin_cpu_access(dmabuf, dir, true);
}
-EXPORT_SYMBOL(ion_share_dma_buf_fd);
-static int ion_share_dma_buf_fd_nolock(struct ion_client *client,
- struct ion_handle *handle)
+static int ion_dma_buf_end_cpu_access_umapped(struct dma_buf *dmabuf,
+ enum dma_data_direction dir)
{
- return __ion_share_dma_buf_fd(client, handle, false);
+ return __ion_dma_buf_end_cpu_access(dmabuf, dir, true);
}
-struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
+static int ion_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf,
+ enum dma_data_direction dir,
+ unsigned int offset,
+ unsigned int len)
{
- struct dma_buf *dmabuf;
- struct ion_buffer *buffer;
- struct ion_handle *handle;
- int ret;
-
- dmabuf = dma_buf_get(fd);
- if (IS_ERR(dmabuf))
- return ERR_CAST(dmabuf);
- /* if this memory came from ion */
+ struct ion_buffer *buffer = dmabuf->priv;
+ struct ion_dma_buf_attachment *a;
+ int ret = 0;
- if (dmabuf->ops != &dma_buf_ops) {
- pr_err("%s: can not import dmabuf from another exporter\n",
- __func__);
- dma_buf_put(dmabuf);
- return ERR_PTR(-EINVAL);
- }
- buffer = dmabuf->priv;
-
- mutex_lock(&client->lock);
- /* if a handle exists for this buffer just take a reference to it */
- handle = ion_handle_lookup(client, buffer);
- if (!IS_ERR(handle)) {
- handle = ion_handle_get_check_overflow(handle);
- mutex_unlock(&client->lock);
- goto end;
+ if (!hlos_accessible_buffer(buffer)) {
+ trace_ion_begin_cpu_access_cmo_skip(NULL, dmabuf->name,
+ ion_buffer_cached(buffer),
+ false, dir,
+ false);
+ ret = -EPERM;
+ goto out;
}
- handle = ion_handle_create(client, buffer);
- if (IS_ERR(handle)) {
- mutex_unlock(&client->lock);
- goto end;
+ if (!(buffer->flags & ION_FLAG_CACHED)) {
+ trace_ion_begin_cpu_access_cmo_skip(NULL, dmabuf->name, false,
+ true, dir,
+ false);
+ goto out;
}
- ret = ion_handle_add(client, handle);
- mutex_unlock(&client->lock);
- if (ret) {
- ion_handle_put(handle);
- handle = ERR_PTR(ret);
- }
+ mutex_lock(&buffer->lock);
+ if (IS_ENABLED(CONFIG_ION_FORCE_DMA_SYNC)) {
+ struct device *dev = buffer->heap->priv;
+ struct sg_table *table = buffer->sg_table;
-end:
- dma_buf_put(dmabuf);
- return handle;
-}
-EXPORT_SYMBOL(ion_import_dma_buf);
+ ret = ion_sgl_sync_range(dev, table->sgl, table->nents,
+ offset, len, dir, true);
-int ion_cached_needsync_dmabuf(struct dma_buf *dmabuf)
-{
- struct ion_buffer *buffer = dmabuf->priv;
- unsigned long cacheflag = ION_FLAG_CACHED | ION_FLAG_CACHED_NEEDS_SYNC;
+ if (!ret)
+ trace_ion_begin_cpu_access_cmo_apply(dev, dmabuf->name,
+ true, true, dir,
+ false);
+ else
+ trace_ion_begin_cpu_access_cmo_skip(dev, dmabuf->name,
+ true, true, dir,
+ false);
+ mutex_unlock(&buffer->lock);
+ goto out;
+ }
- if (dmabuf->ops != &dma_buf_ops)
- return -EINVAL;
+ list_for_each_entry(a, &buffer->attachments, list) {
+ int tmp = 0;
- return ((buffer->flags & cacheflag) == cacheflag) ? 1 : 0;
-}
-EXPORT_SYMBOL(ion_cached_needsync_dmabuf);
+ if (!a->dma_mapped) {
+ trace_ion_begin_cpu_access_notmapped(a->dev,
+ dmabuf->name,
+ true, true,
+ dir,
+ false);
+ continue;
+ }
-bool ion_may_hwrender_dmabuf(struct dma_buf *dmabuf)
-{
- struct ion_buffer *buffer = dmabuf->priv;
+ tmp = ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents,
+ offset, len, dir, true);
- if (dmabuf->ops != &dma_buf_ops) {
- WARN(1, "%s: given dmabuf is not exported by ION\n", __func__);
- return false;
+ if (!tmp) {
+ trace_ion_begin_cpu_access_cmo_apply(a->dev,
+ dmabuf->name,
+ true, true, dir,
+ false);
+ } else {
+ trace_ion_begin_cpu_access_cmo_skip(a->dev,
+ dmabuf->name,
+ true, true, dir,
+ false);
+ ret = tmp;
+ }
}
+ mutex_unlock(&buffer->lock);
- return !!(buffer->flags & ION_FLAG_MAY_HWRENDER);
+out:
+ return ret;
}
-EXPORT_SYMBOL(ion_may_hwrender_dmabuf);
-bool ion_may_hwrender_handle(struct ion_client *client, struct ion_handle *handle)
+static int ion_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf,
+ enum dma_data_direction direction,
+ unsigned int offset,
+ unsigned int len)
{
- struct ion_buffer *buffer = handle->buffer;
- bool valid_handle;
+ struct ion_buffer *buffer = dmabuf->priv;
+ struct ion_dma_buf_attachment *a;
+ int ret = 0;
- mutex_lock(&client->lock);
- valid_handle = ion_handle_validate(client, handle);
+ if (!hlos_accessible_buffer(buffer)) {
+ trace_ion_end_cpu_access_cmo_skip(NULL, dmabuf->name,
+ ion_buffer_cached(buffer),
+ false, direction,
+ false);
+ ret = -EPERM;
+ goto out;
+ }
- if (!valid_handle) {
- WARN(1, "%s: invalid handle passed\n", __func__);
- mutex_unlock(&client->lock);
- return false;
+ if (!(buffer->flags & ION_FLAG_CACHED)) {
+ trace_ion_end_cpu_access_cmo_skip(NULL, dmabuf->name, false,
+ true, direction,
+ false);
+ goto out;
}
- mutex_unlock(&client->lock);
- return !!(buffer->flags & ION_FLAG_MAY_HWRENDER);
-}
-EXPORT_SYMBOL(ion_may_hwrender_handle);
+ mutex_lock(&buffer->lock);
+ if (IS_ENABLED(CONFIG_ION_FORCE_DMA_SYNC)) {
+ struct device *dev = buffer->heap->priv;
+ struct sg_table *table = buffer->sg_table;
-static int ion_sync_for_device(struct ion_client *client, int fd)
-{
- struct dma_buf *dmabuf;
- struct ion_buffer *buffer;
- struct scatterlist *sg, *sgl;
- int nelems;
- void *vaddr;
- int i = 0;
+ ret = ion_sgl_sync_range(dev, table->sgl, table->nents,
+ offset, len, direction, false);
- dmabuf = dma_buf_get(fd);
- if (IS_ERR(dmabuf))
- return PTR_ERR(dmabuf);
+ if (!ret)
+ trace_ion_end_cpu_access_cmo_apply(dev, dmabuf->name,
+ true, true,
+ direction, false);
+ else
+ trace_ion_end_cpu_access_cmo_skip(dev, dmabuf->name,
+ true, true,
+ direction, false);
- /* if this memory came from ion */
- if (dmabuf->ops != &dma_buf_ops) {
- pr_err("%s: can not sync dmabuf from another exporter\n",
- __func__);
- dma_buf_put(dmabuf);
- return -EINVAL;
+ mutex_unlock(&buffer->lock);
+ goto out;
}
- buffer = dmabuf->priv;
- if (!ion_buffer_cached(buffer) ||
- ion_buffer_fault_user_mappings(buffer)) {
- dma_buf_put(dmabuf);
- return 0;
- }
+ list_for_each_entry(a, &buffer->attachments, list) {
+ int tmp = 0;
+
+ if (!a->dma_mapped) {
+ trace_ion_end_cpu_access_notmapped(a->dev,
+ dmabuf->name,
+ true, true,
+ direction,
+ false);
+ continue;
+ }
- trace_ion_sync_start(_RET_IP_, buffer->dev->dev.this_device,
- DMA_BIDIRECTIONAL, buffer->size,
- buffer->vaddr, 0, false);
+ tmp = ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents,
+ offset, len, direction, false);
- sgl = buffer->sg_table->sgl;
- nelems = buffer->sg_table->nents;
+ if (!tmp) {
+ trace_ion_end_cpu_access_cmo_apply(a->dev, dmabuf->name,
+ true, true,
+ direction, false);
- for_each_sg(sgl, sg, nelems, i) {
- vaddr = phys_to_virt(sg_phys(sg));
- __dma_flush_range(vaddr, vaddr + sg->length);
+ } else {
+ trace_ion_end_cpu_access_cmo_skip(a->dev, dmabuf->name,
+ true, true, direction,
+ false);
+ ret = tmp;
+ }
}
+ mutex_unlock(&buffer->lock);
+
+out:
+ return ret;
+}
- trace_ion_sync_end(_RET_IP_, buffer->dev->dev.this_device,
- DMA_BIDIRECTIONAL, buffer->size,
- buffer->vaddr, 0, false);
+static int ion_dma_buf_get_flags(struct dma_buf *dmabuf,
+ unsigned long *flags)
+{
+ struct ion_buffer *buffer = dmabuf->priv;
+ *flags = buffer->flags;
- dma_buf_put(dmabuf);
return 0;
}
-static int ion_sync_partial_for_device(struct ion_client *client, int fd,
- off_t offset, size_t len)
+static const struct dma_buf_ops dma_buf_ops = {
+ .map_dma_buf = ion_map_dma_buf,
+ .unmap_dma_buf = ion_unmap_dma_buf,
+ .mmap = ion_mmap,
+ .release = ion_dma_buf_release,
+ .attach = ion_dma_buf_attach,
+ .detach = ion_dma_buf_detatch,
+ .begin_cpu_access = ion_dma_buf_begin_cpu_access,
+ .end_cpu_access = ion_dma_buf_end_cpu_access,
+ .begin_cpu_access_umapped = ion_dma_buf_begin_cpu_access_umapped,
+ .end_cpu_access_umapped = ion_dma_buf_end_cpu_access_umapped,
+ .begin_cpu_access_partial = ion_dma_buf_begin_cpu_access_partial,
+ .end_cpu_access_partial = ion_dma_buf_end_cpu_access_partial,
+ .map = ion_dma_buf_kmap,
+ .unmap = ion_dma_buf_kunmap,
+ .vmap = ion_dma_buf_vmap,
+ .vunmap = ion_dma_buf_vunmap,
+ .get_flags = ion_dma_buf_get_flags,
+};
+
+struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask,
+ unsigned int flags)
{
+ struct ion_device *dev = internal_dev;
+ struct ion_buffer *buffer = NULL;
+ struct ion_heap *heap;
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct dma_buf *dmabuf;
- struct ion_buffer *buffer;
- struct scatterlist *sg, *sgl;
- size_t remained = len;
- int nelems;
- int i;
-
- dmabuf = dma_buf_get(fd);
- if (IS_ERR(dmabuf))
- return PTR_ERR(dmabuf);
+ char task_comm[TASK_COMM_LEN];
+ unsigned long jiffies_s = jiffies;
+ u64 utime, stime_s, stime_e, stime_d;
+ static DEFINE_RATELIMIT_STATE(show_mem_ratelimit, HZ * 10, 1);
+
+ task_cputime(current, &utime, &stime_s);
+ pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__,
+ len, heap_id_mask, flags);
+ /*
+ * traverse the list of heaps available in this system in priority
+ * order. If the heap type is supported by the client, and matches the
+ * request of the caller allocate from it. Repeat until allocate has
+ * succeeded or all heaps have been tried
+ */
+ len = PAGE_ALIGN(len);
- /* if this memory came from ion */
- if (dmabuf->ops != &dma_buf_ops) {
- pr_err("%s: can not sync dmabuf from another exporter\n",
- __func__);
- dma_buf_put(dmabuf);
- return -EINVAL;
- }
- buffer = dmabuf->priv;
+ if (!len)
+ return ERR_PTR(-EINVAL);
- if (!ion_buffer_cached(buffer) ||
- ion_buffer_fault_user_mappings(buffer)) {
- dma_buf_put(dmabuf);
- return 0;
+ if (heap_id_mask == 0xFFFFFFFF) {
+ heap_id_mask = get_ion_system_heap_id();
+ if (IS_ERR(ERR_PTR(heap_id_mask)))
+ return ERR_PTR(heap_id_mask);
+ heap_id_mask = (1 << heap_id_mask);
}
- trace_ion_sync_start(_RET_IP_, buffer->dev->dev.this_device,
- DMA_BIDIRECTIONAL, buffer->size,
- buffer->vaddr, 0, false);
-
- sgl = buffer->sg_table->sgl;
- nelems = buffer->sg_table->nents;
-
- for_each_sg(sgl, sg, nelems, i) {
- size_t len_to_flush;
- if (offset >= sg->length) {
- offset -= sg->length;
+ down_read(&dev->lock);
+ plist_for_each_entry(heap, &dev->heaps, node) {
+ /* if the caller didn't specify this heap id */
+ if (!((1 << heap->id) & heap_id_mask))
continue;
- }
-
- len_to_flush = sg->length - offset;
- if (remained < len_to_flush) {
- len_to_flush = remained;
- remained = 0;
- } else {
- remained -= len_to_flush;
- }
+ buffer = ion_buffer_create(heap, dev, len, flags);
+ if (!IS_ERR(buffer) || PTR_ERR(buffer) == -EINTR)
+ break;
+ }
+ up_read(&dev->lock);
- __dma_map_area(phys_to_virt(sg_phys(sg)) + offset,
- len_to_flush, DMA_TO_DEVICE);
+ if (!buffer)
+ return ERR_PTR(-ENODEV);
- if (remained == 0)
- break;
- offset = 0;
+ if (IS_ERR(buffer)) {
+ pr_err("%s ion alloc failed len: 0x%zx mask=0x%x flags=0x%x error%ld\n",
+ __func__, len, heap_id_mask, flags, PTR_ERR(buffer));
+ return ERR_CAST(buffer);
}
- trace_ion_sync_end(_RET_IP_, buffer->dev->dev.this_device,
- DMA_BIDIRECTIONAL, buffer->size,
- buffer->vaddr, 0, false);
+ get_task_comm(task_comm, current->group_leader);
- dma_buf_put(dmabuf);
+ exp_info.ops = &dma_buf_ops;
+ exp_info.size = buffer->size;
+ exp_info.flags = O_RDWR;
+ exp_info.priv = buffer;
+ exp_info.exp_name = kasprintf(GFP_KERNEL, "%s-%s-%d-%s", KBUILD_MODNAME,
+ heap->name, current->tgid, task_comm);
- return 0;
-}
+ dmabuf = dma_buf_export(&exp_info);
+ if (IS_ERR(dmabuf)) {
+ _ion_buffer_destroy(buffer);
+ kfree(exp_info.exp_name);
+ }
-/* fix up the cases where the ioctl direction bits are incorrect */
-static unsigned int ion_ioctl_dir(unsigned int cmd)
-{
- switch (cmd) {
- case ION_IOC_SYNC:
- case ION_IOC_SYNC_PARTIAL:
- case ION_IOC_FREE:
- case ION_IOC_CUSTOM:
- return _IOC_WRITE;
- default:
- return _IOC_DIR(cmd);
+ task_cputime(current, &utime, &stime_e);
+ stime_d = stime_e - stime_s;
+ if (!IS_ERR(dmabuf) && stime_d / NSEC_PER_MSEC > 100) {
+ pr_info("%s ion_heap_id: %d mask=0x%x timeJS(ms):%u/%llu len:0x%zx",
+ __func__, heap->id, heap_id_mask,
+ jiffies_to_msecs(jiffies - jiffies_s),
+ stime_d / NSEC_PER_MSEC, len);
+ if (__ratelimit(&show_mem_ratelimit))
+ show_mem(0, NULL);
}
+ return dmabuf;
}
-static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask,
+ unsigned int flags)
{
- struct ion_client *client = filp->private_data;
- struct ion_device *dev = client->dev;
- struct ion_handle *cleanup_handle = NULL;
- int ret = 0;
- unsigned int dir;
-
- union {
- struct ion_fd_data fd;
- struct ion_fd_partial_data fd_partial;
- struct ion_allocation_data allocation;
- struct ion_handle_data handle;
- struct ion_custom_data custom;
- } data;
-
- dir = ion_ioctl_dir(cmd);
-
- if (_IOC_SIZE(cmd) > sizeof(data))
- return -EINVAL;
-
- if (dir & _IOC_WRITE)
- if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
- return -EFAULT;
-
- switch (cmd) {
- case ION_IOC_ALLOC:
- {
- struct ion_handle *handle;
-
- handle = __ion_alloc(client, data.allocation.len,
- data.allocation.align,
- data.allocation.heap_id_mask,
- data.allocation.flags, true);
- if (IS_ERR(handle)) {
- pr_err("%s: len %zu align %zu heap_id_mask %u flags %x (ret %ld)\n",
- __func__, data.allocation.len,
- data.allocation.align,
- data.allocation.heap_id_mask,
- data.allocation.flags, PTR_ERR(handle));
- return PTR_ERR(handle);
- }
+ struct ion_device *dev = internal_dev;
+ struct ion_heap *heap;
+ bool type_valid = false;
- data.allocation.handle = handle->id;
+ pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__,
+ len, heap_id_mask, flags);
+ /*
+ * traverse the list of heaps available in this system in priority
+ * order. Check the heap type is supported.
+ */
- cleanup_handle = handle;
- break;
- }
- case ION_IOC_FREE:
- {
- struct ion_handle *handle;
-
- mutex_lock(&client->lock);
- handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
- if (IS_ERR(handle)) {
- mutex_unlock(&client->lock);
- return PTR_ERR(handle);
- }
- ion_free_nolock(client, handle);
- ion_handle_put_nolock(handle);
- mutex_unlock(&client->lock);
- break;
- }
- case ION_IOC_SHARE:
- case ION_IOC_MAP:
- {
- struct ion_handle *handle;
-
- mutex_lock(&client->lock);
- handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
- if (IS_ERR(handle)) {
- mutex_unlock(&client->lock);
- return PTR_ERR(handle);
+ down_read(&dev->lock);
+ plist_for_each_entry(heap, &dev->heaps, node) {
+ /* if the caller didn't specify this heap id */
+ if (!((1 << heap->id) & heap_id_mask))
+ continue;
+ if (heap->type == ION_HEAP_TYPE_SYSTEM ||
+ heap->type == ION_HEAP_TYPE_CARVEOUT ||
+ heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA ||
+ heap->type == (enum ion_heap_type)ION_HEAP_TYPE_RBIN ||
+ heap->type ==
+ (enum ion_heap_type)ION_HEAP_TYPE_SYSTEM_SECURE) {
+ type_valid = true;
+ } else {
+ pr_warn("%s: heap type not supported, type:%d\n",
+ __func__, heap->type);
}
- data.fd.fd = ion_share_dma_buf_fd_nolock(client, handle);
- ion_handle_put_nolock(handle);
- mutex_unlock(&client->lock);
- if (data.fd.fd < 0)
- ret = data.fd.fd;
break;
}
- case ION_IOC_IMPORT:
- {
- struct ion_handle *handle;
-
- handle = ion_import_dma_buf(client, data.fd.fd);
- if (IS_ERR(handle))
- ret = PTR_ERR(handle);
- else
- data.handle.handle = handle->id;
- break;
- }
- case ION_IOC_SYNC:
- {
- ret = ion_sync_for_device(client, data.fd.fd);
- break;
- }
- case ION_IOC_SYNC_PARTIAL:
- {
- ret = ion_sync_partial_for_device(client, data.fd_partial.fd,
- data.fd_partial.offset, data.fd_partial.len);
- break;
- }
- case ION_IOC_CUSTOM:
- {
- if (!dev->custom_ioctl)
- return -ENOTTY;
- ret = dev->custom_ioctl(client, data.custom.cmd,
- data.custom.arg);
- break;
- }
- default:
- return -ENOTTY;
- }
+ up_read(&dev->lock);
- if (dir & _IOC_READ) {
- if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
- if (cleanup_handle) {
- ion_free(client, cleanup_handle);
- ion_handle_put(cleanup_handle);
- }
- return -EFAULT;
- }
- }
- if (cleanup_handle)
- ion_handle_put(cleanup_handle);
- return ret;
+ if (!type_valid)
+ return ERR_PTR(-EINVAL);
+
+ return ion_alloc_dmabuf(len, heap_id_mask, flags);
}
+EXPORT_SYMBOL(ion_alloc);
-static int ion_release(struct inode *inode, struct file *file)
+int ion_alloc_fd(size_t len, unsigned int heap_id_mask, unsigned int flags)
{
- struct ion_client *client = file->private_data;
+ int fd;
+ struct dma_buf *dmabuf;
- ion_client_destroy(client);
- return 0;
+ dmabuf = ion_alloc_dmabuf(len, heap_id_mask, flags);
+ if (IS_ERR(dmabuf))
+ return PTR_ERR(dmabuf);
+
+ fd = dma_buf_fd(dmabuf, O_CLOEXEC);
+ if (fd < 0)
+ dma_buf_put(dmabuf);
+
+ return fd;
}
-static int ion_open(struct inode *inode, struct file *file)
+int ion_query_heaps(struct ion_heap_query *query)
{
- struct miscdevice *miscdev = file->private_data;
- struct ion_device *dev = container_of(miscdev, struct ion_device, dev);
- struct ion_client *client;
- char debug_name[64];
+ struct ion_device *dev = internal_dev;
+ struct ion_heap_data __user *buffer = u64_to_user_ptr(query->heaps);
+ int ret = -EINVAL, cnt = 0, max_cnt;
+ struct ion_heap *heap;
+ struct ion_heap_data hdata;
- snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader));
- client = ion_client_create(dev, debug_name);
- if (IS_ERR(client))
- return PTR_ERR(client);
- file->private_data = client;
+ memset(&hdata, 0, sizeof(hdata));
- return 0;
+ down_read(&dev->lock);
+ if (!buffer) {
+ query->cnt = dev->heap_cnt;
+ ret = 0;
+ goto out;
+ }
+
+ if (query->cnt <= 0)
+ goto out;
+
+ max_cnt = query->cnt;
+
+ plist_for_each_entry(heap, &dev->heaps, node) {
+ strlcpy(hdata.name, heap->name, sizeof(hdata.name));
+ hdata.name[sizeof(hdata.name) - 1] = '\0';
+ hdata.type = heap->type;
+ hdata.heap_id = heap->id;
+
+ if (copy_to_user(&buffer[cnt], &hdata, sizeof(hdata))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ cnt++;
+ if (cnt >= max_cnt)
+ break;
+ }
+
+ query->cnt = cnt;
+ ret = 0;
+out:
+ up_read(&dev->lock);
+ return ret;
}
static const struct file_operations ion_fops = {
.owner = THIS_MODULE,
- .open = ion_open,
- .release = ion_release,
.unlocked_ioctl = ion_ioctl,
- .compat_ioctl = compat_ion_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ion_ioctl,
+#endif
};
-static size_t ion_debug_heap_total(struct ion_client *client,
- unsigned int id)
+static void __ion_debug_heap_usage_show(struct ion_heap *heap)
{
- size_t size = 0;
+ struct ion_device *dev = heap->dev;
struct rb_node *n;
+ size_t total_size = 0;
- mutex_lock(&client->lock);
- for (n = rb_first(&client->handles); n; n = rb_next(n)) {
- struct ion_handle *handle = rb_entry(n,
- struct ion_handle,
+ pr_info("ion heap: %s %u\n", heap->name, heap->id);
+ pr_info("%16s %16s %16s\n", "task", "pid", "size");
+ mutex_lock(&dev->buffer_lock);
+ for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
+ struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
node);
- if (handle->buffer->heap->id == id)
- size += handle->buffer->size;
+ if (buffer->heap->id != heap->id)
+ continue;
+ total_size += buffer->size;
+ pr_info("%16s %16u (%16s %16u) %16zu\n", buffer->task_comm,
+ buffer->pid, buffer->thread_comm, buffer->tid,
+ buffer->size);
}
- mutex_unlock(&client->lock);
- return size;
+ mutex_unlock(&dev->buffer_lock);
+ pr_info("%16s %16zu\n", "total ", total_size);
+ pr_info("%16.s %16lu\n", "peak allocated",
+ atomic_long_read(&heap->total_allocated_peak));
+}
+
+static void ion_debug_heap_usage_show(struct ion_heap *heap)
+{
+ static DEFINE_RATELIMIT_STATE(show_heap_usage, HZ * 10, 1);
+
+ /* supports only for some heaps */
+ if (heap->type != ION_HEAP_TYPE_CARVEOUT &&
+ heap->type != ION_HEAP_TYPE_DMA &&
+ heap->type != ION_HEAP_TYPE_SECURE_DMA &&
+ heap->type != ION_HEAP_TYPE_HYP_CMA &&
+ heap->type != ION_HEAP_TYPE_SECURE_CARVEOUT)
+ return;
+
+ if (heap->id == ION_CAMERA_HEAP_ID)
+ return;
+
+ if (!__ratelimit(&show_heap_usage))
+ return;
+
+ __ion_debug_heap_usage_show(heap);
}
+static void ion_debug_heap_usage_show_force(struct ion_heap *heap)
+{
+ static DEFINE_RATELIMIT_STATE(show_heap_usage_force, HZ * 10, 1);
+
+ if (!__ratelimit(&show_heap_usage_force))
+ return;
+
+ __ion_debug_heap_usage_show(heap);
+}
+
+static int ion_oom_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct ion_heap *heap;
+
+ /* print ion system_heap */
+ heap = get_ion_heap(ION_SYSTEM_HEAP_ID);
+ ion_debug_heap_usage_show_force(heap);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ion_oom_notifier = {
+ .notifier_call = ion_oom_notify,
+};
+
static int ion_debug_heap_show(struct seq_file *s, void *unused)
{
struct ion_heap *heap = s->private;
struct ion_device *dev = heap->dev;
struct rb_node *n;
size_t total_size = 0;
- size_t total_orphaned_size = 0;
seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size");
- seq_puts(s, "----------------------------------------------------\n");
-
- down_read(&dev->lock);
-
- for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
- struct ion_client *client = rb_entry(n, struct ion_client,
- node);
- size_t size = ion_debug_heap_total(client, heap->id);
-
- if (!size)
- continue;
- if (client->task) {
- char task_comm[TASK_COMM_LEN];
- get_task_comm(task_comm, client->task);
- seq_printf(s, "%16s %16u %16zu\n", task_comm,
- client->pid, size);
- } else {
- seq_printf(s, "%16s %16u %16zu\n", client->name,
- client->pid, size);
- }
- }
seq_puts(s, "----------------------------------------------------\n");
- seq_puts(s, "orphaned allocations (info is from last known client):\n");
mutex_lock(&dev->buffer_lock);
for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
@@ -2059,31 +1316,24 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
if (buffer->heap->id != heap->id)
continue;
total_size += buffer->size;
- if (!buffer->handle_count) {
- seq_printf(s, "%16s %16u %16zu %d %d\n",
- buffer->task_comm, buffer->pid,
- buffer->size, buffer->kmap_cnt,
- atomic_read(&buffer->ref.refcount));
- total_orphaned_size += buffer->size;
- }
+ seq_printf(s, "%16s %16u (%16s %16u) %16zu\n",
+ buffer->task_comm, buffer->pid,
+ buffer->thread_comm, buffer->tid,
+ buffer->size);
}
mutex_unlock(&dev->buffer_lock);
seq_puts(s, "----------------------------------------------------\n");
- seq_printf(s, "%16s %16zu\n", "total orphaned",
- total_orphaned_size);
seq_printf(s, "%16s %16zu\n", "total ", total_size);
seq_printf(s, "%16.s %16lu\n", "peak allocated",
atomic_long_read(&heap->total_allocated_peak));
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
seq_printf(s, "%16s %16zu\n", "deferred free",
- heap->free_list_size);
+ heap->free_list_size);
seq_puts(s, "----------------------------------------------------\n");
if (heap->debug_show)
heap->debug_show(heap, s, unused);
- up_read(&dev->lock);
-
return 0;
}
@@ -2105,7 +1355,7 @@ static int debug_shrink_set(void *data, u64 val)
struct shrink_control sc;
int objs;
- sc.gfp_mask = -1;
+ sc.gfp_mask = GFP_HIGHUSER;
sc.nr_to_scan = val;
if (!val) {
@@ -2123,7 +1373,7 @@ static int debug_shrink_get(void *data, u64 *val)
struct shrink_control sc;
int objs;
- sc.gfp_mask = -1;
+ sc.gfp_mask = GFP_HIGHUSER;
sc.nr_to_scan = 0;
objs = heap->shrinker.count_objects(&heap->shrinker, &sc);
@@ -2136,10 +1386,10 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
{
- struct dentry *debug_file;
+ char debug_name[64], buf[256];
+ int ret;
- if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma ||
- !heap->ops->unmap_dma)
+ if (!heap->ops->allocate || !heap->ops->free)
pr_err("%s: can not add heap with invalid ops struct.\n",
__func__);
@@ -2149,8 +1399,11 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
ion_heap_init_deferred_free(heap);
- if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink)
- ion_heap_init_shrinker(heap);
+ if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink) {
+ ret = ion_heap_init_shrinker(heap);
+ if (ret)
+ pr_err("%s: Failed to register shrinker\n", __func__);
+ }
heap->dev = dev;
down_write(&dev->lock);
@@ -2160,278 +1413,35 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
*/
plist_node_init(&heap->node, -heap->id);
plist_add(&heap->node, &dev->heaps);
- debug_file = debugfs_create_file(heap->name, 0664,
- dev->heaps_debug_root, heap,
- &debug_heap_fops);
-
- if (!debug_file) {
- char buf[256], *path;
- path = dentry_path(dev->heaps_debug_root, buf, 256);
+ snprintf(debug_name, 64, "%s", heap->name);
+ if (!debugfs_create_file(heap->name, 0664, dev->heaps_debug_root,
+ heap, &debug_heap_fops))
pr_err("Failed to create heap debugfs at %s/%s\n",
- path, heap->name);
- }
+ dentry_path(dev->heaps_debug_root, buf, 256),
+ debug_name);
- if (heap->shrinker.count_objects && heap->shrinker.scan_objects) {
- char debug_name[64];
+ if (heap->shrinker.count_objects && heap->shrinker.scan_objects) {
snprintf(debug_name, 64, "%s_shrink", heap->name);
- debug_file = debugfs_create_file(
- debug_name, 0644, dev->heaps_debug_root, heap,
- &debug_shrink_fops);
- if (!debug_file) {
- char buf[256], *path;
-
- path = dentry_path(dev->heaps_debug_root, buf, 256);
- pr_err("Failed to create heap shrinker debugfs at %s/%s\n",
- path, debug_name);
- }
+ if (!debugfs_create_file(debug_name, 0644, dev->heaps_debug_root,
+ heap, &debug_shrink_fops))
+ pr_err("Failed to create heap debugfs at %s/%s\n",
+ dentry_path(dev->heaps_debug_root, buf, 256),
+ debug_name);
}
+ dev->heap_cnt++;
up_write(&dev->lock);
}
EXPORT_SYMBOL(ion_device_add_heap);
-#ifdef CONFIG_ION_EXYNOS_STAT_LOG
-
-#define MAX_DUMP_TASKS 8
-#define MAX_DUMP_NAME_LEN 32
-#define MAX_DUMP_BUFF_LEN 512
-
-static void ion_buffer_dump_flags(struct seq_file *s, unsigned long flags)
-{
- if ((flags & ION_FLAG_CACHED) && !(flags & ION_FLAG_CACHED_NEEDS_SYNC))
- seq_printf(s, "cached|faultmap");
- else if (flags & ION_FLAG_CACHED)
- seq_printf(s, "cached|needsync");
- else
- seq_printf(s, "noncached");
-
- if (flags & ION_FLAG_NOZEROED)
- seq_printf(s, "|nozeroed");
-
- if (flags & ION_FLAG_PROTECTED)
- seq_printf(s, "|protected");
-}
-
-static void ion_buffer_dump_tasks(struct ion_buffer *buffer, char *str)
-{
- struct ion_task *task, *tmp;
- const char *delim = "|";
- size_t total_len = 0;
- int count = 0;
-
- list_for_each_entry_safe(task, tmp, &buffer->master_list, list) {
- const char *name;
- size_t len = strlen(dev_name(task->master));
-
- if (len > MAX_DUMP_NAME_LEN)
- len = MAX_DUMP_NAME_LEN;
- if (!strncmp(dev_name(task->master), "ion", len)) {
- continue;
- } else {
- name = dev_name(task->master) + 9;
- len -= 9;
- }
- if (total_len + len + 1 > MAX_DUMP_BUFF_LEN)
- break;
-
- strncat((char *)(str + total_len), name, len);
- total_len += len;
- if (!list_is_last(&task->list, &buffer->master_list))
- str[total_len++] = *delim;
-
- if (++count > MAX_DUMP_TASKS)
- break;
- }
-}
-
-static int ion_debug_buffer_show(struct seq_file *s, void *unused)
-{
- struct ion_device *dev = s->private;
- struct rb_node *n;
- char *master_name;
- size_t total_size = 0;
-
- master_name = kzalloc(MAX_DUMP_BUFF_LEN, GFP_KERNEL);
- if (!master_name) {
- pr_err("%s: no memory for client string buffer\n", __func__);
- return -ENOMEM;
- }
-
- seq_printf(s, "%20.s %16.s %4.s %16.s %4.s %10.s %4.s %3.s %6.s "
- "%24.s %9.s\n",
- "heap", "task", "pid", "thread", "tid",
- "size", "kmap", "ref", "handle",
- "master", "flag");
- seq_printf(s, "------------------------------------------"
- "----------------------------------------"
- "----------------------------------------"
- "--------------------------------------\n");
-
- mutex_lock(&dev->buffer_lock);
- for (n = rb_first(&dev->buffers); n; n = rb_next(n)) {
- struct ion_buffer *buffer = rb_entry(n, struct ion_buffer,
- node);
- mutex_lock(&buffer->lock);
- ion_buffer_dump_tasks(buffer, master_name);
- total_size += buffer->size;
- seq_printf(s, "%20.s %16.s %4u %16.s %4u %10zu %4d %3d %6d "
- "%24.s %9lx", buffer->heap->name,
- buffer->task_comm, buffer->pid,
- buffer->thread_comm,
- buffer->tid, buffer->size, buffer->kmap_cnt,
- atomic_read(&buffer->ref.refcount),
- buffer->handle_count, master_name,
- buffer->flags);
- seq_printf(s, "(");
- ion_buffer_dump_flags(s, buffer->flags);
- seq_printf(s, ")\n");
- mutex_unlock(&buffer->lock);
-
- memset(master_name, 0, MAX_DUMP_BUFF_LEN);
- }
- mutex_unlock(&dev->buffer_lock);
-
- seq_printf(s, "------------------------------------------"
- "----------------------------------------"
- "----------------------------------------"
- "--------------------------------------\n");
- seq_printf(s, "%16.s %16zu\n", "total ", total_size);
- seq_printf(s, "------------------------------------------"
- "----------------------------------------"
- "----------------------------------------"
- "--------------------------------------\n");
-
- kfree(master_name);
-
- return 0;
-}
-
-static int ion_debug_buffer_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ion_debug_buffer_show, inode->i_private);
-}
-
-static const struct file_operations debug_buffer_fops = {
- .open = ion_debug_buffer_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void ion_debug_event_show_one(struct seq_file *s,
- struct ion_eventlog *log)
-{
- struct timeval tv = ktime_to_timeval(log->begin);
- long elapsed = ktime_us_delta(log->done, log->begin);
-
- if (elapsed == 0)
- return;
-
- seq_printf(s, "[%06ld.%06ld] ", tv.tv_sec, tv.tv_usec);
-
- switch (log->type) {
- case ION_EVENT_TYPE_ALLOC:
- {
- struct ion_event_alloc *data = &log->data.alloc;
- seq_printf(s, "%8s %pK %18s %11zd ", "alloc",
- data->id, data->heapname, data->size);
- break;
- }
- case ION_EVENT_TYPE_FREE:
- {
- struct ion_event_free *data = &log->data.free;
- seq_printf(s, "%8s %pK %18s %11zd ", "free",
- data->id, data->heapname, data->size);
- break;
- }
- case ION_EVENT_TYPE_MMAP:
- {
- struct ion_event_mmap *data = &log->data.mmap;
- seq_printf(s, "%8s %pK %18s %11zd ", "mmap",
- data->id, data->heapname, data->size);
- break;
- }
- case ION_EVENT_TYPE_SHRINK:
- {
- struct ion_event_shrink *data = &log->data.shrink;
- seq_printf(s, "%8s %16lx %18s %11zd ", "shrink",
- 0l, "ion_noncontig_heap", data->size);
- elapsed = 0;
- break;
- }
- case ION_EVENT_TYPE_CLEAR:
- {
- struct ion_event_clear *data = &log->data.clear;
- seq_printf(s, "%8s %pK %18s %11zd ", "clear",
- data->id, data->heapname, data->size);
- break;
- }
- }
-
- seq_printf(s, "%9ld", elapsed);
-
- if (elapsed > 100 * USEC_PER_MSEC)
- seq_printf(s, " *");
-
- if (log->type == ION_EVENT_TYPE_ALLOC) {
- seq_printf(s, " ");
- ion_buffer_dump_flags(s, log->data.alloc.flags);
- } else if (log->type == ION_EVENT_TYPE_CLEAR) {
- seq_printf(s, " ");
- ion_buffer_dump_flags(s, log->data.clear.flags);
- }
-
- if (log->type == ION_EVENT_TYPE_FREE && log->data.free.shrinker)
- seq_printf(s, " shrinker");
-
- seq_printf(s, "\n");
-}
-
-static int ion_debug_event_show(struct seq_file *s, void *unused)
-{
- struct ion_device *dev = s->private;
- int index = atomic_read(&dev->event_idx) % ION_EVENT_LOG_MAX;
- int last = index;
-
- seq_printf(s, "%13s %10s %8s %18s %11s %10s %24s\n", "timestamp",
- "type", "id", "heap", "size", "time (us)", "remarks");
- seq_printf(s, "-------------------------------------------");
- seq_printf(s, "-------------------------------------------");
- seq_printf(s, "-----------------------------------------\n");
-
- do {
- if (++index >= ION_EVENT_LOG_MAX)
- index = 0;
- ion_debug_event_show_one(s, &dev->eventlog[index]);
- } while (index != last);
-
- return 0;
-}
-
-static int ion_debug_event_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ion_debug_event_show, inode->i_private);
-}
-
-static const struct file_operations debug_event_fops = {
- .open = ion_debug_event_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif
-
-struct ion_device *ion_device_create(long (*custom_ioctl)
- (struct ion_client *client,
- unsigned int cmd,
- unsigned long arg))
+struct ion_device *ion_device_create(void)
{
struct ion_device *idev;
int ret;
- idev = kzalloc(sizeof(struct ion_device), GFP_KERNEL);
+ idev = kzalloc(sizeof(*idev), GFP_KERNEL);
if (!idev)
return ERR_PTR(-ENOMEM);
@@ -2447,236 +1457,13 @@ struct ion_device *ion_device_create(long (*custom_ioctl)
}
idev->debug_root = debugfs_create_dir("ion", NULL);
- if (!idev->debug_root) {
- pr_err("ion: failed to create debugfs root directory.\n");
- goto debugfs_done;
- }
idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root);
- if (!idev->heaps_debug_root) {
- pr_err("ion: failed to create debugfs heaps directory.\n");
- goto debugfs_done;
- }
- idev->clients_debug_root = debugfs_create_dir("clients",
- idev->debug_root);
- if (!idev->clients_debug_root) {
- pr_err("ion: failed to create debugfs clients directory.\n");
- goto debugfs_done;
- }
-
-#ifdef CONFIG_ION_EXYNOS_STAT_LOG
- atomic_set(&idev->event_idx, -1);
- idev->buffer_debug_file = debugfs_create_file("buffer", 0444,
- idev->debug_root, idev,
- &debug_buffer_fops);
- if (!idev->buffer_debug_file) {
- pr_err("%s: failed to create buffer debug file\n", __func__);
- goto debugfs_done;
- }
-
- idev->event_debug_file = debugfs_create_file("event", 0444,
- idev->debug_root, idev,
- &debug_event_fops);
- if (!idev->event_debug_file)
- pr_err("%s: failed to create event debug file\n", __func__);
-#endif
-
-debugfs_done:
-
- idev->custom_ioctl = custom_ioctl;
+ WARN_ON(register_oom_notifier(&ion_oom_notifier));
idev->buffers = RB_ROOT;
mutex_init(&idev->buffer_lock);
init_rwsem(&idev->lock);
plist_head_init(&idev->heaps);
- idev->clients = RB_ROOT;
-
- /* backup of ion device: assumes there is only one ion device */
- g_idev = idev;
-
+ internal_dev = idev;
return idev;
}
EXPORT_SYMBOL(ion_device_create);
-
-void ion_device_destroy(struct ion_device *dev)
-{
- misc_deregister(&dev->dev);
- debugfs_remove_recursive(dev->debug_root);
- kfree(dev);
-}
-EXPORT_SYMBOL(ion_device_destroy);
-
-void __init ion_reserve(struct ion_platform_data *data)
-{
- int i;
-
- for (i = 0; i < data->nr; i++) {
- if (data->heaps[i].size == 0)
- continue;
-
- if (data->heaps[i].base == 0) {
- phys_addr_t paddr;
-
- paddr = memblock_alloc_base(data->heaps[i].size,
- data->heaps[i].align,
- MEMBLOCK_ALLOC_ANYWHERE);
- if (!paddr) {
- pr_err("%s: error allocating memblock for heap %d\n",
- __func__, i);
- continue;
- }
- data->heaps[i].base = paddr;
- } else {
- int ret = memblock_reserve(data->heaps[i].base,
- data->heaps[i].size);
- if (ret)
- pr_err("memblock reserve of %zx@%lx failed\n",
- data->heaps[i].size,
- data->heaps[i].base);
- }
- pr_info("%s: %s reserved base %lx size %zu\n", __func__,
- data->heaps[i].name,
- data->heaps[i].base,
- data->heaps[i].size);
- }
-}
-
-static struct ion_iovm_map *ion_buffer_iova_create(struct ion_buffer *buffer,
- struct device *dev, enum dma_data_direction dir, int prop)
-{
- /* Must be called under buffer->lock held */
- struct ion_iovm_map *iovm_map;
- int ret = 0;
-
- iovm_map = kzalloc(sizeof(struct ion_iovm_map), GFP_KERNEL);
- if (!iovm_map) {
- pr_err("%s: Failed to allocate ion_iovm_map for %s\n",
- __func__, dev_name(dev));
- return ERR_PTR(-ENOMEM);
- }
-
- iovm_map->iova = iovmm_map(dev, buffer->sg_table->sgl,
- 0, buffer->size, dir, prop);
-
- if (iovm_map->iova == (dma_addr_t)-ENOSYS) {
- size_t len;
- ion_phys_addr_t addr;
-
- BUG_ON(!buffer->heap->ops->phys);
- ret = buffer->heap->ops->phys(buffer->heap, buffer,
- &addr, &len);
- if (ret)
- pr_err("%s: Unable to get PA for %s\n",
- __func__, dev_name(dev));
- } else if (IS_ERR_VALUE(iovm_map->iova)) {
- ret = iovm_map->iova;
- pr_err("%s: Unable to allocate IOVA for %s\n",
- __func__, dev_name(dev));
- }
-
- if (ret) {
- kfree(iovm_map);
- return ERR_PTR(ret);
- }
-
- iovm_map->dev = dev;
- iovm_map->domain = get_domain_from_dev(dev);
- iovm_map->map_cnt = 1;
-
- pr_debug("%s: new map added for dev %s, iova %pa, prop %d\n", __func__,
- dev_name(dev), &iovm_map->iova, prop);
-
- return iovm_map;
-}
-
-dma_addr_t ion_iovmm_map(struct dma_buf_attachment *attachment,
- off_t offset, size_t size,
- enum dma_data_direction direction, int prop)
-{
- struct dma_buf *dmabuf = attachment->dmabuf;
- struct ion_buffer *buffer = dmabuf->priv;
- struct ion_iovm_map *iovm_map;
- struct iommu_domain *domain;
-
- BUG_ON(dmabuf->ops != &dma_buf_ops);
-
- if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION) &&
- buffer->flags & ION_FLAG_PROTECTED) {
- struct ion_buffer_info *info = buffer->priv_virt;
-
- if (info->prot_desc.dma_addr)
- return info->prot_desc.dma_addr;
- pr_err("%s: protected buffer but no secure iova\n", __func__);
- return -EINVAL;
- }
-
- domain = get_domain_from_dev(attachment->dev);
- if (!domain) {
- pr_err("%s: invalid iommu device\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&buffer->lock);
- list_for_each_entry(iovm_map, &buffer->iovas, list) {
- if (domain == iovm_map->domain) {
- iovm_map->map_cnt++;
- mutex_unlock(&buffer->lock);
- return iovm_map->iova;
- }
- }
-
- if (!ion_buffer_cached(buffer))
- prop &= ~IOMMU_CACHE;
-
- iovm_map = ion_buffer_iova_create(buffer, attachment->dev,
- direction, prop);
- if (IS_ERR(iovm_map)) {
- mutex_unlock(&buffer->lock);
- return PTR_ERR(iovm_map);
- }
-
- list_add_tail(&iovm_map->list, &buffer->iovas);
- mutex_unlock(&buffer->lock);
-
- return iovm_map->iova;
-}
-
-void ion_iovmm_unmap(struct dma_buf_attachment *attachment, dma_addr_t iova)
-{
- struct ion_iovm_map *iovm_map;
- struct dma_buf * dmabuf = attachment->dmabuf;
- struct device *dev = attachment->dev;
- struct ion_buffer *buffer = attachment->dmabuf->priv;
- struct iommu_domain *domain;
-
- BUG_ON(dmabuf->ops != &dma_buf_ops);
-
- if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION) &&
- buffer->flags & ION_FLAG_PROTECTED)
- return;
-
- domain = get_domain_from_dev(attachment->dev);
- if (!domain) {
- pr_err("%s: invalid iommu device\n", __func__);
- return;
- }
-
- mutex_lock(&buffer->lock);
- list_for_each_entry(iovm_map, &buffer->iovas, list) {
- if ((domain == iovm_map->domain) && (iova == iovm_map->iova)) {
- if (--iovm_map->map_cnt == 0) {
- list_del(&iovm_map->list);
- pr_debug("%s: unmap previous %pa for dev %s\n",
- __func__, &iovm_map->iova,
- dev_name(iovm_map->dev));
- iovmm_unmap(iovm_map->dev, iovm_map->iova);
- kfree(iovm_map);
- }
-
- mutex_unlock(&buffer->lock);
- return;
- }
- }
-
- mutex_unlock(&buffer->lock);
-
- WARN(1, "IOVA %pa is not found for %s\n", &iova, dev_name(dev));
-}
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
old mode 100755
new mode 100644
index 6fa9dbe3..b1236ed4
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -1,51 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* drivers/staging/android/ion/ion.h
*
* Copyright (C) 2011 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
*
*/
-#ifndef _LINUX_ION_H
-#define _LINUX_ION_H
+#ifndef _ION_H
+#define _ION_H
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
+#include
+#include
+#include
+#include "ion_kernel.h"
+#include "../uapi/ion.h"
+#include "../uapi/msm_ion.h"
-#include
+#define ION_ADSP_HEAP_NAME "adsp"
+#define ION_SYSTEM_HEAP_NAME "system"
+#define ION_MM_HEAP_NAME "mm"
+#define ION_CAMERA_HEAP_NAME "camera_preview"
+#define ION_SPSS_HEAP_NAME "spss"
+#define ION_SECURE_CARVEOUT_HEAP_NAME "secure_carveout"
+#define ION_USER_CONTIG_HEAP_NAME "user_contig"
+#define ION_QSECOM_HEAP_NAME "qsecom"
+#define ION_QSECOM_TA_HEAP_NAME "qsecom_ta"
+#define ION_SECURE_HEAP_NAME "secure_heap"
+#define ION_SECURE_DISPLAY_HEAP_NAME "secure_display"
+#define ION_AUDIO_HEAP_NAME "audio"
-struct ion_handle;
-struct ion_device;
-struct ion_heap;
-struct ion_mapper;
-struct ion_client;
-struct ion_buffer;
+#define ION_IS_CACHED(__flags) ((__flags) & ION_FLAG_CACHED)
-/*
- * This should be removed some day when phys_addr_t's are fully
- * plumbed in the kernel, and all instances of ion_phys_addr_t should
- * be converted to phys_addr_t. For the time being many kernel interfaces
- * do not accept phys_addr_t's that would have to
+/**
+ * Debug feature. Make ION allocations DMA
+ * ready to help identify clients who are wrongly
+ * dependending on ION allocations being DMA
+ * ready.
+ *
+ * As default set to 'false' since ION allocations
+ * are no longer required to be DMA ready
*/
-#define ion_phys_addr_t unsigned long
+#ifdef CONFIG_ION_FORCE_DMA_SYNC
+#define MAKE_ION_ALLOC_DMA_READY 1
+#else
+#define MAKE_ION_ALLOC_DMA_READY 0
+#endif
+
+/* ION page pool marks in bytes */
+#ifdef CONFIG_ION_POOL_AUTO_REFILL
+#define ION_POOL_FILL_MARK (CONFIG_ION_POOL_FILL_MARK * SZ_1M)
+#define POOL_LOW_MARK_PERCENT 40UL
+#define ION_POOL_LOW_MARK ((ION_POOL_FILL_MARK * POOL_LOW_MARK_PERCENT) / 100)
+#else
+#define ION_POOL_FILL_MARK 0UL
+#define ION_POOL_LOW_MARK 0UL
+#endif
+
+/* if low watermark of zones have reached, defer the refill in this window */
+#define ION_POOL_REFILL_DEFER_WINDOW_MS 10
/**
* struct ion_platform_heap - defines a heap in the given platform
* @type: type of the heap from ion_heap_type enum
- * @id: unique identifier for heap. When allocating higher numbers
+ * @id: unique identifier for heap. When allocating higher numb ers
* will be allocated from first. At allocation these are passed
* as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS.
* @name: used for debug purposes
* @base: base address of heap in physical memory if applicable
* @size: size of the heap in bytes if applicable
- * @align: required alignment in physical memory if applicable
* @priv: private info passed from the board file
*
* Provided by the board file.
@@ -54,16 +87,16 @@ struct ion_platform_heap {
enum ion_heap_type type;
unsigned int id;
const char *name;
- ion_phys_addr_t base;
+ phys_addr_t base;
size_t size;
- ion_phys_addr_t align;
+ phys_addr_t align;
void *priv;
};
/**
* struct ion_platform_data - array of platform heaps passed from board file
- * @nr: number of structures in the array
- * @heaps: array of platform_heap structions
+ * @nr: number of structures in the array
+ * @heaps: array of platform_heap structions
*
* Provided by the board file in the form of platform data to a platform device.
*/
@@ -72,182 +105,420 @@ struct ion_platform_data {
struct ion_platform_heap *heaps;
};
+struct ion_vma_list {
+ struct list_head list;
+ struct vm_area_struct *vma;
+};
+
+/**
+ * struct ion_buffer - metadata for a particular buffer
+ * @ref: reference count
+ * @node: node in the ion_device buffers tree
+ * @dev: back pointer to the ion_device
+ * @heap: back pointer to the heap the buffer came from
+ * @flags: buffer specific flags
+ * @private_flags: internal buffer specific flags
+ * @size: size of the buffer
+ * @priv_virt: private data to the buffer representable as
+ * a void *
+ * @lock: protects the buffers cnt fields
+ * @kmap_cnt: number of times the buffer is mapped to the kernel
+ * @vaddr: the kernel mapping if kmap_cnt is not zero
+ * @sg_table: the sg table for the buffer if dmap_cnt is not zero
+ * @vmas: list of vma's mapping this buffer
+ */
+struct ion_buffer {
+ union {
+ struct rb_node node;
+ struct list_head list;
+ };
+ struct ion_device *dev;
+ struct ion_heap *heap;
+ unsigned long flags;
+ unsigned long private_flags;
+ size_t size;
+ void *priv_virt;
+ /* Protect ion buffer */
+ struct mutex lock;
+ int kmap_cnt;
+ void *vaddr;
+ struct sg_table *sg_table;
+ struct list_head attachments;
+ struct list_head vmas;
+ char task_comm[TASK_COMM_LEN];
+ pid_t pid;
+ char thread_comm[TASK_COMM_LEN];
+ pid_t tid;
+};
+
+void ion_buffer_destroy(struct ion_buffer *buffer);
+
+/**
+ * struct ion_device - the metadata of the ion device node
+ * @dev: the actual misc device
+ * @buffers: an rb tree of all the existing buffers
+ * @buffer_lock: lock protecting the tree of buffers
+ * @lock: rwsem protecting the tree of heaps and clients
+ */
+struct ion_device {
+ struct miscdevice dev;
+ struct rb_root buffers;
+ /* buffer_lock used for adding and removing buffers */
+ struct mutex buffer_lock;
+ struct rw_semaphore lock;
+ struct plist_head heaps;
+ struct dentry *debug_root;
+ struct dentry *heaps_debug_root;
+ int heap_cnt;
+};
+
/**
- * ion_reserve() - reserve memory for ion heaps if applicable
- * @data: platform data specifying starting physical address and
- * size
+ * struct ion_heap_ops - ops to operate on a given heap
+ * @allocate: allocate memory
+ * @free: free memory
+ * @map_kernel map memory to the kernel
+ * @unmap_kernel unmap memory to the kernel
+ * @map_user map memory to userspace
*
- * Calls memblock reserve to set aside memory for heaps that are
- * located at specific memory addresses or of specific sizes not
- * managed by the kernel
+ * allocate, phys, and map_user return 0 on success, -errno on error.
+ * map_dma and map_kernel return pointer on success, ERR_PTR on
+ * error. @free will be called with ION_PRIV_FLAG_SHRINKER_FREE set in
+ * the buffer's private_flags when called from a shrinker. In that
+ * case, the pages being free'd must be truly free'd back to the
+ * system, not put in a page pool or otherwise cached.
*/
-void ion_reserve(struct ion_platform_data *data);
+struct ion_heap_ops {
+ int (*allocate)(struct ion_heap *heap,
+ struct ion_buffer *buffer, unsigned long len,
+ unsigned long flags);
+ void (*free)(struct ion_buffer *buffer);
+ void * (*map_kernel)(struct ion_heap *heap, struct ion_buffer *buffer);
+ void (*unmap_kernel)(struct ion_heap *heap, struct ion_buffer *buffer);
+ int (*map_user)(struct ion_heap *mapper, struct ion_buffer *buffer,
+ struct vm_area_struct *vma);
+ int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan);
+};
/**
- * ion_client_create() - allocate a client and returns it
- * @dev: the global ion device
- * @name: used for debugging
+ * heap flags - flags between the heaps and core ion code
*/
-struct ion_client *ion_client_create(struct ion_device *dev,
- const char *name);
+#define ION_HEAP_FLAG_DEFER_FREE BIT(0)
/**
- * ion_client_create() - allocate a client and returns it
+ * private flags - flags internal to ion
+ */
+/*
+ * Buffer is being freed from a shrinker function. Skip any possible
+ * heap-specific caching mechanism (e.g. page pools). Guarantees that
+ * any buffer storage that came from the system allocator will be
+ * returned to the system allocator.
+ */
+#define ION_PRIV_FLAG_SHRINKER_FREE BIT(0)
+
+/**
+ * struct ion_heap - represents a heap in the system
+ * @node: rb node to put the heap on the device's tree of heaps
+ * @dev: back pointer to the ion_device
+ * @type: type of heap
+ * @ops: ops struct as above
+ * @flags: flags
+ * @id: id of heap, also indicates priority of this heap when
+ * allocating. These are specified by platform data and
+ * MUST be unique
* @name: used for debugging
+ * @shrinker: a shrinker for the heap
+ * @priv: private heap data
+ * @free_list: free list head if deferred free is used
+ * @free_list_size size of the deferred free list in bytes
+ * @lock: protects the free list
+ * @waitqueue: queue to wait on from deferred free thread
+ * @task: task struct of deferred free thread
+ * @debug_show: called when heap debug file is read to add any
+ * heap specific debug info to output
+ *
+ * Represents a pool of memory from which buffers can be made. In some
+ * systems the only heap is regular system memory allocated via vmalloc.
+ * On others, some blocks might require large physically contiguous buffers
+ * that are allocated from a specially reserved heap.
*/
-struct ion_client *exynos_ion_client_create(const char *name);
+struct ion_heap {
+ struct plist_node node;
+ struct ion_device *dev;
+ enum ion_heap_type type;
+ struct ion_heap_ops *ops;
+ unsigned long flags;
+ unsigned int id;
+ const char *name;
+ struct shrinker shrinker;
+ void *priv;
+ struct list_head free_list;
+ size_t free_list_size;
+ /* Protect the free list */
+ spinlock_t free_lock;
+ wait_queue_head_t waitqueue;
+ struct task_struct *task;
+ atomic_long_t total_allocated;
+ atomic_long_t total_allocated_peak;
+
+ int (*debug_show)(struct ion_heap *heap, struct seq_file *s,
+ void *unused);
+};
/**
- * ion_client_destroy() - free's a client and all it's handles
- * @client: the client
+ * ion_buffer_cached - this ion buffer is cached
+ * @buffer: buffer
*
- * Free the provided client and all it's resources including
- * any handles it is holding.
+ * indicates whether this ion buffer is cached
*/
-void ion_client_destroy(struct ion_client *client);
+bool ion_buffer_cached(struct ion_buffer *buffer);
/**
- * ion_alloc - allocate ion memory
- * @client: the client
- * @len: size of the allocation
- * @align: requested allocation alignment, lots of hardware blocks
- * have alignment requirements of some kind
- * @heap_id_mask: mask of heaps to allocate from, if multiple bits are set
- * heaps will be tried in order from highest to lowest
- * id
- * @flags: heap flags, the low 16 bits are consumed by ion, the
- * high 16 bits are passed on to the respective heap and
- * can be heap custom
+ * ion_device_create - allocates and returns an ion device
*
- * Allocate memory in one of the heaps provided in heap mask and return
- * an opaque handle to it.
+ * returns a valid device or -PTR_ERR
*/
-struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
- size_t align, unsigned int heap_id_mask,
- unsigned int flags);
+struct ion_device *ion_device_create(void);
/**
- * ion_free - free a handle
- * @client: the client
- * @handle: the handle to free
+ * ion_device_add_heap - adds a heap to the ion device
+ * @dev: the device
+ * @heap: the heap to add
+ */
+void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap);
+
+/**
+ * some helpers for common operations on buffers using the sg_table
+ * and vaddr fields
+ */
+void *ion_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer);
+void ion_heap_unmap_kernel(struct ion_heap *heap, struct ion_buffer *buffer);
+int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
+ struct vm_area_struct *vma);
+int ion_heap_buffer_zero(struct ion_buffer *buffer);
+int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
+
+int ion_alloc_fd(size_t len, unsigned int heap_id_mask, unsigned int flags);
+
+/**
+ * ion_heap_init_shrinker
+ * @heap: the heap
*
- * Free the provided handle.
+ * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag or defines the shrink op
+ * this function will be called to setup a shrinker to shrink the freelists
+ * and call the heap's shrink op.
*/
-void ion_free(struct ion_client *client, struct ion_handle *handle);
+int ion_heap_init_shrinker(struct ion_heap *heap);
/**
- * ion_phys - returns the physical address and len of a handle
- * @client: the client
- * @handle: the handle
- * @addr: a pointer to put the address in
- * @len: a pointer to put the length in
+ * ion_heap_init_deferred_free -- initialize deferred free functionality
+ * @heap: the heap
*
- * This function queries the heap for a particular handle to get the
- * handle's physical address. It't output is only correct if
- * a heap returns physically contiguous memory -- in other cases
- * this api should not be implemented -- ion_sg_table should be used
- * instead. Returns -EINVAL if the handle is invalid. This has
- * no implications on the reference counting of the handle --
- * the returned value may not be valid if the caller is not
- * holding a reference.
+ * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag this function will
+ * be called to setup deferred frees. Calls to free the buffer will
+ * return immediately and the actual free will occur some time later
*/
-int ion_phys(struct ion_client *client, struct ion_handle *handle,
- ion_phys_addr_t *addr, size_t *len);
+int ion_heap_init_deferred_free(struct ion_heap *heap);
/**
- * ion_map_dma - return an sg_table describing a handle
- * @client: the client
- * @handle: the handle
+ * ion_heap_freelist_add - add a buffer to the deferred free list
+ * @heap: the heap
+ * @buffer: the buffer
*
- * This function returns the sg_table describing
- * a particular ion handle.
+ * Adds an item to the deferred freelist.
*/
-struct sg_table *ion_sg_table(struct ion_client *client,
- struct ion_handle *handle);
+void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer);
/**
- * ion_map_kernel - create mapping for the given handle
- * @client: the client
- * @handle: handle to map
+ * ion_heap_freelist_drain - drain the deferred free list
+ * @heap: the heap
+ * @size: amount of memory to drain in bytes
*
- * Map the given handle into the kernel and return a kernel address that
- * can be used to access this address.
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed. The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
*/
-void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle);
+size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size);
/**
- * ion_unmap_kernel() - destroy a kernel mapping for a handle
- * @client: the client
- * @handle: handle to unmap
+ * ion_heap_freelist_shrink - drain the deferred free
+ * list, skipping any heap-specific
+ * pooling or caching mechanisms
+ *
+ * @heap: the heap
+ * @size: amount of memory to drain in bytes
+ *
+ * Drains the indicated amount of memory from the deferred freelist immediately.
+ * Returns the total amount freed. The total freed may be higher depending
+ * on the size of the items in the list, or lower if there is insufficient
+ * total memory on the freelist.
+ *
+ * Unlike with @ion_heap_freelist_drain, don't put any pages back into
+ * page pools or otherwise cache the pages. Everything must be
+ * genuinely free'd back to the system. If you're free'ing from a
+ * shrinker you probably want to use this. Note that this relies on
+ * the heap.ops.free callback honoring the ION_PRIV_FLAG_SHRINKER_FREE
+ * flag.
*/
-void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle);
+size_t ion_heap_freelist_shrink(struct ion_heap *heap, size_t size);
/**
- * ion_share_dma_buf() - share buffer as dma-buf
- * @client: the client
- * @handle: the handle
+ * ion_heap_freelist_size - returns the size of the freelist in bytes
+ * @heap: the heap
*/
-struct dma_buf *ion_share_dma_buf(struct ion_client *client,
- struct ion_handle *handle);
+size_t ion_heap_freelist_size(struct ion_heap *heap);
/**
- * ion_share_dma_buf_fd() - given an ion client, create a dma-buf fd
- * @client: the client
- * @handle: the handle
+ * functions for creating and destroying the built in ion heaps.
+ * architectures can add their own custom architecture specific
+ * heaps as appropriate.
*/
-int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle);
+
+struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data);
+
+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused);
+#ifdef CONFIG_ION_RBIN_HEAP
+struct ion_heap *ion_rbin_heap_create(struct ion_platform_heap *unused);
+#endif
+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *heap);
+
+struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data);
+
+struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data);
+
+#ifdef CONFIG_CMA
+struct ion_heap *ion_secure_cma_heap_create(struct ion_platform_heap *data);
+void ion_secure_cma_heap_destroy(struct ion_heap *heap);
+
+struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data);
+#else
+static inline struct ion_heap
+ *ion_secure_cma_heap_create(struct ion_platform_heap *h)
+{
+ return NULL;
+}
+
+static inline void ion_cma_heap_destroy(struct ion_heap *h) {}
+
+static inline struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *h)
+{
+ return NULL;
+}
+#endif
+
+struct ion_heap *ion_system_secure_heap_create(struct ion_platform_heap *heap);
+
+struct ion_heap *ion_cma_secure_heap_create(struct ion_platform_heap *heap);
+
+struct ion_heap *
+ion_secure_carveout_heap_create(struct ion_platform_heap *heap);
/**
- * ion_import_dma_buf() - given an dma-buf fd from the ion exporter get handle
- * @client: the client
- * @fd: the dma-buf fd
- *
- * Given an dma-buf fd that was allocated through ion via ion_share_dma_buf,
- * import that fd and return a handle representing it. If a dma-buf from
- * another exporter is passed in this function will return ERR_PTR(-EINVAL)
+ * functions for creating and destroying a heap pool -- allows you
+ * to keep a pool of pre allocated memory to use from your heap. Keeping
+ * a pool of memory that is ready for dma, ie any cached mapping have been
+ * invalidated from the cache, provides a significant performance benefit on
+ * many systems
*/
-struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd);
/**
- * ion_cached_needsync_dmabuf() - check if a dmabuf is cacheable
- * @dmabuf: a pointer to dma_buf
+ * struct ion_page_pool - pagepool struct
+ * @high_count: number of highmem items in the pool
+ * @low_count: number of lowmem items in the pool
+ * @count: total number of pages/items in the pool
+ * @high_items: list of highmem items
+ * @low_items: list of lowmem items
+ * @mutex: lock protecting this struct and especially the count
+ * item list
+ * @gfp_mask: gfp_mask to use from alloc
+ * @order: order of pages in the pool
+ * @list: plist node for list of pools
+ * @cached: it's cached pool or not
+ * @heap: ion heap associated to this pool
*
- * Given a dma-buf that is exported by ION, check if the buffer is allocated
- * with ION_FLAG_CACHED and ION_FLAG_CACHED_NEED_SYNC. If the flags are set
- * the function returns 1. If it is unset, 0. If the given dmabuf is not
- * exported by ION, -error is returned.
+ * Allows you to keep a pool of pre allocated pages to use from your heap.
+ * Keeping a pool of pages that is ready for dma, ie any cached mapping have
+ * been invalidated from the cache, provides a significant performance benefit
+ * on many systems
*/
-int ion_cached_needsync_dmabuf(struct dma_buf *dmabuf);
+struct ion_page_pool {
+ int high_count;
+ int low_count;
+ atomic_t count;
+ bool cached;
+ struct list_head high_items;
+ struct list_head low_items;
+ ktime_t last_low_watermark_ktime;
+ /* Protect the pool */
+ struct mutex mutex;
+ gfp_t gfp_mask;
+ unsigned int order;
+ struct plist_node list;
+ struct device *dev;
+};
-/**
- * ion_may_hwrender_dmabuf() - check if a dmabuf set ION_FLAG_MAY_HWRENDER
- * @dmabuf: a pointer to dma_buf
+struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
+ bool cached);
+void ion_page_pool_refill(struct ion_page_pool *pool);
+void ion_page_pool_destroy(struct ion_page_pool *pool);
+struct page *ion_page_pool_only_alloc(struct ion_page_pool *pool);
+struct page *ion_page_pool_alloc(struct ion_page_pool *a, bool *from_pool);
+void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
+
+struct ion_heap *get_ion_heap(int heap_id);
+struct page *ion_page_pool_alloc_pool_only(struct ion_page_pool *a);
+void ion_page_pool_free_immediate(struct ion_page_pool *pool,
+ struct page *page);
+int ion_page_pool_total(struct ion_page_pool *pool, bool high);
+size_t ion_system_heap_secure_page_pool_total(struct ion_heap *heap, int vmid);
+
+/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
+ * @pool: the pool
+ * @gfp_mask: the memory type to reclaim
+ * @nr_to_scan: number of items to shrink in pages
*
- * Given a dma-buf that is exported by ION, check if the buffer is allocated
- * with ION_FLAG_MAY_HWRENDER. If the flags are set the function returns true.
- * If it is unset, false. If the given dmabuf is not exported by ION,
- * false is returned.
+ * returns the number of items freed in pages
*/
-bool ion_may_hwrender_dmabuf(struct dma_buf *dmabuf);
+int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
+ int nr_to_scan);
/**
- * ion_may_hwrender_handle() - check if a handle set ION_FLAG_MAY_HWRENDER
- * @client: the client
- * @handle: the handle
- *
- * Given a handle, check if the buffer is allocated with ION_FLAG_MAY_HWRENDER.
- * If the flags are set the function returns true. If it is unset, false.
- * If the given handle is not valid, false is returned.
+ * ion_pages_sync_for_device - cache flush pages for use with the specified
+ * device
+ * @dev: the device the pages will be used with
+ * @page: the first page to be flushed
+ * @size: size in bytes of region to be flushed
+ * @dir: direction of dma transfer
*/
-bool ion_may_hwrender_handle(struct ion_client *client, struct ion_handle *handle);
+void ion_pages_sync_for_device(struct device *dev, struct page *page,
+ size_t size, enum dma_data_direction dir);
-#include
-#include
+int ion_walk_heaps(int heap_id, enum ion_heap_type type, void *data,
+ int (*f)(struct ion_heap *heap, void *data));
+
+long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+
+int ion_query_heaps(struct ion_heap_query *query);
+
+unsigned int get_ion_system_heap_id(void);
+
+static __always_inline int get_pool_fillmark(struct ion_page_pool *pool)
+{
+ return ION_POOL_FILL_MARK / (PAGE_SIZE << pool->order);
+}
+
+static __always_inline int get_pool_lowmark(struct ion_page_pool *pool)
+{
+ return ION_POOL_LOW_MARK / (PAGE_SIZE << pool->order);
+}
-dma_addr_t ion_iovmm_map(struct dma_buf_attachment *attachment,
- off_t offset, size_t size,
- enum dma_data_direction direction, int prop);
-void ion_iovmm_unmap(struct dma_buf_attachment *attachment, dma_addr_t iova);
-bool ion_is_heap_available(struct ion_heap *heap, unsigned long flags, void *data);
+static __always_inline bool pool_count_below_lowmark(struct ion_page_pool *pool)
+{
+ return atomic_read(&pool->count) < get_pool_lowmark(pool);
+}
-#endif /* _LINUX_ION_H */
+static __always_inline bool pool_fillmark_reached(struct ion_page_pool *pool)
+{
+ return atomic_read(&pool->count) >= get_pool_fillmark(pool);
+}
+#endif /* _ION_H */
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
old mode 100755
new mode 100644
index ae46bf6b..78075eef
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1,26 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* thermal.c - Generic Thermal Management Sysfs support.
*
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui
* Copyright (C) 2008 Sujith Thomas
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -45,13 +29,21 @@
#include "thermal_core.h"
#include "thermal_hwmon.h"
+#if defined(CONFIG_SEC_PM)
+void *thermal_ipc_log;
+
+/* cooling device state */
+static struct delayed_work cdev_print_work;
+#endif
+
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL v2");
-static DEFINE_IDR(thermal_tz_idr);
-static DEFINE_IDR(thermal_cdev_idr);
-static DEFINE_MUTEX(thermal_idr_lock);
+#define THERMAL_MAX_ACTIVE 16
+
+static DEFINE_IDA(thermal_tz_ida);
+static DEFINE_IDA(thermal_cdev_ida);
static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list);
@@ -59,20 +51,22 @@ static LIST_HEAD(thermal_governor_list);
static DEFINE_MUTEX(thermal_list_lock);
static DEFINE_MUTEX(thermal_governor_lock);
+static DEFINE_MUTEX(poweroff_lock);
static atomic_t in_suspend;
-
-#ifdef CONFIG_SCHED_HMP
-#define BOUNDED_CPU 1
-static void start_poll_queue(struct thermal_zone_device *tz, int delay)
-{
- mod_delayed_work_on(tz->poll_queue_cpu, system_freezable_wq, &tz->poll_queue,
- msecs_to_jiffies(delay));
-}
-#endif
+static bool power_off_triggered;
static struct thermal_governor *def_governor;
+static struct workqueue_struct *thermal_passive_wq;
+
+/*
+ * Governor section: set of functions to handle thermal governors
+ *
+ * Functions to help in the life cycle of thermal governors within
+ * the thermal core and by the thermal governor code.
+ */
+
static struct thermal_governor *__find_governor(const char *name)
{
struct thermal_governor *pos;
@@ -151,11 +145,16 @@ int thermal_register_governor(struct thermal_governor *governor)
mutex_lock(&thermal_governor_lock);
err = -EBUSY;
- if (__find_governor(governor->name) == NULL) {
+ if (!__find_governor(governor->name)) {
+ bool match_default;
+
err = 0;
list_add(&governor->governor_list, &thermal_governor_list);
- if (!def_governor && !strncmp(governor->name,
- DEFAULT_THERMAL_GOVERNOR, THERMAL_NAME_LENGTH))
+ match_default = !strncmp(governor->name,
+ DEFAULT_THERMAL_GOVERNOR,
+ THERMAL_NAME_LENGTH);
+
+ if (!def_governor && match_default)
def_governor = governor;
}
@@ -197,14 +196,14 @@ void thermal_unregister_governor(struct thermal_governor *governor)
mutex_lock(&thermal_governor_lock);
- if (__find_governor(governor->name) == NULL)
+ if (!__find_governor(governor->name))
goto exit;
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node) {
if (!strncasecmp(pos->governor->name, governor->name,
- THERMAL_NAME_LENGTH))
+ THERMAL_NAME_LENGTH))
thermal_set_governor(pos, NULL);
}
@@ -212,212 +211,107 @@ void thermal_unregister_governor(struct thermal_governor *governor)
list_del(&governor->governor_list);
exit:
mutex_unlock(&thermal_governor_lock);
- return;
-}
-
-static int get_idr(struct idr *idr, struct mutex *lock, int *id)
-{
- int ret;
-
- if (lock)
- mutex_lock(lock);
- ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
- if (lock)
- mutex_unlock(lock);
- if (unlikely(ret < 0))
- return ret;
- *id = ret;
- return 0;
-}
-
-static void release_idr(struct idr *idr, struct mutex *lock, int id)
-{
- if (lock)
- mutex_lock(lock);
- idr_remove(idr, id);
- if (lock)
- mutex_unlock(lock);
-}
-
-int get_tz_trend(struct thermal_zone_device *tz, int trip)
-{
- enum thermal_trend trend;
-
- if (tz->emul_temperature || !tz->ops->get_trend ||
- tz->ops->get_trend(tz, trip, &trend)) {
- if (tz->temperature > tz->last_temperature)
- trend = THERMAL_TREND_RAISING;
- else if (tz->temperature < tz->last_temperature)
- trend = THERMAL_TREND_DROPPING;
- else
- trend = THERMAL_TREND_STABLE;
- }
-
- return trend;
}
-EXPORT_SYMBOL(get_tz_trend);
-struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
- struct thermal_cooling_device *cdev, int trip)
+int thermal_zone_device_set_policy(struct thermal_zone_device *tz,
+ char *policy)
{
- struct thermal_instance *pos = NULL;
- struct thermal_instance *target_instance = NULL;
+ struct thermal_governor *gov;
+ int ret = -EINVAL;
+ mutex_lock(&thermal_governor_lock);
mutex_lock(&tz->lock);
- mutex_lock(&cdev->lock);
- list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
- if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
- target_instance = pos;
- break;
- }
- }
+ gov = __find_governor(strim(policy));
+ if (!gov)
+ goto exit;
- mutex_unlock(&cdev->lock);
- mutex_unlock(&tz->lock);
+ ret = thermal_set_governor(tz, gov);
- return target_instance;
-}
-EXPORT_SYMBOL(get_thermal_instance);
+exit:
+ mutex_unlock(&tz->lock);
+ mutex_unlock(&thermal_governor_lock);
-static void print_bind_err_msg(struct thermal_zone_device *tz,
- struct thermal_cooling_device *cdev, int ret)
-{
- dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
- tz->type, cdev->type, ret);
+ return ret;
}
-static void __bind(struct thermal_zone_device *tz, int mask,
- struct thermal_cooling_device *cdev,
- unsigned long *limits,
- unsigned int weight)
+int thermal_build_list_of_policies(char *buf)
{
- int i, ret;
+ struct thermal_governor *pos;
+ ssize_t count = 0;
+ ssize_t size = PAGE_SIZE;
- for (i = 0; i < tz->trips; i++) {
- if (mask & (1 << i)) {
- unsigned long upper, lower;
+ mutex_lock(&thermal_governor_lock);
- upper = THERMAL_NO_LIMIT;
- lower = THERMAL_NO_LIMIT;
- if (limits) {
- lower = limits[i * 2];
- upper = limits[i * 2 + 1];
- }
- ret = thermal_zone_bind_cooling_device(tz, i, cdev,
- upper, lower,
- weight);
- if (ret)
- print_bind_err_msg(tz, cdev, ret);
- }
+ list_for_each_entry(pos, &thermal_governor_list, governor_list) {
+ size = PAGE_SIZE - count;
+ count += scnprintf(buf + count, size, "%s ", pos->name);
}
-}
+ count += scnprintf(buf + count, size, "\n");
-static void __unbind(struct thermal_zone_device *tz, int mask,
- struct thermal_cooling_device *cdev)
-{
- int i;
+ mutex_unlock(&thermal_governor_lock);
- for (i = 0; i < tz->trips; i++)
- if (mask & (1 << i))
- thermal_zone_unbind_cooling_device(tz, i, cdev);
+ return count;
}
-static void bind_cdev(struct thermal_cooling_device *cdev)
+static int __init thermal_register_governors(void)
{
- int i, ret;
- const struct thermal_zone_params *tzp;
- struct thermal_zone_device *pos = NULL;
+ int result;
- mutex_lock(&thermal_list_lock);
+ result = thermal_gov_step_wise_register();
+ if (result)
+ return result;
- list_for_each_entry(pos, &thermal_tz_list, node) {
- if (!pos->tzp && !pos->ops->bind)
- continue;
+ result = thermal_gov_fair_share_register();
+ if (result)
+ return result;
- if (pos->ops->bind) {
- ret = pos->ops->bind(pos, cdev);
- if (ret)
- print_bind_err_msg(pos, cdev, ret);
- continue;
- }
+ result = thermal_gov_bang_bang_register();
+ if (result)
+ return result;
- tzp = pos->tzp;
- if (!tzp || !tzp->tbp)
- continue;
+ result = thermal_gov_user_space_register();
+ if (result)
+ return result;
- for (i = 0; i < tzp->num_tbps; i++) {
- if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
- continue;
- if (tzp->tbp[i].match(pos, cdev))
- continue;
- tzp->tbp[i].cdev = cdev;
- __bind(pos, tzp->tbp[i].trip_mask, cdev,
- tzp->tbp[i].binding_limits,
- tzp->tbp[i].weight);
- }
- }
+ result = thermal_gov_low_limits_register();
+ if (result)
+ return result;
- mutex_unlock(&thermal_list_lock);
+ return thermal_gov_power_allocator_register();
}
-static void bind_tz(struct thermal_zone_device *tz)
+static void thermal_unregister_governors(void)
{
- int i, ret;
- struct thermal_cooling_device *pos = NULL;
- const struct thermal_zone_params *tzp = tz->tzp;
-
- if (!tzp && !tz->ops->bind)
- return;
-
- mutex_lock(&thermal_list_lock);
-
- /* If there is ops->bind, try to use ops->bind */
- if (tz->ops->bind) {
- list_for_each_entry(pos, &thermal_cdev_list, node) {
- ret = tz->ops->bind(tz, pos);
- if (ret)
- print_bind_err_msg(tz, pos, ret);
- }
- goto exit;
- }
-
- if (!tzp || !tzp->tbp)
- goto exit;
-
- list_for_each_entry(pos, &thermal_cdev_list, node) {
- for (i = 0; i < tzp->num_tbps; i++) {
- if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
- continue;
- if (tzp->tbp[i].match(tz, pos))
- continue;
- tzp->tbp[i].cdev = pos;
- __bind(tz, tzp->tbp[i].trip_mask, pos,
- tzp->tbp[i].binding_limits,
- tzp->tbp[i].weight);
- }
- }
-exit:
- mutex_unlock(&thermal_list_lock);
+ thermal_gov_step_wise_unregister();
+ thermal_gov_fair_share_unregister();
+ thermal_gov_bang_bang_unregister();
+ thermal_gov_user_space_unregister();
+ thermal_gov_low_limits_unregister();
+ thermal_gov_power_allocator_unregister();
}
-static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+/*
+ * Zone update section: main control loop applied to each zone while monitoring
+ *
+ * in polling mode. The monitoring is done using a workqueue.
+ * Same update may be done on a zone by calling thermal_zone_device_update().
+ *
+ * An update means:
+ * - Non-critical trips will invoke the governor responsible for that zone;
+ * - Hot trips will produce a notification to userspace;
+ * - Critical trip point will cause a system shutdown.
+ */
+static void thermal_zone_device_set_polling(struct workqueue_struct *queue,
+ struct thermal_zone_device *tz,
int delay)
{
if (delay > 1000)
-#ifdef CONFIG_SCHED_HMP
- start_poll_queue(tz, delay);
-#else
- mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+ mod_delayed_work(queue, &tz->poll_queue,
round_jiffies(msecs_to_jiffies(delay)));
-#endif
else if (delay)
-#ifdef CONFIG_SCHED_HMP
- start_poll_queue(tz, delay);
-#else
- mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+ mod_delayed_work(queue, &tz->poll_queue,
msecs_to_jiffies(delay));
-#endif
else
cancel_delayed_work(&tz->poll_queue);
}
@@ -427,24 +321,76 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
mutex_lock(&tz->lock);
if (tz->passive)
- thermal_zone_device_set_polling(tz, tz->passive_delay);
+ thermal_zone_device_set_polling(thermal_passive_wq,
+ tz, tz->passive_delay);
else if (tz->polling_delay)
- thermal_zone_device_set_polling(tz, tz->polling_delay);
+ thermal_zone_device_set_polling(
+ system_freezable_power_efficient_wq,
+ tz, tz->polling_delay);
else
- thermal_zone_device_set_polling(tz, 0);
+ thermal_zone_device_set_polling(NULL, tz, 0);
mutex_unlock(&tz->lock);
}
static void handle_non_critical_trips(struct thermal_zone_device *tz,
- int trip, enum thermal_trip_type trip_type)
+ int trip,
+ enum thermal_trip_type trip_type)
{
tz->governor ? tz->governor->throttle(tz, trip) :
def_governor->throttle(tz, trip);
}
+/**
+ * thermal_emergency_poweroff_func - emergency poweroff work after a known delay
+ * @work: work_struct associated with the emergency poweroff function
+ *
+ * This function is called in very critical situations to force
+ * a kernel poweroff after a configurable timeout value.
+ */
+static void thermal_emergency_poweroff_func(struct work_struct *work)
+{
+ /*
+ * We have reached here after the emergency thermal shutdown
+ * Waiting period has expired. This means orderly_poweroff has
+ * not been able to shut off the system for some reason.
+ * Try to shut down the system immediately using kernel_power_off
+ * if populated
+ */
+ WARN(1, "Attempting kernel_power_off: Temperature too high\n");
+ kernel_power_off();
+
+ /*
+ * Worst of the worst case trigger emergency restart
+ */
+ WARN(1, "Attempting emergency_restart: Temperature too high\n");
+ emergency_restart();
+}
+
+static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work,
+ thermal_emergency_poweroff_func);
+
+/**
+ * thermal_emergency_poweroff - Trigger an emergency system poweroff
+ *
+ * This may be called from any critical situation to trigger a system shutdown
+ * after a known period of time. By default this is not scheduled.
+ */
+static void thermal_emergency_poweroff(void)
+{
+ int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
+ /*
+ * poweroff_delay_ms must be a carefully profiled positive value.
+ * Its a must for thermal_emergency_poweroff_work to be scheduled
+ */
+ if (poweroff_delay_ms <= 0)
+ return;
+ schedule_delayed_work(&thermal_emergency_poweroff_work,
+ msecs_to_jiffies(poweroff_delay_ms));
+}
+
static void handle_critical_trips(struct thermal_zone_device *tz,
- int trip, enum thermal_trip_type trip_type)
+ int trip, enum thermal_trip_type trip_type)
{
int trip_temp;
@@ -454,93 +400,37 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
if (trip_temp <= 0 || tz->temperature < trip_temp)
return;
- trace_thermal_zone_trip(tz, trip, trip_type);
+ trace_thermal_zone_trip(tz, trip, trip_type, true);
if (tz->ops->notify)
tz->ops->notify(tz, trip, trip_type);
if (trip_type == THERMAL_TRIP_CRITICAL) {
dev_emerg(&tz->device,
- "critical temperature reached(%d C),shutting down\n",
+ "critical temperature reached (%d C), shutting down\n",
tz->temperature / 1000);
- orderly_poweroff(true);
+ mutex_lock(&poweroff_lock);
+ if (!power_off_triggered) {
+ /*
+ * Queue a backup emergency shutdown in the event of
+ * orderly_poweroff failure
+ */
+ thermal_emergency_poweroff();
+ orderly_poweroff(true);
+ power_off_triggered = true;
+ }
+ mutex_unlock(&poweroff_lock);
}
}
-#ifdef CONFIG_SEC_DEBUG_HW_PARAM
-#define APO_THROTTLE_TEMP 81000
-static bool period_check;
-static bool is_apo_check;
-static int trip_temp;
-static u64 last_time[THERMAL_ZONE_MAX], curr_time[THERMAL_ZONE_MAX];
-static u64 last_apo, curr_apo;
-static enum thermal_trip_type result_type;
-struct thermal_data_devices thermal_data_info[THERMAL_ZONE_MAX];
-#endif
-
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
{
enum thermal_trip_type type;
-#ifdef CONFIG_SEC_DEBUG_HW_PARAM
- int tid = tz->id;
-#endif
/* Ignore disabled trip points */
if (test_bit(trip, &tz->trips_disabled))
return;
-#ifdef CONFIG_SEC_DEBUG_HW_PARAM
- if (trip == 0) {
- period_check = false;
- result_type = THERMAL_TRIP_ACTIVE;
- }
-
- if (tz->temperature > thermal_data_info[tid].max_temp)
- thermal_data_info[tid].max_temp = tz->temperature;
-
- tz->ops->get_trip_temp(tz, trip, &trip_temp);
- if (tz->temperature > trip_temp) {
- tz->ops->get_trip_type(tz, trip + 1, &result_type);
- }
- else {
- if (!period_check) {
- curr_time[tid] = ktime_to_ns(ktime_get()) / 1000000;
- if(last_time[tid]) {
- if(result_type == THERMAL_TRIP_ACTIVE)
- thermal_data_info[tid].times[ACTIVE_TIMES] +=
- (curr_time[tid] - last_time[tid]);
- else if (result_type == THERMAL_TRIP_PASSIVE)
- thermal_data_info[tid].times[PASSIVE_TIMES] +=
- (curr_time[tid] - last_time[tid]);
- else if (result_type == THERMAL_TRIP_HOT)
- thermal_data_info[tid].times[HOT_TIMES] +=
- (curr_time[tid] - last_time[tid]);
-
- period_check = true;
- }
-
- if (tid == THERMAL_ZONE_APOLLO) {
- if (tz->temperature >= APO_THROTTLE_TEMP) {
- if (!is_apo_check) {
- is_apo_check = true;
- last_apo = ktime_to_ns(ktime_get()) / 1000000;
- }
- }
- else {
- if (is_apo_check) {
- curr_apo = ktime_to_ns(ktime_get()) / 1000000;
- thermal_data_info[tid].hotplug_out +=
- (curr_apo - last_apo);
- is_apo_check = false;
- }
- }
- }
-
- last_time[tid] = curr_time[tid];
- }
- }
-#endif
-
tz->ops->get_trip_type(tz, trip, &type);
if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
@@ -552,70 +442,29 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
* So, start monitoring again.
*/
monitor_thermal_zone(tz);
+ trace_thermal_handle_trip(tz, trip);
}
-/**
- * thermal_zone_get_temp() - returns the temperature of a thermal zone
- * @tz: a valid pointer to a struct thermal_zone_device
- * @temp: a valid pointer to where to store the resulting temperature.
- *
- * When a valid thermal zone reference is passed, it will fetch its
- * temperature and fill @temp.
- *
- * Return: On success returns 0, an error code otherwise
- */
-int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
+static void store_temperature(struct thermal_zone_device *tz, int temp)
{
- int ret = -EINVAL;
- int count;
- int crit_temp = INT_MAX;
- enum thermal_trip_type type;
-
- if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
- goto exit;
-
mutex_lock(&tz->lock);
-
- ret = tz->ops->get_temp(tz, temp);
-
- if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) {
- for (count = 0; count < tz->trips; count++) {
- ret = tz->ops->get_trip_type(tz, count, &type);
- if (!ret && type == THERMAL_TRIP_CRITICAL) {
- ret = tz->ops->get_trip_temp(tz, count,
- &crit_temp);
- break;
- }
- }
-
- /*
- * Only allow emulating a temperature when the real temperature
- * is below the critical temperature so that the emulation code
- * cannot hide critical conditions.
- */
- if (!ret && *temp < crit_temp)
- *temp = tz->emul_temperature;
- }
-
+ tz->last_temperature = tz->temperature;
+ tz->temperature = temp;
mutex_unlock(&tz->lock);
-exit:
- return ret;
-}
-EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
-#ifdef CONFIG_SEC_PM_DEBUG
-#define TEMP_NORMAL_COUNT 500
-#define TEMP_HOT_COUNT 100
-#define TEMP_THRESHOLD 76000
-#endif
+ trace_thermal_temperature(tz);
+ if (tz->last_temperature == THERMAL_TEMP_INVALID ||
+ tz->last_temperature == THERMAL_TEMP_INVALID_LOW)
+ dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n",
+ tz->temperature);
+ else
+ dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
+ tz->last_temperature, tz->temperature);
+}
static void update_temperature(struct thermal_zone_device *tz)
{
int temp, ret;
-#ifdef CONFIG_SEC_PM_DEBUG
- static int count = 1;
- int count_limit;
-#endif
ret = thermal_zone_get_temp(tz, &temp);
if (ret) {
@@ -625,511 +474,100 @@ static void update_temperature(struct thermal_zone_device *tz)
ret);
return;
}
-
- mutex_lock(&tz->lock);
- tz->last_temperature = tz->temperature;
- tz->temperature = temp;
- mutex_unlock(&tz->lock);
-
- trace_thermal_temperature(tz);
- if (tz->last_temperature == THERMAL_TEMP_INVALID)
- dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n",
- tz->temperature);
- else
- dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
- tz->last_temperature, tz->temperature);
-
-#ifdef CONFIG_SEC_PM_DEBUG
- if (tz->temperature >= TEMP_THRESHOLD)
- count_limit = TEMP_HOT_COUNT;
- else
- count_limit = TEMP_NORMAL_COUNT;
-
- if (count++ >= count_limit) {
- count = 1;
- dev_info(&tz->device, "[TMU] last_temperature=%d, current_temperature=%d\n",
- tz->last_temperature, tz->temperature);
- }
-#endif
+ store_temperature(tz, temp);
}
-static void thermal_zone_device_reset(struct thermal_zone_device *tz)
+static void thermal_zone_device_init(struct thermal_zone_device *tz)
{
struct thermal_instance *pos;
-
tz->temperature = THERMAL_TEMP_INVALID;
- tz->passive = 0;
list_for_each_entry(pos, &tz->thermal_instances, tz_node)
pos->initialized = false;
}
-void thermal_zone_device_update(struct thermal_zone_device *tz)
-{
- int count;
- enum thermal_device_mode mode;
-
- if (atomic_read(&in_suspend))
- return;
-
- if (!tz->ops->get_temp || !tz->ops->get_mode)
- return;
-
- tz->ops->get_mode(tz, &mode);
-
- if (mode == THERMAL_DEVICE_ENABLED) {
- update_temperature(tz);
-
- for (count = 0; count < tz->trips; count++)
- handle_thermal_trip(tz, count);
-
- if (tz->ops->throttle_hotplug)
- tz->ops->throttle_hotplug(tz);
- }
-}
-EXPORT_SYMBOL_GPL(thermal_zone_device_update);
-
-static void thermal_zone_device_check(struct work_struct *work)
-{
- struct thermal_zone_device *tz = container_of(work, struct
- thermal_zone_device,
- poll_queue.work);
- thermal_zone_device_update(tz);
-}
-
-/* sys I/F for thermal zone */
-
-#define to_thermal_zone(_dev) \
- container_of(_dev, struct thermal_zone_device, device)
-
-static ssize_t
-type_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
-
- return sprintf(buf, "%s\n", tz->type);
-}
-
-static ssize_t
-temp_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int temperature, ret;
-
- ret = thermal_zone_get_temp(tz, &temperature);
-
- if (ret)
- return ret;
-
- return sprintf(buf, "%d\n", temperature);
-}
-
-static ssize_t
-mode_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- enum thermal_device_mode mode;
- int result;
-
- if (!tz->ops->get_mode)
- return -EPERM;
-
- result = tz->ops->get_mode(tz, &mode);
- if (result)
- return result;
-
- return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
- : "disabled");
-}
-
-static ssize_t
-mode_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int result;
-
- if (!tz->ops->set_mode)
- return -EPERM;
-
- if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
- result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
- else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
- result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
- else
- result = -EINVAL;
-
- if (result)
- return result;
-
- return count;
-}
-
-static ssize_t
-trip_point_type_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- enum thermal_trip_type type;
- int trip, result;
-
- if (!tz->ops->get_trip_type)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
- return -EINVAL;
-
- result = tz->ops->get_trip_type(tz, trip, &type);
- if (result)
- return result;
-
- switch (type) {
- case THERMAL_TRIP_CRITICAL:
- return sprintf(buf, "critical\n");
- case THERMAL_TRIP_HOT:
- return sprintf(buf, "hot\n");
- case THERMAL_TRIP_PASSIVE:
- return sprintf(buf, "passive\n");
- case THERMAL_TRIP_ACTIVE:
- return sprintf(buf, "active\n");
- default:
- return sprintf(buf, "unknown\n");
- }
-}
-
-static ssize_t
-trip_point_temp_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, ret;
- unsigned long temperature;
-
- if (!tz->ops->set_trip_temp)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
- return -EINVAL;
-
- if (kstrtoul(buf, 10, &temperature))
- return -EINVAL;
-
- ret = tz->ops->set_trip_temp(tz, trip, temperature);
-
- return ret ? ret : count;
-}
-
-static ssize_t
-trip_point_temp_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, ret;
- int temperature;
-
- if (!tz->ops->get_trip_temp)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
- return -EINVAL;
-
- ret = tz->ops->get_trip_temp(tz, trip, &temperature);
-
- if (ret)
- return ret;
-
- return sprintf(buf, "%d\n", temperature);
-}
-
-static ssize_t
-trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, ret;
- int temperature;
-
- if (!tz->ops->set_trip_hyst)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
- return -EINVAL;
-
- if (kstrtoint(buf, 10, &temperature))
- return -EINVAL;
-
- /*
- * We are not doing any check on the 'temperature' value
- * here. The driver implementing 'set_trip_hyst' has to
- * take care of this.
- */
- ret = tz->ops->set_trip_hyst(tz, trip, temperature);
-
- return ret ? ret : count;
-}
-
-static ssize_t
-trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip, ret;
- int temperature;
-
- if (!tz->ops->get_trip_hyst)
- return -EPERM;
-
- if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
- return -EINVAL;
-
- ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
-
- return ret ? ret : sprintf(buf, "%d\n", temperature);
-}
-
-static ssize_t
-passive_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- struct thermal_cooling_device *cdev = NULL;
- int state;
-
- if (!sscanf(buf, "%d\n", &state))
- return -EINVAL;
-
- /* sanity check: values below 1000 millicelcius don't make sense
- * and can cause the system to go into a thermal heart attack
- */
- if (state && state < 1000)
- return -EINVAL;
-
- if (state && !tz->forced_passive) {
- mutex_lock(&thermal_list_lock);
- list_for_each_entry(cdev, &thermal_cdev_list, node) {
- if (!strncmp("Processor", cdev->type,
- sizeof("Processor")))
- thermal_zone_bind_cooling_device(tz,
- THERMAL_TRIPS_NONE, cdev,
- THERMAL_NO_LIMIT,
- THERMAL_NO_LIMIT,
- THERMAL_WEIGHT_DEFAULT);
- }
- mutex_unlock(&thermal_list_lock);
- if (!tz->passive_delay)
- tz->passive_delay = 1000;
- } else if (!state && tz->forced_passive) {
- mutex_lock(&thermal_list_lock);
- list_for_each_entry(cdev, &thermal_cdev_list, node) {
- if (!strncmp("Processor", cdev->type,
- sizeof("Processor")))
- thermal_zone_unbind_cooling_device(tz,
- THERMAL_TRIPS_NONE,
- cdev);
- }
- mutex_unlock(&thermal_list_lock);
- tz->passive_delay = 0;
- }
-
- tz->forced_passive = state;
-
- thermal_zone_device_update(tz);
-
- return count;
-}
-
-static ssize_t
-passive_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static void thermal_zone_device_reset(struct thermal_zone_device *tz)
{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
-
- return sprintf(buf, "%d\n", tz->forced_passive);
+ tz->passive = 0;
+ thermal_zone_device_init(tz);
}
-static ssize_t
-policy_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+void thermal_zone_device_update_temp(struct thermal_zone_device *tz,
+ enum thermal_notify_event event, int temp)
{
- int ret = -EINVAL;
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- struct thermal_governor *gov;
- char name[THERMAL_NAME_LENGTH];
+ int count;
- snprintf(name, sizeof(name), "%s", buf);
+ if (atomic_read(&in_suspend) && (!tz->ops->is_wakeable ||
+ !(tz->ops->is_wakeable(tz))))
+ return;
- mutex_lock(&thermal_governor_lock);
- mutex_lock(&tz->lock);
+ trace_thermal_device_update(tz, event);
+ store_temperature(tz, temp);
- gov = __find_governor(strim(name));
- if (!gov)
- goto exit;
+ thermal_zone_set_trips(tz);
- ret = thermal_set_governor(tz, gov);
- if (!ret)
- ret = count;
+ tz->notify_event = event;
-exit:
- mutex_unlock(&tz->lock);
- mutex_unlock(&thermal_governor_lock);
- return ret;
-}
-
-static ssize_t
-policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
-
- return sprintf(buf, "%s\n", tz->governor->name);
+ for (count = 0; count < tz->trips; count++)
+ handle_thermal_trip(tz, count);
}
+EXPORT_SYMBOL(thermal_zone_device_update_temp);
-static ssize_t
-available_policies_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
+void thermal_zone_device_update(struct thermal_zone_device *tz,
+ enum thermal_notify_event event)
{
- struct thermal_governor *pos;
- ssize_t count = 0;
- ssize_t size = PAGE_SIZE;
-
- mutex_lock(&thermal_governor_lock);
-
- list_for_each_entry(pos, &thermal_governor_list, governor_list) {
- size = PAGE_SIZE - count;
- count += scnprintf(buf + count, size, "%s ", pos->name);
- }
- count += scnprintf(buf + count, size, "\n");
-
- mutex_unlock(&thermal_governor_lock);
+ int count;
- return count;
-}
+ if (atomic_read(&in_suspend) && (!tz->ops->is_wakeable ||
+ !(tz->ops->is_wakeable(tz))))
+ return;
-static ssize_t
-emul_temp_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- int ret = 0;
- unsigned long temperature;
+ if (!tz->ops->get_temp)
+ return;
- if (kstrtoul(buf, 10, &temperature))
- return -EINVAL;
+ trace_thermal_device_update(tz, event);
+ update_temperature(tz);
- if (!tz->ops->set_emul_temp) {
- mutex_lock(&tz->lock);
- tz->emul_temperature = temperature;
- mutex_unlock(&tz->lock);
- } else {
- ret = tz->ops->set_emul_temp(tz, temperature);
- }
+ thermal_zone_set_trips(tz);
- if (!ret)
- thermal_zone_device_update(tz);
+ tz->notify_event = event;
- return ret ? ret : count;
+ for (count = 0; count < tz->trips; count++)
+ handle_thermal_trip(tz, count);
}
-static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
+EXPORT_SYMBOL_GPL(thermal_zone_device_update);
-static ssize_t
-sustainable_power_show(struct device *dev, struct device_attribute *devattr,
- char *buf)
+/**
+ * thermal_notify_framework - Sensor drivers use this API to notify framework
+ * @tz: thermal zone device
+ * @trip: indicates which trip point has been crossed
+ *
+ * This function handles the trip events from sensor drivers. It starts
+ * throttling the cooling devices according to the policy configured.
+ * For CRITICAL and HOT trip points, this notifies the respective drivers,
+ * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
+ * The throttling policy is based on the configured platform data; if no
+ * platform data is provided, this uses the step_wise throttling policy.
+ */
+void thermal_notify_framework(struct thermal_zone_device *tz, int trip)
{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
-
- if (tz->tzp)
- return sprintf(buf, "%u\n", tz->tzp->sustainable_power);
- else
- return -EIO;
+ handle_thermal_trip(tz, trip);
}
+EXPORT_SYMBOL_GPL(thermal_notify_framework);
-static ssize_t
-sustainable_power_store(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
+static void thermal_zone_device_check(struct work_struct *work)
{
- struct thermal_zone_device *tz = to_thermal_zone(dev);
- u32 sustainable_power;
-
- if (!tz->tzp)
- return -EIO;
-
- if (kstrtou32(buf, 10, &sustainable_power))
- return -EINVAL;
-
- tz->tzp->sustainable_power = sustainable_power;
-
- return count;
+ struct thermal_zone_device *tz = container_of(work, struct
+ thermal_zone_device,
+ poll_queue.work);
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
}
-static DEVICE_ATTR(sustainable_power, S_IWUSR | S_IRUGO, sustainable_power_show,
- sustainable_power_store);
-
-#define create_s32_tzp_attr(name) \
- static ssize_t \
- name##_show(struct device *dev, struct device_attribute *devattr, \
- char *buf) \
- { \
- struct thermal_zone_device *tz = to_thermal_zone(dev); \
- \
- if (tz->tzp) \
- return sprintf(buf, "%u\n", tz->tzp->name); \
- else \
- return -EIO; \
- } \
- \
- static ssize_t \
- name##_store(struct device *dev, struct device_attribute *devattr, \
- const char *buf, size_t count) \
- { \
- struct thermal_zone_device *tz = to_thermal_zone(dev); \
- s32 value; \
- \
- if (!tz->tzp) \
- return -EIO; \
- \
- if (kstrtos32(buf, 10, &value)) \
- return -EINVAL; \
- \
- tz->tzp->name = value; \
- \
- return count; \
- } \
- static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, name##_show, name##_store)
-
-create_s32_tzp_attr(k_po);
-create_s32_tzp_attr(k_pu);
-create_s32_tzp_attr(k_i);
-create_s32_tzp_attr(k_d);
-create_s32_tzp_attr(integral_cutoff);
-create_s32_tzp_attr(slope);
-create_s32_tzp_attr(offset);
-create_s32_tzp_attr(integral_max);
-#undef create_s32_tzp_attr
-
-static struct device_attribute *dev_tzp_attrs[] = {
- &dev_attr_sustainable_power,
- &dev_attr_k_po,
- &dev_attr_k_pu,
- &dev_attr_k_i,
- &dev_attr_k_d,
- &dev_attr_integral_cutoff,
- &dev_attr_slope,
- &dev_attr_offset,
- &dev_attr_integral_max,
-};
-
-static int create_tzp_attrs(struct device *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev_tzp_attrs); i++) {
- int ret;
- struct device_attribute *dev_attr = dev_tzp_attrs[i];
-
- ret = device_create_file(dev, dev_attr);
- if (ret)
- return ret;
- }
- return 0;
-}
+/*
+ * Power actor section: interface to power actors to estimate power
+ *
+ * Set of functions used to interact to cooling devices that know
+ * how to estimate their devices power consumption.
+ */
/**
* power_actor_get_max_power() - get the maximum power that a cdev can consume
@@ -1181,12 +619,13 @@ int power_actor_get_min_power(struct thermal_cooling_device *cdev,
}
/**
- * power_actor_set_power() - limit the maximum power that a cooling device can consume
+ * power_actor_set_power() - limit the maximum power a cooling device consumes
* @cdev: pointer to &thermal_cooling_device
* @instance: thermal instance to update
* @power: the power in milliwatts
*
- * Set the cooling device to consume at most @power milliwatts.
+ * Set the cooling device to consume at most @power milliwatts. The limit is
+ * expected to be a cap at the maximum power consumption.
*
* Return: 0 on success, -EINVAL if the cooling device does not
* implement the power actor API or -E* for other failures.
@@ -1205,149 +644,60 @@ int power_actor_set_power(struct thermal_cooling_device *cdev,
return ret;
instance->target = state;
+ mutex_lock(&cdev->lock);
cdev->updated = false;
+ mutex_unlock(&cdev->lock);
thermal_cdev_update(cdev);
return 0;
}
-static DEVICE_ATTR(type, 0444, type_show, NULL);
-static DEVICE_ATTR(temp, 0444, temp_show, NULL);
-static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
-static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
-static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
-static DEVICE_ATTR(available_policies, S_IRUGO, available_policies_show, NULL);
-
-/* sys I/F for cooling device */
-#define to_cooling_device(_dev) \
- container_of(_dev, struct thermal_cooling_device, device)
-
-static ssize_t
-thermal_cooling_device_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct thermal_cooling_device *cdev = to_cooling_device(dev);
-
- return sprintf(buf, "%s\n", cdev->type);
-}
-
-static ssize_t
-thermal_cooling_device_max_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct thermal_cooling_device *cdev = to_cooling_device(dev);
- unsigned long state;
- int ret;
-
- ret = cdev->ops->get_max_state(cdev, &state);
- if (ret)
- return ret;
- return sprintf(buf, "%ld\n", state);
-}
-
-static ssize_t
-thermal_cooling_device_cur_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct thermal_cooling_device *cdev = to_cooling_device(dev);
- unsigned long state;
- int ret;
-
- ret = cdev->ops->get_cur_state(cdev, &state);
- if (ret)
- return ret;
- return sprintf(buf, "%ld\n", state);
-}
-
-static ssize_t
-thermal_cooling_device_cur_state_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+void thermal_zone_device_rebind_exception(struct thermal_zone_device *tz,
+ const char *cdev_type, size_t size)
{
- struct thermal_cooling_device *cdev = to_cooling_device(dev);
- unsigned long state;
- int result;
-
- if (!sscanf(buf, "%ld\n", &state))
- return -EINVAL;
+ struct thermal_cooling_device *cdev = NULL;
- if ((long)state < 0)
- return -EINVAL;
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(cdev, &thermal_cdev_list, node) {
+ /* skip non matching cdevs */
+ if (strncmp(cdev_type, cdev->type, size))
+ continue;
- result = cdev->ops->set_cur_state(cdev, state);
- if (result)
- return result;
- return count;
+ /* re binding the exception matching the type pattern */
+ thermal_zone_bind_cooling_device(tz, THERMAL_TRIPS_NONE, cdev,
+ THERMAL_NO_LIMIT,
+ THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
+ }
+ mutex_unlock(&thermal_list_lock);
}
-static struct device_attribute dev_attr_cdev_type =
-__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
-static DEVICE_ATTR(max_state, 0444,
- thermal_cooling_device_max_state_show, NULL);
-static DEVICE_ATTR(cur_state, 0644,
- thermal_cooling_device_cur_state_show,
- thermal_cooling_device_cur_state_store);
-
-static ssize_t
-thermal_cooling_device_trip_point_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+void thermal_zone_device_unbind_exception(struct thermal_zone_device *tz,
+ const char *cdev_type, size_t size)
{
- struct thermal_instance *instance;
-
- instance =
- container_of(attr, struct thermal_instance, attr);
-
- if (instance->trip == THERMAL_TRIPS_NONE)
- return sprintf(buf, "-1\n");
- else
- return sprintf(buf, "%d\n", instance->trip);
-}
-
-static struct attribute *cooling_device_attrs[] = {
- &dev_attr_cdev_type.attr,
- &dev_attr_max_state.attr,
- &dev_attr_cur_state.attr,
- NULL,
-};
-
-static const struct attribute_group cooling_device_attr_group = {
- .attrs = cooling_device_attrs,
-};
-
-static const struct attribute_group *cooling_device_attr_groups[] = {
- &cooling_device_attr_group,
- NULL,
-};
-
-static ssize_t
-thermal_cooling_device_weight_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct thermal_instance *instance;
-
- instance = container_of(attr, struct thermal_instance, weight_attr);
+ struct thermal_cooling_device *cdev = NULL;
- return sprintf(buf, "%d\n", instance->weight);
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(cdev, &thermal_cdev_list, node) {
+ /* skip non matching cdevs */
+ if (strncmp(cdev_type, cdev->type, size))
+ continue;
+ /* unbinding the exception matching the type pattern */
+ thermal_zone_unbind_cooling_device(tz, THERMAL_TRIPS_NONE,
+ cdev);
+ }
+ mutex_unlock(&thermal_list_lock);
}
-static ssize_t
-thermal_cooling_device_weight_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct thermal_instance *instance;
- int ret, weight;
-
- ret = kstrtoint(buf, 0, &weight);
- if (ret)
- return ret;
-
- instance = container_of(attr, struct thermal_instance, weight_attr);
- instance->weight = weight;
-
- return count;
-}
-/* Device management */
+/*
+ * Device management section: cooling devices, zones devices, and binding
+ *
+ * Set of functions provided by the thermal core for:
+ * - cooling devices lifecycle: registration, unregistration,
+ * binding, and unbinding.
+ * - thermal zone devices lifecycle: registration, unregistration,
+ * binding, and unbinding.
+ */
/**
* thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
@@ -1403,15 +753,31 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
if (ret)
return ret;
- /* lower default 0, upper default max_state */
- lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
- upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
+ /*
+ * If upper or lower has a MACRO to define the mitigation state,
+ * based on the MACRO determine the default state to use or the
+ * offset from the max_state.
+ */
+ if (upper >= (THERMAL_MAX_LIMIT - max_state)) {
+ /* upper default max_state */
+ if (upper == THERMAL_NO_LIMIT)
+ upper = max_state;
+ else
+ upper = max_state - (THERMAL_MAX_LIMIT - upper);
+ }
+
+ if (lower >= (THERMAL_MAX_LIMIT - max_state)) {
+ /* lower default 0 */
+ if (lower == THERMAL_NO_LIMIT)
+ lower = 0;
+ else
+ lower = max_state - (THERMAL_MAX_LIMIT - lower);
+ }
if (lower > upper || upper > max_state)
return -EINVAL;
- dev =
- kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->tz = tz;
@@ -1422,42 +788,65 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
dev->target = THERMAL_NO_TARGET;
dev->weight = weight;
- result = get_idr(&tz->idr, &tz->lock, &dev->id);
- if (result)
+ result = ida_simple_get(&tz->ida, 0, 0, GFP_KERNEL);
+ if (result < 0)
goto free_mem;
+ dev->id = result;
sprintf(dev->name, "cdev%d", dev->id);
result =
sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
if (result)
- goto release_idr;
+ goto release_ida;
sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
sysfs_attr_init(&dev->attr.attr);
dev->attr.attr.name = dev->attr_name;
dev->attr.attr.mode = 0444;
- dev->attr.show = thermal_cooling_device_trip_point_show;
+ dev->attr.show = trip_point_show;
result = device_create_file(&tz->device, &dev->attr);
if (result)
goto remove_symbol_link;
+ snprintf(dev->upper_attr_name, THERMAL_NAME_LENGTH,
+ "cdev%d_upper_limit", dev->id);
+ sysfs_attr_init(&dev->upper_attr.attr);
+ dev->upper_attr.attr.name = dev->upper_attr_name;
+ dev->upper_attr.attr.mode = 0644;
+ dev->upper_attr.show = upper_limit_show;
+ dev->upper_attr.store = upper_limit_store;
+ result = device_create_file(&tz->device, &dev->upper_attr);
+ if (result)
+ goto remove_trip_file;
+
+ snprintf(dev->lower_attr_name, THERMAL_NAME_LENGTH,
+ "cdev%d_lower_limit", dev->id);
+ sysfs_attr_init(&dev->lower_attr.attr);
+ dev->lower_attr.attr.name = dev->lower_attr_name;
+ dev->lower_attr.attr.mode = 0644;
+ dev->lower_attr.show = lower_limit_show;
+ dev->lower_attr.store = lower_limit_store;
+ result = device_create_file(&tz->device, &dev->lower_attr);
+ if (result)
+ goto remove_upper_file;
+
sprintf(dev->weight_attr_name, "cdev%d_weight", dev->id);
sysfs_attr_init(&dev->weight_attr.attr);
dev->weight_attr.attr.name = dev->weight_attr_name;
dev->weight_attr.attr.mode = S_IWUSR | S_IRUGO;
- dev->weight_attr.show = thermal_cooling_device_weight_show;
- dev->weight_attr.store = thermal_cooling_device_weight_store;
+ dev->weight_attr.show = weight_show;
+ dev->weight_attr.store = weight_store;
result = device_create_file(&tz->device, &dev->weight_attr);
if (result)
- goto remove_trip_file;
+ goto remove_lower_file;
mutex_lock(&tz->lock);
mutex_lock(&cdev->lock);
list_for_each_entry(pos, &tz->thermal_instances, tz_node)
- if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
- result = -EEXIST;
- break;
- }
+ if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
+ result = -EEXIST;
+ break;
+ }
if (!result) {
list_add_tail(&dev->tz_node, &tz->thermal_instances);
list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
@@ -1470,12 +859,16 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
return 0;
device_remove_file(&tz->device, &dev->weight_attr);
+remove_lower_file:
+ device_remove_file(&tz->device, &dev->lower_attr);
+remove_upper_file:
+ device_remove_file(&tz->device, &dev->upper_attr);
remove_trip_file:
device_remove_file(&tz->device, &dev->attr);
remove_symbol_link:
sysfs_remove_link(&tz->device.kobj, dev->name);
-release_idr:
- release_idr(&tz->idr, &tz->lock, dev->id);
+release_ida:
+ ida_simple_remove(&tz->ida, dev->id);
free_mem:
kfree(dev);
return result;
@@ -1519,35 +912,110 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
return -ENODEV;
unbind:
+ device_remove_file(&tz->device, &pos->lower_attr);
+ device_remove_file(&tz->device, &pos->upper_attr);
device_remove_file(&tz->device, &pos->weight_attr);
device_remove_file(&tz->device, &pos->attr);
sysfs_remove_link(&tz->device.kobj, pos->name);
- release_idr(&tz->idr, &tz->lock, pos->id);
+ ida_simple_remove(&tz->ida, pos->id);
kfree(pos);
return 0;
}
EXPORT_SYMBOL_GPL(thermal_zone_unbind_cooling_device);
-static void thermal_release(struct device *dev)
-{
- struct thermal_zone_device *tz;
- struct thermal_cooling_device *cdev;
+static void thermal_release(struct device *dev)
+{
+ struct thermal_zone_device *tz;
+ struct thermal_cooling_device *cdev;
+
+ if (!strncmp(dev_name(dev), "thermal_zone",
+ sizeof("thermal_zone") - 1)) {
+ tz = to_thermal_zone(dev);
+ thermal_zone_destroy_device_groups(tz);
+ kfree(tz);
+ } else if (!strncmp(dev_name(dev), "cooling_device",
+ sizeof("cooling_device") - 1)) {
+ cdev = to_cooling_device(dev);
+ kfree(cdev);
+ }
+}
+
+static struct class thermal_class = {
+ .name = "thermal",
+ .dev_release = thermal_release,
+};
+
+static inline
+void print_bind_err_msg(struct thermal_zone_device *tz,
+ struct thermal_cooling_device *cdev, int ret)
+{
+ dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
+ tz->type, cdev->type, ret);
+}
+
+static void __bind(struct thermal_zone_device *tz, int mask,
+ struct thermal_cooling_device *cdev,
+ unsigned long *limits,
+ unsigned int weight)
+{
+ int i, ret;
+
+ for (i = 0; i < tz->trips; i++) {
+ if (mask & (1 << i)) {
+ unsigned long upper, lower;
+
+ upper = THERMAL_NO_LIMIT;
+ lower = THERMAL_NO_LIMIT;
+ if (limits) {
+ lower = limits[i * 2];
+ upper = limits[i * 2 + 1];
+ }
+ ret = thermal_zone_bind_cooling_device(tz, i, cdev,
+ upper, lower,
+ weight);
+ if (ret)
+ print_bind_err_msg(tz, cdev, ret);
+ }
+ }
+}
+
+static void bind_cdev(struct thermal_cooling_device *cdev)
+{
+ int i, ret;
+ const struct thermal_zone_params *tzp;
+ struct thermal_zone_device *pos = NULL;
+
+ mutex_lock(&thermal_list_lock);
+
+ list_for_each_entry(pos, &thermal_tz_list, node) {
+ if (!pos->tzp && !pos->ops->bind)
+ continue;
- if (!strncmp(dev_name(dev), "thermal_zone",
- sizeof("thermal_zone") - 1)) {
- tz = to_thermal_zone(dev);
- kfree(tz);
- } else if(!strncmp(dev_name(dev), "cooling_device",
- sizeof("cooling_device") - 1)){
- cdev = to_cooling_device(dev);
- kfree(cdev);
+ if (pos->ops->bind) {
+ ret = pos->ops->bind(pos, cdev);
+ if (ret)
+ print_bind_err_msg(pos, cdev, ret);
+ continue;
+ }
+
+ tzp = pos->tzp;
+ if (!tzp || !tzp->tbp)
+ continue;
+
+ for (i = 0; i < tzp->num_tbps; i++) {
+ if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
+ continue;
+ if (tzp->tbp[i].match(pos, cdev))
+ continue;
+ tzp->tbp[i].cdev = cdev;
+ __bind(pos, tzp->tbp[i].trip_mask, cdev,
+ tzp->tbp[i].binding_limits,
+ tzp->tbp[i].weight);
+ }
}
-}
-static struct class thermal_class = {
- .name = "thermal",
- .dev_release = thermal_release,
-};
+ mutex_unlock(&thermal_list_lock);
+}
/**
* __thermal_cooling_device_register() - register a new thermal cooling device
@@ -1581,16 +1049,17 @@ __thermal_cooling_device_register(struct device_node *np,
!ops->set_cur_state)
return ERR_PTR(-EINVAL);
- cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return ERR_PTR(-ENOMEM);
- result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
- if (result) {
+ result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
+ if (result < 0) {
kfree(cdev);
return ERR_PTR(result);
}
+ cdev->id = result;
strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
mutex_init(&cdev->lock);
INIT_LIST_HEAD(&cdev->thermal_instances);
@@ -1598,15 +1067,18 @@ __thermal_cooling_device_register(struct device_node *np,
cdev->ops = ops;
cdev->updated = false;
cdev->device.class = &thermal_class;
- cdev->device.groups = cooling_device_attr_groups;
cdev->devdata = devdata;
+ cdev->sysfs_cur_state_req = 0;
+ cdev->sysfs_min_state_req = ULONG_MAX;
+ thermal_cooling_device_setup_sysfs(cdev);
dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
result = device_register(&cdev->device);
if (result) {
- release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+ ida_simple_remove(&thermal_cdev_ida, cdev->id);
kfree(cdev);
return ERR_PTR(result);
}
+ pr_info("register cooling_device%d-%s\n", cdev->id, cdev->type);
/* Add 'this' new cdev to the global cdev list */
mutex_lock(&thermal_list_lock);
@@ -1619,7 +1091,8 @@ __thermal_cooling_device_register(struct device_node *np,
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node)
if (atomic_cmpxchg(&pos->need_update, 1, 0))
- thermal_zone_device_update(pos);
+ thermal_zone_device_update(pos,
+ THERMAL_EVENT_UNSPECIFIED);
mutex_unlock(&thermal_list_lock);
return cdev;
@@ -1670,12 +1143,22 @@ thermal_of_cooling_device_register(struct device_node *np,
}
EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
+static void __unbind(struct thermal_zone_device *tz, int mask,
+ struct thermal_cooling_device *cdev)
+{
+ int i;
+
+ for (i = 0; i < tz->trips; i++)
+ if (mask & (1 << i))
+ thermal_zone_unbind_cooling_device(tz, i, cdev);
+}
+
/**
- * thermal_cooling_device_unregister - removes the registered thermal cooling device
+ * thermal_cooling_device_unregister - removes a thermal cooling device
* @cdev: the thermal cooling device to remove.
*
- * thermal_cooling_device_unregister() must be called when the device is no
- * longer needed.
+ * thermal_cooling_device_unregister() must be called when a registered
+ * thermal cooling device is no longer needed.
*/
void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
{
@@ -1689,8 +1172,8 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_cdev_list, node)
- if (pos == cdev)
- break;
+ if (pos == cdev)
+ break;
if (pos != cdev) {
/* thermal cooling device not found */
mutex_unlock(&thermal_list_lock);
@@ -1719,172 +1202,51 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
mutex_unlock(&thermal_list_lock);
- if (cdev->type[0])
- device_remove_file(&cdev->device, &dev_attr_cdev_type);
- device_remove_file(&cdev->device, &dev_attr_max_state);
- device_remove_file(&cdev->device, &dev_attr_cur_state);
-
- release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
- device_unregister(&cdev->device);
- return;
+ ida_simple_remove(&thermal_cdev_ida, cdev->id);
+ device_del(&cdev->device);
+ thermal_cooling_device_destroy_sysfs(cdev);
+ put_device(&cdev->device);
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister);
-void thermal_cdev_update(struct thermal_cooling_device *cdev)
+static void bind_tz(struct thermal_zone_device *tz)
{
- struct thermal_instance *instance;
- unsigned long target = 0;
-
- /* cooling device is updated*/
- if (cdev->updated)
- return;
-
- mutex_lock(&cdev->lock);
- /* Make sure cdev enters the deepest cooling state */
- list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
- dev_dbg(&cdev->device, "zone%d->target=%lu\n",
- instance->tz->id, instance->target);
- if (instance->target == THERMAL_NO_TARGET)
- continue;
- if (instance->target > target)
- target = instance->target;
- }
- mutex_unlock(&cdev->lock);
- cdev->ops->set_cur_state(cdev, target);
- cdev->updated = true;
- trace_cdev_update(cdev, target);
- dev_dbg(&cdev->device, "set to state %lu\n", target);
-}
-EXPORT_SYMBOL(thermal_cdev_update);
+ int i, ret;
+ struct thermal_cooling_device *pos = NULL;
+ const struct thermal_zone_params *tzp = tz->tzp;
-/**
- * thermal_notify_framework - Sensor drivers use this API to notify framework
- * @tz: thermal zone device
- * @trip: indicates which trip point has been crossed
- *
- * This function handles the trip events from sensor drivers. It starts
- * throttling the cooling devices according to the policy configured.
- * For CRITICAL and HOT trip points, this notifies the respective drivers,
- * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
- * The throttling policy is based on the configured platform data; if no
- * platform data is provided, this uses the step_wise throttling policy.
- */
-void thermal_notify_framework(struct thermal_zone_device *tz, int trip)
-{
- if (atomic_read(&in_suspend))
+ if (!tzp && !tz->ops->bind)
return;
- handle_thermal_trip(tz, trip);
-}
-EXPORT_SYMBOL_GPL(thermal_notify_framework);
-
-/**
- * create_trip_attrs() - create attributes for trip points
- * @tz: the thermal zone device
- * @mask: Writeable trip point bitmap.
- *
- * helper function to instantiate sysfs entries for every trip
- * point and its properties of a struct thermal_zone_device.
- *
- * Return: 0 on success, the proper error value otherwise.
- */
-static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
-{
- int indx;
- int size = sizeof(struct thermal_attr) * tz->trips;
-
- tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
- if (!tz->trip_type_attrs)
- return -ENOMEM;
-
- tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
- if (!tz->trip_temp_attrs) {
- kfree(tz->trip_type_attrs);
- return -ENOMEM;
- }
+ mutex_lock(&thermal_list_lock);
- if (tz->ops->get_trip_hyst) {
- tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
- if (!tz->trip_hyst_attrs) {
- kfree(tz->trip_type_attrs);
- kfree(tz->trip_temp_attrs);
- return -ENOMEM;
+ /* If there is ops->bind, try to use ops->bind */
+ if (tz->ops->bind) {
+ list_for_each_entry(pos, &thermal_cdev_list, node) {
+ ret = tz->ops->bind(tz, pos);
+ if (ret)
+ print_bind_err_msg(tz, pos, ret);
}
+ goto exit;
}
+ if (!tzp || !tzp->tbp)
+ goto exit;
- for (indx = 0; indx < tz->trips; indx++) {
- /* create trip type attribute */
- snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
- "trip_point_%d_type", indx);
-
- sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
- tz->trip_type_attrs[indx].attr.attr.name =
- tz->trip_type_attrs[indx].name;
- tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
- tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
-
- device_create_file(&tz->device,
- &tz->trip_type_attrs[indx].attr);
-
- /* create trip temp attribute */
- snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
- "trip_point_%d_temp", indx);
-
- sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
- tz->trip_temp_attrs[indx].attr.attr.name =
- tz->trip_temp_attrs[indx].name;
- tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
- tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
- if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS) &&
- mask & (1 << indx)) {
- tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
- tz->trip_temp_attrs[indx].attr.store =
- trip_point_temp_store;
- }
-
- device_create_file(&tz->device,
- &tz->trip_temp_attrs[indx].attr);
-
- /* create Optional trip hyst attribute */
- if (!tz->ops->get_trip_hyst)
- continue;
- snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
- "trip_point_%d_hyst", indx);
-
- sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
- tz->trip_hyst_attrs[indx].attr.attr.name =
- tz->trip_hyst_attrs[indx].name;
- tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
- tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
- if (tz->ops->set_trip_hyst) {
- tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
- tz->trip_hyst_attrs[indx].attr.store =
- trip_point_hyst_store;
+ list_for_each_entry(pos, &thermal_cdev_list, node) {
+ for (i = 0; i < tzp->num_tbps; i++) {
+ if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
+ continue;
+ if (tzp->tbp[i].match(tz, pos))
+ continue;
+ tzp->tbp[i].cdev = pos;
+ __bind(tz, tzp->tbp[i].trip_mask, pos,
+ tzp->tbp[i].binding_limits,
+ tzp->tbp[i].weight);
}
-
- device_create_file(&tz->device,
- &tz->trip_hyst_attrs[indx].attr);
- }
- return 0;
-}
-
-static void remove_trip_attrs(struct thermal_zone_device *tz)
-{
- int indx;
-
- for (indx = 0; indx < tz->trips; indx++) {
- device_remove_file(&tz->device,
- &tz->trip_type_attrs[indx].attr);
- device_remove_file(&tz->device,
- &tz->trip_temp_attrs[indx].attr);
- if (tz->ops->get_trip_hyst)
- device_remove_file(&tz->device,
- &tz->trip_hyst_attrs[indx].attr);
}
- kfree(tz->trip_type_attrs);
- kfree(tz->trip_temp_attrs);
- kfree(tz->trip_hyst_attrs);
+exit:
+ mutex_unlock(&thermal_list_lock);
}
/**
@@ -1911,20 +1273,22 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
* in case of error, an ERR_PTR. Caller must check return value with
* IS_ERR*() helpers.
*/
-struct thermal_zone_device *thermal_zone_device_register(const char *type,
- int trips, int mask, void *devdata,
- struct thermal_zone_device_ops *ops,
- struct thermal_zone_params *tzp,
- int passive_delay, int polling_delay)
+struct thermal_zone_device *
+thermal_zone_device_register(const char *type, int trips, int mask,
+ void *devdata, struct thermal_zone_device_ops *ops,
+ struct thermal_zone_params *tzp, int passive_delay,
+ int polling_delay)
{
struct thermal_zone_device *tz;
enum thermal_trip_type trip_type;
int trip_temp;
int result;
int count;
- int passive = 0;
struct thermal_governor *governor;
+ if (!type || strlen(type) == 0)
+ return ERR_PTR(-EINVAL);
+
if (type && strlen(type) >= THERMAL_NAME_LENGTH)
return ERR_PTR(-EINVAL);
@@ -1937,20 +1301,19 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
return ERR_PTR(-EINVAL);
- tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
+ tz = kzalloc(sizeof(*tz), GFP_KERNEL);
if (!tz)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&tz->thermal_instances);
- idr_init(&tz->idr);
+ ida_init(&tz->ida);
mutex_init(&tz->lock);
- result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
- if (result) {
- kfree(tz);
- return ERR_PTR(result);
- }
+ result = ida_simple_get(&thermal_tz_ida, 0, 0, GFP_KERNEL);
+ if (result < 0)
+ goto free_tz;
- strlcpy(tz->type, type ? : "", sizeof(tz->type));
+ tz->id = result;
+ strlcpy(tz->type, type, sizeof(tz->type));
tz->ops = ops;
tz->tzp = tzp;
tz->device.class = &thermal_class;
@@ -1958,46 +1321,24 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
tz->trips = trips;
tz->passive_delay = passive_delay;
tz->polling_delay = polling_delay;
-#ifdef CONFIG_SCHED_HMP
- tz->poll_queue_cpu = BOUNDED_CPU;
-#endif
- /* A new thermal zone needs to be updated anyway. */
- atomic_set(&tz->need_update, 1);
-
- dev_set_name(&tz->device, "thermal_zone%d", tz->id);
- result = device_register(&tz->device);
- if (result) {
- release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
- kfree(tz);
- return ERR_PTR(result);
- }
/* sys I/F */
- if (type) {
- result = device_create_file(&tz->device, &dev_attr_type);
- if (result)
- goto unregister;
- }
-
- result = device_create_file(&tz->device, &dev_attr_temp);
+ /* Add nodes that are always present via .groups */
+ result = thermal_zone_create_device_groups(tz, mask);
if (result)
- goto unregister;
+ goto remove_id;
- if (ops->get_mode) {
- result = device_create_file(&tz->device, &dev_attr_mode);
- if (result)
- goto unregister;
- }
+ /* A new thermal zone needs to be updated anyway. */
+ atomic_set(&tz->need_update, 1);
- result = create_trip_attrs(tz, mask);
+ dev_set_name(&tz->device, "thermal_zone%d", tz->id);
+ result = device_register(&tz->device);
if (result)
- goto unregister;
+ goto remove_device_groups;
for (count = 0; count < trips; count++) {
if (tz->ops->get_trip_type(tz, count, &trip_type))
set_bit(count, &tz->trips_disabled);
- if (trip_type == THERMAL_TRIP_PASSIVE)
- passive = 1;
if (tz->ops->get_trip_temp(tz, count, &trip_temp))
set_bit(count, &tz->trips_disabled);
/* Check for bogus trip points */
@@ -2005,33 +1346,6 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
set_bit(count, &tz->trips_disabled);
}
- if (!passive) {
- result = device_create_file(&tz->device, &dev_attr_passive);
- if (result)
- goto unregister;
- }
-
- if (IS_ENABLED(CONFIG_THERMAL_EMULATION)) {
- result = device_create_file(&tz->device, &dev_attr_emul_temp);
- if (result)
- goto unregister;
- }
-
- /* Create policy attribute */
- result = device_create_file(&tz->device, &dev_attr_policy);
- if (result)
- goto unregister;
-
- /* Add thermal zone params */
- result = create_tzp_attrs(&tz->device);
- if (result)
- goto unregister;
-
- /* Create available_policies attribute */
- result = device_create_file(&tz->device, &dev_attr_available_policies);
- if (result)
- goto unregister;
-
/* Update 'this' zone's governor information */
mutex_lock(&thermal_governor_lock);
@@ -2061,19 +1375,27 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
/* Bind cooling devices for this zone */
bind_tz(tz);
- INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
+ INIT_DEFERRABLE_WORK(&(tz->poll_queue), thermal_zone_device_check);
thermal_zone_device_reset(tz);
/* Update the new thermal zone and mark it as already updated. */
if (atomic_cmpxchg(&tz->need_update, 1, 0))
- thermal_zone_device_update(tz);
+ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
return tz;
unregister:
- release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+ ida_simple_remove(&thermal_tz_ida, tz->id);
device_unregister(&tz->device);
return ERR_PTR(result);
+
+remove_device_groups:
+ thermal_zone_destroy_device_groups(tz);
+remove_id:
+ ida_simple_remove(&thermal_tz_ida, tz->id);
+free_tz:
+ kfree(tz);
+ return ERR_PTR(result);
}
EXPORT_SYMBOL_GPL(thermal_zone_device_register);
@@ -2095,8 +1417,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node)
- if (pos == tz)
- break;
+ if (pos == tz)
+ break;
if (pos != tz) {
/* thermal zone device not found */
mutex_unlock(&thermal_list_lock);
@@ -2124,24 +1446,15 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
mutex_unlock(&thermal_list_lock);
- thermal_zone_device_set_polling(tz, 0);
+ cancel_delayed_work_sync(&tz->poll_queue);
- if (tz->type[0])
- device_remove_file(&tz->device, &dev_attr_type);
- device_remove_file(&tz->device, &dev_attr_temp);
- if (tz->ops->get_mode)
- device_remove_file(&tz->device, &dev_attr_mode);
- device_remove_file(&tz->device, &dev_attr_policy);
- device_remove_file(&tz->device, &dev_attr_available_policies);
- remove_trip_attrs(tz);
thermal_set_governor(tz, NULL);
thermal_remove_hwmon_sysfs(tz);
- release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
- idr_destroy(&tz->idr);
+ ida_simple_remove(&thermal_tz_ida, tz->id);
+ ida_destroy(&tz->ida);
mutex_destroy(&tz->lock);
device_unregister(&tz->device);
- return;
}
EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
@@ -2188,8 +1501,8 @@ static const struct genl_multicast_group thermal_event_mcgrps[] = {
{ .name = THERMAL_GENL_MCAST_GROUP_NAME, },
};
-static struct genl_family thermal_event_genl_family = {
- .id = GENL_ID_GENERATE,
+static struct genl_family thermal_event_genl_family __ro_after_init = {
+ .module = THIS_MODULE,
.name = THERMAL_GENL_FAMILY_NAME,
.version = THERMAL_GENL_VERSION,
.maxattr = THERMAL_GENL_ATTR_MAX,
@@ -2197,8 +1510,10 @@ static struct genl_family thermal_event_genl_family = {
.n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps),
};
+static int allow_netlink_events;
+
int thermal_generate_netlink_event(struct thermal_zone_device *tz,
- enum events event)
+ enum events event)
{
struct sk_buff *skb;
struct nlattr *attr;
@@ -2211,6 +1526,9 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
if (!tz)
return -EINVAL;
+ if (!allow_netlink_events)
+ return -ENODEV;
+
/* allocate memory */
size = nla_total_size(sizeof(struct thermal_genl_event)) +
nla_total_size(0);
@@ -2260,7 +1578,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL_GPL(thermal_generate_netlink_event);
-static int genetlink_init(void)
+static int __init genetlink_init(void)
{
return genl_register_family(&thermal_event_genl_family);
}
@@ -2272,79 +1590,42 @@ static void genetlink_exit(void)
#else /* !CONFIG_NET */
static inline int genetlink_init(void) { return 0; }
static inline void genetlink_exit(void) {}
+static inline int thermal_generate_netlink_event(struct thermal_zone_device *tz,
+ enum events event) { return -ENODEV; }
#endif /* !CONFIG_NET */
-static int __init thermal_register_governors(void)
-{
- int result;
-
- result = thermal_gov_step_wise_register();
- if (result)
- return result;
-
- result = thermal_gov_fair_share_register();
- if (result)
- return result;
-
- result = thermal_gov_bang_bang_register();
- if (result)
- return result;
-
- result = thermal_gov_user_space_register();
- if (result)
- return result;
-
- return thermal_gov_power_allocator_register();
-}
-
-static void thermal_unregister_governors(void)
-{
- thermal_gov_step_wise_unregister();
- thermal_gov_fair_share_unregister();
- thermal_gov_bang_bang_unregister();
- thermal_gov_user_space_unregister();
- thermal_gov_power_allocator_unregister();
-}
-
-#ifdef CONFIG_SCHED_HMP
-static int thermal_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+#if defined(CONFIG_SEC_PM)
+static void __ref cdev_print(struct work_struct *work)
{
- unsigned long cpu = (unsigned long)hcpu;
- struct thermal_zone_device *pos;
+ struct thermal_cooling_device *cdev;
+ unsigned long cur_state = 0;
+ int added = 0, ret = 0;
+ char buffer[500] = { 0, };
+ bool is_state = false;
- switch (action) {
- case CPU_ONLINE:
- if (cpu == BOUNDED_CPU) {
- list_for_each_entry(pos, &thermal_tz_list, node) {
- pos->poll_queue_cpu = BOUNDED_CPU;
- if (pos->polling_delay) {
- start_poll_queue(pos, pos->polling_delay);
- }
- }
- }
- break;
- case CPU_DOWN_PREPARE:
- list_for_each_entry(pos, &thermal_tz_list, node) {
- if (pos->poll_queue_cpu == cpu) {
- pos->poll_queue_cpu = 0;
- if (pos->polling_delay)
- start_poll_queue(pos, pos->polling_delay);
- }
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(cdev, &thermal_cdev_list, node) {
+ if (cdev->ops->get_cur_state)
+ cdev->ops->get_cur_state(cdev, &cur_state);;
+
+ if (cur_state) {
+ is_state = true;
+ ret = snprintf(buffer + added, sizeof(buffer) - added,
+ "[%s:%ld]", cdev->type, cur_state);
+ added += ret;
}
- break;
}
- return NOTIFY_OK;
-}
+ mutex_unlock(&thermal_list_lock);
-static struct notifier_block thermal_cpu_notifier =
-{
- .notifier_call = thermal_cpu_callback,
-};
+ if (is_state)
+ printk("thermal: cdev%s\n", buffer);
+
+ schedule_delayed_work(&cdev_print_work, HZ * 5);
+}
#endif
static int thermal_pm_notify(struct notifier_block *nb,
- unsigned long mode, void *_unused)
+ unsigned long mode, void *_unused)
{
struct thermal_zone_device *tz;
@@ -2352,6 +1633,9 @@ static int thermal_pm_notify(struct notifier_block *nb,
case PM_HIBERNATION_PREPARE:
case PM_RESTORE_PREPARE:
case PM_SUSPEND_PREPARE:
+#if defined(CONFIG_SEC_PM)
+ cancel_delayed_work(&cdev_print_work);
+#endif
atomic_set(&in_suspend, 1);
break;
case PM_POST_HIBERNATION:
@@ -2359,9 +1643,16 @@ static int thermal_pm_notify(struct notifier_block *nb,
case PM_POST_SUSPEND:
atomic_set(&in_suspend, 0);
list_for_each_entry(tz, &thermal_tz_list, node) {
- thermal_zone_device_reset(tz);
- thermal_zone_device_update(tz);
+ if (tz->ops->is_wakeable &&
+ tz->ops->is_wakeable(tz))
+ continue;
+ thermal_zone_device_init(tz);
+ thermal_zone_device_update(tz,
+ THERMAL_EVENT_UNSPECIFIED);
}
+#if defined(CONFIG_SEC_PM)
+ schedule_delayed_work(&cdev_print_work, 0);
+#endif
break;
default:
break;
@@ -2377,63 +1668,91 @@ static int __init thermal_init(void)
{
int result;
+ mutex_init(&poweroff_lock);
+ thermal_passive_wq = alloc_workqueue("thermal_passive_wq",
+ WQ_HIGHPRI | WQ_UNBOUND
+ | WQ_FREEZABLE,
+ THERMAL_MAX_ACTIVE);
+ if (!thermal_passive_wq) {
+ result = -ENOMEM;
+ goto error;
+ }
+
result = thermal_register_governors();
if (result)
- goto error;
+ goto destroy_wq;
result = class_register(&thermal_class);
if (result)
goto unregister_governors;
- result = genetlink_init();
- if (result)
- goto unregister_class;
-
result = of_parse_thermal_zones();
if (result)
- goto exit_netlink;
+ goto exit_zone_parse;
-#ifdef CONFIG_SCHED_HMP
- register_hotcpu_notifier(&thermal_cpu_notifier);
-#endif
result = register_pm_notifier(&thermal_pm_nb);
if (result)
pr_warn("Thermal: Can not register suspend notifier, return %d\n",
result);
+#if defined(CONFIG_SEC_PM)
+ INIT_DELAYED_WORK(&cdev_print_work, cdev_print);
+ schedule_delayed_work(&cdev_print_work, 0);
+
+ if (!thermal_ipc_log)
+ thermal_ipc_log = ipc_log_context_create(10, "lmh_dcvs", 0);
+
+ if (!thermal_ipc_log)
+ pr_err("%s: Failed to create thermal logging context\n", __func__);
+#endif
+
return 0;
-exit_netlink:
- genetlink_exit();
-unregister_class:
+exit_zone_parse:
class_unregister(&thermal_class);
unregister_governors:
thermal_unregister_governors();
+destroy_wq:
+ destroy_workqueue(thermal_passive_wq);
error:
- idr_destroy(&thermal_tz_idr);
- idr_destroy(&thermal_cdev_idr);
- mutex_destroy(&thermal_idr_lock);
+ ida_destroy(&thermal_tz_ida);
+ ida_destroy(&thermal_cdev_ida);
mutex_destroy(&thermal_list_lock);
mutex_destroy(&thermal_governor_lock);
+ mutex_destroy(&poweroff_lock);
return result;
}
-static void __exit thermal_exit(void)
+static void thermal_exit(void)
{
- unregister_pm_notifier(&thermal_pm_nb);
-#ifdef CONFIG_SCHED_HMP
- unregister_hotcpu_notifier(&thermal_cpu_notifier);
+#if defined(CONFIG_SEC_PM)
+ cancel_delayed_work_sync(&cdev_print_work);
#endif
+ unregister_pm_notifier(&thermal_pm_nb);
of_thermal_destroy_zones();
+ destroy_workqueue(thermal_passive_wq);
genetlink_exit();
class_unregister(&thermal_class);
thermal_unregister_governors();
- idr_destroy(&thermal_tz_idr);
- idr_destroy(&thermal_cdev_idr);
- mutex_destroy(&thermal_idr_lock);
+ ida_destroy(&thermal_tz_ida);
+ ida_destroy(&thermal_cdev_ida);
mutex_destroy(&thermal_list_lock);
mutex_destroy(&thermal_governor_lock);
}
-fs_initcall(thermal_init);
+static int __init thermal_netlink_init(void)
+{
+ int ret = 0;
+
+ ret = genetlink_init();
+ if (!ret)
+ goto exit_netlink;
+
+ thermal_exit();
+exit_netlink:
+ return ret;
+}
+
+subsys_initcall(thermal_init);
+fs_initcall(thermal_netlink_init);
module_exit(thermal_exit);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
old mode 100755
new mode 100644
index 749d41ab..3904a52f
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -1,24 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* thermal_core.h
*
* Copyright (C) 2012 Intel Corp
* Author: Durgadoss R
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#ifndef __THERMAL_CORE_H__
@@ -49,13 +34,57 @@ struct thermal_instance {
struct device_attribute attr;
char weight_attr_name[THERMAL_NAME_LENGTH];
struct device_attribute weight_attr;
+ char upper_attr_name[THERMAL_NAME_LENGTH];
+ struct device_attribute upper_attr;
+ char lower_attr_name[THERMAL_NAME_LENGTH];
+ struct device_attribute lower_attr;
struct list_head tz_node; /* node in tz->thermal_instances */
struct list_head cdev_node; /* node in cdev->thermal_instances */
unsigned int weight; /* The weight of the cooling device */
};
+#define to_thermal_zone(_dev) \
+ container_of(_dev, struct thermal_zone_device, device)
+
+#define to_cooling_device(_dev) \
+ container_of(_dev, struct thermal_cooling_device, device)
+
int thermal_register_governor(struct thermal_governor *);
void thermal_unregister_governor(struct thermal_governor *);
+void thermal_zone_device_rebind_exception(struct thermal_zone_device *,
+ const char *, size_t);
+void thermal_zone_device_unbind_exception(struct thermal_zone_device *,
+ const char *, size_t);
+int thermal_zone_device_set_policy(struct thermal_zone_device *, char *);
+int thermal_build_list_of_policies(char *buf);
+
+/* sysfs I/F */
+int thermal_zone_create_device_groups(struct thermal_zone_device *, int);
+void thermal_zone_destroy_device_groups(struct thermal_zone_device *);
+void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *);
+void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev);
+/* used only at binding time */
+ssize_t trip_point_show(struct device *, struct device_attribute *, char *);
+ssize_t weight_show(struct device *, struct device_attribute *, char *);
+ssize_t lower_limit_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+ssize_t upper_limit_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+ssize_t weight_store(struct device *, struct device_attribute *, const char *,
+ size_t);
+ssize_t lower_limit_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+ssize_t upper_limit_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+
+#ifdef CONFIG_THERMAL_STATISTICS
+void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
+ unsigned long new_state);
+#else
+static inline void
+thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
+ unsigned long new_state) {}
+#endif /* CONFIG_THERMAL_STATISTICS */
#ifdef CONFIG_THERMAL_GOV_STEP_WISE
int thermal_gov_step_wise_register(void);
@@ -97,6 +126,14 @@ static inline int thermal_gov_power_allocator_register(void) { return 0; }
static inline void thermal_gov_power_allocator_unregister(void) {}
#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
+#ifdef CONFIG_THERMAL_GOV_LOW_LIMITS
+int thermal_gov_low_limits_register(void);
+void thermal_gov_low_limits_unregister(void);
+#else
+static inline int thermal_gov_low_limits_register(void) { return 0; }
+static inline void thermal_gov_low_limits_unregister(void) {}
+#endif /* CONFIG_THERMAL_GOV_LOW_LIMITS */
+
/* device tree support */
#ifdef CONFIG_THERMAL_OF
int of_parse_thermal_zones(void);
@@ -105,6 +142,12 @@ int of_thermal_get_ntrips(struct thermal_zone_device *);
bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device *);
+int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type type,
+ int *low, int *high);
+void of_thermal_handle_trip(struct thermal_zone_device *tz);
+void of_thermal_handle_trip_temp(struct thermal_zone_device *tz,
+ int trip_temp);
#else
static inline int of_parse_thermal_zones(void) { return 0; }
static inline void of_thermal_destroy_zones(void) { }
@@ -122,6 +165,19 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz)
{
return NULL;
}
+static inline int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type type,
+ int *low, int *high)
+{
+ return -ENODEV;
+}
+static inline
+void of_thermal_handle_trip(struct thermal_zone_device *tz)
+{ }
+static inline
+void of_thermal_handle_trip_temp(struct thermal_zone_device *tz,
+ int trip_temp)
+{ }
#endif
#endif /* __THERMAL_CORE_H__ */