* [PATCH v13 04/25] kasan: rename source files to reflect the new naming scheme
From: Andrey Konovalov @ 2018-12-06 12:24 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov,
Catalin Marinas, Will Deacon, Christoph Lameter, Andrew Morton,
Mark Rutland, Nick Desaulniers, Marc Zyngier, Dave Martin,
Ard Biesheuvel, Eric W . Biederman, Ingo Molnar, Paul Lawrence,
Geert Uytterhoeven, Arnd Bergmann, Kirill A . Shutemov,
Greg Kroah-Hartman, Kate Stewart, Mike Rapoport, kasan-dev,
linux-doc, linux-kernel, linux-arm-kernel, linux-sparse, linux-mm,
linux-kbuild
Cc: Vishwath Mohan, Chintan Pandya, Jacob Bramley, Jann Horn,
Ruben Ayrapetyan, Andrey Konovalov, Lee Smith, Kostya Serebryany,
Mark Brand, Ramana Radhakrishnan, Evgeniy Stepanov
In-Reply-To: <cover.1544099024.git.andreyknvl@google.com>
We now have two KASAN modes: generic KASAN and tag-based KASAN. Rename
kasan.c to generic.c to reflect that. Also rename kasan_init.c to init.c
as it contains initialization code for both KASAN modes.
Reviewed-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/kasan/Makefile | 8 ++++----
mm/kasan/{kasan.c => generic.c} | 0
mm/kasan/{kasan_init.c => init.c} | 0
3 files changed, 4 insertions(+), 4 deletions(-)
rename mm/kasan/{kasan.c => generic.c} (100%)
rename mm/kasan/{kasan_init.c => init.c} (100%)
diff --git a/mm/kasan/Makefile b/mm/kasan/Makefile
index a6df14bffb6b..d643530b24aa 100644
--- a/mm/kasan/Makefile
+++ b/mm/kasan/Makefile
@@ -1,14 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
KASAN_SANITIZE := n
UBSAN_SANITIZE_common.o := n
-UBSAN_SANITIZE_kasan.o := n
+UBSAN_SANITIZE_generic.o := n
KCOV_INSTRUMENT := n
-CFLAGS_REMOVE_kasan.o = -pg
+CFLAGS_REMOVE_generic.o = -pg
# Function splitter causes unnecessary splits in __asan_load1/__asan_store1
# see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533
CFLAGS_common.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
-CFLAGS_kasan.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
+CFLAGS_generic.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
-obj-y := common.o kasan.o report.o kasan_init.o quarantine.o
+obj-y := common.o generic.o report.o init.o quarantine.o
diff --git a/mm/kasan/kasan.c b/mm/kasan/generic.c
similarity index 100%
rename from mm/kasan/kasan.c
rename to mm/kasan/generic.c
diff --git a/mm/kasan/kasan_init.c b/mm/kasan/init.c
similarity index 100%
rename from mm/kasan/kasan_init.c
rename to mm/kasan/init.c
--
2.20.0.rc1.387.gf8505762e3-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v13 02/25] kasan, slub: handle pointer tags in early_kmem_cache_node_alloc
From: Andrey Konovalov @ 2018-12-06 12:24 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov,
Catalin Marinas, Will Deacon, Christoph Lameter, Andrew Morton,
Mark Rutland, Nick Desaulniers, Marc Zyngier, Dave Martin,
Ard Biesheuvel, Eric W . Biederman, Ingo Molnar, Paul Lawrence,
Geert Uytterhoeven, Arnd Bergmann, Kirill A . Shutemov,
Greg Kroah-Hartman, Kate Stewart, Mike Rapoport, kasan-dev,
linux-doc, linux-kernel, linux-arm-kernel, linux-sparse, linux-mm,
linux-kbuild
Cc: Vishwath Mohan, Chintan Pandya, Jacob Bramley, Jann Horn,
Ruben Ayrapetyan, Andrey Konovalov, Lee Smith, Kostya Serebryany,
Mark Brand, Ramana Radhakrishnan, Evgeniy Stepanov
In-Reply-To: <cover.1544099024.git.andreyknvl@google.com>
The previous patch updated KASAN hooks signatures and their usage in SLAB
and SLUB code, except for the early_kmem_cache_node_alloc function. This
patch handles that function separately, as it requires to reorder some of
the initialization code to correctly propagate a tagged pointer in case a
tag is assigned by kasan_kmalloc.
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
mm/slub.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/mm/slub.c b/mm/slub.c
index fdd4a86aa882..8561a32910dd 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3364,16 +3364,16 @@ static void early_kmem_cache_node_alloc(int node)
n = page->freelist;
BUG_ON(!n);
- page->freelist = get_freepointer(kmem_cache_node, n);
- page->inuse = 1;
- page->frozen = 0;
- kmem_cache_node->node[node] = n;
#ifdef CONFIG_SLUB_DEBUG
init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
init_tracking(kmem_cache_node, n);
#endif
- kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node),
+ n = kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node),
GFP_KERNEL);
+ page->freelist = get_freepointer(kmem_cache_node, n);
+ page->inuse = 1;
+ page->frozen = 0;
+ kmem_cache_node->node[node] = n;
init_kmem_cache_node(n);
inc_slabs_node(kmem_cache_node, node, page->objects);
--
2.20.0.rc1.387.gf8505762e3-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v13 00/25] kasan: add software tag-based mode for arm64
From: Andrey Konovalov @ 2018-12-06 12:24 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov,
Catalin Marinas, Will Deacon, Christoph Lameter, Andrew Morton,
Mark Rutland, Nick Desaulniers, Marc Zyngier, Dave Martin,
Ard Biesheuvel, Eric W . Biederman, Ingo Molnar, Paul Lawrence,
Geert Uytterhoeven, Arnd Bergmann, Kirill A . Shutemov,
Greg Kroah-Hartman, Kate Stewart, Mike Rapoport, kasan-dev,
linux-doc, linux-kernel, linux-arm-kernel, linux-sparse, linux-mm,
linux-kbuild
Cc: Vishwath Mohan, Chintan Pandya, Jacob Bramley, Jann Horn,
Ruben Ayrapetyan, Andrey Konovalov, Lee Smith, Kostya Serebryany,
Mark Brand, Ramana Radhakrishnan, Evgeniy Stepanov
This patchset adds a new software tag-based mode to KASAN [1].
(Initially this mode was called KHWASAN, but it got renamed,
see the naming rationale at the end of this section).
The plan is to implement HWASan [2] for the kernel with the incentive,
that it's going to have comparable to KASAN performance, but in the same
time consume much less memory, trading that off for somewhat imprecise
bug detection and being supported only for arm64.
The underlying ideas of the approach used by software tag-based KASAN are:
1. By using the Top Byte Ignore (TBI) arm64 CPU feature, we can store
pointer tags in the top byte of each kernel pointer.
2. Using shadow memory, we can store memory tags for each chunk of kernel
memory.
3. On each memory allocation, we can generate a random tag, embed it into
the returned pointer and set the memory tags that correspond to this
chunk of memory to the same value.
4. By using compiler instrumentation, before each memory access we can add
a check that the pointer tag matches the tag of the memory that is being
accessed.
5. On a tag mismatch we report an error.
With this patchset the existing KASAN mode gets renamed to generic KASAN,
with the word "generic" meaning that the implementation can be supported
by any architecture as it is purely software.
The new mode this patchset adds is called software tag-based KASAN. The
word "tag-based" refers to the fact that this mode uses tags embedded into
the top byte of kernel pointers and the TBI arm64 CPU feature that allows
to dereference such pointers. The word "software" here means that shadow
memory manipulation and tag checking on pointer dereference is done in
software. As it is the only tag-based implementation right now, "software
tag-based" KASAN is sometimes referred to as simply "tag-based" in this
patchset.
A potential expansion of this mode is a hardware tag-based mode, which would
use hardware memory tagging support (announced by Arm [3]) instead of
compiler instrumentation and manual shadow memory manipulation.
Same as generic KASAN, software tag-based KASAN is strictly a debugging
feature.
[1] https://www.kernel.org/doc/html/latest/dev-tools/kasan.html
[2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
[3] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a
====== Rationale
On mobile devices generic KASAN's memory usage is significant problem. One
of the main reasons to have tag-based KASAN is to be able to perform a
similar set of checks as the generic one does, but with lower memory
requirements.
Comment from Vishwath Mohan <vishwath@google.com>:
I don't have data on-hand, but anecdotally both ASAN and KASAN have proven
problematic to enable for environments that don't tolerate the increased
memory pressure well. This includes,
(a) Low-memory form factors - Wear, TV, Things, lower-tier phones like Go,
(c) Connected components like Pixel's visual core [1].
These are both places I'd love to have a low(er) memory footprint option at
my disposal.
Comment from Evgenii Stepanov <eugenis@google.com>:
Looking at a live Android device under load, slab (according to
/proc/meminfo) + kernel stack take 8-10% available RAM (~350MB). KASAN's
overhead of 2x - 3x on top of it is not insignificant.
Not having this overhead enables near-production use - ex. running
KASAN/KHWASAN kernel on a personal, daily-use device to catch bugs that do
not reproduce in test configuration. These are the ones that often cost
the most engineering time to track down.
CPU overhead is bad, but generally tolerable. RAM is critical, in our
experience. Once it gets low enough, OOM-killer makes your life miserable.
[1] https://www.blog.google/products/pixel/pixel-visual-core-image-processing-and-machine-learning-pixel-2/
====== Technical details
Software tag-based KASAN mode is implemented in a very similar way to the
generic one. This patchset essentially does the following:
1. TCR_TBI1 is set to enable Top Byte Ignore.
2. Shadow memory is used (with a different scale, 1:16, so each shadow
byte corresponds to 16 bytes of kernel memory) to store memory tags.
3. All slab objects are aligned to shadow scale, which is 16 bytes.
4. All pointers returned from the slab allocator are tagged with a random
tag and the corresponding shadow memory is poisoned with the same value.
5. Compiler instrumentation is used to insert tag checks. Either by
calling callbacks or by inlining them (CONFIG_KASAN_OUTLINE and
CONFIG_KASAN_INLINE flags are reused).
6. When a tag mismatch is detected in callback instrumentation mode
KASAN simply prints a bug report. In case of inline instrumentation,
clang inserts a brk instruction, and KASAN has it's own brk handler,
which reports the bug.
7. The memory in between slab objects is marked with a reserved tag, and
acts as a redzone.
8. When a slab object is freed it's marked with a reserved tag.
Bug detection is imprecise for two reasons:
1. We won't catch some small out-of-bounds accesses, that fall into the
same shadow cell, as the last byte of a slab object.
2. We only have 1 byte to store tags, which means we have a 1/256
probability of a tag match for an incorrect access (actually even
slightly less due to reserved tag values).
Despite that there's a particular type of bugs that tag-based KASAN can
detect compared to generic KASAN: use-after-free after the object has been
allocated by someone else.
====== Testing
Some kernel developers voiced a concern that changing the top byte of
kernel pointers may lead to subtle bugs that are difficult to discover.
To address this concern deliberate testing has been performed.
It doesn't seem feasible to do some kind of static checking to find
potential issues with pointer tagging, so a dynamic approach was taken.
All pointer comparisons/subtractions have been instrumented in an LLVM
compiler pass and a kernel module that would print a bug report whenever
two pointers with different tags are being compared/subtracted (ignoring
comparisons with NULL pointers and with pointers obtained by casting an
error code to a pointer type) has been used. Then the kernel has been
booted in QEMU and on an Odroid C2 board and syzkaller has been run.
This yielded the following results.
The two places that look interesting are:
is_vmalloc_addr in include/linux/mm.h
is_kernel_rodata in mm/util.c
Here we compare a pointer with some fixed untagged values to make sure
that the pointer lies in a particular part of the kernel address space.
Since tag-based KASAN doesn't add tags to pointers that belong to rodata
or vmalloc regions, this should work as is. To make sure debug checks to
those two functions that check that the result doesn't change whether
we operate on pointers with or without untagging has been added.
A few other cases that don't look that interesting:
Comparing pointers to achieve unique sorting order of pointee objects
(e.g. sorting locks addresses before performing a double lock):
tty_ldisc_lock_pair_timeout in drivers/tty/tty_ldisc.c
pipe_double_lock in fs/pipe.c
unix_state_double_lock in net/unix/af_unix.c
lock_two_nondirectories in fs/inode.c
mutex_lock_double in kernel/events/core.c
ep_cmp_ffd in fs/eventpoll.c
fsnotify_compare_groups fs/notify/mark.c
Nothing needs to be done here, since the tags embedded into pointers
don't change, so the sorting order would still be unique.
Checks that a pointer belongs to some particular allocation:
is_sibling_entry in lib/radix-tree.c
object_is_on_stack in include/linux/sched/task_stack.h
Nothing needs to be done here either, since two pointers can only belong
to the same allocation if they have the same tag.
Overall, since the kernel boots and works, there are no critical bugs.
As for the rest, the traditional kernel testing way (use until fails) is
the only one that looks feasible.
Another point here is that tag-based KASAN is available under a separate
config option that needs to be deliberately enabled. Even though it might
be used in a "near-production" environment to find bugs that are not found
during fuzzing or running tests, it is still a debug tool.
====== Benchmarks
The following numbers were collected on Odroid C2 board. Both generic and
tag-based KASAN were used in inline instrumentation mode.
Boot time [1]:
* ~1.7 sec for clean kernel
* ~5.0 sec for generic KASAN
* ~5.0 sec for tag-based KASAN
Network performance [2]:
* 8.33 Gbits/sec for clean kernel
* 3.17 Gbits/sec for generic KASAN
* 2.85 Gbits/sec for tag-based KASAN
Slab memory usage after boot [3]:
* ~40 kb for clean kernel
* ~105 kb (~260% overhead) for generic KASAN
* ~47 kb (~20% overhead) for tag-based KASAN
KASAN memory overhead consists of three main parts:
1. Increased slab memory usage due to redzones.
2. Shadow memory (the whole reserved once during boot).
3. Quaratine (grows gradually until some preset limit; the more the limit,
the more the chance to detect a use-after-free).
Comparing tag-based vs generic KASAN for each of these points:
1. 20% vs 260% overhead.
2. 1/16th vs 1/8th of physical memory.
3. Tag-based KASAN doesn't require quarantine.
[1] Time before the ext4 driver is initialized.
[2] Measured as `iperf -s & iperf -c 127.0.0.1 -t 30`.
[3] Measured as `cat /proc/meminfo | grep Slab`.
====== Some notes
A few notes:
1. The patchset can be found here:
https://github.com/xairy/kasan-prototype/tree/khwasan
2. Building requires a recent Clang version (7.0.0 or later).
3. Stack instrumentation is not supported yet and will be added later.
====== Changes
Changes in v13:
- Fixed Kconfig KASAN options dependencies to forbid enabling CONFIG_KASAN
without one of the modes.
- Select HAVE_ARCH_KASAN_SW_TAGS if HAVE_ARCH_KASAN in arm64 Kconfig.
- Reverted adding __arm64_skip_faulting_instruction.
- Rebased onto 4.20-rc4+ (cf76c364).
Changes in v12:
- Rebased onto ef78e5ec (4.20-rc4+).
- Used u64 instead of __u64 in arch/arm64/include/asm/memory.h as it isn't
a UAPI header.
- Moved the untagged_addr() macro down into the #ifndef __ASSEMBLY__
block, after we include <linux/bitops.h>, which is necessary for
sign_extend64().
- New patch: "kasan, arm64: select HAVE_ARCH_KASAN_SW_TAGS", that selects
HAVE_ARCH_KASAN_SW_TAGS for arm64 after all the necessary infrastructure
code is added.
- Minor style fixes.
Changes in v11:
- Rebased onto 9ff01193 (4.20-rc3).
- Moved KASAN_SHADOW_SCALE_SHIFT definition to arch/arm64/Makefile.
- Added and used CC_HAS_KASAN_GENERIC and CC_HAS_KASAN_SW_TAGS configs to
detect compiler support.
- New patch: "kasan: rename kasan_zero_page to kasan_early_shadow_page".
- New patch: "arm64: move untagged_addr macro from uaccess.h to memory.h".
- Renamed KASAN_SET_TAG/... macros in arch/arm64/include/asm/memory.h to
__tag_set/... and reused them later in KASAN core code instead of
redefining.
- Removed tag reset from the __kimg_to_phys() macro.
- Fixed tagged pointer handling in arm64 fault handling logic.
Changes in v10:
- Rebased onto 65102238 (4.20-rc1).
- Don't ignore kasan_kmalloc() return valued in kmem_cache_alloc_trace()
and kmem_cache_alloc_node_trace() in include/linux/slab.h.
- New patch: don't ignore kasan_kmalloc return value in
early_kmem_cache_node_alloc.
- New patch: added __must_check annotations to KASAN hooks that assign
tags.
- Changed KASAN clang version requirement to 7.0.0 (as we need rL329612).
- Moved __no_sanitize_address definition from compiler_attributes.h to
compiler-gcc.h and compiler-clang.h.
Changes in v9:
- Fixed kasan_init_slab_obj() hook when KASAN is disabled.
- Added assign_tag() function that preassigns tags for caches with
constructors.
- Fixed KASAN_TAG_MASK redefinition in include/linux/mm.h vs
mm/kasan/kasan.h.
Changes in v8:
- Rebased onto 7876320f (4.19-rc4).
- Renamed KHWASAN to software tag-based KASAN (see the top of the cover
letter for details).
- Explicitly called tag-based KASAN a debug tool.
- Reused kasan_init_slab_obj() callback to preassign tags to caches
without constructors, remove khwasan_preset_sl(u/a)b_tag().
- Moved move obj_to_index to include/linux/slab_def.h from mm/slab.c.
- Moved cache->s_mem untagging to alloc_slabmgmt() for SLAB.
- Fixed check_memory_region() to correctly handle user memory accesses and
size == 0 case.
- Merged __no_sanitize_hwaddress into __no_sanitize_address.
- Defined KASAN_SET_TAG and KASAN_RESET_TAG macros for non KASAN builds to
avoid duplication of __kimg_to_phys, _virt_addr_is_linear and
page_to_virt macros.
- Fixed and simplified find_first_bad_addr for generic KASAN.
- Use non symbolized example KASAN report in documentation.
- Mention clang version requirements for both KASAN modes in the Kconfig
options and in the documentation.
- Various small fixes.
Version v7 got accidentally skipped.
Changes in v6:
- Rebased onto 050cdc6c (4.19-rc1+).
- Added notes regarding patchset testing into the cover letter.
Changes in v5:
- Rebased onto 1ffaddd029 (4.18-rc8).
- Preassign tags for objects from caches with constructors and
SLAB_TYPESAFE_BY_RCU caches.
- Fix SLAB allocator support by untagging page->s_mem in
kasan_poison_slab().
- Performed dynamic testing to find potential places where pointer tagging
might result in bugs [1].
- Clarified and fixed memory usage benchmarks in the cover letter.
- Added a rationale for having KHWASAN to the cover letter.
Changes in v4:
- Fixed SPDX comment style in mm/kasan/kasan.h.
- Fixed mm/kasan/kasan.h changes being included in a wrong patch.
- Swapped "khwasan, arm64: fix up fault handling logic" and "khwasan: add
tag related helper functions" patches order.
- Rebased onto 6f0d349d (4.18-rc2+).
Changes in v3:
- Minor documentation fixes.
- Fixed CFLAGS variable name in KASAN makefile.
- Added a "SPDX-License-Identifier: GPL-2.0" line to all source files
under mm/kasan.
- Rebased onto 81e97f013 (4.18-rc1+).
Changes in v2:
- Changed kmalloc_large_node_hook to return tagged pointer instead of
using an output argument.
- Fix checking whether -fsanitize=hwaddress is supported by the compiler.
- Removed duplication of -fno-builtin for KASAN and KHWASAN.
- Removed {} block for one line for_each_possible_cpu loop.
- Made set_track() static inline as it is used only in common.c.
- Moved optimal_redzone() to common.c.
- Fixed using tagged pointer for shadow calculation in
kasan_unpoison_shadow().
- Restored setting cache->align in kasan_cache_create(), which was
accidentally lost.
- Simplified __kasan_slab_free(), kasan_alloc_pages() and kasan_kmalloc().
- Removed tagging from kasan_kmalloc_large().
- Added page_kasan_tag_reset() to kasan_poison_slab() and removed
!PageSlab() check from page_to_virt.
- Reset pointer tag in _virt_addr_is_linear.
- Set page tag for each page when multiple pages are allocated or freed.
- Added a comment as to why we ignore cma allocated pages.
Changes in v1:
- Rebased onto 4.17-rc4.
- Updated benchmarking stats.
- Documented compiler version requirements, memory usage and slowdown.
- Dropped kvm patches, as clang + arm64 + kvm is completely broken [1].
Changes in RFC v3:
- Renamed CONFIG_KASAN_CLASSIC and CONFIG_KASAN_TAGS to
CONFIG_KASAN_GENERIC and CONFIG_KASAN_HW respectively.
- Switch to -fsanitize=kernel-hwaddress instead of -fsanitize=hwaddress.
- Removed unnecessary excessive shadow initialization.
- Removed khwasan_enabled flag (it's not needed since KHWASAN is
initialized before any slab caches are used).
- Split out kasan_report.c and khwasan_report.c from report.c.
- Moved more common KASAN and KHWASAN functions to common.c.
- Added tagging to pagealloc.
- Rebased onto 4.17-rc1.
- Temporarily dropped patch that adds kvm support (arm64 + kvm + clang
combo is broken right now [2]).
Changes in RFC v2:
- Removed explicit casts to u8 * for kasan_mem_to_shadow() calls.
- Introduced KASAN_TCR_FLAGS for setting the TCR_TBI1 flag.
- Added a comment regarding the non-atomic RMW sequence in
khwasan_random_tag().
- Made all tag related functions accept const void *.
- Untagged pointers in __kimg_to_phys, which is used by virt_to_phys.
- Untagged pointers in show_ptr in fault handling logic.
- Untagged pointers passed to KVM.
- Added two reserved tag values: 0xFF and 0xFE.
- Used the reserved tag 0xFF to disable validity checking (to resolve the
issue with pointer tag being lost after page_address + kmap usage).
- Used the reserved tag 0xFE to mark redzones and freed objects.
- Added mnemonics for esr manipulation in KHWASAN brk handler.
- Added a comment about the -recover flag.
- Some minor cleanups and fixes.
- Rebased onto 3215b9d5 (4.16-rc6+).
- Tested on real hardware (Odroid C2 board).
- Added better benchmarks.
[1] https://lkml.org/lkml/2018/7/18/765
[2] https://lkml.org/lkml/2018/4/19/775
Reviewed-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
Andrey Konovalov (25):
kasan, mm: change hooks signatures
kasan, slub: handle pointer tags in early_kmem_cache_node_alloc
kasan: move common generic and tag-based code to common.c
kasan: rename source files to reflect the new naming scheme
kasan: add CONFIG_KASAN_GENERIC and CONFIG_KASAN_SW_TAGS
kasan, arm64: adjust shadow size for tag-based mode
kasan: rename kasan_zero_page to kasan_early_shadow_page
kasan: initialize shadow to 0xff for tag-based mode
arm64: move untagged_addr macro from uaccess.h to memory.h
kasan: add tag related helper functions
kasan, arm64: untag address in _virt_addr_is_linear
kasan: preassign tags to objects with ctors or SLAB_TYPESAFE_BY_RCU
kasan, arm64: fix up fault handling logic
kasan, arm64: enable top byte ignore for the kernel
kasan, mm: perform untagged pointers comparison in krealloc
kasan: split out generic_report.c from report.c
kasan: add bug reporting routines for tag-based mode
mm: move obj_to_index to include/linux/slab_def.h
kasan: add hooks implementation for tag-based mode
kasan, arm64: add brk handler for inline instrumentation
kasan, mm, arm64: tag non slab memory allocated via pagealloc
kasan: add __must_check annotations to kasan hooks
kasan, arm64: select HAVE_ARCH_KASAN_SW_TAGS
kasan: update documentation
kasan: add SPDX-License-Identifier mark to source files
Documentation/dev-tools/kasan.rst | 232 +++++----
arch/arm64/Kconfig | 1 +
arch/arm64/Makefile | 11 +-
arch/arm64/include/asm/brk-imm.h | 2 +
arch/arm64/include/asm/kasan.h | 8 +-
arch/arm64/include/asm/memory.h | 42 +-
arch/arm64/include/asm/pgtable-hwdef.h | 1 +
arch/arm64/include/asm/uaccess.h | 7 -
arch/arm64/kernel/traps.c | 60 +++
arch/arm64/mm/fault.c | 31 +-
arch/arm64/mm/kasan_init.c | 56 ++-
arch/arm64/mm/proc.S | 8 +-
arch/s390/mm/dump_pagetables.c | 17 +-
arch/s390/mm/kasan_init.c | 33 +-
arch/x86/mm/dump_pagetables.c | 11 +-
arch/x86/mm/kasan_init_64.c | 55 ++-
arch/xtensa/mm/kasan_init.c | 18 +-
include/linux/compiler-clang.h | 6 +-
include/linux/compiler-gcc.h | 6 +
include/linux/compiler_attributes.h | 13 -
include/linux/kasan.h | 101 +++-
include/linux/mm.h | 29 ++
include/linux/page-flags-layout.h | 10 +
include/linux/slab.h | 4 +-
include/linux/slab_def.h | 13 +
lib/Kconfig.kasan | 98 +++-
mm/cma.c | 11 +
mm/kasan/Makefile | 15 +-
mm/kasan/{kasan.c => common.c} | 656 +++++++++----------------
mm/kasan/generic.c | 344 +++++++++++++
mm/kasan/generic_report.c | 153 ++++++
mm/kasan/{kasan_init.c => init.c} | 71 +--
mm/kasan/kasan.h | 59 ++-
mm/kasan/quarantine.c | 1 +
mm/kasan/report.c | 272 +++-------
mm/kasan/tags.c | 161 ++++++
mm/kasan/tags_report.c | 58 +++
mm/page_alloc.c | 1 +
mm/slab.c | 29 +-
mm/slab.h | 2 +-
mm/slab_common.c | 6 +-
mm/slub.c | 51 +-
scripts/Makefile.kasan | 53 +-
43 files changed, 1817 insertions(+), 999 deletions(-)
rename mm/kasan/{kasan.c => common.c} (59%)
create mode 100644 mm/kasan/generic.c
create mode 100644 mm/kasan/generic_report.c
rename mm/kasan/{kasan_init.c => init.c} (82%)
create mode 100644 mm/kasan/tags.c
create mode 100644 mm/kasan/tags_report.c
--
2.20.0.rc1.387.gf8505762e3-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v13 01/25] kasan, mm: change hooks signatures
From: Andrey Konovalov @ 2018-12-06 12:24 UTC (permalink / raw)
To: Andrey Ryabinin, Alexander Potapenko, Dmitry Vyukov,
Catalin Marinas, Will Deacon, Christoph Lameter, Andrew Morton,
Mark Rutland, Nick Desaulniers, Marc Zyngier, Dave Martin,
Ard Biesheuvel, Eric W . Biederman, Ingo Molnar, Paul Lawrence,
Geert Uytterhoeven, Arnd Bergmann, Kirill A . Shutemov,
Greg Kroah-Hartman, Kate Stewart, Mike Rapoport, kasan-dev,
linux-doc, linux-kernel, linux-arm-kernel, linux-sparse, linux-mm,
linux-kbuild
Cc: Vishwath Mohan, Chintan Pandya, Jacob Bramley, Jann Horn,
Ruben Ayrapetyan, Andrey Konovalov, Lee Smith, Kostya Serebryany,
Mark Brand, Ramana Radhakrishnan, Evgeniy Stepanov
In-Reply-To: <cover.1544099024.git.andreyknvl@google.com>
Tag-based KASAN changes the value of the top byte of pointers returned
from the kernel allocation functions (such as kmalloc). This patch updates
KASAN hooks signatures and their usage in SLAB and SLUB code to reflect
that.
Reviewed-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
include/linux/kasan.h | 43 +++++++++++++++++++++++++++++--------------
include/linux/slab.h | 4 ++--
mm/kasan/kasan.c | 30 ++++++++++++++++++------------
mm/slab.c | 12 ++++++------
mm/slab.h | 2 +-
mm/slab_common.c | 4 ++--
mm/slub.c | 15 +++++++--------
7 files changed, 65 insertions(+), 45 deletions(-)
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index 46aae129917c..52c86a568a4e 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -51,16 +51,16 @@ void kasan_cache_shutdown(struct kmem_cache *cache);
void kasan_poison_slab(struct page *page);
void kasan_unpoison_object_data(struct kmem_cache *cache, void *object);
void kasan_poison_object_data(struct kmem_cache *cache, void *object);
-void kasan_init_slab_obj(struct kmem_cache *cache, const void *object);
+void *kasan_init_slab_obj(struct kmem_cache *cache, const void *object);
-void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags);
+void *kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags);
void kasan_kfree_large(void *ptr, unsigned long ip);
void kasan_poison_kfree(void *ptr, unsigned long ip);
-void kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size,
+void *kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size,
gfp_t flags);
-void kasan_krealloc(const void *object, size_t new_size, gfp_t flags);
+void *kasan_krealloc(const void *object, size_t new_size, gfp_t flags);
-void kasan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags);
+void *kasan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags);
bool kasan_slab_free(struct kmem_cache *s, void *object, unsigned long ip);
struct kasan_cache {
@@ -105,19 +105,34 @@ static inline void kasan_unpoison_object_data(struct kmem_cache *cache,
void *object) {}
static inline void kasan_poison_object_data(struct kmem_cache *cache,
void *object) {}
-static inline void kasan_init_slab_obj(struct kmem_cache *cache,
- const void *object) {}
+static inline void *kasan_init_slab_obj(struct kmem_cache *cache,
+ const void *object)
+{
+ return (void *)object;
+}
-static inline void kasan_kmalloc_large(void *ptr, size_t size, gfp_t flags) {}
+static inline void *kasan_kmalloc_large(void *ptr, size_t size, gfp_t flags)
+{
+ return ptr;
+}
static inline void kasan_kfree_large(void *ptr, unsigned long ip) {}
static inline void kasan_poison_kfree(void *ptr, unsigned long ip) {}
-static inline void kasan_kmalloc(struct kmem_cache *s, const void *object,
- size_t size, gfp_t flags) {}
-static inline void kasan_krealloc(const void *object, size_t new_size,
- gfp_t flags) {}
+static inline void *kasan_kmalloc(struct kmem_cache *s, const void *object,
+ size_t size, gfp_t flags)
+{
+ return (void *)object;
+}
+static inline void *kasan_krealloc(const void *object, size_t new_size,
+ gfp_t flags)
+{
+ return (void *)object;
+}
-static inline void kasan_slab_alloc(struct kmem_cache *s, void *object,
- gfp_t flags) {}
+static inline void *kasan_slab_alloc(struct kmem_cache *s, void *object,
+ gfp_t flags)
+{
+ return object;
+}
static inline bool kasan_slab_free(struct kmem_cache *s, void *object,
unsigned long ip)
{
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 918f374e7156..351ac48dabc4 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -444,7 +444,7 @@ static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s,
{
void *ret = kmem_cache_alloc(s, flags);
- kasan_kmalloc(s, ret, size, flags);
+ ret = kasan_kmalloc(s, ret, size, flags);
return ret;
}
@@ -455,7 +455,7 @@ kmem_cache_alloc_node_trace(struct kmem_cache *s,
{
void *ret = kmem_cache_alloc_node(s, gfpflags, node);
- kasan_kmalloc(s, ret, size, gfpflags);
+ ret = kasan_kmalloc(s, ret, size, gfpflags);
return ret;
}
#endif /* CONFIG_TRACING */
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index c3bd5209da38..55deff17a4d9 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -474,20 +474,22 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache,
return (void *)object + cache->kasan_info.free_meta_offset;
}
-void kasan_init_slab_obj(struct kmem_cache *cache, const void *object)
+void *kasan_init_slab_obj(struct kmem_cache *cache, const void *object)
{
struct kasan_alloc_meta *alloc_info;
if (!(cache->flags & SLAB_KASAN))
- return;
+ return (void *)object;
alloc_info = get_alloc_info(cache, object);
__memset(alloc_info, 0, sizeof(*alloc_info));
+
+ return (void *)object;
}
-void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags)
+void *kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags)
{
- kasan_kmalloc(cache, object, cache->object_size, flags);
+ return kasan_kmalloc(cache, object, cache->object_size, flags);
}
static bool __kasan_slab_free(struct kmem_cache *cache, void *object,
@@ -528,7 +530,7 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip)
return __kasan_slab_free(cache, object, ip, true);
}
-void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
+void *kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
gfp_t flags)
{
unsigned long redzone_start;
@@ -538,7 +540,7 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
quarantine_reduce();
if (unlikely(object == NULL))
- return;
+ return NULL;
redzone_start = round_up((unsigned long)(object + size),
KASAN_SHADOW_SCALE_SIZE);
@@ -551,10 +553,12 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
if (cache->flags & SLAB_KASAN)
set_track(&get_alloc_info(cache, object)->alloc_track, flags);
+
+ return (void *)object;
}
EXPORT_SYMBOL(kasan_kmalloc);
-void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags)
+void *kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags)
{
struct page *page;
unsigned long redzone_start;
@@ -564,7 +568,7 @@ void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags)
quarantine_reduce();
if (unlikely(ptr == NULL))
- return;
+ return NULL;
page = virt_to_page(ptr);
redzone_start = round_up((unsigned long)(ptr + size),
@@ -574,21 +578,23 @@ void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags)
kasan_unpoison_shadow(ptr, size);
kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
KASAN_PAGE_REDZONE);
+
+ return (void *)ptr;
}
-void kasan_krealloc(const void *object, size_t size, gfp_t flags)
+void *kasan_krealloc(const void *object, size_t size, gfp_t flags)
{
struct page *page;
if (unlikely(object == ZERO_SIZE_PTR))
- return;
+ return ZERO_SIZE_PTR;
page = virt_to_head_page(object);
if (unlikely(!PageSlab(page)))
- kasan_kmalloc_large(object, size, flags);
+ return kasan_kmalloc_large(object, size, flags);
else
- kasan_kmalloc(page->slab_cache, object, size, flags);
+ return kasan_kmalloc(page->slab_cache, object, size, flags);
}
void kasan_poison_kfree(void *ptr, unsigned long ip)
diff --git a/mm/slab.c b/mm/slab.c
index 2a5654bb3b3f..26f60a22e5e0 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3551,7 +3551,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
void *ret = slab_alloc(cachep, flags, _RET_IP_);
- kasan_slab_alloc(cachep, ret, flags);
+ ret = kasan_slab_alloc(cachep, ret, flags);
trace_kmem_cache_alloc(_RET_IP_, ret,
cachep->object_size, cachep->size, flags);
@@ -3617,7 +3617,7 @@ kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size)
ret = slab_alloc(cachep, flags, _RET_IP_);
- kasan_kmalloc(cachep, ret, size, flags);
+ ret = kasan_kmalloc(cachep, ret, size, flags);
trace_kmalloc(_RET_IP_, ret,
size, cachep->size, flags);
return ret;
@@ -3641,7 +3641,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
{
void *ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_);
- kasan_slab_alloc(cachep, ret, flags);
+ ret = kasan_slab_alloc(cachep, ret, flags);
trace_kmem_cache_alloc_node(_RET_IP_, ret,
cachep->object_size, cachep->size,
flags, nodeid);
@@ -3660,7 +3660,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_);
- kasan_kmalloc(cachep, ret, size, flags);
+ ret = kasan_kmalloc(cachep, ret, size, flags);
trace_kmalloc_node(_RET_IP_, ret,
size, cachep->size,
flags, nodeid);
@@ -3681,7 +3681,7 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller)
if (unlikely(ZERO_OR_NULL_PTR(cachep)))
return cachep;
ret = kmem_cache_alloc_node_trace(cachep, flags, node, size);
- kasan_kmalloc(cachep, ret, size, flags);
+ ret = kasan_kmalloc(cachep, ret, size, flags);
return ret;
}
@@ -3719,7 +3719,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
return cachep;
ret = slab_alloc(cachep, flags, caller);
- kasan_kmalloc(cachep, ret, size, flags);
+ ret = kasan_kmalloc(cachep, ret, size, flags);
trace_kmalloc(caller, ret,
size, cachep->size, flags);
diff --git a/mm/slab.h b/mm/slab.h
index 58c6c1c2a78e..4190c24ef0e9 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -441,7 +441,7 @@ static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
kmemleak_alloc_recursive(object, s->object_size, 1,
s->flags, flags);
- kasan_slab_alloc(s, object, flags);
+ p[i] = kasan_slab_alloc(s, object, flags);
}
if (memcg_kmem_enabled())
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 7eb8dc136c1c..5f3504e26d4c 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -1204,7 +1204,7 @@ void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
page = alloc_pages(flags, order);
ret = page ? page_address(page) : NULL;
kmemleak_alloc(ret, size, 1, flags);
- kasan_kmalloc_large(ret, size, flags);
+ ret = kasan_kmalloc_large(ret, size, flags);
return ret;
}
EXPORT_SYMBOL(kmalloc_order);
@@ -1482,7 +1482,7 @@ static __always_inline void *__do_krealloc(const void *p, size_t new_size,
ks = ksize(p);
if (ks >= new_size) {
- kasan_krealloc((void *)p, new_size, flags);
+ p = kasan_krealloc((void *)p, new_size, flags);
return (void *)p;
}
diff --git a/mm/slub.c b/mm/slub.c
index e3629cd7aff1..fdd4a86aa882 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1372,10 +1372,10 @@ static inline void dec_slabs_node(struct kmem_cache *s, int node,
* Hooks for other subsystems that check memory allocations. In a typical
* production configuration these hooks all should produce no code at all.
*/
-static inline void kmalloc_large_node_hook(void *ptr, size_t size, gfp_t flags)
+static inline void *kmalloc_large_node_hook(void *ptr, size_t size, gfp_t flags)
{
kmemleak_alloc(ptr, size, 1, flags);
- kasan_kmalloc_large(ptr, size, flags);
+ return kasan_kmalloc_large(ptr, size, flags);
}
static __always_inline void kfree_hook(void *x)
@@ -2768,7 +2768,7 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
{
void *ret = slab_alloc(s, gfpflags, _RET_IP_);
trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);
- kasan_kmalloc(s, ret, size, gfpflags);
+ ret = kasan_kmalloc(s, ret, size, gfpflags);
return ret;
}
EXPORT_SYMBOL(kmem_cache_alloc_trace);
@@ -2796,7 +2796,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
trace_kmalloc_node(_RET_IP_, ret,
size, s->size, gfpflags, node);
- kasan_kmalloc(s, ret, size, gfpflags);
+ ret = kasan_kmalloc(s, ret, size, gfpflags);
return ret;
}
EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
@@ -3784,7 +3784,7 @@ void *__kmalloc(size_t size, gfp_t flags)
trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
- kasan_kmalloc(s, ret, size, flags);
+ ret = kasan_kmalloc(s, ret, size, flags);
return ret;
}
@@ -3801,8 +3801,7 @@ static void *kmalloc_large_node(size_t size, gfp_t flags, int node)
if (page)
ptr = page_address(page);
- kmalloc_large_node_hook(ptr, size, flags);
- return ptr;
+ return kmalloc_large_node_hook(ptr, size, flags);
}
void *__kmalloc_node(size_t size, gfp_t flags, int node)
@@ -3829,7 +3828,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node);
- kasan_kmalloc(s, ret, size, flags);
+ ret = kasan_kmalloc(s, ret, size, flags);
return ret;
}
--
2.20.0.rc1.387.gf8505762e3-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v2 0/3] PCIE support for i.MX8MQ
From: Lorenzo Pieralisi @ 2018-12-06 12:15 UTC (permalink / raw)
To: Andrey Smirnov
Cc: A.s. Dong, Mark Rutland, Richard Zhu, linux-arm-kernel,
Rob Herring, linux-pci, linux-kernel, Fabio Estevam, devicetree,
linux-imx, bhelgaas, Leonard Crestez, cphealy, l.stach
In-Reply-To: <20181206073545.10967-1-andrew.smirnov@gmail.com>
On Wed, Dec 05, 2018 at 11:35:42PM -0800, Andrey Smirnov wrote:
> Everyone:
>
> This series contains changes I made in order to enable support of PCIE
> IP block on i.MX8MQ SoCs (full tree can be found at [github-v2]).
>
> NOTE: The last patch have a Kconfig symbol depenency on [imx8mq-kconfig].
>
> Changes since [v1]:
>
> - Driver changed to use single "fsl,controller-id" property to
> distinguish between two intances of PCIE IP block
>
> - All code pertaining to L1SS was dropped to simplify the patch
>
> - Documented additions to DT bindings
>
> Feedback is welcome!
>
> Thanks,
> Andrey Smirnov
Andrey,
I have applied the patches, I would like to make the CC list in standard
format so I kindly ask you firstname/surname for cphealy@gmail.com, I
could not find it in the maintainers list but I want to keep the CC
list as per patches (I removed the lists, though).
Thanks,
Lorenzo
> [v1] https://lore.kernel.org/linux-arm-kernel/20181117181225.10737-1-andrew.smirnov@gmail.com/
> [github-v2] https://github.com/ndreys/linux/commits/imx8mq-pcie-v2
> [imx8mq-kconfig] https://lore.kernel.org/linux-arm-kernel/20181114175242.12468-1-l.stach@pengutronix.de/
>
> Andrey Smirnov (3):
> PCI: imx: No-op imx6_setup_phy_mpll() on i.MX7D
> PCI: imx: No-op imx6_pcie_reset_phy() on i.MX7D
> PCI: imx: Add support for i.MX8MQ
>
> .../bindings/pci/fsl,imx6q-pcie.txt | 6 +-
> drivers/pci/controller/dwc/Kconfig | 2 +-
> drivers/pci/controller/dwc/pci-imx6.c | 87 ++++++++++++++++++-
> 3 files changed, 90 insertions(+), 5 deletions(-)
>
> --
> 2.19.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v11 1/2] perf, uncore: Adding documentation for ThunderX2 pmu uncore driver
From: Kulkarni, Ganapatrao @ 2018-12-06 11:51 UTC (permalink / raw)
To: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Cc: mark.rutland@arm.com, Nair, Jayachandran, suzuki.poulose@arm.com,
gklkml16@gmail.com, rdunlap@infradead.org, Will.Deacon@arm.com,
Lomovtsev, Vadim, Richter, Robert, Jan Glauber
In-Reply-To: <20181206115053.7665-1-ganapatrao.kulkarni@cavium.com>
The SoC has PMU support in its L3 cache controller (L3C) and in the
DDR4 Memory Controller (DMC).
Signed-off-by: Ganapatrao Kulkarni <ganapatrao.kulkarni@cavium.com>
---
Documentation/perf/thunderx2-pmu.txt | 93 ++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 Documentation/perf/thunderx2-pmu.txt
diff --git a/Documentation/perf/thunderx2-pmu.txt b/Documentation/perf/thunderx2-pmu.txt
new file mode 100644
index 000000000000..6ec37f0e6d2c
--- /dev/null
+++ b/Documentation/perf/thunderx2-pmu.txt
@@ -0,0 +1,93 @@
+
+Cavium ThunderX2 SoC Performance Monitoring Unit (PMU UNCORE)
+==========================================================================
+
+ThunderX2 SoC PMU consists of independent system wide per Socket PMUs, such
+as Level 3 Cache(L3C) and DDR4 Memory Controller(DMC).
+
+The DMC has 8 interleaved channels and the L3C has 16 interleaved tiles. Events
+are counted for the default channel(i.e channel 0) and prorated to total number of
+channels/tiles.
+
+DMC and L3C support up to 4 counters. Counters are independently programmable
+and can be started and stopped individually. Each counter can be set to
+a different event. Counters are 32 bit and do not support overflow interrupt;
+they are read every 2 seconds.
+
+PMU UNCORE (perf) driver:
+
+The thunderx2_pmu driver registers per socket perf PMUs for DMC and L3C devices.
+Each PMU can be used to count up to 4 events simultaneously. PMUs provide
+description of its available events and configuration options
+in sysfs, see /sys/devices/uncore_<l3c_S/dmc_S/>; S is the socket id.
+
+The driver does not support sampling, therefore "perf record" will
+not work. Per-task perf sessions are not supported.
+
+Examples:
+
+perf stat -a -e uncore_dmc_0/cnt_cycles/ sleep 1
+
+perf stat -a -e \
+uncore_dmc_0/cnt_cycles/,\
+uncore_dmc_0/data_transfers/,\
+uncore_dmc_0/read_txns/,\
+uncore_dmc_0/write_txns/ sleep 1
+
+perf stat -a -e \
+uncore_l3c_0/read_request/,\
+uncore_l3c_0/read_hit/,\
+uncore_l3c_0/inv_request/,\
+uncore_l3c_0/inv_hit/ sleep 1
+
+
+L3C events:
+============
+
+read_request:
+ Number of Read requests received by the L3 Cache.
+ This includes Read as well as Read Exclusives.
+
+read_hit:
+ Number of Read requests received by the L3 cache that were hit
+ in the L3 (Data provided form the L3)
+
+writeback_request:
+ Number of Write Backs received by the L3 Cache. These are basically
+ the L2 Evicts and writes from the PCIe Write Cache.
+
+inv_nwrite_request:
+ Number of Invalidate and Write requests received by the L3 Cache.
+ Also Writes from IO that did not go through the PCIe Write Cache.
+
+inv_nwrite_hit
+ Number of Invalidate and Write requests received by the L3 Cache
+ that were a hit in the L3 Cache.
+
+inv_request:
+ Number of Invalidate requests received by the L3 Cache.
+
+inv_hit:
+ Number of Invalidate requests received by the L3 Cache that were a
+ hit in the L3 Cache.
+
+evict_request:
+ Number of Evicts that the L3 cache generated.
+
+NOTE:
+1. Granularity of all these event counter values are cache line length(64 bytes)
+2. L3C cache Hit Ratio = (read_hit + inv_nwrite_hit + inv_hit) / (read_request + inv_nwrite_request + inv_request)
+
+DMC events:
+============
+cnt_cycles:
+ Count cycles (Clocks at the DMC clock rate)
+
+write_txns:
+ Number of 64 Bytes write transactions received by the DMC(s)
+
+read_txns:
+ Number of 64 Bytes Read transactions received by the DMC(s)
+
+data_transfers:
+ Number of 64 Bytes data transferred to or from DRAM.
--
2.18.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v11 0/2] Add ThunderX2 SoC Performance Monitoring Unit driver
From: Kulkarni, Ganapatrao @ 2018-12-06 11:51 UTC (permalink / raw)
To: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Cc: mark.rutland@arm.com, Nair, Jayachandran, suzuki.poulose@arm.com,
gklkml16@gmail.com, rdunlap@infradead.org, Will.Deacon@arm.com,
Lomovtsev, Vadim, Richter, Robert, Jan Glauber
This patchset adds PMU driver for Cavium's ThunderX2 SoC UNCORE devices.
The SoC has PMU support in L3 cache controller (L3C) and in the
DDR4 Memory Controller (DMC).
v11:
Updated Patch 2 with minor comments.
v10:
Updated Documentation patch with comments [6].
[6] https://lkml.org/lkml/2018/12/5/649
v9:
Updated with comments [5].
[5] https://lkml.org/lkml/2018/11/22/517
v8:
Updated with comments [4].
[4] https://lkml.org/lkml/2018/10/25/215
v7:
Incorporated review comments [3].
Modified driver as loadable module.
Updated Documentation with Event description.
Removed per-channel(no SMC calls) sampling implementation(
Since DMC and L3C channels are interleave, we have decided to
sample channel zero and prorate it to account for a Device).
[3] https://patchwork.kernel.org/patch/10479203/
v6:
Rebased to 4.18-rc1
Updated with comments from John Garry[3]
[3] https://lkml.org/lkml/2018/5/17/408
v5:
Incorporated review comments from Mark Rutland[2]
v4:
Incorporated review comments from Mark Rutland[1]
[1] https://www.spinics.net/lists/arm-kernel/msg588563.html
[2] https://lkml.org/lkml/2018/4/26/376
v3:
Fixed warning reported by kbuild robot
v2:
Rebased to 4.12-rc1
Removed Arch VULCAN dependency.
Update SMC call parameters as per latest firmware.
v1:
Initial patch
Ganapatrao Kulkarni (2):
perf, uncore: Adding documentation for ThunderX2 pmu uncore driver
ThunderX2, perf : Add Cavium ThunderX2 SoC UNCORE PMU driver
Documentation/perf/thunderx2-pmu.txt | 93 +++
drivers/perf/Kconfig | 9 +
drivers/perf/Makefile | 1 +
drivers/perf/thunderx2_pmu.c | 861 +++++++++++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
5 files changed, 965 insertions(+)
create mode 100644 Documentation/perf/thunderx2-pmu.txt
create mode 100644 drivers/perf/thunderx2_pmu.c
--
2.18.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v7 2/2] PCI: amlogic: Add the Amlogic Meson PCIe controller driver
From: Hanjie Lin @ 2018-12-06 12:02 UTC (permalink / raw)
To: Lorenzo Pieralisi, Bjorn Helgaas
Cc: Yixun Lan, Rob Herring, Hanjie Lin, Jianxin Pan, Kevin Hilman,
Shawn Lin, Philippe Ombredanne, linux-pci, linux-kernel, Yue Wang,
Qiufang Dai, Jian Hu, Liang Yang, Cyrille Pitchen,
Gustavo Pimentel, Carlo Caione, linux-amlogic, linux-arm-kernel,
Jerome Brunet
In-Reply-To: <1544097760-85834-1-git-send-email-hanjie.lin@amlogic.com>
From: Yue Wang <yue.wang@amlogic.com>
The Amlogic Meson PCIe host controller is based on the Synopsys DesignWare
PCI core. This patch adds the driver support for Meson PCIe controller.
Signed-off-by: Yue Wang <yue.wang@amlogic.com>
Signed-off-by: Hanjie Lin <hanjie.lin@amlogic.com>
---
MAINTAINERS | 7 +
drivers/pci/controller/dwc/Kconfig | 10 +
drivers/pci/controller/dwc/Makefile | 1 +
drivers/pci/controller/dwc/pci-meson.c | 603 +++++++++++++++++++++++++++++++++
4 files changed, 621 insertions(+)
create mode 100644 drivers/pci/controller/dwc/pci-meson.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 7fe120f..21ed916 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11600,6 +11600,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
S: Supported
F: drivers/pci/controller/
+PCIE DRIVER FOR AMLOGIC MESON
+M: Yue Wang <yue.wang@Amlogic.com>
+L: linux-pci@vger.kernel.org
+L: linux-amlogic@lists.infradead.org
+S: Maintained
+F: drivers/pci/controller/dwc/pci-meson.c
+
PCIE DRIVER FOR AXIS ARTPEC
M: Jesper Nilsson <jesper.nilsson@axis.com>
L: linux-arm-kernel@axis.com
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 91b0194..7800322 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -193,4 +193,14 @@ config PCIE_HISI_STB
help
Say Y here if you want PCIe controller support on HiSilicon STB SoCs
+config PCI_MESON
+ bool "MESON PCIe controller"
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_DW_HOST
+ help
+ Say Y here if you want to enable PCI controller support on Amlogic
+ SoCs. The PCI controller on Amlogic is based on DesignWare hardware
+ and therefore the driver re-uses the DesignWare core functions to
+ implement the driver.
+
endmenu
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index fcf91ea..e05a015 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
+obj-$(CONFIG_PCI_MESON) += pci-meson.o
# The following drivers are for devices that use the generic ACPI
# pci_root.c driver but don't support standard ECAM config access.
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
new file mode 100644
index 0000000..428ed42
--- /dev/null
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -0,0 +1,603 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for Amlogic MESON SoCs
+ *
+ * Copyright (c) 2018 Amlogic, inc.
+ * Author: Yue Wang <yue.wang@amlogic.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+#include <linux/reset.h>
+
+#include "pcie-designware.h"
+
+#define to_meson_pcie(x) dev_get_drvdata((x)->dev)
+
+/* External local bus interface registers */
+#define PLR_OFFSET 0x700
+#define PCIE_PORT_LINK_CTRL_OFF (PLR_OFFSET + 0x10)
+#define FAST_LINK_MODE BIT(7)
+#define LINK_CAPABLE_MASK GENMASK(21, 16)
+#define LINK_CAPABLE_X1 BIT(16)
+
+#define PCIE_GEN2_CTRL_OFF (PLR_OFFSET + 0x10c)
+#define NUM_OF_LANES_MASK GENMASK(12, 8)
+#define NUM_OF_LANES_X1 BIT(8)
+#define DIRECT_SPEED_CHANGE BIT(17)
+
+#define TYPE1_HDR_OFFSET 0x0
+#define PCIE_STATUS_COMMAND (TYPE1_HDR_OFFSET + 0x04)
+#define PCI_IO_EN BIT(0)
+#define PCI_MEM_SPACE_EN BIT(1)
+#define PCI_BUS_MASTER_EN BIT(2)
+
+#define PCIE_BASE_ADDR0 (TYPE1_HDR_OFFSET + 0x10)
+#define PCIE_BASE_ADDR1 (TYPE1_HDR_OFFSET + 0x14)
+
+#define PCIE_CAP_OFFSET 0x70
+#define PCIE_DEV_CTRL_DEV_STUS (PCIE_CAP_OFFSET + 0x08)
+#define PCIE_CAP_MAX_PAYLOAD_MASK GENMASK(7, 5)
+#define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5)
+#define PCIE_CAP_MAX_READ_REQ_MASK GENMASK(14, 12)
+#define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12)
+
+#define PCI_CLASS_REVISION_MASK GENMASK(7, 0)
+
+/* PCIe specific config registers */
+#define PCIE_CFG0 0x0
+#define APP_LTSSM_ENABLE BIT(7)
+
+#define PCIE_CFG_STATUS12 0x30
+#define IS_SMLH_LINK_UP(x) ((x) & (1 << 6))
+#define IS_RDLH_LINK_UP(x) ((x) & (1 << 16))
+#define IS_LTSSM_UP(x) ((((x) >> 10) & 0x1f) == 0x11)
+
+#define PCIE_CFG_STATUS17 0x44
+#define PM_CURRENT_STATE(x) (((x) >> 7) & 0x1)
+
+#define WAIT_LINKUP_TIMEOUT 2000
+#define PORT_CLK_RATE 100000000UL
+#define MAX_PAYLOAD_SIZE 256
+#define MAX_READ_REQ_SIZE 256
+#define MESON_PCIE_PHY_POWERUP 0x1c
+#define PCIE_RESET_DELAY 500
+#define PCIE_SHARED_RESET 1
+#define PCIE_NORMAL_RESET 0
+
+enum pcie_data_rate {
+ PCIE_GEN1,
+ PCIE_GEN2,
+ PCIE_GEN3,
+ PCIE_GEN4
+};
+
+struct meson_pcie_mem_res {
+ void __iomem *elbi_base;
+ void __iomem *cfg_base;
+ void __iomem *phy_base;
+};
+
+struct meson_pcie_clk_res {
+ struct clk *clk;
+ struct clk *mipi_gate;
+ struct clk *port_clk;
+ struct clk *general_clk;
+};
+
+struct meson_pcie_rc_reset {
+ struct reset_control *phy;
+ struct reset_control *port;
+ struct reset_control *apb;
+};
+
+struct meson_pcie {
+ struct dw_pcie pci;
+ struct meson_pcie_mem_res mem_res;
+ struct meson_pcie_clk_res clk_res;
+ struct meson_pcie_rc_reset mrst;
+ struct gpio_desc *reset_gpio;
+
+ enum of_gpio_flags gpio_flag;
+ int pcie_num;
+ u32 port_num;
+};
+
+static struct reset_control *meson_pcie_get_reset(struct meson_pcie *mp,
+ const char *id,
+ u32 reset_type)
+{
+ struct device *dev = mp->pci.dev;
+ struct reset_control *reset;
+
+ if (reset_type == PCIE_SHARED_RESET)
+ reset = devm_reset_control_get_shared(dev, id);
+ else
+ reset = devm_reset_control_get(dev, id);
+
+ return reset;
+}
+
+static int meson_pcie_get_resets(struct meson_pcie *mp)
+{
+ struct meson_pcie_rc_reset *mrst = &mp->mrst;
+
+ mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET);
+ if (IS_ERR(mrst->phy))
+ return PTR_ERR(mrst->phy);
+ reset_control_deassert(mrst->phy);
+
+ mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET);
+ if (IS_ERR(mrst->port))
+ return PTR_ERR(mrst->port);
+ reset_control_deassert(mrst->port);
+
+ mrst->apb = meson_pcie_get_reset(mp, "apb", PCIE_SHARED_RESET);
+ if (IS_ERR(mrst->apb))
+ return PTR_ERR(mrst->apb);
+ reset_control_deassert(mrst->apb);
+
+ return 0;
+}
+
+static void __iomem *meson_pcie_get_mem(struct platform_device *pdev,
+ struct meson_pcie *mp,
+ const char *id)
+{
+ struct device *dev = mp->pci.dev;
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
+
+ return devm_ioremap_resource(dev, res);
+}
+
+static void __iomem *meson_pcie_get_mem_shared(struct platform_device *pdev,
+ struct meson_pcie *mp,
+ const char *id)
+{
+ struct device *dev = mp->pci.dev;
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
+ if (!res) {
+ dev_err(dev, "No REG resource %s\n", id);
+ return ERR_PTR(-ENXIO);
+ }
+
+ return devm_ioremap(dev, res->start, resource_size(res));
+}
+
+static int meson_pcie_get_mems(struct platform_device *pdev,
+ struct meson_pcie *mp)
+{
+ mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi");
+ if (IS_ERR(mp->mem_res.elbi_base))
+ return PTR_ERR(mp->mem_res.elbi_base);
+
+ mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg");
+ if (IS_ERR(mp->mem_res.cfg_base))
+ return PTR_ERR(mp->mem_res.cfg_base);
+
+ /* Meson SoC has two PCI controllers use same phy register*/
+ mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy");
+ if (IS_ERR(mp->mem_res.phy_base))
+ return PTR_ERR(mp->mem_res.phy_base);
+
+ return 0;
+}
+
+static void meson_pcie_power_on(struct meson_pcie *mp)
+{
+ writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base);
+}
+
+static void meson_pcie_reset(struct meson_pcie *mp)
+{
+ struct meson_pcie_rc_reset *mrst = &mp->mrst;
+
+ reset_control_assert(mrst->phy);
+ udelay(PCIE_RESET_DELAY);
+ reset_control_deassert(mrst->phy);
+ udelay(PCIE_RESET_DELAY);
+
+ reset_control_assert(mrst->port);
+ reset_control_assert(mrst->apb);
+ udelay(PCIE_RESET_DELAY);
+ reset_control_deassert(mrst->port);
+ reset_control_deassert(mrst->apb);
+ udelay(PCIE_RESET_DELAY);
+}
+
+static inline struct clk *meson_pcie_probe_clock(struct device *dev,
+ const char *id, u64 rate)
+{
+ struct clk *clk;
+ int ret;
+
+ clk = devm_clk_get(dev, id);
+ if (IS_ERR(clk))
+ return clk;
+
+ if (rate) {
+ ret = clk_set_rate(clk, rate);
+ if (ret) {
+ dev_err(dev, "set clk rate failed, ret = %d\n", ret);
+ return ERR_PTR(ret);
+ }
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(dev, "couldn't enable clk\n");
+ return ERR_PTR(ret);
+ }
+
+ devm_add_action_or_reset(dev,
+ (void (*) (void *))clk_disable_unprepare,
+ clk);
+
+ return clk;
+}
+
+static int meson_pcie_probe_clocks(struct meson_pcie *mp)
+{
+ struct device *dev = mp->pci.dev;
+ struct meson_pcie_clk_res *res = &mp->clk_res;
+
+ res->port_clk = meson_pcie_probe_clock(dev, "port", PORT_CLK_RATE);
+ if (IS_ERR(res->port_clk))
+ return PTR_ERR(res->port_clk);
+
+ res->mipi_gate = meson_pcie_probe_clock(dev, "pcie_mipi_en", 0);
+ if (IS_ERR(res->mipi_gate))
+ return PTR_ERR(res->mipi_gate);
+
+ res->general_clk = meson_pcie_probe_clock(dev, "pcie_general", 0);
+ if (IS_ERR(res->general_clk))
+ return PTR_ERR(res->general_clk);
+
+ res->clk = meson_pcie_probe_clock(dev, "pcie", 0);
+ if (IS_ERR(res->clk))
+ return PTR_ERR(res->clk);
+
+ return 0;
+}
+
+static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
+{
+ writel(val, mp->mem_res.elbi_base + reg);
+}
+
+static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg)
+{
+ return readl(mp->mem_res.elbi_base + reg);
+}
+
+static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg)
+{
+ return readl(mp->mem_res.cfg_base + reg);
+}
+
+static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
+{
+ writel(val, mp->mem_res.cfg_base + reg);
+}
+
+static void meson_pcie_assert_reset(struct meson_pcie *mp)
+{
+ gpiod_set_value_cansleep(mp->reset_gpio, 0);
+ udelay(500);
+ gpiod_set_value_cansleep(mp->reset_gpio, 1);
+}
+
+static void meson_pcie_init_dw(struct meson_pcie *mp)
+{
+ u32 val;
+
+ val = meson_cfg_readl(mp, PCIE_CFG0);
+ val |= APP_LTSSM_ENABLE;
+ meson_cfg_writel(mp, val, PCIE_CFG0);
+
+ val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
+ val &= ~LINK_CAPABLE_MASK;
+ meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
+
+ val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
+ val |= LINK_CAPABLE_X1 | FAST_LINK_MODE;
+ meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
+
+ val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
+ val &= ~NUM_OF_LANES_MASK;
+ meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
+
+ val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
+ val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE;
+ meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
+
+ meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0);
+ meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1);
+}
+
+static int meson_size_to_payload(struct meson_pcie *mp, int size)
+{
+ struct device *dev = mp->pci.dev;
+
+ /*
+ * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
+ * So if input size is not 2^order alignment or less than 2^7 or bigger
+ * than 2^12, just set to default size 2^(1+7).
+ */
+ if (!is_power_of_2(size) || size < 128 || size > 4096) {
+ dev_warn(dev, "playload size %d, set to default 256\n", size);
+ return 1;
+ }
+
+ return fls(size) - 8;
+}
+
+static void meson_set_max_payload(struct meson_pcie *mp, int size)
+{
+ u32 val = 0;
+ int max_payload_size = meson_size_to_payload(mp, size);
+
+ val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+ val &= ~PCIE_CAP_MAX_PAYLOAD_MASK;
+ meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+
+ val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+ val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
+ meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+}
+
+static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
+{
+ u32 val;
+ int max_rd_req_size = meson_size_to_payload(mp, size);
+
+ val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+ val &= ~PCIE_CAP_MAX_READ_REQ_MASK;
+ meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+
+ val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
+ val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
+ meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
+}
+
+static inline void meson_enable_memory_space(struct meson_pcie *mp)
+{
+ /* Set the RC Bus Master, Memory Space and I/O Space enables */
+ meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN,
+ PCIE_STATUS_COMMAND);
+}
+
+static int meson_pcie_establish_link(struct meson_pcie *mp)
+{
+ struct dw_pcie *pci = &mp->pci;
+ struct pcie_port *pp = &pci->pp;
+
+ meson_pcie_init_dw(mp);
+ meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
+ meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
+
+ dw_pcie_setup_rc(pp);
+ meson_enable_memory_space(mp);
+
+ meson_pcie_assert_reset(mp);
+
+ return dw_pcie_wait_for_link(pci);
+}
+
+static void meson_pcie_enable_interrupts(struct meson_pcie *mp)
+{
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ dw_pcie_msi_init(&mp->pci.pp);
+}
+
+static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+ u32 *val)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ int ret;
+
+ ret = dw_pcie_read(pci->dbi_base + where, size, val);
+ if (ret != PCIBIOS_SUCCESSFUL)
+ return ret;
+
+ /*
+ * There is a bug in the MESON AXG pcie controller whereby software
+ * cannot programme the PCI_CLASS_DEVICE register, so we must fabricate
+ * the return value in the config accessors.
+ */
+ if (where == PCI_CLASS_REVISION && size == 4)
+ *val = (PCI_CLASS_BRIDGE_PCI << 16) | (*val & 0xffff);
+ else if (where == PCI_CLASS_DEVICE && size == 2)
+ *val = PCI_CLASS_BRIDGE_PCI;
+ else if (where == PCI_CLASS_DEVICE && size == 1)
+ *val = PCI_CLASS_BRIDGE_PCI & 0xff;
+ else if (where == PCI_CLASS_DEVICE + 1 && size == 1)
+ *val = (PCI_CLASS_BRIDGE_PCI >> 8) & 0xff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where,
+ int size, u32 val)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+ return dw_pcie_write(pci->dbi_base + where, size, val);
+}
+
+static int meson_pcie_link_up(struct dw_pcie *pci)
+{
+ struct meson_pcie *mp = to_meson_pcie(pci);
+ struct device *dev = pci->dev;
+ u32 smlh_up = 0;
+ u32 ltssm_up = 0;
+ u32 rdlh_up = 0;
+ u32 speed_okay = 0;
+ u32 cnt = 0;
+ u32 state12, state17;
+
+ while (smlh_up == 0 || rdlh_up == 0 || ltssm_up == 0 ||
+ speed_okay == 0) {
+ udelay(20);
+
+ state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12);
+ state17 = meson_cfg_readl(mp, PCIE_CFG_STATUS17);
+ smlh_up = IS_SMLH_LINK_UP(state12);
+ rdlh_up = IS_RDLH_LINK_UP(state12);
+ ltssm_up = IS_LTSSM_UP(state12);
+
+ if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
+ speed_okay = 1;
+
+ if (smlh_up)
+ dev_dbg(dev, "smlh_link_up is on\n");
+ if (rdlh_up)
+ dev_dbg(dev, "rdlh_link_up is on\n");
+ if (ltssm_up)
+ dev_dbg(dev, "ltssm_up is on\n");
+ if (speed_okay)
+ dev_dbg(dev, "speed_okay\n");
+
+ cnt++;
+
+ if (cnt >= WAIT_LINKUP_TIMEOUT) {
+ dev_err(dev, "Error: Wait linkup timeout.\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int meson_pcie_host_init(struct pcie_port *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct meson_pcie *mp = to_meson_pcie(pci);
+ int ret;
+
+ ret = meson_pcie_establish_link(mp);
+ if (ret)
+ return ret;
+
+ meson_pcie_enable_interrupts(mp);
+
+ return 0;
+}
+
+static const struct dw_pcie_host_ops meson_pcie_host_ops = {
+ .rd_own_conf = meson_pcie_rd_own_conf,
+ .wr_own_conf = meson_pcie_wr_own_conf,
+ .host_init = meson_pcie_host_init,
+};
+
+static int meson_add_pcie_port(struct meson_pcie *mp,
+ struct platform_device *pdev)
+{
+ struct dw_pcie *pci = &mp->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ pp->msi_irq = platform_get_irq(pdev, 0);
+ if (pp->msi_irq < 0) {
+ dev_err(dev, "failed to get msi irq\n");
+ return pp->msi_irq;
+ }
+ }
+
+ pp->ops = &meson_pcie_host_ops;
+ pci->dbi_base = mp->mem_res.elbi_base;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(dev, "failed to initialize host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+ .link_up = meson_pcie_link_up,
+};
+
+static int meson_pcie_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct dw_pcie *pci;
+ struct meson_pcie *mp;
+ int ret;
+
+ mp = devm_kzalloc(dev, sizeof(*mp), GFP_KERNEL);
+ if (!mp)
+ return -ENOMEM;
+
+ pci = &mp->pci;
+ pci->dev = dev;
+ pci->ops = &dw_pcie_ops;
+
+ mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(mp->reset_gpio)) {
+ dev_err(dev, "Get reset gpio failed\n");
+ return PTR_ERR(mp->reset_gpio);
+ }
+
+ ret = meson_pcie_get_resets(mp);
+ if (ret) {
+ dev_err(dev, "Get reset resource failed, %d\n", ret);
+ return ret;
+ }
+
+ ret = meson_pcie_get_mems(pdev, mp);
+ if (ret) {
+ dev_err(dev, "Get memory resource failed, %d\n", ret);
+ return ret;
+ }
+
+ meson_pcie_power_on(mp);
+ meson_pcie_reset(mp);
+
+ ret = meson_pcie_probe_clocks(mp);
+ if (ret) {
+ dev_err(dev, "Init clock resources failed, %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, mp);
+
+ ret = meson_add_pcie_port(mp, pdev);
+ if (ret < 0) {
+ dev_err(dev, "Add PCIE port failed, %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id meson_pcie_of_match[] = {
+ {
+ .compatible = "amlogic,axg-pcie",
+ },
+ {},
+};
+
+static struct platform_driver meson_pcie_driver = {
+ .probe = meson_pcie_probe,
+ .driver = {
+ .name = "meson-pcie",
+ .of_match_table = meson_pcie_of_match,
+ },
+};
+
+builtin_platform_driver(meson_pcie_driver);
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v7 1/2] dt-bindings: PCI: meson: add DT bindings for Amlogic Meson PCIe controller
From: Hanjie Lin @ 2018-12-06 12:02 UTC (permalink / raw)
To: Lorenzo Pieralisi, Bjorn Helgaas
Cc: Yixun Lan, Rob Herring, Hanjie Lin, Jianxin Pan, devicetree,
Kevin Hilman, Shawn Lin, Philippe Ombredanne, linux-pci,
linux-kernel, Yue Wang, Qiufang Dai, Jian Hu, Liang Yang,
Cyrille Pitchen, Gustavo Pimentel, Carlo Caione, linux-amlogic,
linux-arm-kernel, Jerome Brunet
In-Reply-To: <1544097760-85834-1-git-send-email-hanjie.lin@amlogic.com>
From: Yue Wang <yue.wang@amlogic.com>
The Amlogic Meson PCIe host controller is based on the Synopsys DesignWare
PCI core. This patch adds documentation for the DT bindings in Meson PCIe
controller.
Signed-off-by: Yue Wang <yue.wang@amlogic.com>
Signed-off-by: Hanjie Lin <hanjie.lin@amlogic.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/pci/amlogic,meson-pcie.txt | 70 ++++++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt
diff --git a/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt b/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt
new file mode 100644
index 0000000..12b18f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt
@@ -0,0 +1,70 @@
+Amlogic Meson AXG DWC PCIE SoC controller
+
+Amlogic Meson PCIe host controller is based on the Synopsys DesignWare PCI core.
+It shares common functions with the PCIe DesignWare core driver and
+inherits common properties defined in
+Documentation/devicetree/bindings/pci/designware-pci.txt.
+
+Additional properties are described here:
+
+Required properties:
+- compatible:
+ should contain "amlogic,axg-pcie" to identify the core.
+- reg:
+ should contain the configuration address space.
+- reg-names: Must be
+ - "elbi" External local bus interface registers
+ - "cfg" Meson specific registers
+ - "phy" Meson PCIE PHY registers
+ - "config" PCIe configuration space
+- reset-gpios: The GPIO to generate PCIe PERST# assert and deassert signal.
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Must include the following entries:
+ - "pclk" PCIe GEN 100M PLL clock
+ - "port" PCIe_x(A or B) RC clock gate
+ - "general" PCIe Phy clock
+ - "mipi" PCIe_x(A or B) 100M ref clock gate
+- resets: phandle to the reset lines.
+- reset-names: must contain "phy" "port" and "apb"
+ - "phy" Share PHY reset
+ - "port" Port A or B reset
+ - "apb" Share APB reset
+- device_type:
+ should be "pci". As specified in designware-pcie.txt
+
+
+Example configuration:
+
+ pcie: pcie@f9800000 {
+ compatible = "amlogic,axg-pcie", "snps,dw-pcie";
+ reg = <0x0 0xf9800000 0x0 0x400000
+ 0x0 0xff646000 0x0 0x2000
+ 0x0 0xff644000 0x0 0x2000
+ 0x0 0xf9f00000 0x0 0x100000>;
+ reg-names = "elbi", "cfg", "phy", "config";
+ reset-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>;
+ interrupts = <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 179 IRQ_TYPE_EDGE_RISING>;
+ bus-range = <0x0 0xff>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x82000000 0 0 0x0 0xf9c00000 0 0x00300000>;
+
+ clocks = <&clkc CLKID_USB
+ &clkc CLKID_MIPI_ENABLE
+ &clkc CLKID_PCIE_A
+ &clkc CLKID_PCIE_CML_EN0>;
+ clock-names = "general",
+ "mipi",
+ "pclk",
+ "port";
+ resets = <&reset RESET_PCIE_PHY>,
+ <&reset RESET_PCIE_A>,
+ <&reset RESET_PCIE_APB>;
+ reset-names = "phy",
+ "port",
+ "apb";
+ };
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v7 0/2] add the Amlogic Meson PCIe controller driver
From: Hanjie Lin @ 2018-12-06 12:02 UTC (permalink / raw)
To: Lorenzo Pieralisi, Bjorn Helgaas
Cc: Yixun Lan, Rob Herring, Hanjie Lin, Jianxin Pan, devicetree,
Kevin Hilman, Shawn Lin, Philippe Ombredanne, linux-pci,
linux-kernel, Qiufang Dai, Jian Hu, Liang Yang, Cyrille Pitchen,
Gustavo Pimentel, Carlo Caione, linux-amlogic, linux-arm-kernel,
Jerome Brunet
The Amlogic Meson PCIe host controller is based on the Synopsys DesignWare
PCI core. This patchset add the driver and dt-bindings of the controller.
Changes since v6: [5]
- fix bad usage of ERR_PTR(ENXIO)
- fix meson_pcie_rd_own_conf() when read PCI_CLASS_DEVICE reg
Changes since v5: [4]
- update MAINTAINER file in alphabetical order
- remove meaningless comment
- use ERR_PTR function instead of (void *) cast
- use is_power_of_2(size) instead of size & (size - 1)
- add comment for PCI_CLASS_REVISION register operation
Changes since v4: [3]
- fix kbuild test robot and compile warnings
Changes since v3: [2]
- modify subject format
- update Kconfig
- update MAINTAINER file
- add comment and error handle for meson_pcie_get_mem_shared()
- drop useless initialization code
- add comment for meson_size_to_payload()
- optimize meson_pcie_establish_link() return code
- optimize meson_pcie_enable_interrupts() redundant function
- drop device_attch related code
- drop dw_pcie_ops read_dbi and write_dbi function
- add error handle for meson_add_pcie_port() when probe
Changes since v2: [1]
- abandon phy driver, move reset to the controller
- use devm_add_action_or_reset() to use clock res
- format correcting
Changes since v1: [0]
- use gpio lib instead open code
- move 'apb' and 'port' reset from phy driver
- format correcting
[0] : https://lkml.kernel.org/r/1534227522-186798-1-git-send-email-hanjie.lin@amlogic.com
[1] : https://lkml.kernel.org/r/1535096165-45827-1-git-send-email-hanjie.lin@amlogic.com
[2] : https://lkml.kernel.org/r/1537509820-52040-1-git-send-email-hanjie.lin@amlogic.com
[3] : https://lkml.kernel.org/r/1538999834-156423-3-git-send-email-hanjie.lin@amlogic.com
[4] : https://lkml.kernel.org/r/1539049990-30810-1-git-send-email-hanjie.lin@amlogic.com
[5] : https://lkml.kernel.org/r/1542876836-191355-1-git-send-email-hanjie.lin@amlogic.com
Yue Wang (2):
dt-bindings: PCI: meson: add DT bindings for Amlogic Meson PCIe
controller
PCI: amlogic: Add the Amlogic Meson PCIe controller driver
.../devicetree/bindings/pci/amlogic,meson-pcie.txt | 70 +++
MAINTAINERS | 7 +
drivers/pci/controller/dwc/Kconfig | 10 +
drivers/pci/controller/dwc/Makefile | 1 +
drivers/pci/controller/dwc/pci-meson.c | 603 +++++++++++++++++++++
5 files changed, 691 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/amlogic,meson-pcie.txt
create mode 100644 drivers/pci/controller/dwc/pci-meson.c
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] arm64/mm: use correct operators for string comparison in cache.S
From: Dave Martin @ 2018-12-06 12:02 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Catalin Marinas, Will Deacon, Robin Murphy, linux-arm-kernel
In-Reply-To: <CAKv+Gu9oQbJHXThZYWue_Mko-CtfT2dcqXozTxs5TXy_UfaYRA@mail.gmail.com>
On Thu, Dec 06, 2018 at 12:47:16PM +0100, Ard Biesheuvel wrote:
> On Thu, 6 Dec 2018 at 12:20, Dave Martin <Dave.Martin@arm.com> wrote:
> >
> > On Mon, Dec 03, 2018 at 05:45:06PM +0000, Will Deacon wrote:
> > > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
[...]
> > > That looks better to me, although I'm not sure why you're inverted the logic
> > > here:
> > >
> > > > .ifnc \op, civac
> > > > .ifnc \op, cvap
> > >
> > > What am I missing?
> >
> > I vote for the .ifc approach.
> >
> > Note, the current works-by-accident approach using == has the odd side-
> > effect of spitting out undefined symbol references in the .o file. It
> > seems that isn't breaking the link, but I wonder whether there are any
> > side-effects we're not aware of.
> >
>
> Did you read the commit log at all? :-)
Due to a combination of a mutt snafu and laziness, no. (However did you
guess? ;)
> > If we don't like the inverted logic, there is always
> >
> > .set .L__foo_\@, 0
> > .ifc \op, civac
> > .set .L__foo_\@, 1
> > .endif
> > .ifc \op, cvap
> > .set .L__foo_\@, 1
> > .endif
> >
> > .if .L__foo_\@
> > // ...
> > .endif
> >
> > which is ugly. Either way, the logic could be wrapped as a helper:
> >
> > .macro if_string_is_either str, cmp1, cmp2, insn:vararg
> > .ifnc "\str","\cmp1"
> > .ifnc "\str","\cmp2"
> > .exitm
> > .endif
> > .endif
> >
> > \insn
> > .endm
> >
>
> Yeah, I don't think this is an improvement over using inverted logic.
As a single instance, no. But if this issue comes up in multiple places
it could be worth wrapping it up.
Cheers
---Dave
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v9 2/2] ThunderX2, perf : Add Cavium ThunderX2 SoC UNCORE PMU driver
From: Ganapatrao Kulkarni @ 2018-12-06 12:00 UTC (permalink / raw)
To: suzuki.poulose
Cc: Mark Rutland, Nair, Jayachandran, linux-doc, Randy Dunlap,
Will Deacon, LKML, Robert Richter, Vadim.Lomovtsev,
Ganapatrao Kulkarni, Jan.Glauber, linux-arm-kernel
In-Reply-To: <866da1c3-6901-8aed-26ef-9a1bfc06cadd@arm.com>
On Thu, Dec 6, 2018 at 2:55 PM Suzuki K Poulose <suzuki.poulose@arm.com> wrote:
>
> Hi Ganpat,
>
> On 05/12/2018 10:59, Kulkarni, Ganapatrao wrote:
> > This patch adds a perf driver for the PMU UNCORE devices DDR4 Memory
> > Controller(DMC) and Level 3 Cache(L3C). Each PMU supports up to 4
> > counters. All counters lack overflow interrupt and are
> > sampled periodically.
> >
> > Signed-off-by: Ganapatrao Kulkarni <ganapatrao.kulkarni@cavium.com>
> > ---
> > drivers/perf/Kconfig | 9 +
> > drivers/perf/Makefile | 1 +
> > drivers/perf/thunderx2_pmu.c | 861 +++++++++++++++++++++++++++++++++++
> > include/linux/cpuhotplug.h | 1 +
> > 4 files changed, 872 insertions(+)
> > create mode 100644 drivers/perf/thunderx2_pmu.c
>
> > --- /dev/null
> > +++ b/drivers/perf/thunderx2_pmu.c
> > @@ -0,0 +1,861 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * CAVIUM THUNDERX2 SoC PMU UNCORE
> > + * Copyright (C) 2018 Cavium Inc.
> > + * Author: Ganapatrao Kulkarni <gkulkarni@cavium.com>
> > + */
> > +
> > +#include <linux/acpi.h>
> > +#include <linux/cpuhotplug.h>
> > +#include <linux/perf_event.h>
> > +#include <linux/platform_device.h>
> > +
> > +/* Each ThunderX2(TX2) Socket has a L3C and DMC UNCORE PMU device.
> > + * Each UNCORE PMU device consists of 4 independent programmable counters.
> > + * Counters are 32 bit and do not support overflow interrupt,
> > + * they need to be sampled before overflow(i.e, at every 2 seconds).
> > + */
> > +
> > +#define TX2_PMU_MAX_COUNTERS 4
> > +#define TX2_PMU_DMC_CHANNELS 8
> > +#define TX2_PMU_L3_TILES 16
> > +
> > +#define TX2_PMU_HRTIMER_INTERVAL (2 * NSEC_PER_SEC)
> > +#define GET_EVENTID(ev) ((ev->hw.config) & 0x1f)
> > +#define GET_COUNTERID(ev) ((ev->hw.idx) & 0x3)
> > + /* 1 byte per counter(4 counters).
> > + * Event id is encoded in bits [5:1] of a byte,
> > + */
> > +#define DMC_EVENT_CFG(idx, val) ((val) << (((idx) * 8) + 1))
> > +
> > +#define L3C_COUNTER_CTL 0xA8
> > +#define L3C_COUNTER_DATA 0xAC
> > +#define DMC_COUNTER_CTL 0x234
> > +#define DMC_COUNTER_DATA 0x240
> > +
> > +/* L3C event IDs */
> > +#define L3_EVENT_READ_REQ 0xD
> > +#define L3_EVENT_WRITEBACK_REQ 0xE
> > +#define L3_EVENT_INV_N_WRITE_REQ 0xF
> > +#define L3_EVENT_INV_REQ 0x10
> > +#define L3_EVENT_EVICT_REQ 0x13
> > +#define L3_EVENT_INV_N_WRITE_HIT 0x14
> > +#define L3_EVENT_INV_HIT 0x15
> > +#define L3_EVENT_READ_HIT 0x17
> > +#define L3_EVENT_MAX 0x18
> > +
> > +/* DMC event IDs */
> > +#define DMC_EVENT_COUNT_CYCLES 0x1
> > +#define DMC_EVENT_WRITE_TXNS 0xB
> > +#define DMC_EVENT_DATA_TRANSFERS 0xD
> > +#define DMC_EVENT_READ_TXNS 0xF
> > +#define DMC_EVENT_MAX 0x10
> > +
> > +enum tx2_uncore_type {
> > + PMU_TYPE_L3C,
> > + PMU_TYPE_DMC,
> > + PMU_TYPE_INVALID,
> > +};
> > +
> > +/*
> > + * pmu on each socket has 2 uncore devices(dmc and l3c),
> > + * each device has 4 counters.
> > + */
> > +struct tx2_uncore_pmu {
> > + struct hlist_node hpnode;
> > + struct list_head entry;
> > + struct pmu pmu;
> > + char *name;
> > + int node;
> > + int cpu;
> > + u32 max_counters;
> > + u32 prorate_factor;
> > + u32 max_events;
> > + u64 hrtimer_interval;
>
> minor nit:
>
> The alignment of the fields are pretty inconsistent. e.g,
> u32 is followed by tabs and the rest are not. Please keep it
> consistent.
>
> > + void __iomem *base;
> > + DECLARE_BITMAP(active_counters, TX2_PMU_MAX_COUNTERS);
> > + struct perf_event *events[TX2_PMU_MAX_COUNTERS];
> > + struct device *dev;
> > + struct hrtimer hrtimer;
> > + const struct attribute_group **attr_groups;
> > + enum tx2_uncore_type type;
> > + void (*init_cntr_base)(struct perf_event *event,
> > + struct tx2_uncore_pmu *tx2_pmu);
> > + void (*stop_event)(struct perf_event *event);
> > + void (*start_event)(struct perf_event *event, int flags);
> > +};
> > +
> > +static LIST_HEAD(tx2_pmus);
> > +
> > +static inline struct tx2_uncore_pmu *pmu_to_tx2_pmu(struct pmu *pmu)
> > +{
> > + return container_of(pmu, struct tx2_uncore_pmu, pmu);
> > +}
> > +
> > +PMU_FORMAT_ATTR(event, "config:0-4");
> > +
> > +static struct attribute *l3c_pmu_format_attrs[] = {
> > + &format_attr_event.attr,
> > + NULL,
> > +};
> > +
> > +static struct attribute *dmc_pmu_format_attrs[] = {
> > + &format_attr_event.attr,
> > + NULL,
> > +};
> > +
> > +static const struct attribute_group l3c_pmu_format_attr_group = {
> > + .name = "format",
> > + .attrs = l3c_pmu_format_attrs,
> > +};
> > +
> > +static const struct attribute_group dmc_pmu_format_attr_group = {
> > + .name = "format",
> > + .attrs = dmc_pmu_format_attrs,
> > +};
> > +
> > +/*
> > + * sysfs event attributes
> > + */
> > +static ssize_t tx2_pmu_event_show(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + struct dev_ext_attribute *eattr;
> > +
> > + eattr = container_of(attr, struct dev_ext_attribute, attr);
> > + return sprintf(buf, "event=0x%lx\n", (unsigned long) eattr->var);
> > +}
> > +
> > +#define TX2_EVENT_ATTR(name, config) \
> > + PMU_EVENT_ATTR(name, tx2_pmu_event_attr_##name, \
> > + config, tx2_pmu_event_show)
> > +
> > +TX2_EVENT_ATTR(read_request, L3_EVENT_READ_REQ);
> > +TX2_EVENT_ATTR(writeback_request, L3_EVENT_WRITEBACK_REQ);
> > +TX2_EVENT_ATTR(inv_nwrite_request, L3_EVENT_INV_N_WRITE_REQ);
> > +TX2_EVENT_ATTR(inv_request, L3_EVENT_INV_REQ);
> > +TX2_EVENT_ATTR(evict_request, L3_EVENT_EVICT_REQ);
> > +TX2_EVENT_ATTR(inv_nwrite_hit, L3_EVENT_INV_N_WRITE_HIT);
> > +TX2_EVENT_ATTR(inv_hit, L3_EVENT_INV_HIT);
> > +TX2_EVENT_ATTR(read_hit, L3_EVENT_READ_HIT);
> > +
> > +static struct attribute *l3c_pmu_events_attrs[] = {
> > + &tx2_pmu_event_attr_read_request.attr.attr,
> > + &tx2_pmu_event_attr_writeback_request.attr.attr,
> > + &tx2_pmu_event_attr_inv_nwrite_request.attr.attr,
> > + &tx2_pmu_event_attr_inv_request.attr.attr,
> > + &tx2_pmu_event_attr_evict_request.attr.attr,
> > + &tx2_pmu_event_attr_inv_nwrite_hit.attr.attr,
> > + &tx2_pmu_event_attr_inv_hit.attr.attr,
> > + &tx2_pmu_event_attr_read_hit.attr.attr,
> > + NULL,
> > +};
> > +
> > +TX2_EVENT_ATTR(cnt_cycles, DMC_EVENT_COUNT_CYCLES);
> > +TX2_EVENT_ATTR(write_txns, DMC_EVENT_WRITE_TXNS);
> > +TX2_EVENT_ATTR(data_transfers, DMC_EVENT_DATA_TRANSFERS);
> > +TX2_EVENT_ATTR(read_txns, DMC_EVENT_READ_TXNS);
> > +
> > +static struct attribute *dmc_pmu_events_attrs[] = {
> > + &tx2_pmu_event_attr_cnt_cycles.attr.attr,
> > + &tx2_pmu_event_attr_write_txns.attr.attr,
> > + &tx2_pmu_event_attr_data_transfers.attr.attr,
> > + &tx2_pmu_event_attr_read_txns.attr.attr,
> > + NULL,
> > +};
> > +
> > +static const struct attribute_group l3c_pmu_events_attr_group = {
> > + .name = "events",
> > + .attrs = l3c_pmu_events_attrs,
> > +};
> > +
> > +static const struct attribute_group dmc_pmu_events_attr_group = {
> > + .name = "events",
> > + .attrs = dmc_pmu_events_attrs,
> > +};
> > +
> > +/*
> > + * sysfs cpumask attributes
> > + */
> > +static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr,
> > + char *buf)
> > +{
> > + struct tx2_uncore_pmu *tx2_pmu;
> > +
> > + tx2_pmu = pmu_to_tx2_pmu(dev_get_drvdata(dev));
> > + return cpumap_print_to_pagebuf(true, buf, cpumask_of(tx2_pmu->cpu));
> > +}
> > +static DEVICE_ATTR_RO(cpumask);
> > +
> > +static struct attribute *tx2_pmu_cpumask_attrs[] = {
> > + &dev_attr_cpumask.attr,
> > + NULL,
> > +};
> > +
> > +static const struct attribute_group pmu_cpumask_attr_group = {
> > + .attrs = tx2_pmu_cpumask_attrs,
> > +};
> > +
> > +/*
> > + * Per PMU device attribute groups
> > + */
> > +static const struct attribute_group *l3c_pmu_attr_groups[] = {
> > + &l3c_pmu_format_attr_group,
> > + &pmu_cpumask_attr_group,
> > + &l3c_pmu_events_attr_group,
> > + NULL
> > +};
> > +
> > +static const struct attribute_group *dmc_pmu_attr_groups[] = {
> > + &dmc_pmu_format_attr_group,
> > + &pmu_cpumask_attr_group,
> > + &dmc_pmu_events_attr_group,
> > + NULL
> > +};
> > +
> > +static inline u32 reg_readl(unsigned long addr)
> > +{
> > + return readl((void __iomem *)addr);
> > +}
> > +
> > +static inline void reg_writel(u32 val, unsigned long addr)
> > +{
> > + writel(val, (void __iomem *)addr);
> > +}
> > +
> > +static int alloc_counter(struct tx2_uncore_pmu *tx2_pmu)
> > +{
> > + int counter;
> > +
> > + counter = find_first_zero_bit(tx2_pmu->active_counters,
> > + tx2_pmu->max_counters);
> > + if (counter == tx2_pmu->max_counters)
> > + return -ENOSPC;
> > +
> > + set_bit(counter, tx2_pmu->active_counters);
> > + return counter;
> > +}
> > +
> > +static inline void free_counter(struct tx2_uncore_pmu *tx2_pmu, int counter)
> > +{
> > + clear_bit(counter, tx2_pmu->active_counters);
> > +}
> > +
> > +static void init_cntr_base_l3c(struct perf_event *event,
> > + struct tx2_uncore_pmu *tx2_pmu)
> > +{
> > + struct hw_perf_event *hwc = &event->hw;
> > +
> > + /* counter ctrl/data reg offset at 8 */
> > + hwc->config_base = (unsigned long)tx2_pmu->base
> > + + L3C_COUNTER_CTL + (8 * GET_COUNTERID(event));
> > + hwc->event_base = (unsigned long)tx2_pmu->base
> > + + L3C_COUNTER_DATA + (8 * GET_COUNTERID(event));
> > +}
> > +
> > +static void init_cntr_base_dmc(struct perf_event *event,
> > + struct tx2_uncore_pmu *tx2_pmu)
> > +{
> > + struct hw_perf_event *hwc = &event->hw;
> > +
> > + hwc->config_base = (unsigned long)tx2_pmu->base
> > + + DMC_COUNTER_CTL;
> > + /* counter data reg offset at 0xc */
> > + hwc->event_base = (unsigned long)tx2_pmu->base
> > + + DMC_COUNTER_DATA + (0xc * GET_COUNTERID(event));
> > +}
> > +
> > +static void uncore_start_event_l3c(struct perf_event *event, int flags)
> > +{
> > + u32 val;
> > + struct hw_perf_event *hwc = &event->hw;
> > +
> > + /* event id encoded in bits [07:03] */
> > + val = GET_EVENTID(event) << 3;
> > + reg_writel(val, hwc->config_base);
> > + local64_set(&hwc->prev_count, 0);
> > + reg_writel(0, hwc->event_base);
> > +}
> > +
> > +static inline void uncore_stop_event_l3c(struct perf_event *event)
> > +{
> > + reg_writel(0, event->hw.config_base);
> > +}
> > +
> > +static void uncore_start_event_dmc(struct perf_event *event, int flags)
> > +{
> > + u32 val;
> > + struct hw_perf_event *hwc = &event->hw;
> > + int idx = GET_COUNTERID(event);
> > + int event_id = GET_EVENTID(event);
> > +
> > + /* enable and start counters.
> > + * 8 bits for each counter, bits[05:01] of a counter to set event type.
> > + */
> > + val = reg_readl(hwc->config_base);
> > + val &= ~DMC_EVENT_CFG(idx, 0x1f);
> > + val |= DMC_EVENT_CFG(idx, event_id);
> > + reg_writel(val, hwc->config_base);
> > + local64_set(&hwc->prev_count, 0);
> > + reg_writel(0, hwc->event_base);
> > +}
> > +
> > +static void uncore_stop_event_dmc(struct perf_event *event)
> > +{
> > + u32 val;
> > + struct hw_perf_event *hwc = &event->hw;
> > + int idx = GET_COUNTERID(event);
> > +
> > + /* clear event type(bits[05:01]) to stop counter */
> > + val = reg_readl(hwc->config_base);
> > + val &= ~DMC_EVENT_CFG(idx, 0x1f);
> > + reg_writel(val, hwc->config_base);
> > +}
> > +
> > +static void tx2_uncore_event_update(struct perf_event *event)
> > +{
> > + s64 prev, delta, new = 0;
> > + struct hw_perf_event *hwc = &event->hw;
> > + struct tx2_uncore_pmu *tx2_pmu;
> > + enum tx2_uncore_type type;
> > + u32 prorate_factor;
> > +
> > + tx2_pmu = pmu_to_tx2_pmu(event->pmu);
> > + type = tx2_pmu->type;
> > + prorate_factor = tx2_pmu->prorate_factor;
> > +
> > + new = reg_readl(hwc->event_base);
> > + prev = local64_xchg(&hwc->prev_count, new);
> > +
> > + /* handles rollover of 32 bit counter */
> > + delta = (u32)(((1UL << 32) - prev) + new);
> > +
> > + /* DMC event data_transfers granularity is 16 Bytes, convert it to 64 */
> > + if (type == PMU_TYPE_DMC &&
> > + GET_EVENTID(event) == DMC_EVENT_DATA_TRANSFERS)
> > + delta = delta/4;
> > +
> > + /* L3C and DMC has 16 and 8 interleave channels respectively.
> > + * The sampled value is for channel 0 and multiplied with
> > + * prorate_factor to get the count for a device.
> > + */
> > + local64_add(delta * prorate_factor, &event->count);
> > +}
> > +
> > +enum tx2_uncore_type get_tx2_pmu_type(struct acpi_device *adev)
> > +{
> > + int i = 0;
> > + struct acpi_tx2_pmu_device {
> > + __u8 id[ACPI_ID_LEN];
> > + enum tx2_uncore_type type;
> > + } devices[] = {
> > + {"CAV901D", PMU_TYPE_L3C},
> > + {"CAV901F", PMU_TYPE_DMC},
> > + {"", PMU_TYPE_INVALID}
> > + };
> > +
> > + while (devices[i].type != PMU_TYPE_INVALID) {
> > + if (!strcmp(acpi_device_hid(adev), devices[i].id))
> > + break;
> > + i++;
> > + }
> > +
> > + return devices[i].type;
> > +}
> > +
> > +static bool tx2_uncore_validate_event(struct pmu *pmu,
> > + struct perf_event *event, int *counters)
> > +{
> > + if (is_software_event(event))
> > + return true;
> > + /* Reject groups spanning multiple HW PMUs. */
> > + if (event->pmu != pmu)
> > + return false;
> > +
> > + *counters = *counters + 1;
> > + return true;
>
> nit: alignment.
>
> Otherwise looks good to me.
> FWIW, with the above nits fixed:
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Thanks Suzuki!
thanks,
Ganapat
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] arm64/mm: use correct operators for string comparison in cache.S
From: Ard Biesheuvel @ 2018-12-06 11:59 UTC (permalink / raw)
To: Will Deacon; +Cc: Catalin Marinas, Robin Murphy, linux-arm-kernel
In-Reply-To: <20181206115150.GA24063@arm.com>
On Thu, 6 Dec 2018 at 12:51, Will Deacon <will.deacon@arm.com> wrote:
>
> On Tue, Dec 04, 2018 at 01:44:01AM +0100, Ard Biesheuvel wrote:
> > On Mon, 3 Dec 2018 at 19:10, Will Deacon <will.deacon@arm.com> wrote:
> > >
> > > On Mon, Dec 03, 2018 at 06:54:35PM +0100, Ard Biesheuvel wrote:
> > > > On Mon, 3 Dec 2018 at 18:44, Will Deacon <will.deacon@arm.com> wrote:
> > > > >
> > > > > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > > > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > > > > rely on assembler behavior that is not documented, and probably not
> > > > > > > > guaranteed to produce the correct behavior going forward.
> > > > > > > >
> > > > > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > > > > >
> > > > > > > > $ nm arch/arm64/mm/cache.o
> > > > > > > > ...
> > > > > > > > U civac
> > > > > > > > ...
> > > > > > > > U cvac
> > > > > > > > U cvap
> > > > > > > > U cvau
> > > > > > > >
> > > > > > > > This is due to the fact that the comparisons used to select the
> > > > > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > > > > not strings, and even though it seems that GAS is doing the right
> > > > > > > > thing here (undefined symbols by the same name are equal to each
> > > > > > > > other), it seems unwise to rely on this.
> > > > > > > >
> > > > > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > > > > and make them local so they don't pollute the gobal symbol space.
> > > > > > >
> > > > > > > Rather than making the unintended symbol comparisons work properly, can
> > > > > > > we not just implement the string comparisons that were supposed to be?
> > > > > > > Superficially, the diff below seems to still generate the desired output
> > > > > > > (although as always there's probably some subtlety I'm missing).
> > > > > > >
> > > > > > > Robin.
> > > > > > >
> > > > > > > ----->8-----
> > > > > > >
> > > > > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > > > > b/arch/arm64/include/asm/assembler.h
> > > > > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > > > > --- a/arch/arm64/include/asm/assembler.h
> > > > > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > > > > @@ -383,13 +383,13 @@ alternative_endif
> > > > > > > sub \tmp2, \tmp1, #1
> > > > > > > bic \kaddr, \kaddr, \tmp2
> > > > > > > 9998:
> > > > > > > - .if (\op == cvau || \op == cvac)
> > > > > > > + .if ("\op" == "cvau" || "\op" == "cvac")
> > > > > > > alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > > > > > dc \op, \kaddr
> > > > > > > alternative_else
> > > > > > > dc civac, \kaddr
> > > > > > > alternative_endif
> > > > > > > - .elseif (\op == cvap)
> > > > > > > + .elseif ("\op" == "cvap")
> > > > > > > alternative_if ARM64_HAS_DCPOP
> > > > > > > sys 3, c7, c12, 1, \kaddr // dc cvap
> > > > > > > alternative_else
> > > > > > >
> > > > > >
> > > > > > Looking at the GAS info pages, I find
> > > > > >
> > > > > > "Operators" are arithmetic functions, like '+' or '%'.
> > > > > > "Arguments" are symbols, numbers or subexpressions.
> > > > > > An "expression" specifies an address or numeric value.
> > > > > >
> > > > > > so even if the comparison works as expected, I'm hesitant to rely on
> > > > > > it to work as expected on any version of GAS or any other assembler
> > > > > > claiming to implement the GAS asm dialect.
> > > > > >
> > > > > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> > > > >
> > > > > That looks better to me, although I'm not sure why you're inverted the logic
> > > > > here:
> > > > >
> > > > > > .ifnc \op, civac
> > > > > > .ifnc \op, cvap
> > > > >
> > > > > What am I missing?
> > > > >
> > > >
> > > > .ifc does not permit '\op equals string1 or \op equals string2'
> > >
> > > Thanks. Then I guess we invert the logic as you suggest, or we duplicate the
> > > alternative code. Looking at this some more, I think what we currently have
> > > is broken because on a system with ARM64_WORKAROUND_CLEAN_CACHE but not
> > > ARM64_HAS_DCPOP, you'll get DC CVAC for __clean_dcache_area_pop, which
> > > would be broken on that CPU.
> > >
> >
> > Can we just fallback to civac instead? Or do we need to add logic to
> > combine the two feature flags?
>
> I guess this could introduce a performance regression for CPUs without
> either DCPOP or ARM64_WORKAROUND_CLEAN_CACHE, since we're effectively
> forcing a hefty cache miss on a subsequent access to the persisted data.
>
> So I'd prefer not to make the CIVAC unconditional unless we have to.
>
OK
I have some patches that extend alternative patching via callbacks for
this. I will send them out shortly.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v11 2/2] ThunderX2, perf : Add Cavium ThunderX2 SoC UNCORE PMU driver
From: Kulkarni, Ganapatrao @ 2018-12-06 11:51 UTC (permalink / raw)
To: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
Cc: mark.rutland@arm.com, Nair, Jayachandran, suzuki.poulose@arm.com,
gklkml16@gmail.com, rdunlap@infradead.org, Will.Deacon@arm.com,
Lomovtsev, Vadim, Richter, Robert, Jan Glauber
In-Reply-To: <20181206115053.7665-1-ganapatrao.kulkarni@cavium.com>
This patch adds a perf driver for the PMU UNCORE devices DDR4 Memory
Controller(DMC) and Level 3 Cache(L3C). Each PMU supports up to 4
counters. All counters lack overflow interrupt and are
sampled periodically.
Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Ganapatrao Kulkarni <ganapatrao.kulkarni@cavium.com>
---
drivers/perf/Kconfig | 9 +
drivers/perf/Makefile | 1 +
drivers/perf/thunderx2_pmu.c | 861 +++++++++++++++++++++++++++++++++++
include/linux/cpuhotplug.h | 1 +
4 files changed, 872 insertions(+)
create mode 100644 drivers/perf/thunderx2_pmu.c
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 08ebaf7cca8b..af9bc178495d 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -87,6 +87,15 @@ config QCOM_L3_PMU
Adds the L3 cache PMU into the perf events subsystem for
monitoring L3 cache events.
+config THUNDERX2_PMU
+ tristate "Cavium ThunderX2 SoC PMU UNCORE"
+ depends on ARCH_THUNDER2 && ARM64 && ACPI && NUMA
+ default m
+ help
+ Provides support for ThunderX2 UNCORE events.
+ The SoC has PMU support in its L3 cache controller (L3C) and
+ in the DDR4 Memory Controller (DMC).
+
config XGENE_PMU
depends on ARCH_XGENE
bool "APM X-Gene SoC PMU"
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index b3902bd37d53..909f27fd9db3 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
obj-$(CONFIG_HISI_PMU) += hisilicon/
obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o
obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o
+obj-$(CONFIG_THUNDERX2_PMU) += thunderx2_pmu.o
obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o
diff --git a/drivers/perf/thunderx2_pmu.c b/drivers/perf/thunderx2_pmu.c
new file mode 100644
index 000000000000..f72438cad38e
--- /dev/null
+++ b/drivers/perf/thunderx2_pmu.c
@@ -0,0 +1,861 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CAVIUM THUNDERX2 SoC PMU UNCORE
+ * Copyright (C) 2018 Cavium Inc.
+ * Author: Ganapatrao Kulkarni <gkulkarni@cavium.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/cpuhotplug.h>
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+
+/* Each ThunderX2(TX2) Socket has a L3C and DMC UNCORE PMU device.
+ * Each UNCORE PMU device consists of 4 independent programmable counters.
+ * Counters are 32 bit and do not support overflow interrupt,
+ * they need to be sampled before overflow(i.e, at every 2 seconds).
+ */
+
+#define TX2_PMU_MAX_COUNTERS 4
+#define TX2_PMU_DMC_CHANNELS 8
+#define TX2_PMU_L3_TILES 16
+
+#define TX2_PMU_HRTIMER_INTERVAL (2 * NSEC_PER_SEC)
+#define GET_EVENTID(ev) ((ev->hw.config) & 0x1f)
+#define GET_COUNTERID(ev) ((ev->hw.idx) & 0x3)
+ /* 1 byte per counter(4 counters).
+ * Event id is encoded in bits [5:1] of a byte,
+ */
+#define DMC_EVENT_CFG(idx, val) ((val) << (((idx) * 8) + 1))
+
+#define L3C_COUNTER_CTL 0xA8
+#define L3C_COUNTER_DATA 0xAC
+#define DMC_COUNTER_CTL 0x234
+#define DMC_COUNTER_DATA 0x240
+
+/* L3C event IDs */
+#define L3_EVENT_READ_REQ 0xD
+#define L3_EVENT_WRITEBACK_REQ 0xE
+#define L3_EVENT_INV_N_WRITE_REQ 0xF
+#define L3_EVENT_INV_REQ 0x10
+#define L3_EVENT_EVICT_REQ 0x13
+#define L3_EVENT_INV_N_WRITE_HIT 0x14
+#define L3_EVENT_INV_HIT 0x15
+#define L3_EVENT_READ_HIT 0x17
+#define L3_EVENT_MAX 0x18
+
+/* DMC event IDs */
+#define DMC_EVENT_COUNT_CYCLES 0x1
+#define DMC_EVENT_WRITE_TXNS 0xB
+#define DMC_EVENT_DATA_TRANSFERS 0xD
+#define DMC_EVENT_READ_TXNS 0xF
+#define DMC_EVENT_MAX 0x10
+
+enum tx2_uncore_type {
+ PMU_TYPE_L3C,
+ PMU_TYPE_DMC,
+ PMU_TYPE_INVALID,
+};
+
+/*
+ * pmu on each socket has 2 uncore devices(dmc and l3c),
+ * each device has 4 counters.
+ */
+struct tx2_uncore_pmu {
+ struct hlist_node hpnode;
+ struct list_head entry;
+ struct pmu pmu;
+ char *name;
+ int node;
+ int cpu;
+ u32 max_counters;
+ u32 prorate_factor;
+ u32 max_events;
+ u64 hrtimer_interval;
+ void __iomem *base;
+ DECLARE_BITMAP(active_counters, TX2_PMU_MAX_COUNTERS);
+ struct perf_event *events[TX2_PMU_MAX_COUNTERS];
+ struct device *dev;
+ struct hrtimer hrtimer;
+ const struct attribute_group **attr_groups;
+ enum tx2_uncore_type type;
+ void (*init_cntr_base)(struct perf_event *event,
+ struct tx2_uncore_pmu *tx2_pmu);
+ void (*stop_event)(struct perf_event *event);
+ void (*start_event)(struct perf_event *event, int flags);
+};
+
+static LIST_HEAD(tx2_pmus);
+
+static inline struct tx2_uncore_pmu *pmu_to_tx2_pmu(struct pmu *pmu)
+{
+ return container_of(pmu, struct tx2_uncore_pmu, pmu);
+}
+
+PMU_FORMAT_ATTR(event, "config:0-4");
+
+static struct attribute *l3c_pmu_format_attrs[] = {
+ &format_attr_event.attr,
+ NULL,
+};
+
+static struct attribute *dmc_pmu_format_attrs[] = {
+ &format_attr_event.attr,
+ NULL,
+};
+
+static const struct attribute_group l3c_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = l3c_pmu_format_attrs,
+};
+
+static const struct attribute_group dmc_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = dmc_pmu_format_attrs,
+};
+
+/*
+ * sysfs event attributes
+ */
+static ssize_t tx2_pmu_event_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dev_ext_attribute *eattr;
+
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
+ return sprintf(buf, "event=0x%lx\n", (unsigned long) eattr->var);
+}
+
+#define TX2_EVENT_ATTR(name, config) \
+ PMU_EVENT_ATTR(name, tx2_pmu_event_attr_##name, \
+ config, tx2_pmu_event_show)
+
+TX2_EVENT_ATTR(read_request, L3_EVENT_READ_REQ);
+TX2_EVENT_ATTR(writeback_request, L3_EVENT_WRITEBACK_REQ);
+TX2_EVENT_ATTR(inv_nwrite_request, L3_EVENT_INV_N_WRITE_REQ);
+TX2_EVENT_ATTR(inv_request, L3_EVENT_INV_REQ);
+TX2_EVENT_ATTR(evict_request, L3_EVENT_EVICT_REQ);
+TX2_EVENT_ATTR(inv_nwrite_hit, L3_EVENT_INV_N_WRITE_HIT);
+TX2_EVENT_ATTR(inv_hit, L3_EVENT_INV_HIT);
+TX2_EVENT_ATTR(read_hit, L3_EVENT_READ_HIT);
+
+static struct attribute *l3c_pmu_events_attrs[] = {
+ &tx2_pmu_event_attr_read_request.attr.attr,
+ &tx2_pmu_event_attr_writeback_request.attr.attr,
+ &tx2_pmu_event_attr_inv_nwrite_request.attr.attr,
+ &tx2_pmu_event_attr_inv_request.attr.attr,
+ &tx2_pmu_event_attr_evict_request.attr.attr,
+ &tx2_pmu_event_attr_inv_nwrite_hit.attr.attr,
+ &tx2_pmu_event_attr_inv_hit.attr.attr,
+ &tx2_pmu_event_attr_read_hit.attr.attr,
+ NULL,
+};
+
+TX2_EVENT_ATTR(cnt_cycles, DMC_EVENT_COUNT_CYCLES);
+TX2_EVENT_ATTR(write_txns, DMC_EVENT_WRITE_TXNS);
+TX2_EVENT_ATTR(data_transfers, DMC_EVENT_DATA_TRANSFERS);
+TX2_EVENT_ATTR(read_txns, DMC_EVENT_READ_TXNS);
+
+static struct attribute *dmc_pmu_events_attrs[] = {
+ &tx2_pmu_event_attr_cnt_cycles.attr.attr,
+ &tx2_pmu_event_attr_write_txns.attr.attr,
+ &tx2_pmu_event_attr_data_transfers.attr.attr,
+ &tx2_pmu_event_attr_read_txns.attr.attr,
+ NULL,
+};
+
+static const struct attribute_group l3c_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = l3c_pmu_events_attrs,
+};
+
+static const struct attribute_group dmc_pmu_events_attr_group = {
+ .name = "events",
+ .attrs = dmc_pmu_events_attrs,
+};
+
+/*
+ * sysfs cpumask attributes
+ */
+static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct tx2_uncore_pmu *tx2_pmu;
+
+ tx2_pmu = pmu_to_tx2_pmu(dev_get_drvdata(dev));
+ return cpumap_print_to_pagebuf(true, buf, cpumask_of(tx2_pmu->cpu));
+}
+static DEVICE_ATTR_RO(cpumask);
+
+static struct attribute *tx2_pmu_cpumask_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL,
+};
+
+static const struct attribute_group pmu_cpumask_attr_group = {
+ .attrs = tx2_pmu_cpumask_attrs,
+};
+
+/*
+ * Per PMU device attribute groups
+ */
+static const struct attribute_group *l3c_pmu_attr_groups[] = {
+ &l3c_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &l3c_pmu_events_attr_group,
+ NULL
+};
+
+static const struct attribute_group *dmc_pmu_attr_groups[] = {
+ &dmc_pmu_format_attr_group,
+ &pmu_cpumask_attr_group,
+ &dmc_pmu_events_attr_group,
+ NULL
+};
+
+static inline u32 reg_readl(unsigned long addr)
+{
+ return readl((void __iomem *)addr);
+}
+
+static inline void reg_writel(u32 val, unsigned long addr)
+{
+ writel(val, (void __iomem *)addr);
+}
+
+static int alloc_counter(struct tx2_uncore_pmu *tx2_pmu)
+{
+ int counter;
+
+ counter = find_first_zero_bit(tx2_pmu->active_counters,
+ tx2_pmu->max_counters);
+ if (counter == tx2_pmu->max_counters)
+ return -ENOSPC;
+
+ set_bit(counter, tx2_pmu->active_counters);
+ return counter;
+}
+
+static inline void free_counter(struct tx2_uncore_pmu *tx2_pmu, int counter)
+{
+ clear_bit(counter, tx2_pmu->active_counters);
+}
+
+static void init_cntr_base_l3c(struct perf_event *event,
+ struct tx2_uncore_pmu *tx2_pmu)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ /* counter ctrl/data reg offset at 8 */
+ hwc->config_base = (unsigned long)tx2_pmu->base
+ + L3C_COUNTER_CTL + (8 * GET_COUNTERID(event));
+ hwc->event_base = (unsigned long)tx2_pmu->base
+ + L3C_COUNTER_DATA + (8 * GET_COUNTERID(event));
+}
+
+static void init_cntr_base_dmc(struct perf_event *event,
+ struct tx2_uncore_pmu *tx2_pmu)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ hwc->config_base = (unsigned long)tx2_pmu->base
+ + DMC_COUNTER_CTL;
+ /* counter data reg offset at 0xc */
+ hwc->event_base = (unsigned long)tx2_pmu->base
+ + DMC_COUNTER_DATA + (0xc * GET_COUNTERID(event));
+}
+
+static void uncore_start_event_l3c(struct perf_event *event, int flags)
+{
+ u32 val;
+ struct hw_perf_event *hwc = &event->hw;
+
+ /* event id encoded in bits [07:03] */
+ val = GET_EVENTID(event) << 3;
+ reg_writel(val, hwc->config_base);
+ local64_set(&hwc->prev_count, 0);
+ reg_writel(0, hwc->event_base);
+}
+
+static inline void uncore_stop_event_l3c(struct perf_event *event)
+{
+ reg_writel(0, event->hw.config_base);
+}
+
+static void uncore_start_event_dmc(struct perf_event *event, int flags)
+{
+ u32 val;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = GET_COUNTERID(event);
+ int event_id = GET_EVENTID(event);
+
+ /* enable and start counters.
+ * 8 bits for each counter, bits[05:01] of a counter to set event type.
+ */
+ val = reg_readl(hwc->config_base);
+ val &= ~DMC_EVENT_CFG(idx, 0x1f);
+ val |= DMC_EVENT_CFG(idx, event_id);
+ reg_writel(val, hwc->config_base);
+ local64_set(&hwc->prev_count, 0);
+ reg_writel(0, hwc->event_base);
+}
+
+static void uncore_stop_event_dmc(struct perf_event *event)
+{
+ u32 val;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = GET_COUNTERID(event);
+
+ /* clear event type(bits[05:01]) to stop counter */
+ val = reg_readl(hwc->config_base);
+ val &= ~DMC_EVENT_CFG(idx, 0x1f);
+ reg_writel(val, hwc->config_base);
+}
+
+static void tx2_uncore_event_update(struct perf_event *event)
+{
+ s64 prev, delta, new = 0;
+ struct hw_perf_event *hwc = &event->hw;
+ struct tx2_uncore_pmu *tx2_pmu;
+ enum tx2_uncore_type type;
+ u32 prorate_factor;
+
+ tx2_pmu = pmu_to_tx2_pmu(event->pmu);
+ type = tx2_pmu->type;
+ prorate_factor = tx2_pmu->prorate_factor;
+
+ new = reg_readl(hwc->event_base);
+ prev = local64_xchg(&hwc->prev_count, new);
+
+ /* handles rollover of 32 bit counter */
+ delta = (u32)(((1UL << 32) - prev) + new);
+
+ /* DMC event data_transfers granularity is 16 Bytes, convert it to 64 */
+ if (type == PMU_TYPE_DMC &&
+ GET_EVENTID(event) == DMC_EVENT_DATA_TRANSFERS)
+ delta = delta/4;
+
+ /* L3C and DMC has 16 and 8 interleave channels respectively.
+ * The sampled value is for channel 0 and multiplied with
+ * prorate_factor to get the count for a device.
+ */
+ local64_add(delta * prorate_factor, &event->count);
+}
+
+enum tx2_uncore_type get_tx2_pmu_type(struct acpi_device *adev)
+{
+ int i = 0;
+ struct acpi_tx2_pmu_device {
+ __u8 id[ACPI_ID_LEN];
+ enum tx2_uncore_type type;
+ } devices[] = {
+ {"CAV901D", PMU_TYPE_L3C},
+ {"CAV901F", PMU_TYPE_DMC},
+ {"", PMU_TYPE_INVALID}
+ };
+
+ while (devices[i].type != PMU_TYPE_INVALID) {
+ if (!strcmp(acpi_device_hid(adev), devices[i].id))
+ break;
+ i++;
+ }
+
+ return devices[i].type;
+}
+
+static bool tx2_uncore_validate_event(struct pmu *pmu,
+ struct perf_event *event, int *counters)
+{
+ if (is_software_event(event))
+ return true;
+ /* Reject groups spanning multiple HW PMUs. */
+ if (event->pmu != pmu)
+ return false;
+
+ *counters = *counters + 1;
+ return true;
+}
+
+/*
+ * Make sure the group of events can be scheduled at once
+ * on the PMU.
+ */
+static bool tx2_uncore_validate_event_group(struct perf_event *event)
+{
+ struct perf_event *sibling, *leader = event->group_leader;
+ int counters = 0;
+
+ if (event->group_leader == event)
+ return true;
+
+ if (!tx2_uncore_validate_event(event->pmu, leader, &counters))
+ return false;
+
+ for_each_sibling_event(sibling, leader) {
+ if (!tx2_uncore_validate_event(event->pmu, sibling, &counters))
+ return false;
+ }
+
+ if (!tx2_uncore_validate_event(event->pmu, event, &counters))
+ return false;
+
+ /*
+ * If the group requires more counters than the HW has,
+ * it cannot ever be scheduled.
+ */
+ return counters <= TX2_PMU_MAX_COUNTERS;
+}
+
+
+static int tx2_uncore_event_init(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct tx2_uncore_pmu *tx2_pmu;
+
+ /* Test the event attr type check for PMU enumeration */
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /*
+ * SOC PMU counters are shared across all cores.
+ * Therefore, it does not support per-process mode.
+ * Also, it does not support event sampling mode.
+ */
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EINVAL;
+
+ /* We have no filtering of any kind */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest)
+ return -EINVAL;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ tx2_pmu = pmu_to_tx2_pmu(event->pmu);
+ if (tx2_pmu->cpu >= nr_cpu_ids)
+ return -EINVAL;
+ event->cpu = tx2_pmu->cpu;
+
+ if (event->attr.config >= tx2_pmu->max_events)
+ return -EINVAL;
+
+ /* store event id */
+ hwc->config = event->attr.config;
+
+ /* Validate the group */
+ if (!tx2_uncore_validate_event_group(event))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void tx2_uncore_event_start(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct tx2_uncore_pmu *tx2_pmu;
+
+ hwc->state = 0;
+ tx2_pmu = pmu_to_tx2_pmu(event->pmu);
+
+ tx2_pmu->start_event(event, flags);
+ perf_event_update_userpage(event);
+
+ /* Start timer for first event */
+ if (bitmap_weight(tx2_pmu->active_counters,
+ tx2_pmu->max_counters) == 1) {
+ hrtimer_start(&tx2_pmu->hrtimer,
+ ns_to_ktime(tx2_pmu->hrtimer_interval),
+ HRTIMER_MODE_REL_PINNED);
+ }
+}
+
+static void tx2_uncore_event_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct tx2_uncore_pmu *tx2_pmu;
+
+ if (hwc->state & PERF_HES_UPTODATE)
+ return;
+
+ tx2_pmu = pmu_to_tx2_pmu(event->pmu);
+ tx2_pmu->stop_event(event);
+ WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+ hwc->state |= PERF_HES_STOPPED;
+ if (flags & PERF_EF_UPDATE) {
+ tx2_uncore_event_update(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static int tx2_uncore_event_add(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct tx2_uncore_pmu *tx2_pmu;
+
+ tx2_pmu = pmu_to_tx2_pmu(event->pmu);
+
+ /* Allocate a free counter */
+ hwc->idx = alloc_counter(tx2_pmu);
+ if (hwc->idx < 0)
+ return -EAGAIN;
+
+ tx2_pmu->events[hwc->idx] = event;
+ /* set counter control and data registers base address */
+ tx2_pmu->init_cntr_base(event, tx2_pmu);
+
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ tx2_uncore_event_start(event, flags);
+
+ return 0;
+}
+
+static void tx2_uncore_event_del(struct perf_event *event, int flags)
+{
+ struct tx2_uncore_pmu *tx2_pmu = pmu_to_tx2_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+
+ tx2_uncore_event_stop(event, PERF_EF_UPDATE);
+
+ /* clear the assigned counter */
+ free_counter(tx2_pmu, GET_COUNTERID(event));
+
+ perf_event_update_userpage(event);
+ tx2_pmu->events[hwc->idx] = NULL;
+ hwc->idx = -1;
+}
+
+static void tx2_uncore_event_read(struct perf_event *event)
+{
+ tx2_uncore_event_update(event);
+}
+
+static enum hrtimer_restart tx2_hrtimer_callback(struct hrtimer *timer)
+{
+ struct tx2_uncore_pmu *tx2_pmu;
+ int max_counters, idx;
+
+ tx2_pmu = container_of(timer, struct tx2_uncore_pmu, hrtimer);
+ max_counters = tx2_pmu->max_counters;
+
+ if (bitmap_empty(tx2_pmu->active_counters, max_counters))
+ return HRTIMER_NORESTART;
+
+ for_each_set_bit(idx, tx2_pmu->active_counters, max_counters) {
+ struct perf_event *event = tx2_pmu->events[idx];
+
+ tx2_uncore_event_update(event);
+ }
+ hrtimer_forward_now(timer, ns_to_ktime(tx2_pmu->hrtimer_interval));
+ return HRTIMER_RESTART;
+}
+
+static int tx2_uncore_pmu_register(
+ struct tx2_uncore_pmu *tx2_pmu)
+{
+ struct device *dev = tx2_pmu->dev;
+ char *name = tx2_pmu->name;
+
+ /* Perf event registration */
+ tx2_pmu->pmu = (struct pmu) {
+ .module = THIS_MODULE,
+ .attr_groups = tx2_pmu->attr_groups,
+ .task_ctx_nr = perf_invalid_context,
+ .event_init = tx2_uncore_event_init,
+ .add = tx2_uncore_event_add,
+ .del = tx2_uncore_event_del,
+ .start = tx2_uncore_event_start,
+ .stop = tx2_uncore_event_stop,
+ .read = tx2_uncore_event_read,
+ };
+
+ tx2_pmu->pmu.name = devm_kasprintf(dev, GFP_KERNEL,
+ "%s", name);
+
+ return perf_pmu_register(&tx2_pmu->pmu, tx2_pmu->pmu.name, -1);
+}
+
+static int tx2_uncore_pmu_add_dev(struct tx2_uncore_pmu *tx2_pmu)
+{
+ int ret, cpu;
+
+ cpu = cpumask_any_and(cpumask_of_node(tx2_pmu->node),
+ cpu_online_mask);
+
+ tx2_pmu->cpu = cpu;
+ hrtimer_init(&tx2_pmu->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ tx2_pmu->hrtimer.function = tx2_hrtimer_callback;
+
+ ret = tx2_uncore_pmu_register(tx2_pmu);
+ if (ret) {
+ dev_err(tx2_pmu->dev, "%s PMU: Failed to init driver\n",
+ tx2_pmu->name);
+ return -ENODEV;
+ }
+
+ /* register hotplug callback for the pmu */
+ ret = cpuhp_state_add_instance(
+ CPUHP_AP_PERF_ARM_TX2_UNCORE_ONLINE,
+ &tx2_pmu->hpnode);
+ if (ret) {
+ dev_err(tx2_pmu->dev, "Error %d registering hotplug", ret);
+ return ret;
+ }
+
+ /* Add to list */
+ list_add(&tx2_pmu->entry, &tx2_pmus);
+
+ dev_dbg(tx2_pmu->dev, "%s PMU UNCORE registered\n",
+ tx2_pmu->pmu.name);
+ return ret;
+}
+
+static struct tx2_uncore_pmu *tx2_uncore_pmu_init_dev(struct device *dev,
+ acpi_handle handle, struct acpi_device *adev, u32 type)
+{
+ struct tx2_uncore_pmu *tx2_pmu;
+ void __iomem *base;
+ struct resource res;
+ struct resource_entry *rentry;
+ struct list_head list;
+ int ret;
+
+ INIT_LIST_HEAD(&list);
+ ret = acpi_dev_get_resources(adev, &list, NULL, NULL);
+ if (ret <= 0) {
+ dev_err(dev, "failed to parse _CRS method, error %d\n", ret);
+ return NULL;
+ }
+
+ list_for_each_entry(rentry, &list, node) {
+ if (resource_type(rentry->res) == IORESOURCE_MEM) {
+ res = *rentry->res;
+ break;
+ }
+ }
+
+ if (!rentry->res)
+ return NULL;
+
+ acpi_dev_free_resource_list(&list);
+ base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(base)) {
+ dev_err(dev, "PMU type %d: Fail to map resource\n", type);
+ return NULL;
+ }
+
+ tx2_pmu = devm_kzalloc(dev, sizeof(*tx2_pmu), GFP_KERNEL);
+ if (!tx2_pmu)
+ return NULL;
+
+ tx2_pmu->dev = dev;
+ tx2_pmu->type = type;
+ tx2_pmu->base = base;
+ tx2_pmu->node = dev_to_node(dev);
+ INIT_LIST_HEAD(&tx2_pmu->entry);
+
+ switch (tx2_pmu->type) {
+ case PMU_TYPE_L3C:
+ tx2_pmu->max_counters = TX2_PMU_MAX_COUNTERS;
+ tx2_pmu->prorate_factor = TX2_PMU_L3_TILES;
+ tx2_pmu->max_events = L3_EVENT_MAX;
+ tx2_pmu->hrtimer_interval = TX2_PMU_HRTIMER_INTERVAL;
+ tx2_pmu->attr_groups = l3c_pmu_attr_groups;
+ tx2_pmu->name = devm_kasprintf(dev, GFP_KERNEL,
+ "uncore_l3c_%d", tx2_pmu->node);
+ tx2_pmu->init_cntr_base = init_cntr_base_l3c;
+ tx2_pmu->start_event = uncore_start_event_l3c;
+ tx2_pmu->stop_event = uncore_stop_event_l3c;
+ break;
+ case PMU_TYPE_DMC:
+ tx2_pmu->max_counters = TX2_PMU_MAX_COUNTERS;
+ tx2_pmu->prorate_factor = TX2_PMU_DMC_CHANNELS;
+ tx2_pmu->max_events = DMC_EVENT_MAX;
+ tx2_pmu->hrtimer_interval = TX2_PMU_HRTIMER_INTERVAL;
+ tx2_pmu->attr_groups = dmc_pmu_attr_groups;
+ tx2_pmu->name = devm_kasprintf(dev, GFP_KERNEL,
+ "uncore_dmc_%d", tx2_pmu->node);
+ tx2_pmu->init_cntr_base = init_cntr_base_dmc;
+ tx2_pmu->start_event = uncore_start_event_dmc;
+ tx2_pmu->stop_event = uncore_stop_event_dmc;
+ break;
+ case PMU_TYPE_INVALID:
+ devm_kfree(dev, tx2_pmu);
+ return NULL;
+ }
+
+ return tx2_pmu;
+}
+
+static acpi_status tx2_uncore_pmu_add(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct tx2_uncore_pmu *tx2_pmu;
+ struct acpi_device *adev;
+ enum tx2_uncore_type type;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+ if (acpi_bus_get_status(adev) || !adev->status.present)
+ return AE_OK;
+
+ type = get_tx2_pmu_type(adev);
+ if (type == PMU_TYPE_INVALID)
+ return AE_OK;
+
+ tx2_pmu = tx2_uncore_pmu_init_dev((struct device *)data,
+ handle, adev, type);
+
+ if (!tx2_pmu)
+ return AE_ERROR;
+
+ if (tx2_uncore_pmu_add_dev(tx2_pmu)) {
+ /* Can't add the PMU device, abort */
+ return AE_ERROR;
+ }
+ return AE_OK;
+}
+
+static int tx2_uncore_pmu_online_cpu(unsigned int cpu,
+ struct hlist_node *hpnode)
+{
+ struct tx2_uncore_pmu *tx2_pmu;
+
+ tx2_pmu = hlist_entry_safe(hpnode,
+ struct tx2_uncore_pmu, hpnode);
+
+ /* Pick this CPU, If there is no CPU/PMU association and both are
+ * from same node.
+ */
+ if ((tx2_pmu->cpu >= nr_cpu_ids) &&
+ (tx2_pmu->node == cpu_to_node(cpu)))
+ tx2_pmu->cpu = cpu;
+
+ return 0;
+}
+
+static int tx2_uncore_pmu_offline_cpu(unsigned int cpu,
+ struct hlist_node *hpnode)
+{
+ int new_cpu;
+ struct tx2_uncore_pmu *tx2_pmu;
+ struct cpumask cpu_online_mask_temp;
+
+ tx2_pmu = hlist_entry_safe(hpnode,
+ struct tx2_uncore_pmu, hpnode);
+
+ if (cpu != tx2_pmu->cpu)
+ return 0;
+
+ hrtimer_cancel(&tx2_pmu->hrtimer);
+ cpumask_copy(&cpu_online_mask_temp, cpu_online_mask);
+ cpumask_clear_cpu(cpu, &cpu_online_mask_temp);
+ new_cpu = cpumask_any_and(
+ cpumask_of_node(tx2_pmu->node),
+ &cpu_online_mask_temp);
+
+ tx2_pmu->cpu = new_cpu;
+ if (new_cpu >= nr_cpu_ids)
+ return 0;
+ perf_pmu_migrate_context(&tx2_pmu->pmu, cpu, new_cpu);
+
+ return 0;
+}
+
+static const struct acpi_device_id tx2_uncore_acpi_match[] = {
+ {"CAV901C", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, tx2_uncore_acpi_match);
+
+static int tx2_uncore_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ acpi_handle handle;
+ acpi_status status;
+
+ set_dev_node(dev, acpi_get_node(ACPI_HANDLE(dev)));
+
+ if (!has_acpi_companion(dev))
+ return -ENODEV;
+
+ handle = ACPI_HANDLE(dev);
+ if (!handle)
+ return -EINVAL;
+
+ /* Walk through the tree for all PMU UNCORE devices */
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ tx2_uncore_pmu_add,
+ NULL, dev, NULL);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to probe PMU devices\n");
+ return_ACPI_STATUS(status);
+ }
+
+ dev_info(dev, "node%d: pmu uncore registered\n", dev_to_node(dev));
+ return 0;
+}
+
+static int tx2_uncore_remove(struct platform_device *pdev)
+{
+ struct tx2_uncore_pmu *tx2_pmu, *temp;
+ struct device *dev = &pdev->dev;
+
+ if (!list_empty(&tx2_pmus)) {
+ list_for_each_entry_safe(tx2_pmu, temp, &tx2_pmus, entry) {
+ if (tx2_pmu->node == dev_to_node(dev)) {
+ cpuhp_state_remove_instance_nocalls(
+ CPUHP_AP_PERF_ARM_TX2_UNCORE_ONLINE,
+ &tx2_pmu->hpnode);
+ perf_pmu_unregister(&tx2_pmu->pmu);
+ list_del(&tx2_pmu->entry);
+ }
+ }
+ }
+ return 0;
+}
+
+static struct platform_driver tx2_uncore_driver = {
+ .driver = {
+ .name = "tx2-uncore-pmu",
+ .acpi_match_table = ACPI_PTR(tx2_uncore_acpi_match),
+ },
+ .probe = tx2_uncore_probe,
+ .remove = tx2_uncore_remove,
+};
+
+static int __init tx2_uncore_driver_init(void)
+{
+ int ret;
+
+ ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_TX2_UNCORE_ONLINE,
+ "perf/tx2/uncore:online",
+ tx2_uncore_pmu_online_cpu,
+ tx2_uncore_pmu_offline_cpu);
+ if (ret) {
+ pr_err("TX2 PMU: setup hotplug failed(%d)\n", ret);
+ return ret;
+ }
+ ret = platform_driver_register(&tx2_uncore_driver);
+ if (ret)
+ cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_TX2_UNCORE_ONLINE);
+
+ return ret;
+}
+module_init(tx2_uncore_driver_init);
+
+static void __exit tx2_uncore_driver_exit(void)
+{
+ platform_driver_unregister(&tx2_uncore_driver);
+ cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_TX2_UNCORE_ONLINE);
+}
+module_exit(tx2_uncore_driver_exit);
+
+MODULE_DESCRIPTION("ThunderX2 UNCORE PMU driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ganapatrao Kulkarni <gkulkarni@cavium.com>");
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index e0cd2baa8380..d50b711614f2 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -164,6 +164,7 @@ enum cpuhp_state {
CPUHP_AP_PERF_ARM_L2X0_ONLINE,
CPUHP_AP_PERF_ARM_QCOM_L2_ONLINE,
CPUHP_AP_PERF_ARM_QCOM_L3_ONLINE,
+ CPUHP_AP_PERF_ARM_TX2_UNCORE_ONLINE,
CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE,
CPUHP_AP_PERF_POWERPC_CORE_IMC_ONLINE,
CPUHP_AP_PERF_POWERPC_THREAD_IMC_ONLINE,
--
2.18.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH] arm64/mm: use correct operators for string comparison in cache.S
From: Will Deacon @ 2018-12-06 11:51 UTC (permalink / raw)
To: Ard Biesheuvel; +Cc: Catalin Marinas, Robin Murphy, linux-arm-kernel
In-Reply-To: <CAKv+Gu8=_PH1n2Z7QBNYpLMKAodo0GVWfzduo4UBdH_vmOnc1w@mail.gmail.com>
On Tue, Dec 04, 2018 at 01:44:01AM +0100, Ard Biesheuvel wrote:
> On Mon, 3 Dec 2018 at 19:10, Will Deacon <will.deacon@arm.com> wrote:
> >
> > On Mon, Dec 03, 2018 at 06:54:35PM +0100, Ard Biesheuvel wrote:
> > > On Mon, 3 Dec 2018 at 18:44, Will Deacon <will.deacon@arm.com> wrote:
> > > >
> > > > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > > > rely on assembler behavior that is not documented, and probably not
> > > > > > > guaranteed to produce the correct behavior going forward.
> > > > > > >
> > > > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > > > >
> > > > > > > $ nm arch/arm64/mm/cache.o
> > > > > > > ...
> > > > > > > U civac
> > > > > > > ...
> > > > > > > U cvac
> > > > > > > U cvap
> > > > > > > U cvau
> > > > > > >
> > > > > > > This is due to the fact that the comparisons used to select the
> > > > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > > > not strings, and even though it seems that GAS is doing the right
> > > > > > > thing here (undefined symbols by the same name are equal to each
> > > > > > > other), it seems unwise to rely on this.
> > > > > > >
> > > > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > > > and make them local so they don't pollute the gobal symbol space.
> > > > > >
> > > > > > Rather than making the unintended symbol comparisons work properly, can
> > > > > > we not just implement the string comparisons that were supposed to be?
> > > > > > Superficially, the diff below seems to still generate the desired output
> > > > > > (although as always there's probably some subtlety I'm missing).
> > > > > >
> > > > > > Robin.
> > > > > >
> > > > > > ----->8-----
> > > > > >
> > > > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > > > b/arch/arm64/include/asm/assembler.h
> > > > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > > > --- a/arch/arm64/include/asm/assembler.h
> > > > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > > > @@ -383,13 +383,13 @@ alternative_endif
> > > > > > sub \tmp2, \tmp1, #1
> > > > > > bic \kaddr, \kaddr, \tmp2
> > > > > > 9998:
> > > > > > - .if (\op == cvau || \op == cvac)
> > > > > > + .if ("\op" == "cvau" || "\op" == "cvac")
> > > > > > alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > > > > dc \op, \kaddr
> > > > > > alternative_else
> > > > > > dc civac, \kaddr
> > > > > > alternative_endif
> > > > > > - .elseif (\op == cvap)
> > > > > > + .elseif ("\op" == "cvap")
> > > > > > alternative_if ARM64_HAS_DCPOP
> > > > > > sys 3, c7, c12, 1, \kaddr // dc cvap
> > > > > > alternative_else
> > > > > >
> > > > >
> > > > > Looking at the GAS info pages, I find
> > > > >
> > > > > "Operators" are arithmetic functions, like '+' or '%'.
> > > > > "Arguments" are symbols, numbers or subexpressions.
> > > > > An "expression" specifies an address or numeric value.
> > > > >
> > > > > so even if the comparison works as expected, I'm hesitant to rely on
> > > > > it to work as expected on any version of GAS or any other assembler
> > > > > claiming to implement the GAS asm dialect.
> > > > >
> > > > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> > > >
> > > > That looks better to me, although I'm not sure why you're inverted the logic
> > > > here:
> > > >
> > > > > .ifnc \op, civac
> > > > > .ifnc \op, cvap
> > > >
> > > > What am I missing?
> > > >
> > >
> > > .ifc does not permit '\op equals string1 or \op equals string2'
> >
> > Thanks. Then I guess we invert the logic as you suggest, or we duplicate the
> > alternative code. Looking at this some more, I think what we currently have
> > is broken because on a system with ARM64_WORKAROUND_CLEAN_CACHE but not
> > ARM64_HAS_DCPOP, you'll get DC CVAC for __clean_dcache_area_pop, which
> > would be broken on that CPU.
> >
>
> Can we just fallback to civac instead? Or do we need to add logic to
> combine the two feature flags?
I guess this could introduce a performance regression for CPUs without
either DCPOP or ARM64_WORKAROUND_CLEAN_CACHE, since we're effectively
forcing a hefty cache miss on a subsequent access to the persisted data.
So I'd prefer not to make the CIVAC unconditional unless we have to.
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH V4 6/6] arm64: mm: Allow forcing all userspace addresses to 52-bit
From: Catalin Marinas @ 2018-12-06 11:51 UTC (permalink / raw)
To: Steve Capper; +Cc: linux-mm, ard.biesheuvel, will.deacon, linux-arm-kernel, jcm
In-Reply-To: <20181205164145.24568-7-steve.capper@arm.com>
On Wed, Dec 05, 2018 at 04:41:45PM +0000, Steve Capper wrote:
> On arm64 52-bit VAs are provided to userspace when a hint is supplied to
> mmap. This helps maintain compatibility with software that expects at
> most 48-bit VAs to be returned.
>
> In order to help identify software that has 48-bit VA assumptions, this
> patch allows one to compile a kernel where 52-bit VAs are returned by
> default on HW that supports it.
>
> This feature is intended to be for development systems only.
>
> Signed-off-by: Steve Capper <steve.capper@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH V4 4/6] arm64: mm: Offset TTBR1 to allow 52-bit PTRS_PER_PGD
From: Catalin Marinas @ 2018-12-06 11:50 UTC (permalink / raw)
To: Steve Capper; +Cc: linux-mm, ard.biesheuvel, will.deacon, linux-arm-kernel, jcm
In-Reply-To: <20181205164145.24568-5-steve.capper@arm.com>
On Wed, Dec 05, 2018 at 04:41:43PM +0000, Steve Capper wrote:
> diff --git a/arch/arm64/include/asm/asm-uaccess.h b/arch/arm64/include/asm/asm-uaccess.h
> index 4128bec033f6..cd361dd16b12 100644
> --- a/arch/arm64/include/asm/asm-uaccess.h
> +++ b/arch/arm64/include/asm/asm-uaccess.h
> @@ -14,11 +14,13 @@
> #ifdef CONFIG_ARM64_SW_TTBR0_PAN
> .macro __uaccess_ttbr0_disable, tmp1
> mrs \tmp1, ttbr1_el1 // swapper_pg_dir
> + restore_ttbr1 \tmp1
> bic \tmp1, \tmp1, #TTBR_ASID_MASK
> sub \tmp1, \tmp1, #RESERVED_TTBR0_SIZE // reserved_ttbr0 just before swapper_pg_dir
> msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1
> isb
> add \tmp1, \tmp1, #RESERVED_TTBR0_SIZE
> + offset_ttbr1 \tmp1
> msr ttbr1_el1, \tmp1 // set reserved ASID
> isb
> .endm
> @@ -27,8 +29,10 @@
> get_thread_info \tmp1
> ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1
> mrs \tmp2, ttbr1_el1
> + restore_ttbr1 \tmp2
> extr \tmp2, \tmp2, \tmp1, #48
> ror \tmp2, \tmp2, #16
> + offset_ttbr1 \tmp2
> msr ttbr1_el1, \tmp2 // set the active ASID
> isb
> msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1
The patch looks alright but I think we can simplify it further if we add:
depends on ARM64_PAN || !ARM64_SW_TTBR0_PAN
to the 52-bit Kconfig entry.
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2] media: remove bdisp_dbg_declare() and hva_dbg_declare()
From: Fabien DESSENNE @ 2018-12-06 11:49 UTC (permalink / raw)
To: Yangtao Li, kyungmin.park@samsung.com, s.nawrocki@samsung.com,
mchehab@kernel.org, kgene@kernel.org, krzk@kernel.org,
Jean Christophe TROTIN
Cc: linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-media@vger.kernel.org
In-Reply-To: <20181202020425.9189-1-tiny.windzz@gmail.com>
Hi,
The patch itself is OK, but the commit talks about bdisp & hva while the
patch is also for fimc-is.
Could you please update the commit header & messages?
BR
Fabien
On 02/12/2018 3:04 AM, Yangtao Li wrote:
> We already have the DEFINE_SHOW_ATTRIBUTE.There is no need to define
> bdisp_dbg_declare and hva_dbg_declare,so remove them.Also use
> DEFINE_SHOW_ATTRIBUTE to simplify some code.
>
> Signed-off-by: Yangtao Li <tiny.windzz@gmail.com>
> ---
> Changes in v2:
> -delete fimc_is_debugfs_open
> ---
> drivers/media/platform/exynos4-is/fimc-is.c | 16 ++-------
> .../media/platform/sti/bdisp/bdisp-debug.c | 34 ++++++------------
> drivers/media/platform/sti/hva/hva-debugfs.c | 36 +++++++------------
> 3 files changed, 26 insertions(+), 60 deletions(-)
>
> diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
> index f5fc54de19da..02da0b06e56a 100644
> --- a/drivers/media/platform/exynos4-is/fimc-is.c
> +++ b/drivers/media/platform/exynos4-is/fimc-is.c
> @@ -738,7 +738,7 @@ int fimc_is_hw_initialize(struct fimc_is *is)
> return 0;
> }
>
> -static int fimc_is_log_show(struct seq_file *s, void *data)
> +static int fimc_is_show(struct seq_file *s, void *data)
> {
> struct fimc_is *is = s->private;
> const u8 *buf = is->memory.vaddr + FIMC_IS_DEBUG_REGION_OFFSET;
> @@ -752,17 +752,7 @@ static int fimc_is_log_show(struct seq_file *s, void *data)
> return 0;
> }
>
> -static int fimc_is_debugfs_open(struct inode *inode, struct file *file)
> -{
> - return single_open(file, fimc_is_log_show, inode->i_private);
> -}
> -
> -static const struct file_operations fimc_is_debugfs_fops = {
> - .open = fimc_is_debugfs_open,
> - .read = seq_read,
> - .llseek = seq_lseek,
> - .release = single_release,
> -};
> +DEFINE_SHOW_ATTRIBUTE(fimc_is);
>
> static void fimc_is_debugfs_remove(struct fimc_is *is)
> {
> @@ -777,7 +767,7 @@ static int fimc_is_debugfs_create(struct fimc_is *is)
> is->debugfs_entry = debugfs_create_dir("fimc_is", NULL);
>
> dentry = debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry,
> - is, &fimc_is_debugfs_fops);
> + is, &fimc_is_fops);
> if (!dentry)
> fimc_is_debugfs_remove(is);
>
> diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c
> index c6a4e2de5c0c..77ca7517fa3e 100644
> --- a/drivers/media/platform/sti/bdisp/bdisp-debug.c
> +++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c
> @@ -315,7 +315,7 @@ static void bdisp_dbg_dump_ivmx(struct seq_file *s,
> seq_puts(s, "Unknown conversion\n");
> }
>
> -static int bdisp_dbg_last_nodes(struct seq_file *s, void *data)
> +static int last_nodes_show(struct seq_file *s, void *data)
> {
> /* Not dumping all fields, focusing on significant ones */
> struct bdisp_dev *bdisp = s->private;
> @@ -388,7 +388,7 @@ static int bdisp_dbg_last_nodes(struct seq_file *s, void *data)
> return 0;
> }
>
> -static int bdisp_dbg_last_nodes_raw(struct seq_file *s, void *data)
> +static int last_nodes_raw_show(struct seq_file *s, void *data)
> {
> struct bdisp_dev *bdisp = s->private;
> struct bdisp_node *node;
> @@ -437,7 +437,7 @@ static const char *bdisp_fmt_to_str(struct bdisp_frame frame)
> }
> }
>
> -static int bdisp_dbg_last_request(struct seq_file *s, void *data)
> +static int last_request_show(struct seq_file *s, void *data)
> {
> struct bdisp_dev *bdisp = s->private;
> struct bdisp_request *request = &bdisp->dbg.copy_request;
> @@ -474,7 +474,7 @@ static int bdisp_dbg_last_request(struct seq_file *s, void *data)
>
> #define DUMP(reg) seq_printf(s, #reg " \t0x%08X\n", readl(bdisp->regs + reg))
>
> -static int bdisp_dbg_regs(struct seq_file *s, void *data)
> +static int regs_show(struct seq_file *s, void *data)
> {
> struct bdisp_dev *bdisp = s->private;
> int ret;
> @@ -582,7 +582,7 @@ static int bdisp_dbg_regs(struct seq_file *s, void *data)
>
> #define SECOND 1000000
>
> -static int bdisp_dbg_perf(struct seq_file *s, void *data)
> +static int perf_show(struct seq_file *s, void *data)
> {
> struct bdisp_dev *bdisp = s->private;
> struct bdisp_request *request = &bdisp->dbg.copy_request;
> @@ -627,27 +627,15 @@ static int bdisp_dbg_perf(struct seq_file *s, void *data)
> return 0;
> }
>
> -#define bdisp_dbg_declare(name) \
> - static int bdisp_dbg_##name##_open(struct inode *i, struct file *f) \
> - { \
> - return single_open(f, bdisp_dbg_##name, i->i_private); \
> - } \
> - static const struct file_operations bdisp_dbg_##name##_fops = { \
> - .open = bdisp_dbg_##name##_open, \
> - .read = seq_read, \
> - .llseek = seq_lseek, \
> - .release = single_release, \
> - }
> -
> #define bdisp_dbg_create_entry(name) \
> debugfs_create_file(#name, S_IRUGO, bdisp->dbg.debugfs_entry, bdisp, \
> - &bdisp_dbg_##name##_fops)
> + &name##_fops)
>
> -bdisp_dbg_declare(regs);
> -bdisp_dbg_declare(last_nodes);
> -bdisp_dbg_declare(last_nodes_raw);
> -bdisp_dbg_declare(last_request);
> -bdisp_dbg_declare(perf);
> +DEFINE_SHOW_ATTRIBUTE(regs);
> +DEFINE_SHOW_ATTRIBUTE(last_nodes);
> +DEFINE_SHOW_ATTRIBUTE(last_nodes_raw);
> +DEFINE_SHOW_ATTRIBUTE(last_request);
> +DEFINE_SHOW_ATTRIBUTE(perf);
>
> int bdisp_debugfs_create(struct bdisp_dev *bdisp)
> {
> diff --git a/drivers/media/platform/sti/hva/hva-debugfs.c b/drivers/media/platform/sti/hva/hva-debugfs.c
> index 9f7e8ac875d1..7d12a5b5d914 100644
> --- a/drivers/media/platform/sti/hva/hva-debugfs.c
> +++ b/drivers/media/platform/sti/hva/hva-debugfs.c
> @@ -271,7 +271,7 @@ static void hva_dbg_perf_compute(struct hva_ctx *ctx)
> * device debug info
> */
>
> -static int hva_dbg_device(struct seq_file *s, void *data)
> +static int device_show(struct seq_file *s, void *data)
> {
> struct hva_dev *hva = s->private;
>
> @@ -281,7 +281,7 @@ static int hva_dbg_device(struct seq_file *s, void *data)
> return 0;
> }
>
> -static int hva_dbg_encoders(struct seq_file *s, void *data)
> +static int encoders_show(struct seq_file *s, void *data)
> {
> struct hva_dev *hva = s->private;
> unsigned int i = 0;
> @@ -299,7 +299,7 @@ static int hva_dbg_encoders(struct seq_file *s, void *data)
> return 0;
> }
>
> -static int hva_dbg_last(struct seq_file *s, void *data)
> +static int last_show(struct seq_file *s, void *data)
> {
> struct hva_dev *hva = s->private;
> struct hva_ctx *last_ctx = &hva->dbg.last_ctx;
> @@ -316,7 +316,7 @@ static int hva_dbg_last(struct seq_file *s, void *data)
> return 0;
> }
>
> -static int hva_dbg_regs(struct seq_file *s, void *data)
> +static int regs_show(struct seq_file *s, void *data)
> {
> struct hva_dev *hva = s->private;
>
> @@ -325,26 +325,14 @@ static int hva_dbg_regs(struct seq_file *s, void *data)
> return 0;
> }
>
> -#define hva_dbg_declare(name) \
> - static int hva_dbg_##name##_open(struct inode *i, struct file *f) \
> - { \
> - return single_open(f, hva_dbg_##name, i->i_private); \
> - } \
> - static const struct file_operations hva_dbg_##name##_fops = { \
> - .open = hva_dbg_##name##_open, \
> - .read = seq_read, \
> - .llseek = seq_lseek, \
> - .release = single_release, \
> - }
> -
> #define hva_dbg_create_entry(name) \
> debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
> - &hva_dbg_##name##_fops)
> + &name##_fops)
>
> -hva_dbg_declare(device);
> -hva_dbg_declare(encoders);
> -hva_dbg_declare(last);
> -hva_dbg_declare(regs);
> +DEFINE_SHOW_ATTRIBUTE(device);
> +DEFINE_SHOW_ATTRIBUTE(encoders);
> +DEFINE_SHOW_ATTRIBUTE(last);
> +DEFINE_SHOW_ATTRIBUTE(regs);
>
> void hva_debugfs_create(struct hva_dev *hva)
> {
> @@ -380,7 +368,7 @@ void hva_debugfs_remove(struct hva_dev *hva)
> * context (instance) debug info
> */
>
> -static int hva_dbg_ctx(struct seq_file *s, void *data)
> +static int ctx_show(struct seq_file *s, void *data)
> {
> struct hva_ctx *ctx = s->private;
>
> @@ -392,7 +380,7 @@ static int hva_dbg_ctx(struct seq_file *s, void *data)
> return 0;
> }
>
> -hva_dbg_declare(ctx);
> +DEFINE_SHOW_ATTRIBUTE(ctx);
>
> void hva_dbg_ctx_create(struct hva_ctx *ctx)
> {
> @@ -407,7 +395,7 @@ void hva_dbg_ctx_create(struct hva_ctx *ctx)
>
> ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444,
> hva->dbg.debugfs_entry,
> - ctx, &hva_dbg_ctx_fops);
> + ctx, &ctx_fops);
> }
>
> void hva_dbg_ctx_remove(struct hva_ctx *ctx)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] arm64/mm: use correct operators for string comparison in cache.S
From: Ard Biesheuvel @ 2018-12-06 11:47 UTC (permalink / raw)
To: Dave Martin; +Cc: Catalin Marinas, Will Deacon, Robin Murphy, linux-arm-kernel
In-Reply-To: <20181206112026.GV3505@e103592.cambridge.arm.com>
On Thu, 6 Dec 2018 at 12:20, Dave Martin <Dave.Martin@arm.com> wrote:
>
> On Mon, Dec 03, 2018 at 05:45:06PM +0000, Will Deacon wrote:
> > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > rely on assembler behavior that is not documented, and probably not
> > > > > guaranteed to produce the correct behavior going forward.
> > > > >
> > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > >
> > > > > $ nm arch/arm64/mm/cache.o
> > > > > ...
> > > > > U civac
> > > > > ...
> > > > > U cvac
> > > > > U cvap
> > > > > U cvau
> > > > >
> > > > > This is due to the fact that the comparisons used to select the
> > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > not strings, and even though it seems that GAS is doing the right
> > > > > thing here (undefined symbols by the same name are equal to each
> > > > > other), it seems unwise to rely on this.
> > > > >
> > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > and make them local so they don't pollute the gobal symbol space.
> > > >
> > > > Rather than making the unintended symbol comparisons work properly, can
> > > > we not just implement the string comparisons that were supposed to be?
> > > > Superficially, the diff below seems to still generate the desired output
> > > > (although as always there's probably some subtlety I'm missing).
> > > >
> > > > Robin.
> > > >
> > > > ----->8-----
> > > >
> > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > b/arch/arm64/include/asm/assembler.h
> > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > --- a/arch/arm64/include/asm/assembler.h
> > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > @@ -383,13 +383,13 @@ alternative_endif
> > > > sub \tmp2, \tmp1, #1
> > > > bic \kaddr, \kaddr, \tmp2
> > > > 9998:
> > > > - .if (\op == cvau || \op == cvac)
> > > > + .if ("\op" == "cvau" || "\op" == "cvac")
> > > > alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > > dc \op, \kaddr
> > > > alternative_else
> > > > dc civac, \kaddr
> > > > alternative_endif
> > > > - .elseif (\op == cvap)
> > > > + .elseif ("\op" == "cvap")
>
> (Whatever this looks like, it's still comparing symbols someone probably
> already pointed that out. Oh, and the () are redundant. This isn't C,
> but, meh.)
>
> > > > alternative_if ARM64_HAS_DCPOP
> > > > sys 3, c7, c12, 1, \kaddr // dc cvap
> > > > alternative_else
> > > >
> > >
> > > Looking at the GAS info pages, I find
> > >
> > > "Operators" are arithmetic functions, like '+' or '%'.
> > > "Arguments" are symbols, numbers or subexpressions.
> > > An "expression" specifies an address or numeric value.
> > >
> > > so even if the comparison works as expected, I'm hesitant to rely on
> > > it to work as expected on any version of GAS or any other assembler
> > > claiming to implement the GAS asm dialect.
> > >
> > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> >
> > That looks better to me, although I'm not sure why you're inverted the logic
> > here:
> >
> > > .ifnc \op, civac
> > > .ifnc \op, cvap
> >
> > What am I missing?
>
> I vote for the .ifc approach.
>
> Note, the current works-by-accident approach using == has the odd side-
> effect of spitting out undefined symbol references in the .o file. It
> seems that isn't breaking the link, but I wonder whether there are any
> side-effects we're not aware of.
>
Did you read the commit log at all? :-)
> If we don't like the inverted logic, there is always
>
> .set .L__foo_\@, 0
> .ifc \op, civac
> .set .L__foo_\@, 1
> .endif
> .ifc \op, cvap
> .set .L__foo_\@, 1
> .endif
>
> .if .L__foo_\@
> // ...
> .endif
>
> which is ugly. Either way, the logic could be wrapped as a helper:
>
> .macro if_string_is_either str, cmp1, cmp2, insn:vararg
> .ifnc "\str","\cmp1"
> .ifnc "\str","\cmp2"
> .exitm
> .endif
> .endif
>
> \insn
> .endm
>
Yeah, I don't think this is an improvement over using inverted logic.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 5/5] irqchip/irq-imx-gpcv2: Add support for i.MX8MQ
From: Lucas Stach @ 2018-12-06 11:36 UTC (permalink / raw)
To: Andrey Smirnov, Marc Zyngier
Cc: A.s. Dong, Richard Zhu, Jason Cooper, linux-kernel, linux-imx,
Thomas Gleixner, Leonard Crestez, cphealy, linux-arm-kernel
In-Reply-To: <20181206073125.7255-6-andrew.smirnov@gmail.com>
Am Mittwoch, den 05.12.2018, 23:31 -0800 schrieb Andrey Smirnov:
> Add code needed to support i.MX8MQ.
>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Jason Cooper <jason@lakedaemon.net>
> > Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: cphealy@gmail.com
> Cc: l.stach@pengutronix.de
> > Cc: Leonard Crestez <leonard.crestez@nxp.com>
> > Cc: "A.s. Dong" <aisheng.dong@nxp.com>
> > Cc: Richard Zhu <hongxing.zhu@nxp.com>
> Cc: linux-imx@nxp.com
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
> drivers/irqchip/irq-imx-gpcv2.c | 31 +++++++++++++++++++++++++++++--
> 1 file changed, 29 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
> index c2b2b3128ddd..17a2dad2d4c2 100644
> --- a/drivers/irqchip/irq-imx-gpcv2.c
> +++ b/drivers/irqchip/irq-imx-gpcv2.c
> @@ -17,6 +17,9 @@
>
> > #define GPC_IMR1_CORE0 0x30
> > #define GPC_IMR1_CORE1 0x40
> > +#define GPC_IMR1_CORE2 0x1c0
> > +#define GPC_IMR1_CORE3 0x1d0
> +
>
> struct gpcv2_irqchip_data {
> > > struct raw_spinlock rlock;
> @@ -192,11 +195,19 @@ static const struct irq_domain_ops gpcv2_irqchip_data_domain_ops = {
> > > .free = irq_domain_free_irqs_common,
> };
>
> +static const struct of_device_id gpcv2_of_match[] = {
> > + { .compatible = "fsl,imx7d-gpc", .data = (const void *) 2 },
> > + { .compatible = "fsl,imx8mq-gpc", .data = (const void *) 4 },
> > + { /* END */ }
> +};
> +
> static int __init imx_gpcv2_irqchip_init(struct device_node *node,
> > struct device_node *parent)
> {
> > struct irq_domain *parent_domain, *domain;
> > struct gpcv2_irqchip_data *cd;
> > + const struct of_device_id *id;
> > + unsigned long core_num;
> > int i;
>
> > if (!parent) {
> @@ -204,6 +215,14 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
> > return -ENODEV;
> > }
>
> > + id = of_match_node(gpcv2_of_match, node);
> > + if (!id) {
> > + pr_err("%pOF: unknown compatibility string\n", node);
> > + return -ENODEV;
> > + }
> +
> > + core_num = (unsigned long)id->data;
> +
> > parent_domain = irq_find_host(parent);
> > if (!parent_domain) {
> > pr_err("%pOF: unable to get parent domain\n", node);
> @@ -236,8 +255,16 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
>
> > /* Initially mask all interrupts */
> > for (i = 0; i < IMR_NUM; i++) {
> > - writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE0 + i * 4);
> > - writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE1 + i * 4);
> > + void __iomem *reg = cd->gpc_base + i * 4;
> +
> > + switch (core_num) {
> > + case 4:
> > + writel_relaxed(~0, reg + GPC_IMR1_CORE2);
> > + writel_relaxed(~0, reg + GPC_IMR1_CORE3);
> > > + case 2: /* FALLTHROUGH */
> > + writel_relaxed(~0, reg + GPC_IMR1_CORE0);
> > + writel_relaxed(~0, reg + GPC_IMR1_CORE1);
> + }
The writes being not being in linear descending core order does trigger
something in me, but obviously this doesn't has any effect on the code,
so:
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> cd->wakeup_sources[i] = ~0;
> > }
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 4/5] irqchip/irq-imx-gpcv2: Make error messages more consistent
From: Lucas Stach @ 2018-12-06 11:32 UTC (permalink / raw)
To: Andrey Smirnov, Marc Zyngier
Cc: A.s. Dong, Richard Zhu, Jason Cooper, linux-kernel, linux-imx,
Thomas Gleixner, Leonard Crestez, cphealy, linux-arm-kernel
In-Reply-To: <20181206073125.7255-5-andrew.smirnov@gmail.com>
Am Mittwoch, den 05.12.2018, 23:31 -0800 schrieb Andrey Smirnov:
> Make error messages more consistent by making sure each starts with
> "%pOF:".
>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Jason Cooper <jason@lakedaemon.net>
> > Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: cphealy@gmail.com
> Cc: l.stach@pengutronix.de
> > Cc: Leonard Crestez <leonard.crestez@nxp.com>
> > Cc: "A.s. Dong" <aisheng.dong@nxp.com>
> > Cc: Richard Zhu <hongxing.zhu@nxp.com>
> Cc: linux-imx@nxp.com
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> ---
> drivers/irqchip/irq-imx-gpcv2.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
> index 077d56b3183a..c2b2b3128ddd 100644
> --- a/drivers/irqchip/irq-imx-gpcv2.c
> +++ b/drivers/irqchip/irq-imx-gpcv2.c
> @@ -212,7 +212,7 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
>
> > cd = kzalloc(sizeof(struct gpcv2_irqchip_data), GFP_KERNEL);
> > if (!cd) {
> > - pr_err("kzalloc failed!\n");
> > + pr_err("%pOF: kzalloc failed!\n", node);
> > return -ENOMEM;
> > }
>
> @@ -220,7 +220,7 @@ static int __init imx_gpcv2_irqchip_init(struct device_node *node,
>
> > cd->gpc_base = of_iomap(node, 0);
> > if (!cd->gpc_base) {
> > - pr_err("fsl-gpcv2: unable to map gpc registers\n");
> > + pr_err("%pOF: unable to map gpc registers\n", node);
> > kfree(cd);
> > return -ENOMEM;
> > }
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* RE: [v11 1/7] dmaengine: fsldma: Replace DMA_IN/OUT by FSL_DMA_IN/OUT
From: Peng Ma @ 2018-12-06 11:24 UTC (permalink / raw)
To: Vinod Koul
Cc: mark.rutland@arm.com, devicetree@vger.kernel.org, Wen He,
linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
Leo Li, zw@zh-kernel.org, robh+dt@kernel.org,
dmaengine@vger.kernel.org, dan.j.williams@intel.com,
shawnguo@kernel.org, linux-arm-kernel@lists.infradead.org
In-Reply-To: <20181205174923.GU2847@vkoul-mobl>
Hi Vinod,
Thanks for your apply, I have finished update DTS patch, please review.
Best Regards,
Peng
>-----Original Message-----
>From: Vinod Koul <vkoul@kernel.org>
>Sent: 2018年12月6日 1:49
>To: Peng Ma <peng.ma@nxp.com>
>Cc: robh+dt@kernel.org; mark.rutland@arm.com; shawnguo@kernel.org; Leo
>Li <leoyang.li@nxp.com>; dan.j.williams@intel.com; zw@zh-kernel.org;
>dmaengine@vger.kernel.org; devicetree@vger.kernel.org;
>linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
>linuxppc-dev@lists.ozlabs.org; Wen He <wen.he_1@nxp.com>
>Subject: Re: [v11 1/7] dmaengine: fsldma: Replace DMA_IN/OUT by
>FSL_DMA_IN/OUT
>
>On 30-10-18, 10:35, Peng Ma wrote:
>> From: Wen He <wen.he_1@nxp.com>
>>
>> This patch implement a standard macro call functions is used to NXP
>> dma drivers.
>
>Applied all except DTS patches, thanks
>--
>~Vinod
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 2/3] arm64: dts: ls1043a: add qdma device tree nodes
From: Peng Ma @ 2018-12-06 11:18 UTC (permalink / raw)
To: vkoul, shawnguo
Cc: mark.rutland, devicetree, Wen He, Peng Ma, linux-kernel,
leoyang.li, robh+dt, linux-arm-kernel
In-Reply-To: <20181206111823.45985-1-peng.ma@nxp.com>
add the qDMA device tree nodes for LS1043A devices.
Signed-off-by: Wen He <wen.he_1@nxp.com>
Signed-off-by: Peng Ma <peng.ma@nxp.com>
---
change in v12:
- used GIC_SPI and IRQ_TYPE_LEVEL_HIGH to instead immediate
number
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index 3fed504..23b78df 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -734,6 +734,28 @@
<0000 0 0 3 &gic 0 156 0x4>,
<0000 0 0 4 &gic 0 157 0x4>;
};
+
+ qdma: dma-controller@8380000 {
+ compatible = "fsl,ls1021a-qdma", "fsl,ls1043a-qdma";
+ reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */
+ <0x0 0x8390000 0x0 0x10000>, /* Status regs */
+ <0x0 0x83a0000 0x0 0x40000>; /* Block regs */
+ interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "qdma-error", "qdma-queue0",
+ "qdma-queue1", "qdma-queue2", "qdma-queue3";
+ dma-channels = <8>;
+ block-number = <1>;
+ block-offset = <0x10000>;
+ fsl,dma-queues = <2>;
+ status-sizes = <64>;
+ queue-sizes = <64 64>;
+ big-endian;
+ };
+
};
firmware {
--
1.7.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 3/3] arm64: dts: ls1046a: add qdma device tree nodes
From: Peng Ma @ 2018-12-06 11:18 UTC (permalink / raw)
To: vkoul, shawnguo
Cc: mark.rutland, devicetree, Wen He, Peng Ma, linux-kernel,
leoyang.li, robh+dt, linux-arm-kernel
In-Reply-To: <20181206111823.45985-1-peng.ma@nxp.com>
add the qDMA device tree nodes for LS1046A devices.
Signed-off-by: Wen He <wen.he_1@nxp.com>
Signed-off-by: Peng Ma <peng.ma@nxp.com>
---
change in v12:
- used GIC_SPI and IRQ_TYPE_LEVEL_HIGH to instead immediate
number
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 51cbd50..8fcce79 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -704,6 +704,27 @@
<0000 0 0 4 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
};
+ qdma: dma-controller@8380000 {
+ compatible = "fsl,ls1046a-qdma", "fsl,ls1021a-qdma";
+ reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */
+ <0x0 0x8390000 0x0 0x10000>, /* Status regs */
+ <0x0 0x83a0000 0x0 0x40000>; /* Block regs */
+ interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "qdma-error", "qdma-queue0",
+ "qdma-queue1", "qdma-queue2", "qdma-queue3";
+ dma-channels = <8>;
+ block-number = <1>;
+ block-offset = <0x10000>;
+ fsl,dma-queues = <2>;
+ status-sizes = <64>;
+ queue-sizes = <64 64>;
+ big-endian;
+ };
+
};
reserved-memory {
--
1.7.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [v12 1/3] arm: dts: ls1021a: add qdma device tree nodes
From: Peng Ma @ 2018-12-06 11:18 UTC (permalink / raw)
To: vkoul, shawnguo
Cc: mark.rutland, devicetree, Wen He, Peng Ma, linux-kernel,
leoyang.li, robh+dt, linux-arm-kernel
add the qDMA device tree nodes for LS1021A devices.
Signed-off-by: Wen He <wen.he_1@nxp.com>
Signed-off-by: Peng Ma <peng.ma@nxp.com>
---
change in v12:
- no
arch/arm/boot/dts/ls1021a.dtsi | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index bdd6e66..b3d7807 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -812,5 +812,25 @@
#size-cells = <1>;
ranges = <0x0 0x0 0x10010000 0x10000>;
};
+
+ qdma: dma-controller@8390000 {
+ compatible = "fsl,ls1021a-qdma";
+ reg = <0x0 0x8388000 0x0 0x1000>, /* Controller regs */
+ <0x0 0x8389000 0x0 0x1000>, /* Status regs */
+ <0x0 0x838a000 0x0 0x2000>; /* Block regs */
+ interrupts = <GIC_SPI 185 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "qdma-error",
+ "qdma-queue0", "qdma-queue1";
+ dma-channels = <8>;
+ block-number = <1>;
+ block-offset = <0x1000>;
+ fsl,dma-queues = <2>;
+ status-sizes = <64>;
+ queue-sizes = <64 64>;
+ big-endian;
+ };
+
};
};
--
1.7.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox