The invalid_io file is read-only and specifies the number of
non-page-size-aligned I/O requests issued to this device.
+What: /sys/block/zram<id>/failed_reads
+Date: February 2014
+Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+ The failed_reads file is read-only and specifies the number of
+ failed reads happened on this device.
+
+What: /sys/block/zram<id>/failed_writes
+Date: February 2014
+Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+ The failed_writes file is read-only and specifies the number of
+ failed writes happened on this device.
+
+What: /sys/block/zram<id>/max_comp_streams
+Date: February 2014
+Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+ The max_comp_streams file is read-write and specifies the
+ number of backend's zcomp_strm compression streams (number of
+ concurrent compress operations).
+
+What: /sys/block/zram<id>/comp_algorithm
+Date: February 2014
+Contact: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+ The comp_algorithm file is read-write and lets to show
+ available and selected compression algorithms, change
+ compression algorithm selection.
+
What: /sys/block/zram<id>/notify_free
Date: August 2010
Contact: Nitin Gupta <ngupta@vflare.org>
Description:
- The notify_free file is read-only and specifies the number of
- swap slot free notifications received by this device. These
- notifications are send to a swap block device when a swap slot
- is freed. This statistic is applicable only when this disk is
- being used as a swap disk.
+ The notify_free file is read-only. Depending on device usage
+ scenario it may account a) the number of pages freed because
+ of swap slot free notifications or b) the number of pages freed
+ because of REQ_DISCARD requests sent by bio. The former ones
+ are sent to a swap block device when a swap slot is freed, which
+ implies that this disk is being used as a swap disk. The latter
+ ones are sent by filesystem mounted with discard option,
+ whenever some data blocks are getting discarded.
What: /sys/block/zram<id>/discard
Date: August 2010
efficiency can be calculated using compr_data_size and this
statistic.
Unit: bytes
+
+What: /sys/block/zram<id>/mem_used_max
+Date: August 2014
+Contact: Minchan Kim <minchan@kernel.org>
+Description:
+ The mem_used_max file is read/write and specifies the amount
+ of maximum memory zram have consumed to store compressed data.
+ For resetting the value, you should write "0". Otherwise,
+ you could see -EINVAL.
+ Unit: bytes
+
+What: /sys/block/zram<id>/mem_limit
+Date: August 2014
+Contact: Minchan Kim <minchan@kernel.org>
+Description:
+ The mem_limit file is read/write and specifies the maximum
+ amount of memory ZRAM can use to store the compressed data. The
+ limit could be changed in run time and "0" means disable the
+ limit. No limit is the initial state. Unit: bytes
--- /dev/null
+zram: Compressed RAM based block devices
+----------------------------------------
+
+* Introduction
+
+The zram module creates RAM based block devices named /dev/zram<id>
+(<id> = 0, 1, ...). Pages written to these disks are compressed and stored
+in memory itself. These disks allow very fast I/O and compression provides
+good amounts of memory savings. Some of the usecases include /tmp storage,
+use as swap disks, various caches under /var and maybe many more :)
+
+Statistics for individual zram devices are exported through sysfs nodes at
+/sys/block/zram<id>/
+
+* Usage
+
+Following shows a typical sequence of steps for using zram.
+
+1) Load Module:
+ modprobe zram num_devices=4
+ This creates 4 devices: /dev/zram{0,1,2,3}
+ (num_devices parameter is optional. Default: 1)
+
+2) Set max number of compression streams
+ Compression backend may use up to max_comp_streams compression streams,
+ thus allowing up to max_comp_streams concurrent compression operations.
+ By default, compression backend uses single compression stream.
+
+ Examples:
+ #show max compression streams number
+ cat /sys/block/zram0/max_comp_streams
+
+ #set max compression streams number to 3
+ echo 3 > /sys/block/zram0/max_comp_streams
+
+Note:
+In order to enable compression backend's multi stream support max_comp_streams
+must be initially set to desired concurrency level before ZRAM device
+initialisation. Once the device initialised as a single stream compression
+backend (max_comp_streams equals to 1), you will see error if you try to change
+the value of max_comp_streams because single stream compression backend
+implemented as a special case by lock overhead issue and does not support
+dynamic max_comp_streams. Only multi stream backend supports dynamic
+max_comp_streams adjustment.
+
+3) Select compression algorithm
+ Using comp_algorithm device attribute one can see available and
+ currently selected (shown in square brackets) compression algortithms,
+ change selected compression algorithm (once the device is initialised
+ there is no way to change compression algorithm).
+
+ Examples:
+ #show supported compression algorithms
+ cat /sys/block/zram0/comp_algorithm
+ lzo [lz4]
+
+ #select lzo compression algorithm
+ echo lzo > /sys/block/zram0/comp_algorithm
+
+4) Set Disksize
+ Set disk size by writing the value to sysfs node 'disksize'.
+ The value can be either in bytes or you can use mem suffixes.
+ Examples:
+ # Initialize /dev/zram0 with 50MB disksize
+ echo $((50*1024*1024)) > /sys/block/zram0/disksize
+
+ # Using mem suffixes
+ echo 256K > /sys/block/zram0/disksize
+ echo 512M > /sys/block/zram0/disksize
+ echo 1G > /sys/block/zram0/disksize
+
+Note:
+There is little point creating a zram of greater than twice the size of memory
+since we expect a 2:1 compression ratio. Note that zram uses about 0.1% of the
+size of the disk when not in use so a huge zram is wasteful.
+
+5) Set memory limit: Optional
+ Set memory limit by writing the value to sysfs node 'mem_limit'.
+ The value can be either in bytes or you can use mem suffixes.
+ In addition, you could change the value in runtime.
+ Examples:
+ # limit /dev/zram0 with 50MB memory
+ echo $((50*1024*1024)) > /sys/block/zram0/mem_limit
+
+ # Using mem suffixes
+ echo 256K > /sys/block/zram0/mem_limit
+ echo 512M > /sys/block/zram0/mem_limit
+ echo 1G > /sys/block/zram0/mem_limit
+
+ # To disable memory limit
+ echo 0 > /sys/block/zram0/mem_limit
+
+6) Activate:
+ mkswap /dev/zram0
+ swapon /dev/zram0
+
+ mkfs.ext4 /dev/zram1
+ mount /dev/zram1 /tmp
+
+7) Stats:
+ Per-device statistics are exported as various nodes under
+ /sys/block/zram<id>/
+ disksize
+ num_reads
+ num_writes
+ invalid_io
+ notify_free
+ discard
+ zero_pages
+ orig_data_size
+ compr_data_size
+ mem_used_total
+ mem_used_max
+
+8) Deactivate:
+ swapoff /dev/zram0
+ umount /dev/zram1
+
+9) Reset:
+ Write any positive value to 'reset' sysfs node
+ echo 1 > /sys/block/zram0/reset
+ echo 1 > /sys/block/zram1/reset
+
+ This frees all the memory allocated for the given device and
+ resets the disksize to zero. You must set the disksize again
+ before reusing the device.
+
+Nitin Gupta
+ngupta@vflare.org
80 81 68 69
70 71 72 73
74 75 76 77>;
- interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty",
+ interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty",
"saif0", "saif1", "i2c0", "i2c1",
"auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
"auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";
VERSION = 3
PATCHLEVEL = 10
-SUBLEVEL = 74
+SUBLEVEL = 79
EXTRAVERSION =
NAME = TOSSUG Baby Fish
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_ARMV7_COMPAT=y
CONFIG_ASHMEM=y
+CONFIG_AUDIT=y
CONFIG_BLK_DEV_DM=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_CGROUPS=y
CONFIG_IP_NF_MATCH_ECN=y
CONFIG_IP_NF_MATCH_TTL=y
CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_NETFILTER_XT_MATCH_U32=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_TRACE=y
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
CONFIG_NF_CONNTRACK_PPTP=y
CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
CONFIG_NF_CT_PROTO_DCCP=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_RTC_CLASS=y
CONFIG_RT_GROUP_SCHED=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SND=y
+CONFIG_SOUND=y
CONFIG_STAGING=y
CONFIG_SWITCH=y
CONFIG_SYNC=y
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
/* Don't restart from sigreturn */
syscall_wont_restart(regs);
+ /*
+ * Ensure that sigreturn always returns to user mode (in case the
+ * regs saved on user stack got fudged between save and sigreturn)
+ * Otherwise it is easy to panic the kernel with a custom
+ * signal handler and/or restorer which clobberes the status32/ret
+ * to return to a bogus location in kernel mode.
+ */
+ regs->status32 |= STATUS_U_MASK;
+
return regs->r0;
badframe:
/*
* handler returns using sigreturn stub provided already by userpsace
+ * If not, nuke the process right away
*/
- BUG_ON(!(ka->sa.sa_flags & SA_RESTORER));
+ if(!(ka->sa.sa_flags & SA_RESTORER))
+ return 1;
+
regs->blink = (unsigned long)ka->sa.sa_restorer;
/* User Stack for signal handler will be above the frame just carved */
struct pt_regs *regs)
{
sigset_t *oldset = sigmask_to_save();
- int ret;
+ int failed;
/* Set up the stack frame */
- ret = setup_rt_frame(sig, ka, info, oldset, regs);
+ failed = setup_rt_frame(sig, ka, info, oldset, regs);
- if (ret)
+ if (failed)
force_sigsegv(sig, current);
else
signal_delivered(sig, info, ka, regs, 0);
/* TBD: switch to pagefault_out_of_memory() */
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
0xf0000000 0 0xf0000000 0x8000000 /* Device Bus, NOR 128MiB */>;
internal-regs {
+ rtc@10300 {
+ /* No crystal connected to the internal RTC */
+ status = "disabled";
+ };
serial@12000 {
clock-frequency = <250000000>;
status = "okay";
uart2: serial@12200 {
compatible = "ns16550a";
- reg = <0x12000 0x100>;
+ reg = <0x12200 0x100>;
reg-shift = <2>;
interrupts = <9>;
clocks = <&core_clk 0>;
uart3: serial@12300 {
compatible = "ns16550a";
- reg = <0x12100 0x100>;
+ reg = <0x12300 0x100>;
reg-shift = <2>;
interrupts = <10>;
clocks = <&core_clk 0>;
<1 14 0xf08>,
<1 11 0xf08>,
<1 10 0xf08>;
+ /* Unfortunately we need this since some versions of U-Boot
+ * on Exynos don't set the CNTFRQ register, so we need the
+ * value from DT.
+ */
+ clock-frequency = <24000000>;
};
combiner:interrupt-controller@10440000 {
ahb@80080000 {
usb0: usb@80080000 {
+ dr_mode = "host";
vbus-supply = <®_usb0_vbus>;
status = "okay";
};
pwm4: pwm@53fc8000 {
compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
+ #pwm-cells = <2>;
reg = <0x53fc8000 0x4000>;
clocks = <&clks 108>, <&clks 52>;
clock-names = "ipg", "per";
80 81 68 69
70 71 72 73
74 75 76 77>;
- interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty",
+ interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty",
"saif0", "saif1", "i2c0", "i2c1",
"auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
"auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
-#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
/* When the program starts, a1 contains a pointer to a function to be
registered with atexit, as per the SVR4 ABI. A value of 0 means we
#include <linux/gpio.h>
#define GLENFARCLAS_PMIC_IRQ_BASE IRQ_BOARD_START
+#define BANFF_PMIC_IRQ_BASE (IRQ_BOARD_START + 64)
#define PCA935X_GPIO_BASE GPIO_BOARD_START
#define CODEC_GPIO_BASE (GPIO_BOARD_START + 8)
static struct wm831x_pdata crag_pmic_pdata = {
.wm831x_num = 1,
+ .irq_base = BANFF_PMIC_IRQ_BASE,
.gpio_base = BANFF_PMIC_GPIO_BASE,
.soft_shutdown = true,
menu "Kernel Features"
+menu "ARM errata workarounds"
+
+config ARM64_ERRATUM_845719
+ bool "Cortex-A53: 845719: a load might read incorrect data"
+ depends on COMPAT
+ default n
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 845719 on Cortex-A53 parts up to r0p4.
+
+ When running a compat (AArch32) userspace on an affected Cortex-A53
+ part, a load at EL0 from a virtual address that matches the bottom 32
+ bits of the virtual address used by a recent load at (AArch64) EL1
+ might return incorrect data.
+
+ The workaround is to write the contextidr_el1 register on exception
+ return to a 32-bit task.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+endmenu
+
+
config ARM64_64K_PAGES
bool "Enable 64KB pages support"
help
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
- hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \
+ hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o return_address.o \
opcodes.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
.if \el == 0
ldr x23, [sp, #S_SP] // load return stack pointer
+#ifdef CONFIG_ARM64_ERRATUM_845719
+ tbz x22, #4, 1f
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+ mrs x29, contextidr_el1
+ msr contextidr_el1, x29
+1:
+#else
+ msr contextidr_el1, xzr
+1:
+#endif
+#endif
.endif
.if \ret
ldr x1, [sp, #S_X1] // preserve x0 (syscall return)
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2015 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/linkage.h>
+
+/* int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_hvc)
+ hvc #0
+ ret
+ENDPROC(__invoke_psci_fn_hvc)
+
+/* int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
+ENTRY(__invoke_psci_fn_smc)
+ smc #0
+ ret
+ENDPROC(__invoke_psci_fn_smc)
static int (*invoke_psci_fn)(u64, u64, u64, u64);
typedef int (*psci_initcall_t)(const struct device_node *);
+asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64);
+asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64);
+
enum psci_function {
PSCI_FN_CPU_SUSPEND,
PSCI_FN_CPU_ON,
PSCI_0_2_POWER_STATE_AFFL_SHIFT;
}
-/*
- * The following two functions are invoked via the invoke_psci_fn pointer
- * and will not be inlined, allowing us to piggyback on the AAPCS.
- */
-static noinline int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1,
- u64 arg2)
-{
- asm volatile(
- __asmeq("%0", "x0")
- __asmeq("%1", "x1")
- __asmeq("%2", "x2")
- __asmeq("%3", "x3")
- "hvc #0\n"
- : "+r" (function_id)
- : "r" (arg0), "r" (arg1), "r" (arg2));
-
- return function_id;
-}
-
-static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
- u64 arg2)
-{
- asm volatile(
- __asmeq("%0", "x0")
- __asmeq("%1", "x1")
- __asmeq("%2", "x2")
- __asmeq("%3", "x3")
- "smc #0\n"
- : "+r" (function_id)
- : "r" (arg0), "r" (arg1), "r" (arg2));
-
- return function_id;
-}
-
static int psci_get_version(void)
{
int err;
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT;
}
-void time_init(void)
+void __init time_init(void)
{
u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT;
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
*/
if (fault & VM_FAULT_OOM) {
goto out_of_memory;
+ } else if (fault & VM_FAULT_SIGSEGV) {
+ goto bad_area;
} else if (fault & VM_FAULT_SIGBUS) {
signal = SIGBUS;
goto bad_area;
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto map_err;
else if (fault & VM_FAULT_SIGBUS)
goto bus_err;
BUG();
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
+++ /dev/null
-#ifndef __ASM_SUSPEND_H
-#define __ASM_SUSPEND_H
-
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
-
-#endif /* __ASM_SUSPEND_H */
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
* Author: Hu Hongbing <huhb@lemote.com>
* Wu Zhangjin <wuzhangjin@gmail.com>
*/
-#include <asm/suspend.h>
+#include <asm/sections.h>
#include <asm/fpu.h>
#include <asm/dsp.h>
END(swsusp_arch_suspend)
LEAF(swsusp_arch_resume)
+ /* Avoid TLB mismatch during and after kernel resume */
+ jal local_flush_tlb_all
PTR_L t0, restore_pblist
0:
PTR_L t1, PBE_ADDRESS(t0) /* source */
bne t1, t3, 1b
PTR_L t0, PBE_NEXT(t0)
bnez t0, 0b
- jal local_flush_tlb_all /* Avoid TLB mismatch after kernel resume */
PTR_LA t0, saved_regs
PTR_L ra, PT_R31(t0)
PTR_L sp, PT_R29(t0)
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
*/
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto bad_area;
BUG();
#include <linux/mm.h>
#include <asm/page.h>
-
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
+#include <asm/sections.h>
/*
* pfn_is_nosave - check if given pfn is in the 'nosave' section
*/
fault = handle_mm_fault(mm, vma, address, flags);
if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
+ if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
rc = mm_fault_error(regs, address, fault);
if (rc >= MM_FAULT_RETURN)
goto bail;
sp = regs->gpr[1];
perf_callchain_store(entry, next_ip);
- for (;;) {
+ while (entry->nr < PERF_MAX_STACK_DEPTH) {
fp = (unsigned long __user *) sp;
if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
return;
if (*flt & VM_FAULT_OOM) {
ret = -ENOMEM;
goto out_unlock;
- } else if (*flt & VM_FAULT_SIGBUS) {
+ } else if (*flt & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) {
ret = -EFAULT;
goto out_unlock;
}
struct dentry *dentry, *tmp;
mutex_lock(&dir->d_inode->i_mutex);
- list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry)) && dentry->d_inode) {
dget_dlock(dentry);
#include <linux/pfn.h>
#include <linux/suspend.h>
#include <linux/mm.h>
+#include <asm/sections.h>
#include <asm/ctl_reg.h>
-
-/*
- * References to section boundaries
- */
-extern const void __nosave_begin, __nosave_end;
+#include <asm/ipl.h>
/*
* The restore of the saved pages in an hibernation image will set
{
unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
unsigned long nosave_end_pfn = PFN_DOWN(__pa(&__nosave_end));
+ unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1;
+ unsigned long stext_pfn = PFN_DOWN(__pa(&_stext));
/* Always save lowcore pages (LC protection might be enabled). */
if (pfn <= LC_PAGES)
if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
return 1;
/* Skip memory holes and read-only pages (NSS, DCSS, ...). */
+ if (pfn >= stext_pfn && pfn <= eshared_pfn)
+ return ipl_info.type == IPL_TYPE_NSS ? 1 : 0;
if (tprot(PFN_PHYS(pfn)))
return 1;
return 0;
for (n = mem->count - 1; n > 0 ; n--)
memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0]));
+ memset(&mem->vm[0], 0, sizeof(mem->vm[0]));
mem->vm[0].cpus_total = cpus;
mem->vm[0].cpus_configured = cpus;
mem->vm[0].cpus_standby = 0;
do_no_context(regs);
else
pagefault_out_of_memory();
+ } else if (fault & VM_FAULT_SIGSEGV) {
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ do_no_context(regs);
+ else
+ do_sigsegv(regs, SEGV_MAPERR);
} else if (fault & VM_FAULT_SIGBUS) {
/* Kernel mode? Handle exceptions or die */
if (!user_mode(regs))
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
#include <asm-generic/sections.h>
-extern long __nosave_begin, __nosave_end;
extern long __machvec_start, __machvec_end;
extern char __uncached_start, __uncached_end;
extern char __start_eh_frame[], __stop_eh_frame[];
} else {
if (fault & VM_FAULT_SIGBUS)
do_sigbus(regs, error_code, address);
+ else if (fault & VM_FAULT_SIGSEGV)
+ bad_area(regs, error_code, address);
else
BUG();
}
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
#include <asm/hibernate.h>
#include <asm/visasm.h>
#include <asm/page.h>
+#include <asm/sections.h>
#include <asm/tlb.h>
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
-
struct saved_context saved_context;
/*
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM) {
goto out_of_memory;
+ } else if (fault & VM_FAULT_SIGSEGV) {
+ goto out;
} else if (fault & VM_FAULT_SIGBUS) {
err = -EACCES;
goto out;
/* Defined in hibernate_asm.S */
extern int restore_image(pgd_t *resume_pg_dir, struct pbe *restore_pblist);
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
-
extern struct pbe *restore_pblist;
#endif
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/sections.h>
#include <asm/suspend.h>
#include "mach/pm.h"
* Not recognized on AMD in compat mode (but is recognized in legacy
* mode).
*/
- if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA)
+ if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA)
&& !vendor_intel(ctxt))
return emulate_ud(ctxt);
setup_syscalls_segments(ctxt, &cs, &ss);
ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data);
- switch (ctxt->mode) {
- case X86EMUL_MODE_PROT32:
- if ((msr_data & 0xfffc) == 0x0)
- return emulate_gp(ctxt, 0);
- break;
- case X86EMUL_MODE_PROT64:
- if (msr_data == 0x0)
- return emulate_gp(ctxt, 0);
- break;
- default:
- break;
- }
+ if ((msr_data & 0xfffc) == 0x0)
+ return emulate_gp(ctxt, 0);
ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
- cs_sel = (u16)msr_data;
- cs_sel &= ~SELECTOR_RPL_MASK;
+ cs_sel = (u16)msr_data & ~SELECTOR_RPL_MASK;
ss_sel = cs_sel + 8;
- ss_sel &= ~SELECTOR_RPL_MASK;
- if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) {
+ if (efer & EFER_LMA) {
cs.d = 0;
cs.l = 1;
}
ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);
ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data);
- ctxt->_eip = msr_data;
+ ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data;
ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
- *reg_write(ctxt, VCPU_REGS_RSP) = msr_data;
+ *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data :
+ (u32)msr_data;
return X86EMUL_CONTINUE;
}
unsigned int fault)
{
struct task_struct *tsk = current;
- struct mm_struct *mm = tsk->mm;
int code = BUS_ADRERR;
- up_read(&mm->mmap_sem);
-
/* Kernel mode? Handle exceptions or die: */
if (!(error_code & PF_USER)) {
no_context(regs, error_code, address, SIGBUS, BUS_ADRERR);
unsigned long address, unsigned int fault)
{
if (fatal_signal_pending(current) && !(error_code & PF_USER)) {
- up_read(¤t->mm->mmap_sem);
no_context(regs, error_code, address, 0, 0);
return;
}
if (fault & VM_FAULT_OOM) {
/* Kernel mode? Handle exceptions or die: */
if (!(error_code & PF_USER)) {
- up_read(¤t->mm->mmap_sem);
no_context(regs, error_code, address,
SIGSEGV, SEGV_MAPERR);
return;
}
- up_read(¤t->mm->mmap_sem);
-
/*
* We ran out of memory, call the OOM killer, and return the
* userspace (which will retry the fault, or kill us if we got
if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
VM_FAULT_HWPOISON_LARGE))
do_sigbus(regs, error_code, address, fault);
+ else if (fault & VM_FAULT_SIGSEGV)
+ bad_area_nosemaphore(regs, error_code, address);
else
BUG();
}
return;
if (unlikely(fault & VM_FAULT_ERROR)) {
+ up_read(&mm->mmap_sem);
mm_fault_error(regs, error_code, address, fault);
return;
}
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/mmzone.h>
+#include <asm/sections.h>
/* Defined in hibernate_asm_32.S */
extern int restore_image(void);
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
-
/* Pointer to the temporary resume page tables */
pgd_t *resume_pg_dir;
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/mtrr.h>
+#include <asm/sections.h>
#include <asm/suspend.h>
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
-
/* Defined in hibernate_asm_64.S */
extern int restore_image(void);
source "fs/Kconfig.binfmt"
+config XTFPGA_LCD
+ bool "Enable XTFPGA LCD driver"
+ depends on XTENSA_PLATFORM_XTFPGA
+ default n
+ help
+ There's a 2x16 LCD on most of XTFPGA boards, kernel may output
+ progress messages there during bootup/shutdown. It may be useful
+ during board bringup.
+
+ If unsure, say N.
+
+config XTFPGA_LCD_BASE_ADDR
+ hex "XTFPGA LCD base address"
+ depends on XTFPGA_LCD
+ default "0x0d0c0000"
+ help
+ Base address of the LCD controller inside KIO region.
+ Different boards from XTFPGA family have LCD controller at different
+ addresses. Please consult prototyping user guide for your board for
+ the correct address. Wrong address here may lead to hardware lockup.
+
+config XTFPGA_LCD_8BIT_ACCESS
+ bool "Use 8-bit access to XTFPGA LCD"
+ depends on XTFPGA_LCD
+ default n
+ help
+ LCD may be connected with 4- or 8-bit interface, 8-bit access may
+ only be used with 8-bit interface. Please consult prototyping user
+ guide for your board for the correct interface width.
+
endmenu
source "net/Kconfig"
__SYSCALL(324, sys_name_to_handle_at, 5)
#define __NR_open_by_handle_at 325
__SYSCALL(325, sys_open_by_handle_at, 3)
-#define __NR_sync_file_range 326
+#define __NR_sync_file_range2 326
__SYSCALL(326, sys_sync_file_range2, 6)
#define __NR_perf_event_open 327
__SYSCALL(327, sys_perf_event_open, 5)
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
else if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
BUG();
#
# Note 2! The CFLAGS definitions are in the main makefile...
-obj-y = setup.o lcd.o
+obj-y += setup.o
+obj-$(CONFIG_XTFPGA_LCD) += lcd.o
/* UART */
#define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020)
-/* LCD instruction and data addresses. */
-#define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000))
-#define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004))
/* Misc. */
#define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000)
#ifndef __XTENSA_XTAVNET_LCD_H
#define __XTENSA_XTAVNET_LCD_H
+#ifdef CONFIG_XTFPGA_LCD
/* Display string STR at position POS on the LCD. */
void lcd_disp_at_pos(char *str, unsigned char pos);
/* Shift the contents of the LCD display left or right. */
void lcd_shiftleft(void);
void lcd_shiftright(void);
+#else
+static inline void lcd_disp_at_pos(char *str, unsigned char pos)
+{
+}
+
+static inline void lcd_shiftleft(void)
+{
+}
+
+static inline void lcd_shiftright(void)
+{
+}
+#endif
+
#endif
/*
- * Driver for the LCD display on the Tensilica LX60 Board.
+ * Driver for the LCD display on the Tensilica XTFPGA board family.
+ * http://www.mytechcorp.com/cfdata/productFile/File1/MOC-16216B-B-A0A04.pdf
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2001, 2006 Tensilica Inc.
+ * Copyright (C) 2015 Cadence Design Systems Inc.
*/
-/*
- *
- * FIXME: this code is from the examples from the LX60 user guide.
- *
- * The lcd_pause function does busy waiting, which is probably not
- * great. Maybe the code could be changed to use kernel timers, or
- * change the hardware to not need to wait.
- */
-
+#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <platform/hardware.h>
#include <platform/lcd.h>
-#include <linux/delay.h>
-#define LCD_PAUSE_ITERATIONS 4000
+/* LCD instruction and data addresses. */
+#define LCD_INSTR_ADDR ((char *)IOADDR(CONFIG_XTFPGA_LCD_BASE_ADDR))
+#define LCD_DATA_ADDR (LCD_INSTR_ADDR + 4)
+
#define LCD_CLEAR 0x1
#define LCD_DISPLAY_ON 0xc
/* 8bit and 2 lines display */
#define LCD_DISPLAY_MODE8BIT 0x38
+#define LCD_DISPLAY_MODE4BIT 0x28
#define LCD_DISPLAY_POS 0x80
#define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1c
+static void lcd_put_byte(u8 *addr, u8 data)
+{
+#ifdef CONFIG_XTFPGA_LCD_8BIT_ACCESS
+ ACCESS_ONCE(*addr) = data;
+#else
+ ACCESS_ONCE(*addr) = data & 0xf0;
+ ACCESS_ONCE(*addr) = (data << 4) & 0xf0;
+#endif
+}
+
static int __init lcd_init(void)
{
- *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+ ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
mdelay(5);
- *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+ ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
udelay(200);
- *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+ ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
+ udelay(50);
+#ifndef CONFIG_XTFPGA_LCD_8BIT_ACCESS
+ ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE4BIT;
+ udelay(50);
+ lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT);
udelay(50);
- *LCD_INSTR_ADDR = LCD_DISPLAY_ON;
+#endif
+ lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_ON);
udelay(50);
- *LCD_INSTR_ADDR = LCD_CLEAR;
+ lcd_put_byte(LCD_INSTR_ADDR, LCD_CLEAR);
mdelay(10);
lcd_disp_at_pos("XTENSA LINUX", 0);
return 0;
void lcd_disp_at_pos(char *str, unsigned char pos)
{
- *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos;
+ lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_POS | pos);
udelay(100);
while (*str != 0) {
- *LCD_DATA_ADDR = *str;
+ lcd_put_byte(LCD_DATA_ADDR, *str);
udelay(200);
str++;
}
void lcd_shiftleft(void)
{
- *LCD_INSTR_ADDR = LCD_SHIFT_LEFT;
+ lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_LEFT);
udelay(50);
}
void lcd_shiftright(void)
{
- *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT;
+ lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_RIGHT);
udelay(50);
}
return_ACPI_STATUS(AE_NOT_EXIST);
}
- obj_desc->region.address =
- (acpi_physical_address) ACPI_TO_INTEGER(table);
+ obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table);
obj_desc->region.length = table->length;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
"%4.4s %p Attempted physical table override failed",
table_header->signature,
- ACPI_CAST_PTR(void,
- table_desc->address)));
+ ACPI_PHYSADDR_TO_PTR(table_desc->address)));
return (NULL);
}
ACPI_INFO((AE_INFO,
"%4.4s %p %s table override, new table: %p",
table_header->signature,
- ACPI_CAST_PTR(void, table_desc->address),
+ ACPI_PHYSADDR_TO_PTR(table_desc->address),
override_type, new_table));
/* We can now unmap/delete the original table (if fully mapped) */
*
******************************************************************************/
-acpi_status acpi_find_root_pointer(acpi_size *table_address)
+acpi_status acpi_find_root_pointer(acpi_physical_address * table_address)
{
u8 *table_ptr;
u8 *mem_rover;
physical_address +=
(u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
- *table_address = physical_address;
+ *table_address =
+ (acpi_physical_address) physical_address;
return_ACPI_STATUS(AE_OK);
}
}
(ACPI_HI_RSDP_WINDOW_BASE +
ACPI_PTR_DIFF(mem_rover, table_ptr));
- *table_address = physical_address;
+ *table_address = (acpi_physical_address) physical_address;
return_ACPI_STATUS(AE_OK);
}
return -EINVAL;
drv->safe_state_index = -1;
- for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+ for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) {
drv->states[i].name[0] = '\0';
drv->states[i].desc[0] = '\0';
}
source "drivers/block/mtip32xx/Kconfig"
+source "drivers/block/zram/Kconfig"
+
config BLK_CPQ_DA
tristate "Compaq SMART2 support"
depends on PCI && VIRT_TO_BUS
obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/
obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/
+obj-$(CONFIG_ZRAM) += zram/
nvme-y := nvme-core.o nvme-scsi.o
swim_mod-y := swim.o swim_asm.o
return -EINVAL;
}
- nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
- if (!nbd_dev)
- return -ENOMEM;
-
part_shift = 0;
if (max_part > 0) {
part_shift = fls(max_part);
if (nbds_max > 1UL << (MINORBITS - part_shift))
return -EINVAL;
+ nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
+ if (!nbd_dev)
+ return -ENOMEM;
+
for (i = 0; i < nbds_max; i++) {
struct gendisk *disk = alloc_disk(1 << part_shift);
if (!disk)
result, xferred);
if (!img_request->result)
img_request->result = result;
+ /*
+ * Need to end I/O on the entire obj_request worth of
+ * bytes in case of error.
+ */
+ xferred = obj_request->length;
}
/* Image object requests don't own their page array */
--- /dev/null
+config ZRAM
+ tristate "Compressed RAM block device support"
+ depends on BLOCK && SYSFS && ZSMALLOC
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
+ default n
+ help
+ Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
+ Pages written to these disks are compressed and stored in memory
+ itself. These disks allow very fast I/O and compression provides
+ good amounts of memory savings.
+
+ It has several use cases, for example: /tmp storage, use as swap
+ disks and maybe many more.
+
+ See zram.txt for more information.
+
+config ZRAM_LZ4_COMPRESS
+ bool "Enable LZ4 algorithm support"
+ depends on ZRAM
+ select LZ4_COMPRESS
+ select LZ4_DECOMPRESS
+ default n
+ help
+ This option enables LZ4 compression algorithm support. Compression
+ algorithm can be changed using `comp_algorithm' device attribute.
+
+config ZRAM_DEBUG
+ bool "Compressed RAM block device debug support"
+ depends on ZRAM
+ default n
+ help
+ This option adds additional debugging code to the compressed
+ RAM block device driver.
--- /dev/null
+zram-y := zcomp_lzo.o zcomp.o zram_drv.o
+
+zram-$(CONFIG_ZRAM_LZ4_COMPRESS) += zcomp_lz4.o
+
+obj-$(CONFIG_ZRAM) += zram.o
--- /dev/null
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#include "zcomp.h"
+#include "zcomp_lzo.h"
+#ifdef CONFIG_ZRAM_LZ4_COMPRESS
+#include "zcomp_lz4.h"
+#endif
+
+/*
+ * single zcomp_strm backend
+ */
+struct zcomp_strm_single {
+ struct mutex strm_lock;
+ struct zcomp_strm *zstrm;
+};
+
+/*
+ * multi zcomp_strm backend
+ */
+struct zcomp_strm_multi {
+ /* protect strm list */
+ spinlock_t strm_lock;
+ /* max possible number of zstrm streams */
+ int max_strm;
+ /* number of available zstrm streams */
+ int avail_strm;
+ /* list of available strms */
+ struct list_head idle_strm;
+ wait_queue_head_t strm_wait;
+};
+
+static struct zcomp_backend *backends[] = {
+ &zcomp_lzo,
+#ifdef CONFIG_ZRAM_LZ4_COMPRESS
+ &zcomp_lz4,
+#endif
+ NULL
+};
+
+static struct zcomp_backend *find_backend(const char *compress)
+{
+ int i = 0;
+ while (backends[i]) {
+ if (sysfs_streq(compress, backends[i]->name))
+ break;
+ i++;
+ }
+ return backends[i];
+}
+
+static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+ if (zstrm->private)
+ comp->backend->destroy(zstrm->private);
+ free_pages((unsigned long)zstrm->buffer, 1);
+ kfree(zstrm);
+}
+
+/*
+ * allocate new zcomp_strm structure with ->private initialized by
+ * backend, return NULL on error
+ */
+static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
+{
+ struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL);
+ if (!zstrm)
+ return NULL;
+
+ zstrm->private = comp->backend->create();
+ /*
+ * allocate 2 pages. 1 for compressed data, plus 1 extra for the
+ * case when compressed size is larger than the original one
+ */
+ zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+ if (!zstrm->private || !zstrm->buffer) {
+ zcomp_strm_free(comp, zstrm);
+ zstrm = NULL;
+ }
+ return zstrm;
+}
+
+/*
+ * get idle zcomp_strm or wait until other process release
+ * (zcomp_strm_release()) one for us
+ */
+static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp)
+{
+ struct zcomp_strm_multi *zs = comp->stream;
+ struct zcomp_strm *zstrm;
+
+ while (1) {
+ spin_lock(&zs->strm_lock);
+ if (!list_empty(&zs->idle_strm)) {
+ zstrm = list_entry(zs->idle_strm.next,
+ struct zcomp_strm, list);
+ list_del(&zstrm->list);
+ spin_unlock(&zs->strm_lock);
+ return zstrm;
+ }
+ /* zstrm streams limit reached, wait for idle stream */
+ if (zs->avail_strm >= zs->max_strm) {
+ spin_unlock(&zs->strm_lock);
+ wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
+ continue;
+ }
+ /* allocate new zstrm stream */
+ zs->avail_strm++;
+ spin_unlock(&zs->strm_lock);
+
+ zstrm = zcomp_strm_alloc(comp);
+ if (!zstrm) {
+ spin_lock(&zs->strm_lock);
+ zs->avail_strm--;
+ spin_unlock(&zs->strm_lock);
+ wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
+ continue;
+ }
+ break;
+ }
+ return zstrm;
+}
+
+/* add stream back to idle list and wake up waiter or free the stream */
+static void zcomp_strm_multi_release(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+ struct zcomp_strm_multi *zs = comp->stream;
+
+ spin_lock(&zs->strm_lock);
+ if (zs->avail_strm <= zs->max_strm) {
+ list_add(&zstrm->list, &zs->idle_strm);
+ spin_unlock(&zs->strm_lock);
+ wake_up(&zs->strm_wait);
+ return;
+ }
+
+ zs->avail_strm--;
+ spin_unlock(&zs->strm_lock);
+ zcomp_strm_free(comp, zstrm);
+}
+
+/* change max_strm limit */
+static bool zcomp_strm_multi_set_max_streams(struct zcomp *comp, int num_strm)
+{
+ struct zcomp_strm_multi *zs = comp->stream;
+ struct zcomp_strm *zstrm;
+
+ spin_lock(&zs->strm_lock);
+ zs->max_strm = num_strm;
+ /*
+ * if user has lowered the limit and there are idle streams,
+ * immediately free as much streams (and memory) as we can.
+ */
+ while (zs->avail_strm > num_strm && !list_empty(&zs->idle_strm)) {
+ zstrm = list_entry(zs->idle_strm.next,
+ struct zcomp_strm, list);
+ list_del(&zstrm->list);
+ zcomp_strm_free(comp, zstrm);
+ zs->avail_strm--;
+ }
+ spin_unlock(&zs->strm_lock);
+ return true;
+}
+
+static void zcomp_strm_multi_destroy(struct zcomp *comp)
+{
+ struct zcomp_strm_multi *zs = comp->stream;
+ struct zcomp_strm *zstrm;
+
+ while (!list_empty(&zs->idle_strm)) {
+ zstrm = list_entry(zs->idle_strm.next,
+ struct zcomp_strm, list);
+ list_del(&zstrm->list);
+ zcomp_strm_free(comp, zstrm);
+ }
+ kfree(zs);
+}
+
+static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm)
+{
+ struct zcomp_strm *zstrm;
+ struct zcomp_strm_multi *zs;
+
+ comp->destroy = zcomp_strm_multi_destroy;
+ comp->strm_find = zcomp_strm_multi_find;
+ comp->strm_release = zcomp_strm_multi_release;
+ comp->set_max_streams = zcomp_strm_multi_set_max_streams;
+ zs = kmalloc(sizeof(struct zcomp_strm_multi), GFP_KERNEL);
+ if (!zs)
+ return -ENOMEM;
+
+ comp->stream = zs;
+ spin_lock_init(&zs->strm_lock);
+ INIT_LIST_HEAD(&zs->idle_strm);
+ init_waitqueue_head(&zs->strm_wait);
+ zs->max_strm = max_strm;
+ zs->avail_strm = 1;
+
+ zstrm = zcomp_strm_alloc(comp);
+ if (!zstrm) {
+ kfree(zs);
+ return -ENOMEM;
+ }
+ list_add(&zstrm->list, &zs->idle_strm);
+ return 0;
+}
+
+static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp)
+{
+ struct zcomp_strm_single *zs = comp->stream;
+ mutex_lock(&zs->strm_lock);
+ return zs->zstrm;
+}
+
+static void zcomp_strm_single_release(struct zcomp *comp,
+ struct zcomp_strm *zstrm)
+{
+ struct zcomp_strm_single *zs = comp->stream;
+ mutex_unlock(&zs->strm_lock);
+}
+
+static bool zcomp_strm_single_set_max_streams(struct zcomp *comp, int num_strm)
+{
+ /* zcomp_strm_single support only max_comp_streams == 1 */
+ return false;
+}
+
+static void zcomp_strm_single_destroy(struct zcomp *comp)
+{
+ struct zcomp_strm_single *zs = comp->stream;
+ zcomp_strm_free(comp, zs->zstrm);
+ kfree(zs);
+}
+
+static int zcomp_strm_single_create(struct zcomp *comp)
+{
+ struct zcomp_strm_single *zs;
+
+ comp->destroy = zcomp_strm_single_destroy;
+ comp->strm_find = zcomp_strm_single_find;
+ comp->strm_release = zcomp_strm_single_release;
+ comp->set_max_streams = zcomp_strm_single_set_max_streams;
+ zs = kmalloc(sizeof(struct zcomp_strm_single), GFP_KERNEL);
+ if (!zs)
+ return -ENOMEM;
+
+ comp->stream = zs;
+ mutex_init(&zs->strm_lock);
+ zs->zstrm = zcomp_strm_alloc(comp);
+ if (!zs->zstrm) {
+ kfree(zs);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/* show available compressors */
+ssize_t zcomp_available_show(const char *comp, char *buf)
+{
+ ssize_t sz = 0;
+ int i = 0;
+
+ while (backends[i]) {
+ if (sysfs_streq(comp, backends[i]->name))
+ sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
+ "[%s] ", backends[i]->name);
+ else
+ sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
+ "%s ", backends[i]->name);
+ i++;
+ }
+ sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
+ return sz;
+}
+
+bool zcomp_set_max_streams(struct zcomp *comp, int num_strm)
+{
+ return comp->set_max_streams(comp, num_strm);
+}
+
+struct zcomp_strm *zcomp_strm_find(struct zcomp *comp)
+{
+ return comp->strm_find(comp);
+}
+
+void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+ comp->strm_release(comp, zstrm);
+}
+
+int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const unsigned char *src, size_t *dst_len)
+{
+ return comp->backend->compress(src, zstrm->buffer, dst_len,
+ zstrm->private);
+}
+
+int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
+ size_t src_len, unsigned char *dst)
+{
+ return comp->backend->decompress(src, src_len, dst);
+}
+
+void zcomp_destroy(struct zcomp *comp)
+{
+ comp->destroy(comp);
+ kfree(comp);
+}
+
+/*
+ * search available compressors for requested algorithm.
+ * allocate new zcomp and initialize it. return compressing
+ * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
+ * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
+ * case of allocation error.
+ */
+struct zcomp *zcomp_create(const char *compress, int max_strm)
+{
+ struct zcomp *comp;
+ struct zcomp_backend *backend;
+
+ backend = find_backend(compress);
+ if (!backend)
+ return ERR_PTR(-EINVAL);
+
+ comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
+ if (!comp)
+ return ERR_PTR(-ENOMEM);
+
+ comp->backend = backend;
+ if (max_strm > 1)
+ zcomp_strm_multi_create(comp, max_strm);
+ else
+ zcomp_strm_single_create(comp);
+ if (!comp->stream) {
+ kfree(comp);
+ return ERR_PTR(-ENOMEM);
+ }
+ return comp;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ZCOMP_H_
+#define _ZCOMP_H_
+
+#include <linux/mutex.h>
+
+struct zcomp_strm {
+ /* compression/decompression buffer */
+ void *buffer;
+ /*
+ * The private data of the compression stream, only compression
+ * stream backend can touch this (e.g. compression algorithm
+ * working memory)
+ */
+ void *private;
+ /* used in multi stream backend, protected by backend strm_lock */
+ struct list_head list;
+};
+
+/* static compression backend */
+struct zcomp_backend {
+ int (*compress)(const unsigned char *src, unsigned char *dst,
+ size_t *dst_len, void *private);
+
+ int (*decompress)(const unsigned char *src, size_t src_len,
+ unsigned char *dst);
+
+ void *(*create)(void);
+ void (*destroy)(void *private);
+
+ const char *name;
+};
+
+/* dynamic per-device compression frontend */
+struct zcomp {
+ void *stream;
+ struct zcomp_backend *backend;
+
+ struct zcomp_strm *(*strm_find)(struct zcomp *comp);
+ void (*strm_release)(struct zcomp *comp, struct zcomp_strm *zstrm);
+ bool (*set_max_streams)(struct zcomp *comp, int num_strm);
+ void (*destroy)(struct zcomp *comp);
+};
+
+ssize_t zcomp_available_show(const char *comp, char *buf);
+
+struct zcomp *zcomp_create(const char *comp, int max_strm);
+void zcomp_destroy(struct zcomp *comp);
+
+struct zcomp_strm *zcomp_strm_find(struct zcomp *comp);
+void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm);
+
+int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const unsigned char *src, size_t *dst_len);
+
+int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
+ size_t src_len, unsigned char *dst);
+
+bool zcomp_set_max_streams(struct zcomp *comp, int num_strm);
+#endif /* _ZCOMP_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/lz4.h>
+
+#include "zcomp_lz4.h"
+
+static void *zcomp_lz4_create(void)
+{
+ return kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
+}
+
+static void zcomp_lz4_destroy(void *private)
+{
+ kfree(private);
+}
+
+static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst,
+ size_t *dst_len, void *private)
+{
+ /* return : Success if return 0 */
+ return lz4_compress(src, PAGE_SIZE, dst, dst_len, private);
+}
+
+static int zcomp_lz4_decompress(const unsigned char *src, size_t src_len,
+ unsigned char *dst)
+{
+ size_t dst_len = PAGE_SIZE;
+ /* return : Success if return 0 */
+ return lz4_decompress_unknownoutputsize(src, src_len, dst, &dst_len);
+}
+
+struct zcomp_backend zcomp_lz4 = {
+ .compress = zcomp_lz4_compress,
+ .decompress = zcomp_lz4_decompress,
+ .create = zcomp_lz4_create,
+ .destroy = zcomp_lz4_destroy,
+ .name = "lz4",
+};
--- /dev/null
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ZCOMP_LZ4_H_
+#define _ZCOMP_LZ4_H_
+
+#include "zcomp.h"
+
+extern struct zcomp_backend zcomp_lz4;
+
+#endif /* _ZCOMP_LZ4_H_ */
--- /dev/null
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/lzo.h>
+
+#include "zcomp_lzo.h"
+
+static void *lzo_create(void)
+{
+ return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+}
+
+static void lzo_destroy(void *private)
+{
+ kfree(private);
+}
+
+static int lzo_compress(const unsigned char *src, unsigned char *dst,
+ size_t *dst_len, void *private)
+{
+ int ret = lzo1x_1_compress(src, PAGE_SIZE, dst, dst_len, private);
+ return ret == LZO_E_OK ? 0 : ret;
+}
+
+static int lzo_decompress(const unsigned char *src, size_t src_len,
+ unsigned char *dst)
+{
+ size_t dst_len = PAGE_SIZE;
+ int ret = lzo1x_decompress_safe(src, src_len, dst, &dst_len);
+ return ret == LZO_E_OK ? 0 : ret;
+}
+
+struct zcomp_backend zcomp_lzo = {
+ .compress = lzo_compress,
+ .decompress = lzo_decompress,
+ .create = lzo_create,
+ .destroy = lzo_destroy,
+ .name = "lzo",
+};
--- /dev/null
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ZCOMP_LZO_H_
+#define _ZCOMP_LZO_H_
+
+#include "zcomp.h"
+
+extern struct zcomp_backend zcomp_lzo;
+
+#endif /* _ZCOMP_LZO_H_ */
--- /dev/null
+/*
+ * Compressed RAM block device
+ *
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
+ * 2012, 2013 Minchan Kim
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+#define KMSG_COMPONENT "zram"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#ifdef CONFIG_ZRAM_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bio.h>
+#include <linux/bitops.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/device.h>
+#include <linux/genhd.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+
+#include "zram_drv.h"
+
+/* Globals */
+static int zram_major;
+static struct zram *zram_devices;
+static const char *default_compressor = "lzo";
+
+/* Module params (documentation at end) */
+static unsigned int num_devices = 1;
+
+#define ZRAM_ATTR_RO(name) \
+static ssize_t zram_attr_##name##_show(struct device *d, \
+ struct device_attribute *attr, char *b) \
+{ \
+ struct zram *zram = dev_to_zram(d); \
+ return scnprintf(b, PAGE_SIZE, "%llu\n", \
+ (u64)atomic64_read(&zram->stats.name)); \
+} \
+static struct device_attribute dev_attr_##name = \
+ __ATTR(name, S_IRUGO, zram_attr_##name##_show, NULL);
+
+static inline int init_done(struct zram *zram)
+{
+ return zram->meta != NULL;
+}
+
+static inline struct zram *dev_to_zram(struct device *dev)
+{
+ return (struct zram *)dev_to_disk(dev)->private_data;
+}
+
+static ssize_t disksize_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", zram->disksize);
+}
+
+static ssize_t initstate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 val;
+ struct zram *zram = dev_to_zram(dev);
+
+ down_read(&zram->init_lock);
+ val = init_done(zram);
+ up_read(&zram->init_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+}
+
+static ssize_t orig_data_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
+ (u64)(atomic64_read(&zram->stats.pages_stored)) << PAGE_SHIFT);
+}
+
+static ssize_t mem_used_total_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u64 val = 0;
+ struct zram *zram = dev_to_zram(dev);
+
+ down_read(&zram->init_lock);
+ if (init_done(zram)) {
+ struct zram_meta *meta = zram->meta;
+ val = zs_get_total_pages(meta->mem_pool);
+ }
+ up_read(&zram->init_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT);
+}
+
+static ssize_t max_comp_streams_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int val;
+ struct zram *zram = dev_to_zram(dev);
+
+ down_read(&zram->init_lock);
+ val = zram->max_comp_streams;
+ up_read(&zram->init_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t mem_limit_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u64 val;
+ struct zram *zram = dev_to_zram(dev);
+
+ down_read(&zram->init_lock);
+ val = zram->limit_pages;
+ up_read(&zram->init_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT);
+}
+
+static ssize_t mem_limit_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ u64 limit;
+ char *tmp;
+ struct zram *zram = dev_to_zram(dev);
+
+ limit = memparse(buf, &tmp);
+ if (buf == tmp) /* no chars parsed, invalid input */
+ return -EINVAL;
+
+ down_write(&zram->init_lock);
+ zram->limit_pages = PAGE_ALIGN(limit) >> PAGE_SHIFT;
+ up_write(&zram->init_lock);
+
+ return len;
+}
+
+static ssize_t mem_used_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u64 val = 0;
+ struct zram *zram = dev_to_zram(dev);
+
+ down_read(&zram->init_lock);
+ if (init_done(zram))
+ val = atomic_long_read(&zram->stats.max_used_pages);
+ up_read(&zram->init_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT);
+}
+
+static ssize_t mem_used_max_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ int err;
+ unsigned long val;
+ struct zram *zram = dev_to_zram(dev);
+
+ err = kstrtoul(buf, 10, &val);
+ if (err || val != 0)
+ return -EINVAL;
+
+ down_read(&zram->init_lock);
+ if (init_done(zram)) {
+ struct zram_meta *meta = zram->meta;
+ atomic_long_set(&zram->stats.max_used_pages,
+ zs_get_total_pages(meta->mem_pool));
+ }
+ up_read(&zram->init_lock);
+
+ return len;
+}
+
+static ssize_t max_comp_streams_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ int num;
+ struct zram *zram = dev_to_zram(dev);
+ int ret;
+
+ ret = kstrtoint(buf, 0, &num);
+ if (ret < 0)
+ return ret;
+ if (num < 1)
+ return -EINVAL;
+
+ down_write(&zram->init_lock);
+ if (init_done(zram)) {
+ if (!zcomp_set_max_streams(zram->comp, num)) {
+ pr_info("Cannot change max compression streams\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ zram->max_comp_streams = num;
+ ret = len;
+out:
+ up_write(&zram->init_lock);
+ return ret;
+}
+
+static ssize_t comp_algorithm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ size_t sz;
+ struct zram *zram = dev_to_zram(dev);
+
+ down_read(&zram->init_lock);
+ sz = zcomp_available_show(zram->compressor, buf);
+ up_read(&zram->init_lock);
+
+ return sz;
+}
+
+static ssize_t comp_algorithm_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct zram *zram = dev_to_zram(dev);
+ down_write(&zram->init_lock);
+ if (init_done(zram)) {
+ up_write(&zram->init_lock);
+ pr_info("Can't change algorithm for initialized device\n");
+ return -EBUSY;
+ }
+ strlcpy(zram->compressor, buf, sizeof(zram->compressor));
+ up_write(&zram->init_lock);
+ return len;
+}
+
+/* flag operations needs meta->tb_lock */
+static int zram_test_flag(struct zram_meta *meta, u32 index,
+ enum zram_pageflags flag)
+{
+ return meta->table[index].value & BIT(flag);
+}
+
+static void zram_set_flag(struct zram_meta *meta, u32 index,
+ enum zram_pageflags flag)
+{
+ meta->table[index].value |= BIT(flag);
+}
+
+static void zram_clear_flag(struct zram_meta *meta, u32 index,
+ enum zram_pageflags flag)
+{
+ meta->table[index].value &= ~BIT(flag);
+}
+
+static size_t zram_get_obj_size(struct zram_meta *meta, u32 index)
+{
+ return meta->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
+}
+
+static void zram_set_obj_size(struct zram_meta *meta,
+ u32 index, size_t size)
+{
+ unsigned long flags = meta->table[index].value >> ZRAM_FLAG_SHIFT;
+
+ meta->table[index].value = (flags << ZRAM_FLAG_SHIFT) | size;
+}
+
+static inline int is_partial_io(struct bio_vec *bvec)
+{
+ return bvec->bv_len != PAGE_SIZE;
+}
+
+/*
+ * Check if request is within bounds and aligned on zram logical blocks.
+ */
+static inline int valid_io_request(struct zram *zram, struct bio *bio)
+{
+ u64 start, end, bound;
+
+ /* unaligned request */
+ if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
+ return 0;
+ if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
+ return 0;
+
+ start = bio->bi_sector;
+ end = start + (bio->bi_size >> SECTOR_SHIFT);
+ bound = zram->disksize >> SECTOR_SHIFT;
+ /* out of range range */
+ if (unlikely(start >= bound || end >= bound || start > end))
+ return 0;
+
+ /* I/O request is valid */
+ return 1;
+}
+
+static void zram_meta_free(struct zram_meta *meta, u64 disksize)
+{
+ size_t num_pages = disksize >> PAGE_SHIFT;
+ size_t index;
+
+ /* Free all pages that are still in this zram device */
+ for (index = 0; index < num_pages; index++) {
+ unsigned long handle = meta->table[index].handle;
+
+ if (!handle)
+ continue;
+
+ zs_free(meta->mem_pool, handle);
+ }
+
+ zs_destroy_pool(meta->mem_pool);
+ vfree(meta->table);
+ kfree(meta);
+}
+
+static struct zram_meta *zram_meta_alloc(u64 disksize)
+{
+ size_t num_pages;
+ struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+ if (!meta)
+ goto out;
+
+ num_pages = disksize >> PAGE_SHIFT;
+ meta->table = vzalloc(num_pages * sizeof(*meta->table));
+ if (!meta->table) {
+ pr_err("Error allocating zram address table\n");
+ goto free_meta;
+ }
+
+ meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
+ if (!meta->mem_pool) {
+ pr_err("Error creating memory pool\n");
+ goto free_table;
+ }
+
+ return meta;
+
+free_table:
+ vfree(meta->table);
+free_meta:
+ kfree(meta);
+ meta = NULL;
+out:
+ return meta;
+}
+
+static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+{
+ if (*offset + bvec->bv_len >= PAGE_SIZE)
+ (*index)++;
+ *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
+}
+
+static int page_zero_filled(void *ptr)
+{
+ unsigned int pos;
+ unsigned long *page;
+
+ page = (unsigned long *)ptr;
+
+ for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
+ if (page[pos])
+ return 0;
+ }
+
+ return 1;
+}
+
+static void handle_zero_page(struct bio_vec *bvec)
+{
+ struct page *page = bvec->bv_page;
+ void *user_mem;
+
+ user_mem = kmap_atomic(page);
+ if (is_partial_io(bvec))
+ memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ else
+ clear_page(user_mem);
+ kunmap_atomic(user_mem);
+
+ flush_dcache_page(page);
+}
+
+
+/*
+ * To protect concurrent access to the same index entry,
+ * caller should hold this table index entry's bit_spinlock to
+ * indicate this index entry is accessing.
+ */
+static void zram_free_page(struct zram *zram, size_t index)
+{
+ struct zram_meta *meta = zram->meta;
+ unsigned long handle = meta->table[index].handle;
+
+ if (unlikely(!handle)) {
+ /*
+ * No memory is allocated for zero filled pages.
+ * Simply clear zero page flag.
+ */
+ if (zram_test_flag(meta, index, ZRAM_ZERO)) {
+ zram_clear_flag(meta, index, ZRAM_ZERO);
+ atomic64_dec(&zram->stats.zero_pages);
+ }
+ return;
+ }
+
+ zs_free(meta->mem_pool, handle);
+
+ atomic64_sub(zram_get_obj_size(meta, index),
+ &zram->stats.compr_data_size);
+ atomic64_dec(&zram->stats.pages_stored);
+
+ meta->table[index].handle = 0;
+ zram_set_obj_size(meta, index, 0);
+}
+
+static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
+{
+ int ret = 0;
+ unsigned char *cmem;
+ struct zram_meta *meta = zram->meta;
+ unsigned long handle;
+ size_t size;
+
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ handle = meta->table[index].handle;
+ size = zram_get_obj_size(meta, index);
+
+ if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+ clear_page(mem);
+ return 0;
+ }
+
+ cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
+ if (size == PAGE_SIZE)
+ copy_page(mem, cmem);
+ else
+ ret = zcomp_decompress(zram->comp, cmem, size, mem);
+ zs_unmap_object(meta->mem_pool, handle);
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+
+ /* Should NEVER happen. Return bio error if it does. */
+ if (unlikely(ret)) {
+ pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
+ u32 index, int offset, struct bio *bio)
+{
+ int ret;
+ struct page *page;
+ unsigned char *user_mem, *uncmem = NULL;
+ struct zram_meta *meta = zram->meta;
+ page = bvec->bv_page;
+
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ if (unlikely(!meta->table[index].handle) ||
+ zram_test_flag(meta, index, ZRAM_ZERO)) {
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+ handle_zero_page(bvec);
+ return 0;
+ }
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+
+ if (is_partial_io(bvec))
+ /* Use a temporary buffer to decompress the page */
+ uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
+
+ user_mem = kmap_atomic(page);
+ if (!is_partial_io(bvec))
+ uncmem = user_mem;
+
+ if (!uncmem) {
+ pr_info("Unable to allocate temp memory\n");
+ ret = -ENOMEM;
+ goto out_cleanup;
+ }
+
+ ret = zram_decompress_page(zram, uncmem, index);
+ /* Should NEVER happen. Return bio error if it does. */
+ if (unlikely(ret))
+ goto out_cleanup;
+
+ if (is_partial_io(bvec))
+ memcpy(user_mem + bvec->bv_offset, uncmem + offset,
+ bvec->bv_len);
+
+ flush_dcache_page(page);
+ ret = 0;
+out_cleanup:
+ kunmap_atomic(user_mem);
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+ return ret;
+}
+
+static inline void update_used_max(struct zram *zram,
+ const unsigned long pages)
+{
+ int old_max, cur_max;
+
+ old_max = atomic_long_read(&zram->stats.max_used_pages);
+
+ do {
+ cur_max = old_max;
+ if (pages > cur_max)
+ old_max = atomic_long_cmpxchg(
+ &zram->stats.max_used_pages, cur_max, pages);
+ } while (old_max != cur_max);
+}
+
+static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
+ int offset)
+{
+ int ret = 0;
+ size_t clen;
+ unsigned long handle;
+ struct page *page;
+ unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+ struct zram_meta *meta = zram->meta;
+ struct zcomp_strm *zstrm;
+ bool locked = false;
+ unsigned long alloced_pages;
+
+ page = bvec->bv_page;
+ if (is_partial_io(bvec)) {
+ /*
+ * This is a partial IO. We need to read the full page
+ * before to write the changes.
+ */
+ uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
+ if (!uncmem) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = zram_decompress_page(zram, uncmem, index);
+ if (ret)
+ goto out;
+ }
+
+ zstrm = zcomp_strm_find(zram->comp);
+ locked = true;
+ user_mem = kmap_atomic(page);
+
+ if (is_partial_io(bvec)) {
+ memcpy(uncmem + offset, user_mem + bvec->bv_offset,
+ bvec->bv_len);
+ kunmap_atomic(user_mem);
+ user_mem = NULL;
+ } else {
+ uncmem = user_mem;
+ }
+
+ if (page_zero_filled(uncmem)) {
+ if (user_mem)
+ kunmap_atomic(user_mem);
+ /* Free memory associated with this sector now. */
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ zram_free_page(zram, index);
+ zram_set_flag(meta, index, ZRAM_ZERO);
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+
+ atomic64_inc(&zram->stats.zero_pages);
+ ret = 0;
+ goto out;
+ }
+
+ ret = zcomp_compress(zram->comp, zstrm, uncmem, &clen);
+ if (!is_partial_io(bvec)) {
+ kunmap_atomic(user_mem);
+ user_mem = NULL;
+ uncmem = NULL;
+ }
+
+ if (unlikely(ret)) {
+ pr_err("Compression failed! err=%d\n", ret);
+ goto out;
+ }
+ src = zstrm->buffer;
+ if (unlikely(clen > max_zpage_size)) {
+ clen = PAGE_SIZE;
+ if (is_partial_io(bvec))
+ src = uncmem;
+ }
+
+ handle = zs_malloc(meta->mem_pool, clen);
+ if (!handle) {
+ pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
+ index, clen);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ alloced_pages = zs_get_total_pages(meta->mem_pool);
+ if (zram->limit_pages && alloced_pages > zram->limit_pages) {
+ zs_free(meta->mem_pool, handle);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ update_used_max(zram, alloced_pages);
+
+ cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);
+
+ if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
+ src = kmap_atomic(page);
+ copy_page(cmem, src);
+ kunmap_atomic(src);
+ } else {
+ memcpy(cmem, src, clen);
+ }
+
+ zcomp_strm_release(zram->comp, zstrm);
+ locked = false;
+ zs_unmap_object(meta->mem_pool, handle);
+
+ /*
+ * Free memory associated with this sector
+ * before overwriting unused sectors.
+ */
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ zram_free_page(zram, index);
+
+ meta->table[index].handle = handle;
+ zram_set_obj_size(meta, index, clen);
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+
+ /* Update stats */
+ atomic64_add(clen, &zram->stats.compr_data_size);
+ atomic64_inc(&zram->stats.pages_stored);
+out:
+ if (locked)
+ zcomp_strm_release(zram->comp, zstrm);
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+ return ret;
+}
+
+static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
+ int offset, struct bio *bio)
+{
+ int ret;
+ int rw = bio_data_dir(bio);
+
+ if (rw == READ) {
+ atomic64_inc(&zram->stats.num_reads);
+ ret = zram_bvec_read(zram, bvec, index, offset, bio);
+ } else {
+ atomic64_inc(&zram->stats.num_writes);
+ ret = zram_bvec_write(zram, bvec, index, offset);
+ }
+
+ if (unlikely(ret)) {
+ if (rw == READ)
+ atomic64_inc(&zram->stats.failed_reads);
+ else
+ atomic64_inc(&zram->stats.failed_writes);
+ }
+
+ return ret;
+}
+
+/*
+ * zram_bio_discard - handler on discard request
+ * @index: physical block index in PAGE_SIZE units
+ * @offset: byte offset within physical block
+ */
+static void zram_bio_discard(struct zram *zram, u32 index,
+ int offset, struct bio *bio)
+{
+ size_t n = bio->bi_size;
+ struct zram_meta *meta = zram->meta;
+
+ /*
+ * zram manages data in physical block size units. Because logical block
+ * size isn't identical with physical block size on some arch, we
+ * could get a discard request pointing to a specific offset within a
+ * certain physical block. Although we can handle this request by
+ * reading that physiclal block and decompressing and partially zeroing
+ * and re-compressing and then re-storing it, this isn't reasonable
+ * because our intent with a discard request is to save memory. So
+ * skipping this logical block is appropriate here.
+ */
+ if (offset) {
+ if (n <= (PAGE_SIZE - offset))
+ return;
+
+ n -= (PAGE_SIZE - offset);
+ index++;
+ }
+
+ while (n >= PAGE_SIZE) {
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ zram_free_page(zram, index);
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+ atomic64_inc(&zram->stats.notify_free);
+ index++;
+ n -= PAGE_SIZE;
+ }
+}
+
+static void zram_reset_device(struct zram *zram)
+{
+ down_write(&zram->init_lock);
+
+ zram->limit_pages = 0;
+
+ if (!init_done(zram)) {
+ up_write(&zram->init_lock);
+ return;
+ }
+
+ zcomp_destroy(zram->comp);
+ zram->max_comp_streams = 1;
+ zram_meta_free(zram->meta, zram->disksize);
+ zram->meta = NULL;
+ /* Reset stats */
+ memset(&zram->stats, 0, sizeof(zram->stats));
+
+ zram->disksize = 0;
+ up_write(&zram->init_lock);
+}
+
+static ssize_t disksize_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ u64 disksize;
+ struct zcomp *comp;
+ struct zram_meta *meta;
+ struct zram *zram = dev_to_zram(dev);
+ int err;
+
+ disksize = memparse(buf, NULL);
+ if (!disksize)
+ return -EINVAL;
+
+ disksize = PAGE_ALIGN(disksize);
+ meta = zram_meta_alloc(disksize);
+ if (!meta)
+ return -ENOMEM;
+
+ comp = zcomp_create(zram->compressor, zram->max_comp_streams);
+ if (IS_ERR(comp)) {
+ pr_info("Cannot initialise %s compressing backend\n",
+ zram->compressor);
+ err = PTR_ERR(comp);
+ goto out_free_meta;
+ }
+
+ down_write(&zram->init_lock);
+ if (init_done(zram)) {
+ pr_info("Cannot change disksize for initialized device\n");
+ err = -EBUSY;
+ goto out_destroy_comp;
+ }
+
+ zram->meta = meta;
+ zram->comp = comp;
+ zram->disksize = disksize;
+ set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+ up_write(&zram->init_lock);
+
+ /*
+ * Revalidate disk out of the init_lock to avoid lockdep splat.
+ * It's okay because disk's capacity is protected by init_lock
+ * so that revalidate_disk always sees up-to-date capacity.
+ */
+ revalidate_disk(zram->disk);
+
+ return len;
+
+out_destroy_comp:
+ up_write(&zram->init_lock);
+ zcomp_destroy(comp);
+out_free_meta:
+ zram_meta_free(meta, disksize);
+ return err;
+}
+
+static ssize_t reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ int ret;
+ unsigned short do_reset;
+ struct zram *zram;
+ struct block_device *bdev;
+
+ zram = dev_to_zram(dev);
+ bdev = bdget_disk(zram->disk, 0);
+
+ if (!bdev)
+ return -ENOMEM;
+
+ mutex_lock(&bdev->bd_mutex);
+ /* Do not reset an active device! */
+ if (bdev->bd_holders) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = kstrtou16(buf, 10, &do_reset);
+ if (ret)
+ goto out;
+
+ if (!do_reset) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Make sure all pending I/O is finished */
+ fsync_bdev(bdev);
+ zram_reset_device(zram);
+ set_capacity(zram->disk, 0);
+
+ mutex_unlock(&bdev->bd_mutex);
+ revalidate_disk(zram->disk);
+ bdput(bdev);
+
+ return len;
+
+out:
+ mutex_unlock(&bdev->bd_mutex);
+ bdput(bdev);
+ return ret;
+}
+
+static void __zram_make_request(struct zram *zram, struct bio *bio)
+{
+ int i, offset;
+ u32 index;
+ struct bio_vec *bvec;
+
+
+ index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
+ offset = (bio->bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
+
+ if (unlikely(bio->bi_rw & REQ_DISCARD)) {
+ zram_bio_discard(zram, index, offset, bio);
+ bio_endio(bio, 0);
+ return;
+ }
+
+ bio_for_each_segment(bvec, bio, i) {
+ int max_transfer_size = PAGE_SIZE - offset;
+
+ if (bvec->bv_len > max_transfer_size) {
+ /*
+ * zram_bvec_rw() can only make operation on a single
+ * zram page. Split the bio vector.
+ */
+ struct bio_vec bv;
+
+ bv.bv_page = bvec->bv_page;
+ bv.bv_len = max_transfer_size;
+ bv.bv_offset = bvec->bv_offset;
+
+ if (zram_bvec_rw(zram, &bv, index, offset, bio) < 0)
+ goto out;
+
+ bv.bv_len = bvec->bv_len - max_transfer_size;
+ bv.bv_offset += max_transfer_size;
+ if (zram_bvec_rw(zram, &bv, index + 1, 0, bio) < 0)
+ goto out;
+ } else
+ if (zram_bvec_rw(zram, bvec, index, offset, bio) < 0)
+ goto out;
+
+ update_position(&index, &offset, bvec);
+ }
+
+ set_bit(BIO_UPTODATE, &bio->bi_flags);
+ bio_endio(bio, 0);
+ return;
+
+out:
+ bio_io_error(bio);
+}
+
+/*
+ * Handler function for all zram I/O requests.
+ */
+static void zram_make_request(struct request_queue *queue, struct bio *bio)
+{
+ struct zram *zram = queue->queuedata;
+
+ down_read(&zram->init_lock);
+ if (unlikely(!init_done(zram)))
+ goto error;
+
+ if (!valid_io_request(zram, bio)) {
+ atomic64_inc(&zram->stats.invalid_io);
+ goto error;
+ }
+
+ __zram_make_request(zram, bio);
+ up_read(&zram->init_lock);
+
+ return;
+
+error:
+ up_read(&zram->init_lock);
+ bio_io_error(bio);
+}
+
+static void zram_slot_free_notify(struct block_device *bdev,
+ unsigned long index)
+{
+ struct zram *zram;
+ struct zram_meta *meta;
+
+ zram = bdev->bd_disk->private_data;
+ meta = zram->meta;
+
+ bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
+ zram_free_page(zram, index);
+ bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
+ atomic64_inc(&zram->stats.notify_free);
+}
+
+static const struct block_device_operations zram_devops = {
+ .swap_slot_free_notify = zram_slot_free_notify,
+ .owner = THIS_MODULE
+};
+
+static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
+ disksize_show, disksize_store);
+static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
+static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
+static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
+static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
+static DEVICE_ATTR(mem_limit, S_IRUGO | S_IWUSR, mem_limit_show,
+ mem_limit_store);
+static DEVICE_ATTR(mem_used_max, S_IRUGO | S_IWUSR, mem_used_max_show,
+ mem_used_max_store);
+static DEVICE_ATTR(max_comp_streams, S_IRUGO | S_IWUSR,
+ max_comp_streams_show, max_comp_streams_store);
+static DEVICE_ATTR(comp_algorithm, S_IRUGO | S_IWUSR,
+ comp_algorithm_show, comp_algorithm_store);
+
+ZRAM_ATTR_RO(num_reads);
+ZRAM_ATTR_RO(num_writes);
+ZRAM_ATTR_RO(failed_reads);
+ZRAM_ATTR_RO(failed_writes);
+ZRAM_ATTR_RO(invalid_io);
+ZRAM_ATTR_RO(notify_free);
+ZRAM_ATTR_RO(zero_pages);
+ZRAM_ATTR_RO(compr_data_size);
+
+static struct attribute *zram_disk_attrs[] = {
+ &dev_attr_disksize.attr,
+ &dev_attr_initstate.attr,
+ &dev_attr_reset.attr,
+ &dev_attr_num_reads.attr,
+ &dev_attr_num_writes.attr,
+ &dev_attr_failed_reads.attr,
+ &dev_attr_failed_writes.attr,
+ &dev_attr_invalid_io.attr,
+ &dev_attr_notify_free.attr,
+ &dev_attr_zero_pages.attr,
+ &dev_attr_orig_data_size.attr,
+ &dev_attr_compr_data_size.attr,
+ &dev_attr_mem_used_total.attr,
+ &dev_attr_mem_limit.attr,
+ &dev_attr_mem_used_max.attr,
+ &dev_attr_max_comp_streams.attr,
+ &dev_attr_comp_algorithm.attr,
+ NULL,
+};
+
+static struct attribute_group zram_disk_attr_group = {
+ .attrs = zram_disk_attrs,
+};
+
+static int create_device(struct zram *zram, int device_id)
+{
+ int ret = -ENOMEM;
+
+ init_rwsem(&zram->init_lock);
+
+ zram->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!zram->queue) {
+ pr_err("Error allocating disk queue for device %d\n",
+ device_id);
+ goto out;
+ }
+
+ blk_queue_make_request(zram->queue, zram_make_request);
+ zram->queue->queuedata = zram;
+
+ /* gendisk structure */
+ zram->disk = alloc_disk(1);
+ if (!zram->disk) {
+ pr_warn("Error allocating disk structure for device %d\n",
+ device_id);
+ goto out_free_queue;
+ }
+
+ zram->disk->major = zram_major;
+ zram->disk->first_minor = device_id;
+ zram->disk->fops = &zram_devops;
+ zram->disk->queue = zram->queue;
+ zram->disk->private_data = zram;
+ snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
+
+ /* Actual capacity set using syfs (/sys/block/zram<id>/disksize */
+ set_capacity(zram->disk, 0);
+ /* zram devices sort of resembles non-rotational disks */
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
+ /*
+ * To ensure that we always get PAGE_SIZE aligned
+ * and n*PAGE_SIZED sized I/O requests.
+ */
+ blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE);
+ blk_queue_logical_block_size(zram->disk->queue,
+ ZRAM_LOGICAL_BLOCK_SIZE);
+ blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
+ blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
+ zram->disk->queue->limits.discard_granularity = PAGE_SIZE;
+ zram->disk->queue->limits.max_discard_sectors = UINT_MAX;
+ /*
+ * zram_bio_discard() will clear all logical blocks if logical block
+ * size is identical with physical block size(PAGE_SIZE). But if it is
+ * different, we will skip discarding some parts of logical blocks in
+ * the part of the request range which isn't aligned to physical block
+ * size. So we can't ensure that all discarded logical blocks are
+ * zeroed.
+ */
+ if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE)
+ zram->disk->queue->limits.discard_zeroes_data = 1;
+ else
+ zram->disk->queue->limits.discard_zeroes_data = 0;
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue);
+
+ add_disk(zram->disk);
+
+ ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
+ &zram_disk_attr_group);
+ if (ret < 0) {
+ pr_warn("Error creating sysfs group");
+ goto out_free_disk;
+ }
+ strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor));
+ zram->meta = NULL;
+ zram->max_comp_streams = 1;
+ return 0;
+
+out_free_disk:
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
+out_free_queue:
+ blk_cleanup_queue(zram->queue);
+out:
+ return ret;
+}
+
+static void destroy_device(struct zram *zram)
+{
+ sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
+ &zram_disk_attr_group);
+
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
+
+ blk_cleanup_queue(zram->queue);
+}
+
+static int __init zram_init(void)
+{
+ int ret, dev_id;
+
+ if (num_devices > max_num_devices) {
+ pr_warn("Invalid value for num_devices: %u\n",
+ num_devices);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ zram_major = register_blkdev(0, "zram");
+ if (zram_major <= 0) {
+ pr_warn("Unable to get major number\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* Allocate the device array and initialize each one */
+ zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
+ if (!zram_devices) {
+ ret = -ENOMEM;
+ goto unregister;
+ }
+
+ for (dev_id = 0; dev_id < num_devices; dev_id++) {
+ ret = create_device(&zram_devices[dev_id], dev_id);
+ if (ret)
+ goto free_devices;
+ }
+
+ pr_info("Created %u device(s) ...\n", num_devices);
+
+ return 0;
+
+free_devices:
+ while (dev_id)
+ destroy_device(&zram_devices[--dev_id]);
+ kfree(zram_devices);
+unregister:
+ unregister_blkdev(zram_major, "zram");
+out:
+ return ret;
+}
+
+static void __exit zram_exit(void)
+{
+ int i;
+ struct zram *zram;
+
+ for (i = 0; i < num_devices; i++) {
+ zram = &zram_devices[i];
+
+ destroy_device(zram);
+ /*
+ * Shouldn't access zram->disk after destroy_device
+ * because destroy_device already released zram->disk.
+ */
+ zram_reset_device(zram);
+ }
+
+ unregister_blkdev(zram_major, "zram");
+
+ kfree(zram_devices);
+ pr_debug("Cleanup done!\n");
+}
+
+module_init(zram_init);
+module_exit(zram_exit);
+
+module_param(num_devices, uint, 0);
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
+MODULE_DESCRIPTION("Compressed RAM Block Device");
--- /dev/null
+/*
+ * Compressed RAM block device
+ *
+ * Copyright (C) 2008, 2009, 2010 Nitin Gupta
+ * 2012, 2013 Minchan Kim
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the licence that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ *
+ */
+
+#ifndef _ZRAM_DRV_H_
+#define _ZRAM_DRV_H_
+
+#include <linux/spinlock.h>
+#include <linux/zsmalloc.h>
+
+#include "zcomp.h"
+
+/*
+ * Some arbitrary value. This is just to catch
+ * invalid value for num_devices module parameter.
+ */
+static const unsigned max_num_devices = 32;
+
+/*-- Configurable parameters */
+
+/*
+ * Pages that compress to size greater than this are stored
+ * uncompressed in memory.
+ */
+static const size_t max_zpage_size = PAGE_SIZE / 4 * 3;
+
+/*
+ * NOTE: max_zpage_size must be less than or equal to:
+ * ZS_MAX_ALLOC_SIZE. Otherwise, zs_malloc() would
+ * always return failure.
+ */
+
+/*-- End of configurable params */
+
+#define SECTOR_SHIFT 9
+#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
+#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT)
+#define ZRAM_LOGICAL_BLOCK_SHIFT 12
+#define ZRAM_LOGICAL_BLOCK_SIZE (1 << ZRAM_LOGICAL_BLOCK_SHIFT)
+#define ZRAM_SECTOR_PER_LOGICAL_BLOCK \
+ (1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT))
+
+
+/*
+ * The lower ZRAM_FLAG_SHIFT bits of table.value is for
+ * object size (excluding header), the higher bits is for
+ * zram_pageflags.
+ *
+ * zram is mainly used for memory efficiency so we want to keep memory
+ * footprint small so we can squeeze size and flags into a field.
+ * The lower ZRAM_FLAG_SHIFT bits is for object size (excluding header),
+ * the higher bits is for zram_pageflags.
+ */
+#define ZRAM_FLAG_SHIFT 24
+
+/* Flags for zram pages (table[page_no].value) */
+enum zram_pageflags {
+ /* Page consists entirely of zeros */
+ ZRAM_ZERO = ZRAM_FLAG_SHIFT,
+ ZRAM_ACCESS, /* page is now accessed */
+
+ __NR_ZRAM_PAGEFLAGS,
+};
+
+/*-- Data structures */
+
+/* Allocated for each disk page */
+struct zram_table_entry {
+ unsigned long handle;
+ unsigned long value;
+};
+
+struct zram_stats {
+ atomic64_t compr_data_size; /* compressed size of pages stored */
+ atomic64_t num_reads; /* failed + successful */
+ atomic64_t num_writes; /* --do-- */
+ atomic64_t failed_reads; /* can happen when memory is too low */
+ atomic64_t failed_writes; /* can happen when memory is too low */
+ atomic64_t invalid_io; /* non-page-aligned I/O requests */
+ atomic64_t notify_free; /* no. of swap slot free notifications */
+ atomic64_t zero_pages; /* no. of zero filled pages */
+ atomic64_t pages_stored; /* no. of pages currently stored */
+ atomic_long_t max_used_pages; /* no. of maximum pages stored */
+};
+
+struct zram_meta {
+ struct zram_table_entry *table;
+ struct zs_pool *mem_pool;
+};
+
+struct zram {
+ struct zram_meta *meta;
+ struct request_queue *queue;
+ struct gendisk *disk;
+ struct zcomp *comp;
+
+ /* Prevent concurrent execution of device init, reset and R/W request */
+ struct rw_semaphore init_lock;
+ /*
+ * This is the limit on amount of *uncompressed* worth of data
+ * we can store in a disk.
+ */
+ u64 disksize; /* bytes */
+ int max_comp_streams;
+ struct zram_stats stats;
+ /*
+ * the number of pages zram can consume for storing compressed data
+ */
+ unsigned long limit_pages;
+
+ char compressor[10];
+};
+#endif
{ USB_DEVICE(0x0CF3, 0x3004) },
{ USB_DEVICE(0x0CF3, 0x3008) },
{ USB_DEVICE(0x0CF3, 0x311D) },
+ { USB_DEVICE(0x0CF3, 0x311E) },
+ { USB_DEVICE(0x0CF3, 0x311F) },
{ USB_DEVICE(0x0CF3, 0x817a) },
{ USB_DEVICE(0x13d3, 0x3375) },
{ USB_DEVICE(0x04CA, 0x3004) },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311F), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
#define BTUSB_WRONG_SCO_MTU 0x40
#define BTUSB_ATH3012 0x80
#define BTUSB_INTEL 0x100
+#define BTUSB_INTEL_BOOT 0x200
static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
/*Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+ /* IMC Networks - Broadcom based */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) },
+
+ /* Intel Bluetooth USB Bootloader (RAM module) */
+ { USB_DEVICE(0x8087, 0x0a5a),
+ .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC },
+
{ } /* Terminating entry */
};
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
if (id->driver_info & BTUSB_INTEL)
hdev->setup = btusb_setup_intel;
+ if (id->driver_info & BTUSB_INTEL_BOOT)
+ set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+
/* Interface numbers are hardcoded in the specification */
data->isoc = usb_ifnum_to_if(data->udev, 1);
spin_lock_irqsave(&pcpu->target_freq_lock, flags);
do_div(cputime_speedadj, delta_time);
loadadjfreq = (unsigned int)cputime_speedadj * 100;
- cpu_load = loadadjfreq / pcpu->target_freq;
+ cpu_load = loadadjfreq / pcpu->policy->cur;
tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime;
#ifdef CONFIG_ARCH_ROCKCHIP
* c->desc is NULL and exit.)
*/
if (c->desc) {
+ omap_dma_desc_free(&c->desc->vd);
c->desc = NULL;
/* Avoid stopping the dma twice */
if (!c->paused)
* sbridge structs
*/
-#define NUM_CHANNELS 4
-#define MAX_DIMMS 3 /* Max DIMMS per channel */
+#define NUM_CHANNELS 4
+#define MAX_DIMMS 3 /* Max DIMMS per channel */
+#define CHANNEL_UNSPECIFIED 0xf /* Intel IA32 SDM 15-14 */
struct sbridge_info {
u32 mcmtr;
/* FIXME: need support for channel mask */
+ if (channel == CHANNEL_UNSPECIFIED)
+ channel = -1;
+
/* Call the helper to output message */
edac_mc_handle_error(tp_event, mci, core_err_cnt,
m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
gator-$(CONFIG_ARM64) +=
+$(obj)/gator_main.o: $(obj)/gator_src_md5.h
+
+clean-files := gator_src_md5.h
+
+# Note, in the recipe below we use "cd $(srctree) && cd $(src)" rather than
+# "cd $(srctree)/$(src)" because under DKMS $(src) is an absolute path, and we
+# can't just use $(src) because for normal kernel builds this is relative to
+# $(srctree)
+
+ chk_events.h = :
+ quiet_chk_events.h = echo ' CHK $@'
+silent_chk_events.h = :
+$(obj)/gator_src_md5.h: FORCE
+ @$($(quiet)chk_events.h)
+ $(Q)cd $(srctree) && cd $(src) ; $(CONFIG_SHELL) -c "echo 'static char *gator_src_md5 = \"'\`ls *.c *.h mali/*.h | grep -Ev '^(gator_src_md5\.c|gator\.mod\.c)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32\`'\";'" > $(abspath $@)
+
else
all:
$(error)
clean:
- rm -f *.o .*.cmd modules.order Module.symvers gator.ko gator.mod.c
+ rm -f *.o .*.cmd gator_src_md5.h modules.order Module.symvers gator.ko gator.mod.c
rm -rf .tmp_versions
endif
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER)
/* cpu ids */
-#define ARM1136 0xb36
-#define ARM1156 0xb56
-#define ARM1176 0xb76
-#define ARM11MPCORE 0xb02
-#define CORTEX_A5 0xc05
-#define CORTEX_A7 0xc07
-#define CORTEX_A8 0xc08
-#define CORTEX_A9 0xc09
-#define CORTEX_A15 0xc0f
-#define CORTEX_A17 0xc0e
-#define SCORPION 0x00f
-#define SCORPIONMP 0x02d
-#define KRAITSIM 0x049
-#define KRAIT 0x04d
-#define KRAIT_S4_PRO 0x06f
-#define CORTEX_A53 0xd03
-#define CORTEX_A57 0xd07
-#define AARCH64 0xd0f
-#define OTHER 0xfff
+#define ARM1136 0x41b36
+#define ARM1156 0x41b56
+#define ARM1176 0x41b76
+#define ARM11MPCORE 0x41b02
+#define CORTEX_A5 0x41c05
+#define CORTEX_A7 0x41c07
+#define CORTEX_A8 0x41c08
+#define CORTEX_A9 0x41c09
+#define CORTEX_A15 0x41c0f
+#define CORTEX_A12 0x41c0d
+#define CORTEX_A17 0x41c0e
+#define SCORPION 0x5100f
+#define SCORPIONMP 0x5102d
+#define KRAITSIM 0x51049
+#define KRAIT 0x5104d
+#define KRAIT_S4_PRO 0x5106f
+#define CORTEX_A53 0x41d03
+#define CORTEX_A57 0x41d07
+#define CORTEX_A72 0x41d08
+#define OTHER 0xfffff
/* gpu enums */
#define MALI_4xx 1
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2012-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2012-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
* l2c310 (L2 Cache Controller) event counters for gator
*
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2011-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2011-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2012-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2012-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2012-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2012-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2011-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2011-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2012-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2012-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/* Mali Midgard DDK includes */
#if defined(MALI_SIMPLE_API)
/* Header with wrapper functions to kbase structures and functions */
-#include "mali/mali_kbase_gator_api.h"
+#include "mali_kbase_gator_api.h"
#elif defined(MALI_DIR_MIDGARD)
/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard */
#include "mali_linux_trace.h"
#error MALI_DDK_GATOR_API_VERSION is invalid (must be 1 for r1/r2 DDK, or 2 for r3/r4 DDK, or 3 for r5 and later DDK).
#endif
+#if !defined(CONFIG_MALI_GATOR_SUPPORT)
+#error CONFIG_MALI_GATOR_SUPPORT is required for GPU activity and software counters
+#endif
+
#include "gator_events_mali_common.h"
/*
{
const int block = GET_HW_BLOCK(cnt);
const int counter_offset = GET_COUNTER_OFFSET(cnt);
+ u32 value = 0;
#if MALI_DDK_GATOR_API_VERSION == 3
const char *block_base_address = (char *)in_out_info->kernel_dump_buffer;
int i;
int shader_core_count = 0;
- u32 value = 0;
for (i = 0; i < in_out_info->nr_hwc_blocks; i++) {
if (block == in_out_info->hwc_layout[i]) {
if (shader_core_count > 1)
value /= shader_core_count;
#else
+ const unsigned int vithar_blocks[] = {
+ 0x700, /* VITHAR_JOB_MANAGER, Block 0 */
+ 0x400, /* VITHAR_TILER, Block 1 */
+ 0x000, /* VITHAR_SHADER_CORE, Block 2 */
+ 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */
+ };
const char *block_base_address = (char *)kernel_dump_buffer + vithar_blocks[block];
/* If counter belongs to shader block need to take into account all cores */
* Only process hardware counters if at least one of the hardware counters is enabled.
*/
if (num_hardware_counters_enabled > 0) {
-#if MALI_DDK_GATOR_API_VERSION != 3
- const unsigned int vithar_blocks[] = {
- 0x700, /* VITHAR_JOB_MANAGER, Block 0 */
- 0x400, /* VITHAR_TILER, Block 1 */
- 0x000, /* VITHAR_SHADER_CORE, Block 2 */
- 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */
- };
-#endif
-
#if MALI_DDK_GATOR_API_VERSION == 3
if (!handles)
return -1;
/* Mali symbols can be called safely since a kbcontext is valid */
- if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success) == MALI_TRUE) {
+ if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success)) {
#else
if (!kbcontext)
return -1;
/* Mali symbols can be called safely since a kbcontext is valid */
- if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success) == MALI_TRUE) {
+ if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success)) {
#endif
kbase_device_busy = false;
- if (success == MALI_TRUE) {
+ if (success) {
/* Cycle through hardware counters and accumulate totals */
for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
const struct mali_counter *counter = &counters[cnt];
/**
- * Copyright (C) ARM Limited 2012-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2012-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
static ulong proc_keys[PROC_COUNT];
static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]);
+static void do_read(void);
+
#if USE_THREAD
static int gator_meminfo_func(void *data);
if (GATOR_REGISTER_TRACE(mm_page_alloc))
goto mm_page_alloc_exit;
+ do_read();
#if USE_THREAD
/* Start worker thread */
gator_meminfo_run = true;
/*
* Example events provider
*
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/* Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE */
#define CNTMAX 16
#define CCI_400 4
+#define CCI_500 8
#define CCN_5XX 8
/* Maximum number of uncore counters */
/* + 1 for the cci-400 cycles counter */
+/* cci-500 has no cycles counter */
/* + 1 for the CCN-5xx cycles counter */
-#define UCCNT (CCI_400 + 1 + CCN_5XX + 1)
+#define UCCNT (CCI_400 + 1 + CCI_500 + CCN_5XX + 1)
/* Default to 0 if unable to probe the revision which was the previous behavior */
#define DEFAULT_CCI_REVISION 0
static int uc_attr_count;
struct gator_event {
- int curr;
- int prev;
- int prev_delta;
+ uint32_t curr;
+ uint32_t prev;
+ uint32_t prev_delta;
bool zero;
struct perf_event *pevent;
struct perf_event_attr *pevent_attr;
static void __read(int *const len, int cpu, struct gator_attr *const attr, struct gator_event *const event)
{
- int delta;
+ uint32_t delta;
struct perf_event *const ev = event->pevent;
if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
event->prev_delta = delta;
event->prev = event->curr;
per_cpu(perf_cnt, cpu)[(*len)++] = attr->key;
- if (delta < 0)
- delta *= -1;
per_cpu(perf_cnt, cpu)[(*len)++] = delta;
}
}
#endif
-static void gator_events_perf_pmu_uncore_init(const char *const name, const int type, const int count)
+static void gator_events_perf_pmu_uncore_init(const char *const name, const int type, const int count, const bool has_cycles_counter)
{
int cnt;
- snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", name);
- uc_attrs[uc_attr_count].type = type;
- ++uc_attr_count;
+ if (has_cycles_counter) {
+ snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", name);
+ uc_attrs[uc_attr_count].type = type;
+ ++uc_attr_count;
+ }
for (cnt = 0; cnt < count; ++cnt, ++uc_attr_count) {
struct gator_attr *const attr = &uc_attrs[uc_attr_count];
}
}
-static void gator_events_perf_pmu_cci_init(const int type)
+static void gator_events_perf_pmu_cci_400_init(const int type)
{
const char *cci_name;
return;
}
- gator_events_perf_pmu_uncore_init(cci_name, type, CCI_400);
+ gator_events_perf_pmu_uncore_init(cci_name, type, CCI_400, true);
}
static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_cpu, const int type)
if (pe->pmu != NULL && type == pe->pmu->type) {
if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400-r1", pe->pmu->name) == 0) {
- gator_events_perf_pmu_cci_init(type);
+ gator_events_perf_pmu_cci_400_init(type);
+ } else if (strcmp("CCI_500", pe->pmu->name) == 0) {
+ gator_events_perf_pmu_uncore_init("CCI_500", type, CCI_500, false);
} else if (strcmp("ccn", pe->pmu->name) == 0) {
- gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX);
+ gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX, true);
} else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) {
found_cpu = true;
gator_events_perf_pmu_cpu_init(gator_cpu, type);
}
if (!found_cpu) {
- const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid());
+ const struct gator_cpu *gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid());
- if (gator_cpu == NULL)
- return -1;
+ if (gator_cpu == NULL) {
+ gator_cpu = gator_find_cpu_by_cpuid(OTHER);
+ if (gator_cpu == NULL) {
+ pr_err("gator: Didn't find cpu\n");
+ return -1;
+ }
+ }
gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW);
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2011-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2011-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2011-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2011-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
*/
/* This version must match the gator daemon version */
-#define PROTOCOL_VERSION 20
+#define PROTOCOL_VERSION 21
static unsigned long gator_protocol_version = PROTOCOL_VERSION;
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "gator.h"
+#include "gator_src_md5.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
#error kernels prior to 2.6.32 are not supported
/* Name Frame Messages */
#define MESSAGE_COOKIE 1
#define MESSAGE_THREAD_NAME 2
-#define MESSAGE_LINK 4
/* Scheduler Trace Frame Messages */
#define MESSAGE_SCHED_SWITCH 1
#define MESSAGE_SCHED_EXIT 2
-/* Idle Frame Messages */
-#define MESSAGE_IDLE_ENTER 1
-#define MESSAGE_IDLE_EXIT 2
-
/* Summary Frame Messages */
#define MESSAGE_SUMMARY 1
#define MESSAGE_CORE_NAME 3
/* Activity Frame Messages */
+#define MESSAGE_LINK 1
#define MESSAGE_SWITCH 2
#define MESSAGE_EXIT 3
* Misc
******************************************************************************/
+MODULE_PARM_DESC(gator_src_md5, "Gator driver source code md5sum");
+module_param_named(src_md5, gator_src_md5, charp, 0444);
+
static const struct gator_cpu gator_cpus[] = {
{
.cpuid = ARM1136,
.dt_name = "arm,cortex-a15",
.pmnc_counters = 6,
},
+ {
+ .cpuid = CORTEX_A12,
+ .core_name = "Cortex-A17",
+ .pmnc_name = "ARMv7_Cortex_A17",
+ .dt_name = "arm,cortex-a17",
+ .pmnc_counters = 6,
+ },
{
.cpuid = CORTEX_A17,
.core_name = "Cortex-A17",
.pmnc_counters = 6,
},
{
- .cpuid = AARCH64,
- .core_name = "AArch64",
- .pmnc_name = "ARM_AArch64",
+ .cpuid = CORTEX_A72,
+ .core_name = "Cortex-A72",
+ .pmnc_name = "ARM_Cortex-A72",
+ .dt_name = "arm,cortex-a72",
.pmnc_counters = 6,
},
{
#else
asm volatile("mrs %0, midr_el1" : "=r" (val));
#endif
- return (val >> 4) & 0xfff;
+ return ((val & 0xff000000) >> 12) | ((val & 0xfff0) >> 4);
#else
return OTHER;
#endif
if (cpuid == -1)
snprintf(core_name_buf, sizeof(core_name_buf), "Unknown");
else
- snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid);
+ snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.5x)", cpuid);
core_name = core_name_buf;
}
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
if (time >= gator_sync_time) {
- int cpu = get_physical_cpu();
-
marshal_event_single64(0, -1, local_clock());
gator_sync_time += NSEC_PER_SEC;
- gator_commit_buffer(cpu, COUNTER_BUF, time);
+ if (gator_live_rate <= 0) {
+ gator_commit_buffer(get_physical_cpu(), COUNTER_BUF, time);
+ }
}
#endif
}
marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf);
gator_sync_time = 0;
- gator_emit_perf_time(gator_monotonic_started);
+ gator_emit_perf_time(gator_monotonic_started);
+ /* Always flush COUNTER_BUF so that the initial perf_time is received before it's used */
+ gator_commit_buffer(get_physical_cpu(), COUNTER_BUF, 0);
preempt_enable();
}
/**
- * Copyright (C) ARM Limited 2012-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2012-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
local_irq_save(flags);
time = gator_get_time();
- if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
- gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_LINK);
- gator_buffer_write_packed_int64(cpu, NAME_BUF, time);
- gator_buffer_write_packed_int(cpu, NAME_BUF, cookie);
- gator_buffer_write_packed_int(cpu, NAME_BUF, tgid);
- gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
+ if (buffer_check_space(cpu, ACTIVITY_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
+ gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, MESSAGE_LINK);
+ gator_buffer_write_packed_int64(cpu, ACTIVITY_BUF, time);
+ gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, cookie);
+ gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, tgid);
+ gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, pid);
}
local_irq_restore(flags);
/* Check and commit; commit is set to occur once buffer is 3/4 full */
- buffer_check(cpu, NAME_BUF, time);
+ buffer_check(cpu, ACTIVITY_BUF, time);
}
static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 time)
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2011-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2011-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
return;
if (implements_wfi()) {
- if (state == PWR_EVENT_EXIT) {
- /* transition from wfi to non-wfi */
- marshal_idle(cpu, MESSAGE_IDLE_EXIT);
- } else {
- /* transition from non-wfi to wfi */
- marshal_idle(cpu, MESSAGE_IDLE_ENTER);
- }
+ marshal_idle(cpu, state);
}
per_cpu(idle_prev_state, cpu) = state;
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
+++ /dev/null
-/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#ifndef _KBASE_GATOR_API_H_
-#define _KBASE_GATOR_API_H_
-
-/**
- * @brief This file describes the API used by Gator to collect hardware counters data from a Mali device.
- */
-
-/* This define is used by the gator kernel module compile to select which DDK
- * API calling convention to use. If not defined (legacy DDK) gator assumes
- * version 1. The version to DDK release mapping is:
- * Version 1 API: DDK versions r1px, r2px
- * Version 2 API: DDK versions r3px, r4px
- * Version 3 API: DDK version r5p0 and newer
- *
- * API Usage
- * =========
- *
- * 1] Call kbase_gator_hwcnt_init_names() to return the list of short counter
- * names for the GPU present in this device.
- *
- * 2] Create a kbase_gator_hwcnt_info structure and set the counter enables for
- * the counters you want enabled. The enables can all be set for simplicity in
- * most use cases, but disabling some will let you minimize bandwidth impact.
- *
- * 3] Call kbase_gator_hwcnt_init() using the above structure, to create a
- * counter context. On successful return the DDK will have populated the
- * structure with a variety of useful information.
- *
- * 4] Call kbase_gator_hwcnt_dump_irq() to queue a non-blocking request for a
- * counter dump. If this returns a non-zero value the request has been queued,
- * otherwise the driver has been unable to do so (typically because of another
- * user of the instrumentation exists concurrently).
- *
- * 5] Call kbase_gator_hwcnt_dump_complete() to test whether the previously
- * requested dump has been succesful. If this returns non-zero the counter dump
- * has resolved, but the value of *success must also be tested as the dump
- * may have not been successful. If it returns zero the counter dump was
- * abandoned due to the device being busy (typically because of another
- * user of the instrumentation exists concurrently).
- *
- * 6] Process the counters stored in the buffer pointed to by ...
- *
- * kbase_gator_hwcnt_info->kernel_dump_buffer
- *
- * In pseudo code you can find all of the counters via this approach:
- *
- *
- * hwcnt_info # pointer to kbase_gator_hwcnt_info structure
- * hwcnt_name # pointer to name list
- *
- * u32 * hwcnt_data = (u32*)hwcnt_info->kernel_dump_buffer
- *
- * # Iterate over each 64-counter block in this GPU configuration
- * for( i = 0; i < hwcnt_info->nr_hwc_blocks; i++) {
- * hwc_type type = hwcnt_info->hwc_layout[i];
- *
- * # Skip reserved type blocks - they contain no counters at all
- * if( type == RESERVED_BLOCK ) {
- * continue;
- * }
- *
- * size_t name_offset = type * 64;
- * size_t data_offset = i * 64;
- *
- * # Iterate over the names of the counters in this block type
- * for( j = 0; j < 64; j++) {
- * const char * name = hwcnt_name[name_offset+j];
- *
- * # Skip empty name strings - there is no counter here
- * if( name[0] == '\0' ) {
- * continue;
- * }
- *
- * u32 data = hwcnt_data[data_offset+j];
- *
- * printk( "COUNTER: %s DATA: %u\n", name, data );
- * }
- * }
- *
- *
- * Note that in most implementations you typically want to either SUM or
- * AVERAGE multiple instances of the same counter if, for example, you have
- * multiple shader cores or multiple L2 caches. The most sensible view for
- * analysis is to AVERAGE shader core counters, but SUM L2 cache and MMU
- * counters.
- *
- * 7] Goto 4, repeating until you want to stop collecting counters.
- *
- * 8] Release the dump resources by calling kbase_gator_hwcnt_term().
- *
- * 9] Release the name table resources by calling kbase_gator_hwcnt_term_names().
- * This function must only be called if init_names() returned a non-NULL value.
- **/
-
-#define MALI_DDK_GATOR_API_VERSION 3
-
-#if !defined(MALI_TRUE)
- #define MALI_TRUE ((uint32_t)1)
-#endif
-
-#if !defined(MALI_FALSE)
- #define MALI_FALSE ((uint32_t)0)
-#endif
-
-enum hwc_type {
- JM_BLOCK = 0,
- TILER_BLOCK,
- SHADER_BLOCK,
- MMU_L2_BLOCK,
- RESERVED_BLOCK
-};
-
-struct kbase_gator_hwcnt_info {
-
- /* Passed from Gator to kbase */
-
- /* the bitmask of enabled hardware counters for each counter block */
- uint16_t bitmask[4];
-
- /* Passed from kbase to Gator */
-
- /* ptr to counter dump memory */
- void *kernel_dump_buffer;
-
- /* size of counter dump memory */
- uint32_t size;
-
- /* the ID of the Mali device */
- uint32_t gpu_id;
-
- /* the number of shader cores in the GPU */
- uint32_t nr_cores;
-
- /* the number of core groups */
- uint32_t nr_core_groups;
-
- /* the memory layout of the performance counters */
- enum hwc_type *hwc_layout;
-
- /* the total number of hardware couter blocks */
- uint32_t nr_hwc_blocks;
-};
-
-/**
- * @brief Opaque block of Mali data which Gator needs to return to the API later.
- */
-struct kbase_gator_hwcnt_handles;
-
-/**
- * @brief Initialize the resources Gator needs for performance profiling.
- *
- * @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the Mali
- * specific information that will be returned to Gator. On entry Gator must have populated the
- * 'bitmask' field with the counters it wishes to enable for each class of counter block.
- * Each entry in the array corresponds to a single counter class based on the "hwc_type"
- * enumeration, and each bit corresponds to an enable for 4 sequential counters (LSB enables
- * the first 4 counters in the block, and so on). See the GPU counter array as returned by
- * kbase_gator_hwcnt_get_names() for the index values of each counter for the curernt GPU.
- *
- * @return Pointer to an opaque handle block on success, NULL on error.
- */
-extern struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info);
-
-/**
- * @brief Free all resources once Gator has finished using performance counters.
- *
- * @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the
- * Mali specific information that will be returned to Gator.
- * @param opaque_handles A wrapper structure for kbase structures.
- */
-extern void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles);
-
-/**
- * @brief Poll whether a counter dump is successful.
- *
- * @param opaque_handles A wrapper structure for kbase structures.
- * @param[out] success Non-zero on success, zero on failure.
- *
- * @return Zero if the dump is still pending, non-zero if the dump has completed. Note that a
- * completed dump may not have dumped succesfully, so the caller must test for both
- * a completed and successful dump before processing counters.
- */
-extern uint32_t kbase_gator_instr_hwcnt_dump_complete(struct kbase_gator_hwcnt_handles *opaque_handles, uint32_t * const success);
-
-/**
- * @brief Request the generation of a new counter dump.
- *
- * @param opaque_handles A wrapper structure for kbase structures.
- *
- * @return Zero if the hardware device is busy and cannot handle the request, non-zero otherwise.
- */
-extern uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles);
-
-/**
- * @brief This function is used to fetch the names table based on the Mali device in use.
- *
- * @param[out] total_number_of_counters The total number of counters short names in the Mali devices' list.
- *
- * @return Pointer to an array of strings of length *total_number_of_counters.
- */
-extern const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_number_of_counters);
-
-/**
- * @brief This function is used to terminate the use of the names table.
- *
- * This function must only be called if the initial call to kbase_gator_hwcnt_init_names returned a non-NULL value.
- */
-extern void kbase_gator_hwcnt_term_names(void);
-
-#endif
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/midgard/mali_kbase_gator_api.h),)
EXTRA_CFLAGS += -DMALI_SIMPLE_API=1
+EXTRA_CFLAGS += -I$(DDK_DIR)/drivers/gpu/arm/midgard
endif
UMP_DIR = $(DDK_DIR)/include/linux
*/
static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
+ struct gpio_chip *chip;
unsigned long flags;
int status;
const char *ioname = NULL;
return -EINVAL;
}
+ chip = desc->chip;
+
mutex_lock(&sysfs_lock);
+ /* check if chip is being removed */
+ if (!chip || !chip->exported) {
+ status = -ENODEV;
+ goto fail_unlock;
+ }
+
spin_lock_irqsave(&gpio_lock, flags);
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags)) {
{
int status;
struct device *dev;
+ struct gpio_desc *desc;
+ unsigned int i;
mutex_lock(&sysfs_lock);
dev = class_find_device(&gpio_class, NULL, chip, match_export);
sysfs_remove_group(&dev->kobj, &gpiochip_attr_group);
put_device(dev);
device_unregister(dev);
+ /* prevent further gpiod exports */
chip->exported = 0;
status = 0;
} else
if (status)
pr_debug("%s: chip %s status %d\n", __func__,
chip->label, status);
+
+ /* unregister gpiod class devices owned by sysfs */
+ for (i = 0; i < chip->ngpio; i++) {
+ desc = &chip->desc[i];
+ if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
+ gpiod_free(desc);
+ }
}
static int __init gpiolib_sysfs_init(void)
int status = 0;
unsigned id;
+ gpiochip_unexport(chip);
+
spin_lock_irqsave(&gpio_lock, flags);
gpiochip_remove_pin_ranges(chip);
spin_unlock_irqrestore(&gpio_lock, flags);
- if (status == 0)
- gpiochip_unexport(chip);
-
return status;
}
EXPORT_SYMBOL_GPL(gpiochip_remove);
#define GMBUS_CYCLE_INDEX (2<<25)
#define GMBUS_CYCLE_STOP (4<<25)
#define GMBUS_BYTE_COUNT_SHIFT 16
+#define GMBUS_BYTE_COUNT_MAX 256U
#define GMBUS_SLAVE_INDEX_SHIFT 8
#define GMBUS_SLAVE_ADDR_SHIFT 1
#define GMBUS_SLAVE_READ (1<<0)
}
static int
-gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
- u32 gmbus1_index)
+gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
+ unsigned short addr, u8 *buf, unsigned int len,
+ u32 gmbus1_index)
{
int reg_offset = dev_priv->gpio_mmio_base;
- u16 len = msg->len;
- u8 *buf = msg->buf;
I915_WRITE(GMBUS1 + reg_offset,
gmbus1_index |
GMBUS_CYCLE_WAIT |
(len << GMBUS_BYTE_COUNT_SHIFT) |
- (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
+ (addr << GMBUS_SLAVE_ADDR_SHIFT) |
GMBUS_SLAVE_READ | GMBUS_SW_RDY);
while (len) {
int ret;
}
static int
-gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
+gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
+ u32 gmbus1_index)
{
- int reg_offset = dev_priv->gpio_mmio_base;
- u16 len = msg->len;
u8 *buf = msg->buf;
+ unsigned int rx_size = msg->len;
+ unsigned int len;
+ int ret;
+
+ do {
+ len = min(rx_size, GMBUS_BYTE_COUNT_MAX);
+
+ ret = gmbus_xfer_read_chunk(dev_priv, msg->addr,
+ buf, len, gmbus1_index);
+ if (ret)
+ return ret;
+
+ rx_size -= len;
+ buf += len;
+ } while (rx_size != 0);
+
+ return 0;
+}
+
+static int
+gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
+ unsigned short addr, u8 *buf, unsigned int len)
+{
+ int reg_offset = dev_priv->gpio_mmio_base;
+ unsigned int chunk_size = len;
u32 val, loop;
val = loop = 0;
I915_WRITE(GMBUS3 + reg_offset, val);
I915_WRITE(GMBUS1 + reg_offset,
GMBUS_CYCLE_WAIT |
- (msg->len << GMBUS_BYTE_COUNT_SHIFT) |
- (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
+ (chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
+ (addr << GMBUS_SLAVE_ADDR_SHIFT) |
GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
while (len) {
int ret;
if (ret)
return ret;
}
+
+ return 0;
+}
+
+static int
+gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
+{
+ u8 *buf = msg->buf;
+ unsigned int tx_size = msg->len;
+ unsigned int len;
+ int ret;
+
+ do {
+ len = min(tx_size, GMBUS_BYTE_COUNT_MAX);
+
+ ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len);
+ if (ret)
+ return ret;
+
+ buf += len;
+ tx_size -= len;
+ } while (tx_size != 0);
+
return 0;
}
static const struct dmi_system_id intel_dual_link_lvds[] = {
{
.callback = intel_dual_link_lvds_callback,
- .ident = "Apple MacBook Pro (Core i5/i7 Series)",
+ .ident = "Apple MacBook Pro 15\" (2010)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6,2"),
+ },
+ },
+ {
+ .callback = intel_dual_link_lvds_callback,
+ .ident = "Apple MacBook Pro 15\" (2011)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"),
},
},
+ {
+ .callback = intel_dual_link_lvds_callback,
+ .ident = "Apple MacBook Pro 15\" (2012)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,1"),
+ },
+ },
{ } /* terminating entry */
};
misc |= ATOM_COMPOSITESYNC;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
misc |= ATOM_INTERLACE;
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
misc |= ATOM_DOUBLE_CLOCK_MODE;
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
misc |= ATOM_COMPOSITESYNC;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
misc |= ATOM_INTERLACE;
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
misc |= ATOM_DOUBLE_CLOCK_MODE;
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+ misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2;
args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
args.ucCRTC = radeon_crtc->crtc_id;
static bool radeon_read_bios(struct radeon_device *rdev)
{
- uint8_t __iomem *bios;
+ uint8_t __iomem *bios, val1, val2;
size_t size;
rdev->bios = NULL;
return false;
}
- if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ val1 = readb(&bios[0]);
+ val2 = readb(&bios[1]);
+
+ if (size == 0 || val1 != 0x55 || val2 != 0xaa) {
pci_unmap_rom(rdev->pdev, bios);
return false;
}
- rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+ rdev->bios = kzalloc(size, GFP_KERNEL);
if (rdev->bios == NULL) {
pci_unmap_rom(rdev->pdev, bios);
return false;
}
+ memcpy_fromio(rdev->bios, bios, size);
pci_unmap_rom(rdev->pdev, bios);
return true;
}
GFP_KERNEL);
if (!open_info) {
err = -ENOMEM;
- goto error0;
+ goto error_gpadl;
}
init_completion(&open_info->waitevent);
if (userdatalen > MAX_USER_DEFINED_BYTES) {
err = -EINVAL;
- goto error0;
+ goto error_gpadl;
}
if (userdatalen)
list_del(&open_info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+error_gpadl:
+ vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
+
error0:
free_pages((unsigned long)out,
get_order(send_ringbuffer_size + recv_ringbuffer_size));
{
struct vmbus_channel_message_header *msg;
struct vmbus_channel_msginfo *msginfo;
- int ret, t;
+ int ret;
msginfo = kmalloc(sizeof(*msginfo) +
sizeof(struct vmbus_channel_message_header),
if (!msginfo)
return -ENOMEM;
- init_completion(&msginfo->waitevent);
-
msg = (struct vmbus_channel_message_header *)msginfo->msg;
msg->msgtype = CHANNELMSG_REQUESTOFFERS;
goto cleanup;
}
- t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
-
-
cleanup:
kfree(msginfo);
adap->bus_recovery_info->set_scl(adap, 1);
return i2c_generic_recovery(adap);
}
+EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
int i2c_generic_gpio_recovery(struct i2c_adapter *adap)
{
return ret;
}
+EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery);
int i2c_recover_bus(struct i2c_adapter *adap)
{
dev_dbg(&adap->dev, "Trying i2c bus recovery\n");
return adap->bus_recovery_info->recover_bus(adap);
}
+EXPORT_SYMBOL_GPL(i2c_recover_bus);
static int i2c_device_probe(struct device *dev)
{
iio_trigger_set_drvdata(adis->trig, adis);
ret = iio_trigger_register(adis->trig);
- indio_dev->trig = adis->trig;
+ indio_dev->trig = iio_trigger_get(adis->trig);
if (ret)
goto error_free_irq;
#include <linux/poll.h>
#include "inv_mpu_iio.h"
+static void inv_clear_kfifo(struct inv_mpu6050_state *st)
+{
+ unsigned long flags;
+
+ /* take the spin lock sem to avoid interrupt kick in */
+ spin_lock_irqsave(&st->time_stamp_lock, flags);
+ kfifo_reset(&st->timestamps);
+ spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
int inv_reset_fifo(struct iio_dev *indio_dev)
{
int result;
INV_MPU6050_BIT_FIFO_RST);
if (result)
goto reset_fifo_fail;
+
+ /* clear timestamps fifo */
+ inv_clear_kfifo(st);
+
/* enable interrupt */
if (st->chip_config.accl_fifo_enable ||
st->chip_config.gyro_fifo_enable) {
return result;
}
-static void inv_clear_kfifo(struct inv_mpu6050_state *st)
-{
- unsigned long flags;
-
- /* take the spin lock sem to avoid interrupt kick in */
- spin_lock_irqsave(&st->time_stamp_lock, flags);
- kfifo_reset(&st->timestamps);
- spin_unlock_irqrestore(&st->time_stamp_lock, flags);
-}
-
/**
* inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt.
*/
flush_fifo:
/* Flush HW and SW FIFOs. */
inv_reset_fifo(indio_dev);
- inv_clear_kfifo(st);
mutex_unlock(&indio_dev->mlock);
iio_trigger_notify_done(indio_dev->trig);
if (dmasync)
dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
+ if (!size)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * If the combination of the addr and size requested for this memory
+ * region causes an integer overflow, return error.
+ */
+ if (((addr + size) < addr) ||
+ PAGE_ALIGN(addr + size) < (addr + size))
+ return ERR_PTR(-EINVAL);
+
if (!can_do_mlock())
return ERR_PTR(-EPERM);
entry->desc.async.element = element;
entry->desc.async.event_type = event;
+ entry->desc.async.reserved = 0;
entry->counter = counter;
list_add_tail(&entry->list, &file->async_file->event_list);
#define GUID_TBL_BLK_NUM_ENTRIES 8
#define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES)
+/* Counters should be saturate once they reach their maximum value */
+#define ASSIGN_32BIT_COUNTER(counter, value) do {\
+ if ((value) > U32_MAX) \
+ counter = cpu_to_be32(U32_MAX); \
+ else \
+ counter = cpu_to_be32(value); \
+} while (0)
+
struct mlx4_mad_rcv_buf {
struct ib_grh grh;
u8 payload[256];
static void edit_counter(struct mlx4_counter *cnt,
struct ib_pma_portcounters *pma_cnt)
{
- pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2));
- pma_cnt->port_rcv_data = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2));
- pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames));
- pma_cnt->port_rcv_packets = cpu_to_be32(be64_to_cpu(cnt->rx_frames));
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
+ (be64_to_cpu(cnt->tx_bytes) >> 2));
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
+ (be64_to_cpu(cnt->rx_bytes) >> 2));
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
+ be64_to_cpu(cnt->tx_frames));
+ ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
+ be64_to_cpu(cnt->rx_frames));
}
static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen);
- *lso_hdr_sz = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 |
- wr->wr.ud.hlen);
+ *lso_hdr_sz = cpu_to_be32(wr->wr.ud.mss << 16 | wr->wr.ud.hlen);
*lso_seg_len = halign;
return 0;
}
return PSMOUSE_FULL_PACKET;
}
+/*
+ * This writes the reg_07 value again to the hardware at the end of every
+ * set_rate call because the register loses its value. reg_07 allows setting
+ * absolute mode on v4 hardware
+ */
+static void elantech_set_rate_restore_reg_07(struct psmouse *psmouse,
+ unsigned int rate)
+{
+ struct elantech_data *etd = psmouse->private;
+
+ etd->original_set_rate(psmouse, rate);
+ if (elantech_write_reg(psmouse, 0x07, etd->reg_07))
+ psmouse_err(psmouse, "restoring reg_07 failed\n");
+}
+
/*
* Put the touchpad into absolute mode
*/
* Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons
* Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons
* Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons
+ * Asus TP500LN 0x381f17 10, 14, 0e clickpad
+ * Asus X750JN 0x381f17 10, 14, 0e clickpad
* Asus UX31 0x361f00 20, 15, 0e clickpad
* Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad
goto init_fail;
}
+ if (etd->fw_version == 0x381f17) {
+ etd->original_set_rate = psmouse->set_rate;
+ psmouse->set_rate = elantech_set_rate_restore_reg_07;
+ }
+
if (elantech_set_input_params(psmouse)) {
psmouse_err(psmouse, "failed to query touchpad range.\n");
goto init_fail;
struct finger_pos mt[ETP_MAX_FINGERS];
unsigned char parity[256];
int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param);
+ void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate);
};
#ifdef CONFIG_MOUSE_PS2_ELANTECH
/* Offset base used to differentiate between CAPTURE and OUTPUT
* while mmaping */
-#define DST_QUEUE_OFF_BASE (TASK_SIZE / 2)
+#define DST_QUEUE_OFF_BASE (1 << 30)
#define MFC_BANK1_ALLOC_CTX 0
#define MFC_BANK2_ALLOC_CTX 1
if (mutex_lock_interruptible(&dev->v4l_lock))
return -ERESTARTSYS;
+ /*
+ * Once URBs are cancelled, the URB complete handler
+ * won't be running. This is required to safely release the
+ * current buffer (dev->isoc_ctl.buf).
+ */
stk1160_cancel_isoc(dev);
/*
stk1160_info("buffer [%p/%d] aborted\n",
buf, buf->vb.v4l2_buf.index);
}
- /* It's important to clear current buffer */
- dev->isoc_ctl.buf = NULL;
+
+ /* It's important to release the current buffer */
+ if (dev->isoc_ctl.buf) {
+ buf = dev->isoc_ctl.buf;
+ dev->isoc_ctl.buf = NULL;
+
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ stk1160_info("buffer [%p/%d] aborted\n",
+ buf, buf->vb.v4l2_buf.index);
+ }
spin_unlock_irqrestore(&dev->buf_lock, flags);
}
if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) {
if (msb->data_dir == READ) {
- for (cnt = 0; cnt < msb->current_seg; cnt++)
+ for (cnt = 0; cnt < msb->current_seg; cnt++) {
t_len += msb->req_sg[cnt].length
/ msb->page_size;
t_len += msb->current_page - 1;
t_len *= msb->page_size;
+ }
}
} else
t_len = blk_rq_bytes(msb->block_req);
md->reset_done &= ~type;
}
+int mmc_access_rpmb(struct mmc_queue *mq)
+{
+ struct mmc_blk_data *md = mq->data;
+ /*
+ * If this is a RPMB partition access, return ture
+ */
+ if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ return true;
+
+ return false;
+}
+
static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
return BLKPREP_KILL;
}
- if (mq && mmc_card_removed(mq->card))
+ if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
return BLKPREP_KILL;
req->cmd_flags |= REQ_DONTPREP;
extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
extern void mmc_packed_clean(struct mmc_queue *);
+extern int mmc_access_rpmb(struct mmc_queue *);
+
#endif
second_is_newer = !second_is_newer;
} else {
dbg_bld("PEB %d CRC is OK", pnum);
- bitflips = !!err;
+ bitflips |= !!err;
}
mutex_unlock(&ubi->buf_mutex);
/* Validate the request */
err = -EINVAL;
if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
- req.bytes < 0 || req.lnum >= vol->usable_leb_size)
+ req.bytes < 0 || req.bytes > vol->usable_leb_size)
break;
err = get_exclusive(desc);
* during re-size.
*/
ubi_move_aeb_to_list(av, aeb, &ai->erase);
- vol->eba_tbl[aeb->lnum] = aeb->pnum;
+ else
+ vol->eba_tbl[aeb->lnum] = aeb->pnum;
}
}
for (i = 0; i < vol->used_ebs; i++) {
int size;
+ cond_resched();
+
if (i == vol->used_ebs - 1)
size = vol->last_eb_bytes;
else
int cancel)
{
int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
- int vol_id = -1, uninitialized_var(lnum);
+ int vol_id = -1, lnum = -1;
#ifdef CONFIG_MTD_UBI_FASTMAP
int anchor = wrk->anchor;
#endif
sw_cons = BNX2_NEXT_TX_BD(sw_cons);
tx_bytes += skb->len;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
tx_pkt++;
if (tx_pkt == budget)
break;
mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
if (dma_mapping_error(&bp->pdev->dev, mapping)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
PCI_DMA_TODEVICE);
}
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
pkts_compl++;
bytes_compl += skb->len;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
if (unlikely(tx_bug)) {
tg3_tx_recover(tp);
if (len > (tp->dev->mtu + ETH_HLEN) &&
skb->protocol != htons(ETH_P_8021Q) &&
skb->protocol != htons(ETH_P_8021AD)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
goto drop_it_no_recycle;
}
PCI_DMA_TODEVICE);
/* Make sure the mapping succeeded */
if (pci_dma_mapping_error(tp->pdev, new_addr)) {
- dev_kfree_skb(new_skb);
+ dev_kfree_skb_any(new_skb);
ret = -1;
} else {
u32 save_entry = *entry;
new_skb->len, base_flags,
mss, vlan)) {
tg3_tx_skb_unmap(tnapi, save_entry, -1);
- dev_kfree_skb(new_skb);
+ dev_kfree_skb_any(new_skb);
ret = -1;
}
}
}
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
*pskb = new_skb;
return ret;
}
} while (segs);
tg3_tso_bug_end:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i);
tnapi->tx_buffers[tnapi->tx_prod].skb = NULL;
drop:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
drop_nofree:
tp->tx_dropped++;
return NETDEV_TX_OK;
queue_tail_inc(txq);
} while (cur_index != last_index);
- kfree_skb(sent_skb);
+ dev_kfree_skb_any(sent_skb);
return num_wrbs;
}
static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
+static void e1000_alloc_dummy_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int cleaned_count)
+{
+}
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int cleaned_count);
msleep(1);
/* e1000_down has a dependency on max_frame_size */
hw->max_frame_size = max_frame;
- if (netif_running(netdev))
+ if (netif_running(netdev)) {
+ /* prevent buffers from being reallocated */
+ adapter->alloc_rx_buf = e1000_alloc_dummy_rx_buffers;
e1000_down(adapter);
+ }
/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
* means we reserve 2 more, this pushes us to allocate from the next
int tso;
if (test_bit(__IXGB_DOWN, &adapter->flags)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
if (skb->len <= 0) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
tso = ixgb_tso(adapter, skb);
if (tso < 0) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
return NETDEV_TX_OK;
out_dma_error:
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
cp->dev->stats.tx_dropped++;
goto out_unlock;
}
if (len < ETH_ZLEN)
memset(tp->tx_buf[entry], 0, ETH_ZLEN);
skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
} else {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
tp->TxDescArray + entry);
if (skb) {
tp->dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
tx_skb->skb = NULL;
}
}
err_dma_1:
rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
err_dma_0:
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
err_update_stats:
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
tp->tx_stats.packets++;
tp->tx_stats.bytes += tx_skb->skb->len;
u64_stats_update_end(&tp->tx_stats.syncp);
- dev_kfree_skb(tx_skb->skb);
+ dev_kfree_skb_any(tx_skb->skb);
tx_skb->skb = NULL;
}
dirty_tx++;
unsigned long reload_jiffies;
int reload_count;
bool ucode_loaded;
- bool init_ucode_run; /* Don't run init uCode again */
u8 plcp_delta_threshold;
if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len)
return 0;
- if (priv->init_ucode_run)
- return 0;
-
iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
calib_complete, ARRAY_SIZE(calib_complete),
iwlagn_wait_calib, priv);
*/
ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
UCODE_CALIB_TIMEOUT);
- if (!ret)
- priv->init_ucode_run = true;
goto out;
{RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
{RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
{RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
+ {RTL_USB_DEVICE(0x0b05, 0x17ba, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
{RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
{RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
{RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
{RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/
{RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
{RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
+ {RTL_USB_DEVICE(0x2001, 0x330d, rtl92cu_hal_cfg)}, /*D-Link DWA-131 */
{RTL_USB_DEVICE(0x2019, 0xab2b, rtl92cu_hal_cfg)}, /*Planex -Abocom*/
{RTL_USB_DEVICE(0x20f4, 0x624d, rtl92cu_hal_cfg)}, /*TRENDNet*/
{RTL_USB_DEVICE(0x2357, 0x0100, rtl92cu_hal_cfg)}, /*TP-Link WN8200ND*/
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, accum_arp_pend_requests, "%u");
WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u");
-WL18XX_DEBUGFS_FWSTATS_FILE(rx_rate, rx_frames_per_rates, "%u");
+WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(rx_rate, rx_frames_per_rates, 50);
WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate,
AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE);
#include "wlcore.h"
-int wl1271_format_buffer(char __user *userbuf, size_t count,
- loff_t *ppos, char *fmt, ...);
+__printf(4, 5) int wl1271_format_buffer(char __user *userbuf, size_t count,
+ loff_t *ppos, char *fmt, ...);
int wl1271_debugfs_init(struct wl1271 *wl);
void wl1271_debugfs_exit(struct wl1271 *wl);
config PARPORT_PC
tristate "PC-style hardware"
depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \
- (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && !XTENSA
+ (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && \
+ !XTENSA && !CRIS && !H8300 && !ARM64
+
---help---
You should say Y here if you have a PC-style parallel port. All
IBM PC compatible computers and some Alphas have PC-style
EXPORT_SYMBOL_GPL(devm_pinctrl_put);
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
- bool dup, bool locked)
+ bool dup)
{
int i, ret;
struct pinctrl_maps *maps_node;
maps_node->maps = maps;
}
- if (!locked)
- mutex_lock(&pinctrl_maps_mutex);
+ mutex_lock(&pinctrl_maps_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps);
- if (!locked)
- mutex_unlock(&pinctrl_maps_mutex);
+ mutex_unlock(&pinctrl_maps_mutex);
return 0;
}
int pinctrl_register_mappings(struct pinctrl_map const *maps,
unsigned num_maps)
{
- return pinctrl_register_map(maps, num_maps, true, false);
+ return pinctrl_register_map(maps, num_maps, true);
}
void pinctrl_unregister_map(struct pinctrl_map const *map)
}
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
- bool dup, bool locked);
+ bool dup);
void pinctrl_unregister_map(struct pinctrl_map const *map);
extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
dt_map->num_maps = num_maps;
list_add_tail(&dt_map->node, &p->dt_maps);
- return pinctrl_register_map(map, num_maps, false, true);
+ return pinctrl_register_map(map, num_maps, false);
}
struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
pchg->battery.num_properties = ARRAY_SIZE(lp8788_battery_prop);
pchg->battery.get_property = lp8788_battery_get_property;
- if (power_supply_register(&pdev->dev, &pchg->battery))
+ if (power_supply_register(&pdev->dev, &pchg->battery)) {
+ power_supply_unregister(&pchg->charger);
return -EPERM;
+ }
return 0;
}
static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
-static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
/* Functions */
}
/* Now complete the io */
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd);
tw_dev->state[request_id] = TW_S_COMPLETED;
twa_free_request_id(tw_dev, request_id);
tw_dev->posted_request_count--;
- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
- twa_unmap_scsi_data(tw_dev, request_id);
}
/* Check for valid status after each drain */
}
} /* End twa_load_sgl() */
-/* This function will perform a pci-dma mapping for a scatter gather list */
-static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
-{
- int use_sg;
- struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
- use_sg = scsi_dma_map(cmd);
- if (!use_sg)
- return 0;
- else if (use_sg < 0) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
- return 0;
- }
-
- cmd->SCp.phase = TW_PHASE_SGLIST;
- cmd->SCp.have_data_in = use_sg;
-
- return use_sg;
-} /* End twa_map_scsi_sg_data() */
-
/* This function will poll for a response interrupt of a request */
static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
{
(tw_dev->state[i] != TW_S_INITIAL) &&
(tw_dev->state[i] != TW_S_COMPLETED)) {
if (tw_dev->srb[i]) {
- tw_dev->srb[i]->result = (DID_RESET << 16);
- tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
- twa_unmap_scsi_data(tw_dev, i);
+ struct scsi_cmnd *cmd = tw_dev->srb[i];
+
+ cmd->result = (DID_RESET << 16);
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd);
}
}
}
/* Save the scsi command for use by the ISR */
tw_dev->srb[request_id] = SCpnt;
- /* Initialize phase to zero */
- SCpnt->SCp.phase = TW_PHASE_INITIAL;
-
retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
switch (retval) {
case SCSI_MLQUEUE_HOST_BUSY:
+ scsi_dma_unmap(SCpnt);
twa_free_request_id(tw_dev, request_id);
- twa_unmap_scsi_data(tw_dev, request_id);
break;
case 1:
- tw_dev->state[request_id] = TW_S_COMPLETED;
- twa_free_request_id(tw_dev, request_id);
- twa_unmap_scsi_data(tw_dev, request_id);
SCpnt->result = (DID_ERROR << 16);
+ scsi_dma_unmap(SCpnt);
done(SCpnt);
+ tw_dev->state[request_id] = TW_S_COMPLETED;
+ twa_free_request_id(tw_dev, request_id);
retval = 0;
}
out:
command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
} else {
- sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
- if (sg_count == 0)
+ sg_count = scsi_dma_map(srb);
+ if (sg_count < 0)
goto out;
scsi_for_each_sg(srb, sg, sg_count, i) {
return(table[index].text);
} /* End twa_string_lookup() */
-/* This function will perform a pci-dma unmap */
-static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
-{
- struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
- if (cmd->SCp.phase == TW_PHASE_SGLIST)
- scsi_dma_unmap(cmd);
-} /* End twa_unmap_scsi_data() */
-
/* This function gets called when a disk is coming on-line */
static int twa_slave_configure(struct scsi_device *sdev)
{
#define TW_CURRENT_DRIVER_BUILD 0
#define TW_CURRENT_DRIVER_BRANCH 0
-/* Phase defines */
-#define TW_PHASE_INITIAL 0
-#define TW_PHASE_SINGLE 1
-#define TW_PHASE_SGLIST 2
-
/* Misc defines */
#define TW_9550SX_DRAIN_COMPLETED 0xFFFF
#define TW_SECTOR_SIZE 512
return 0;
} /* End twl_post_command_packet() */
-/* This function will perform a pci-dma mapping for a scatter gather list */
-static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
-{
- int use_sg;
- struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
- use_sg = scsi_dma_map(cmd);
- if (!use_sg)
- return 0;
- else if (use_sg < 0) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list");
- return 0;
- }
-
- cmd->SCp.phase = TW_PHASE_SGLIST;
- cmd->SCp.have_data_in = use_sg;
-
- return use_sg;
-} /* End twl_map_scsi_sg_data() */
-
/* This function hands scsi cdb's to the firmware */
static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg)
{
if (!sglistarg) {
/* Map sglist from scsi layer to cmd packet */
if (scsi_sg_count(srb)) {
- sg_count = twl_map_scsi_sg_data(tw_dev, request_id);
- if (sg_count == 0)
+ sg_count = scsi_dma_map(srb);
+ if (sg_count <= 0)
goto out;
scsi_for_each_sg(srb, sg, sg_count, i) {
return retval;
} /* End twl_initialize_device_extension() */
-/* This function will perform a pci-dma unmap */
-static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
-{
- struct scsi_cmnd *cmd = tw_dev->srb[request_id];
-
- if (cmd->SCp.phase == TW_PHASE_SGLIST)
- scsi_dma_unmap(cmd);
-} /* End twl_unmap_scsi_data() */
-
/* This function will handle attention interrupts */
static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev)
{
}
/* Now complete the io */
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd);
tw_dev->state[request_id] = TW_S_COMPLETED;
twl_free_request_id(tw_dev, request_id);
tw_dev->posted_request_count--;
- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
- twl_unmap_scsi_data(tw_dev, request_id);
}
/* Check for another response interrupt */
if ((tw_dev->state[i] != TW_S_FINISHED) &&
(tw_dev->state[i] != TW_S_INITIAL) &&
(tw_dev->state[i] != TW_S_COMPLETED)) {
- if (tw_dev->srb[i]) {
- tw_dev->srb[i]->result = (DID_RESET << 16);
- tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
- twl_unmap_scsi_data(tw_dev, i);
+ struct scsi_cmnd *cmd = tw_dev->srb[i];
+
+ if (cmd) {
+ cmd->result = (DID_RESET << 16);
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd);
}
}
}
/* Save the scsi command for use by the ISR */
tw_dev->srb[request_id] = SCpnt;
- /* Initialize phase to zero */
- SCpnt->SCp.phase = TW_PHASE_INITIAL;
-
retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
if (retval) {
tw_dev->state[request_id] = TW_S_COMPLETED;
#define TW_CURRENT_DRIVER_BUILD 0
#define TW_CURRENT_DRIVER_BRANCH 0
-/* Phase defines */
-#define TW_PHASE_INITIAL 0
-#define TW_PHASE_SGLIST 2
-
/* Misc defines */
#define TW_SECTOR_SIZE 512
#define TW_MAX_UNITS 32
return 0;
} /* End tw_initialize_device_extension() */
-static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- int use_sg;
-
- dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
-
- use_sg = scsi_dma_map(cmd);
- if (use_sg < 0) {
- printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
- return 0;
- }
-
- cmd->SCp.phase = TW_PHASE_SGLIST;
- cmd->SCp.have_data_in = use_sg;
-
- return use_sg;
-} /* End tw_map_scsi_sg_data() */
-
-static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
-
- if (cmd->SCp.phase == TW_PHASE_SGLIST)
- scsi_dma_unmap(cmd);
-} /* End tw_unmap_scsi_data() */
-
/* This function will reset a device extension */
static int tw_reset_device_extension(TW_Device_Extension *tw_dev)
{
srb = tw_dev->srb[i];
if (srb != NULL) {
srb->result = (DID_RESET << 16);
- tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
- tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
+ scsi_dma_unmap(srb);
+ srb->scsi_done(srb);
}
}
}
command_packet->byte8.io.lba = lba;
command_packet->byte6.block_count = num_sectors;
- use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
- if (!use_sg)
+ use_sg = scsi_dma_map(srb);
+ if (use_sg <= 0)
return 1;
scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) {
/* Save the scsi command for use by the ISR */
tw_dev->srb[request_id] = SCpnt;
- /* Initialize phase to zero */
- SCpnt->SCp.phase = TW_PHASE_INITIAL;
-
switch (*command) {
case READ_10:
case READ_6:
/* Now complete the io */
if ((error != TW_ISR_DONT_COMPLETE)) {
+ scsi_dma_unmap(tw_dev->srb[request_id]);
+ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
tw_dev->state[request_id] = TW_S_COMPLETED;
tw_state_request_finish(tw_dev, request_id);
tw_dev->posted_request_count--;
- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-
- tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
}
}
#define TW_AEN_SMART_FAIL 0x000F
#define TW_AEN_SBUF_FAIL 0x0024
-/* Phase defines */
-#define TW_PHASE_INITIAL 0
-#define TW_PHASE_SINGLE 1
-#define TW_PHASE_SGLIST 2
-
/* Misc defines */
#define TW_ALIGNMENT_6000 64 /* 64 bytes */
#define TW_ALIGNMENT_7000 4 /* 4 bytes */
hba_free:
if (phba->msix_enabled)
pci_disable_msix(phba->pcidev);
- iscsi_host_remove(phba->shost);
pci_dev_put(phba->pcidev);
iscsi_host_free(phba->shost);
+ pci_set_drvdata(pcidev, NULL);
disable_pci:
pci_disable_device(pcidev);
return ret;
static int mvs_task_prep_ata(struct mvs_info *mvi,
struct mvs_task_exec_info *tei)
{
- struct sas_ha_struct *sha = mvi->sas;
struct sas_task *task = tei->task;
struct domain_device *dev = task->dev;
struct mvs_device *mvi_dev = dev->lldd_dev;
struct mvs_cmd_hdr *hdr = tei->hdr;
struct asd_sas_port *sas_port = dev->port;
- struct sas_phy *sphy = dev->phy;
- struct asd_sas_phy *sas_phy = sha->sas_phy[sphy->number];
struct mvs_slot_info *slot;
void *buf_prd;
u32 tag = tei->tag, hdr_tag;
slot->tx = mvi->tx_prod;
del_q = TXQ_MODE_I | tag |
(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
- (MVS_PHY_ID << TXQ_PHY_SHIFT) |
+ ((sas_port->phy_mask & TXQ_PHY_MASK) << TXQ_PHY_SHIFT) |
(mvi_dev->taskfileset << TXQ_SRS_SHIFT);
mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
"rejecting I/O to dead device\n");
ret = BLKPREP_KILL;
break;
- case SDEV_QUIESCE:
case SDEV_BLOCK:
case SDEV_CREATED_BLOCK:
+ ret = BLKPREP_DEFER;
+ break;
+ case SDEV_QUIESCE:
/*
* If the devices is blocked we defer normal commands.
*/
if (bounce_sgl[j].length == PAGE_SIZE) {
/* full..move to next entry */
sg_kunmap_atomic(bounce_addr);
+ bounce_addr = 0;
j++;
+ }
- /* if we need to use another bounce buffer */
- if (srclen || i != orig_sgl_count - 1)
- bounce_addr = sg_kmap_atomic(bounce_sgl,j);
+ /* if we need to use another bounce buffer */
+ if (srclen && bounce_addr == 0)
+ bounce_addr = sg_kmap_atomic(bounce_sgl, j);
- } else if (srclen == 0 && i == orig_sgl_count - 1) {
- /* unmap the last bounce that is < PAGE_SIZE */
- sg_kunmap_atomic(bounce_addr);
- }
}
sg_kunmap_atomic(src_addr - orig_sgl[i].offset);
}
+ if (bounce_addr)
+ sg_kunmap_atomic(bounce_addr);
+
local_irq_restore(flags);
return total_copied;
k_tmp->len = u_tmp->len;
total += k_tmp->len;
- if (total > bufsiz) {
+ /* Check total length of transfers. Also check each
+ * transfer length to avoid arithmetic overflow.
+ */
+ if (total > bufsiz || k_tmp->len > bufsiz) {
status = -EMSGSIZE;
goto done;
}
source "drivers/staging/iio/Kconfig"
-source "drivers/staging/zsmalloc/Kconfig"
-
-source "drivers/staging/zram/Kconfig"
-
source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig"
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
-obj-$(CONFIG_ZRAM) += zram/
-obj-$(CONFIG_ZSMALLOC) += zsmalloc/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_FB_SM7XX) += sm7xxfb/
" pc PC status\n"
" regs Register dump\n"
" allregs Extended Register dump\n"
- " bt Stack trace\n"
+ " bt Stack trace\n");
+ fiq_debugger_printf(&state->output,
" reboot [<c>] Reboot with command <c>\n"
" reset [<c>] Hard reset with command <c>\n"
" irqs Interupt status\n"
* LCD types
*/
#define LCD_TYPE_NONE 0
-#define LCD_TYPE_OLD 1
-#define LCD_TYPE_KS0074 2
-#define LCD_TYPE_HANTRONIX 3
-#define LCD_TYPE_NEXCOM 4
-#define LCD_TYPE_CUSTOM 5
+#define LCD_TYPE_CUSTOM 1
+#define LCD_TYPE_OLD 2
+#define LCD_TYPE_KS0074 3
+#define LCD_TYPE_HANTRONIX 4
+#define LCD_TYPE_NEXCOM 5
/*
* keypad types
static int lcd_type = -1;
module_param(lcd_type, int, 0000);
MODULE_PARM_DESC(lcd_type,
- "LCD type: 0=none, 1=old //, 2=serial ks0074, "
- "3=hantronix //, 4=nexcom //, 5=compiled-in");
+ "LCD type: 0=none, 1=compiled-in, 2=old, 3=serial ks0074, 4=hantronix, 5=nexcom");
static int lcd_proto = -1;
module_param(lcd_proto, int, 0000);
+++ /dev/null
-config ZRAM
- tristate "Compressed RAM block device support"
- depends on BLOCK && SYSFS && ZSMALLOC
- select LZO_COMPRESS
- select LZO_DECOMPRESS
- default n
- help
- Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
- Pages written to these disks are compressed and stored in memory
- itself. These disks allow very fast I/O and compression provides
- good amounts of memory savings.
-
- It has several use cases, for example: /tmp storage, use as swap
- disks and maybe many more.
-
- See zram.txt for more information.
- Project home: <https://compcache.googlecode.com/>
-
-config ZRAM_DEBUG
- bool "Compressed RAM block device debug support"
- depends on ZRAM
- default n
- help
- This option adds additional debugging code to the compressed
- RAM block device driver.
+++ /dev/null
-zram-y := zram_drv.o zram_sysfs.o
-
-obj-$(CONFIG_ZRAM) += zram.o
+++ /dev/null
-zram: Compressed RAM based block devices
-----------------------------------------
-
-Project home: http://compcache.googlecode.com/
-
-* Introduction
-
-The zram module creates RAM based block devices named /dev/zram<id>
-(<id> = 0, 1, ...). Pages written to these disks are compressed and stored
-in memory itself. These disks allow very fast I/O and compression provides
-good amounts of memory savings. Some of the usecases include /tmp storage,
-use as swap disks, various caches under /var and maybe many more :)
-
-Statistics for individual zram devices are exported through sysfs nodes at
-/sys/block/zram<id>/
-
-* Usage
-
-Following shows a typical sequence of steps for using zram.
-
-1) Load Module:
- modprobe zram num_devices=4
- This creates 4 devices: /dev/zram{0,1,2,3}
- (num_devices parameter is optional. Default: 1)
-
-2) Set Disksize
- Set disk size by writing the value to sysfs node 'disksize'.
- The value can be either in bytes or you can use mem suffixes.
- Examples:
- # Initialize /dev/zram0 with 50MB disksize
- echo $((50*1024*1024)) > /sys/block/zram0/disksize
-
- # Using mem suffixes
- echo 256K > /sys/block/zram0/disksize
- echo 512M > /sys/block/zram0/disksize
- echo 1G > /sys/block/zram0/disksize
-
-3) Activate:
- mkswap /dev/zram0
- swapon /dev/zram0
-
- mkfs.ext4 /dev/zram1
- mount /dev/zram1 /tmp
-
-4) Stats:
- Per-device statistics are exported as various nodes under
- /sys/block/zram<id>/
- disksize
- num_reads
- num_writes
- invalid_io
- notify_free
- discard
- zero_pages
- orig_data_size
- compr_data_size
- mem_used_total
-
-5) Deactivate:
- swapoff /dev/zram0
- umount /dev/zram1
-
-6) Reset:
- Write any positive value to 'reset' sysfs node
- echo 1 > /sys/block/zram0/reset
- echo 1 > /sys/block/zram1/reset
-
- This frees all the memory allocated for the given device and
- resets the disksize to zero. You must set the disksize again
- before reusing the device.
-
-Please report any problems at:
- - Mailing list: linux-mm-cc at laptop dot org
- - Issue tracker: http://code.google.com/p/compcache/issues/list
-
-Nitin Gupta
-ngupta@vflare.org
+++ /dev/null
-/*
- * Compressed RAM block device
- *
- * Copyright (C) 2008, 2009, 2010 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- *
- * Project home: http://compcache.googlecode.com
- */
-
-#define KMSG_COMPONENT "zram"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#ifdef CONFIG_ZRAM_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bio.h>
-#include <linux/bitops.h>
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
-#include <linux/device.h>
-#include <linux/genhd.h>
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/lzo.h>
-#include <linux/string.h>
-#include <linux/vmalloc.h>
-
-#include "zram_drv.h"
-
-/* Globals */
-static int zram_major;
-struct zram *zram_devices;
-
-/* Module params (documentation at end) */
-static unsigned int num_devices = 1;
-
-static void zram_stat64_add(struct zram *zram, u64 *v, u64 inc)
-{
- spin_lock(&zram->stat64_lock);
- *v = *v + inc;
- spin_unlock(&zram->stat64_lock);
-}
-
-static void zram_stat64_sub(struct zram *zram, u64 *v, u64 dec)
-{
- spin_lock(&zram->stat64_lock);
- *v = *v - dec;
- spin_unlock(&zram->stat64_lock);
-}
-
-static void zram_stat64_inc(struct zram *zram, u64 *v)
-{
- zram_stat64_add(zram, v, 1);
-}
-
-static int zram_test_flag(struct zram_meta *meta, u32 index,
- enum zram_pageflags flag)
-{
- return meta->table[index].flags & BIT(flag);
-}
-
-static void zram_set_flag(struct zram_meta *meta, u32 index,
- enum zram_pageflags flag)
-{
- meta->table[index].flags |= BIT(flag);
-}
-
-static void zram_clear_flag(struct zram_meta *meta, u32 index,
- enum zram_pageflags flag)
-{
- meta->table[index].flags &= ~BIT(flag);
-}
-
-static int page_zero_filled(void *ptr)
-{
- unsigned int pos;
- unsigned long *page;
-
- page = (unsigned long *)ptr;
-
- for (pos = 0; pos != PAGE_SIZE / sizeof(*page); pos++) {
- if (page[pos])
- return 0;
- }
-
- return 1;
-}
-
-static void zram_free_page(struct zram *zram, size_t index)
-{
- struct zram_meta *meta = zram->meta;
- unsigned long handle = meta->table[index].handle;
- u16 size = meta->table[index].size;
-
- if (unlikely(!handle)) {
- /*
- * No memory is allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (zram_test_flag(meta, index, ZRAM_ZERO)) {
- zram_clear_flag(meta, index, ZRAM_ZERO);
- zram->stats.pages_zero--;
- }
- return;
- }
-
- if (unlikely(size > max_zpage_size))
- zram->stats.bad_compress--;
-
- zs_free(meta->mem_pool, handle);
-
- if (size <= PAGE_SIZE / 2)
- zram->stats.good_compress--;
-
- zram_stat64_sub(zram, &zram->stats.compr_size,
- meta->table[index].size);
- zram->stats.pages_stored--;
-
- meta->table[index].handle = 0;
- meta->table[index].size = 0;
-}
-
-static void handle_zero_page(struct bio_vec *bvec)
-{
- struct page *page = bvec->bv_page;
- void *user_mem;
-
- user_mem = kmap_atomic(page);
- memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
- kunmap_atomic(user_mem);
-
- flush_dcache_page(page);
-}
-
-static inline int is_partial_io(struct bio_vec *bvec)
-{
- return bvec->bv_len != PAGE_SIZE;
-}
-
-static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
-{
- int ret = LZO_E_OK;
- size_t clen = PAGE_SIZE;
- unsigned char *cmem;
- struct zram_meta *meta = zram->meta;
- unsigned long handle = meta->table[index].handle;
-
- if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
- memset(mem, 0, PAGE_SIZE);
- return 0;
- }
-
- cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
- if (meta->table[index].size == PAGE_SIZE)
- memcpy(mem, cmem, PAGE_SIZE);
- else
- ret = lzo1x_decompress_safe(cmem, meta->table[index].size,
- mem, &clen);
- zs_unmap_object(meta->mem_pool, handle);
-
- /* Should NEVER happen. Return bio error if it does. */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
- zram_stat64_inc(zram, &zram->stats.failed_reads);
- return ret;
- }
-
- return 0;
-}
-
-static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
- u32 index, int offset, struct bio *bio)
-{
- int ret;
- struct page *page;
- unsigned char *user_mem, *uncmem = NULL;
- struct zram_meta *meta = zram->meta;
- page = bvec->bv_page;
-
- if (unlikely(!meta->table[index].handle) ||
- zram_test_flag(meta, index, ZRAM_ZERO)) {
- handle_zero_page(bvec);
- return 0;
- }
-
- if (is_partial_io(bvec))
- /* Use a temporary buffer to decompress the page */
- uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
-
- user_mem = kmap_atomic(page);
- if (!is_partial_io(bvec))
- uncmem = user_mem;
-
- if (!uncmem) {
- pr_info("Unable to allocate temp memory\n");
- ret = -ENOMEM;
- goto out_cleanup;
- }
-
- ret = zram_decompress_page(zram, uncmem, index);
- /* Should NEVER happen. Return bio error if it does. */
- if (unlikely(ret != LZO_E_OK))
- goto out_cleanup;
-
- if (is_partial_io(bvec))
- memcpy(user_mem + bvec->bv_offset, uncmem + offset,
- bvec->bv_len);
-
- flush_dcache_page(page);
- ret = 0;
-out_cleanup:
- kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
- return ret;
-}
-
-static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
- int offset)
-{
- int ret = 0;
- size_t clen;
- unsigned long handle;
- struct page *page;
- unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
- struct zram_meta *meta = zram->meta;
-
- page = bvec->bv_page;
- src = meta->compress_buffer;
-
- if (is_partial_io(bvec)) {
- /*
- * This is a partial IO. We need to read the full page
- * before to write the changes.
- */
- uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
- if (!uncmem) {
- ret = -ENOMEM;
- goto out;
- }
- ret = zram_decompress_page(zram, uncmem, index);
- if (ret)
- goto out;
- }
-
- /*
- * System overwrites unused sectors. Free memory associated
- * with this sector now.
- */
- if (meta->table[index].handle ||
- zram_test_flag(meta, index, ZRAM_ZERO))
- zram_free_page(zram, index);
-
- user_mem = kmap_atomic(page);
-
- if (is_partial_io(bvec)) {
- memcpy(uncmem + offset, user_mem + bvec->bv_offset,
- bvec->bv_len);
- kunmap_atomic(user_mem);
- user_mem = NULL;
- } else {
- uncmem = user_mem;
- }
-
- if (page_zero_filled(uncmem)) {
- kunmap_atomic(user_mem);
- zram->stats.pages_zero++;
- zram_set_flag(meta, index, ZRAM_ZERO);
- ret = 0;
- goto out;
- }
-
- ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
- meta->compress_workmem);
-
- if (!is_partial_io(bvec)) {
- kunmap_atomic(user_mem);
- user_mem = NULL;
- uncmem = NULL;
- }
-
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Compression failed! err=%d\n", ret);
- goto out;
- }
-
- if (unlikely(clen > max_zpage_size)) {
- zram->stats.bad_compress++;
- clen = PAGE_SIZE;
- src = NULL;
- if (is_partial_io(bvec))
- src = uncmem;
- }
-
- handle = zs_malloc(meta->mem_pool, clen);
- if (!handle) {
- pr_info("Error allocating memory for compressed "
- "page: %u, size=%zu\n", index, clen);
- ret = -ENOMEM;
- goto out;
- }
- cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);
-
- if ((clen == PAGE_SIZE) && !is_partial_io(bvec))
- src = kmap_atomic(page);
- memcpy(cmem, src, clen);
- if ((clen == PAGE_SIZE) && !is_partial_io(bvec))
- kunmap_atomic(src);
-
- zs_unmap_object(meta->mem_pool, handle);
-
- meta->table[index].handle = handle;
- meta->table[index].size = clen;
-
- /* Update stats */
- zram_stat64_add(zram, &zram->stats.compr_size, clen);
- zram->stats.pages_stored++;
- if (clen <= PAGE_SIZE / 2)
- zram->stats.good_compress++;
-
-out:
- if (is_partial_io(bvec))
- kfree(uncmem);
-
- if (ret)
- zram_stat64_inc(zram, &zram->stats.failed_writes);
- return ret;
-}
-
-static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
- int offset, struct bio *bio, int rw)
-{
- int ret;
-
- if (rw == READ) {
- down_read(&zram->lock);
- ret = zram_bvec_read(zram, bvec, index, offset, bio);
- up_read(&zram->lock);
- } else {
- down_write(&zram->lock);
- ret = zram_bvec_write(zram, bvec, index, offset);
- up_write(&zram->lock);
- }
-
- return ret;
-}
-
-static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
-{
- if (*offset + bvec->bv_len >= PAGE_SIZE)
- (*index)++;
- *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
-}
-
-static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
-{
- int i, offset;
- u32 index;
- struct bio_vec *bvec;
-
- switch (rw) {
- case READ:
- zram_stat64_inc(zram, &zram->stats.num_reads);
- break;
- case WRITE:
- zram_stat64_inc(zram, &zram->stats.num_writes);
- break;
- }
-
- index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
- offset = (bio->bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
-
- bio_for_each_segment(bvec, bio, i) {
- int max_transfer_size = PAGE_SIZE - offset;
-
- if (bvec->bv_len > max_transfer_size) {
- /*
- * zram_bvec_rw() can only make operation on a single
- * zram page. Split the bio vector.
- */
- struct bio_vec bv;
-
- bv.bv_page = bvec->bv_page;
- bv.bv_len = max_transfer_size;
- bv.bv_offset = bvec->bv_offset;
-
- if (zram_bvec_rw(zram, &bv, index, offset, bio, rw) < 0)
- goto out;
-
- bv.bv_len = bvec->bv_len - max_transfer_size;
- bv.bv_offset += max_transfer_size;
- if (zram_bvec_rw(zram, &bv, index+1, 0, bio, rw) < 0)
- goto out;
- } else
- if (zram_bvec_rw(zram, bvec, index, offset, bio, rw)
- < 0)
- goto out;
-
- update_position(&index, &offset, bvec);
- }
-
- set_bit(BIO_UPTODATE, &bio->bi_flags);
- bio_endio(bio, 0);
- return;
-
-out:
- bio_io_error(bio);
-}
-
-/*
- * Check if request is within bounds and aligned on zram logical blocks.
- */
-static inline int valid_io_request(struct zram *zram, struct bio *bio)
-{
- u64 start, end, bound;
-
- /* unaligned request */
- if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
- return 0;
- if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
- return 0;
-
- start = bio->bi_sector;
- end = start + (bio->bi_size >> SECTOR_SHIFT);
- bound = zram->disksize >> SECTOR_SHIFT;
- /* out of range range */
- if (unlikely(start >= bound || end > bound || start > end))
- return 0;
-
- /* I/O request is valid */
- return 1;
-}
-
-/*
- * Handler function for all zram I/O requests.
- */
-static void zram_make_request(struct request_queue *queue, struct bio *bio)
-{
- struct zram *zram = queue->queuedata;
-
- down_read(&zram->init_lock);
- if (unlikely(!zram->init_done))
- goto error;
-
- if (!valid_io_request(zram, bio)) {
- zram_stat64_inc(zram, &zram->stats.invalid_io);
- goto error;
- }
-
- __zram_make_request(zram, bio, bio_data_dir(bio));
- up_read(&zram->init_lock);
-
- return;
-
-error:
- up_read(&zram->init_lock);
- bio_io_error(bio);
-}
-
-static void __zram_reset_device(struct zram *zram)
-{
- size_t index;
- struct zram_meta *meta;
-
- if (!zram->init_done)
- return;
-
- meta = zram->meta;
- zram->init_done = 0;
-
- /* Free all pages that are still in this zram device */
- for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
- unsigned long handle = meta->table[index].handle;
- if (!handle)
- continue;
-
- zs_free(meta->mem_pool, handle);
- }
-
- zram_meta_free(zram->meta);
- zram->meta = NULL;
- /* Reset stats */
- memset(&zram->stats, 0, sizeof(zram->stats));
-
- zram->disksize = 0;
- set_capacity(zram->disk, 0);
-}
-
-void zram_reset_device(struct zram *zram)
-{
- down_write(&zram->init_lock);
- __zram_reset_device(zram);
- up_write(&zram->init_lock);
-}
-
-void zram_meta_free(struct zram_meta *meta)
-{
- zs_destroy_pool(meta->mem_pool);
- kfree(meta->compress_workmem);
- free_pages((unsigned long)meta->compress_buffer, 1);
- vfree(meta->table);
- kfree(meta);
-}
-
-struct zram_meta *zram_meta_alloc(u64 disksize)
-{
- size_t num_pages;
- struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
- if (!meta)
- goto out;
-
- meta->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
- if (!meta->compress_workmem)
- goto free_meta;
-
- meta->compress_buffer =
- (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
- if (!meta->compress_buffer) {
- pr_err("Error allocating compressor buffer space\n");
- goto free_workmem;
- }
-
- num_pages = disksize >> PAGE_SHIFT;
- meta->table = vzalloc(num_pages * sizeof(*meta->table));
- if (!meta->table) {
- pr_err("Error allocating zram address table\n");
- goto free_buffer;
- }
-
- meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
- if (!meta->mem_pool) {
- pr_err("Error creating memory pool\n");
- goto free_table;
- }
-
- return meta;
-
-free_table:
- vfree(meta->table);
-free_buffer:
- free_pages((unsigned long)meta->compress_buffer, 1);
-free_workmem:
- kfree(meta->compress_workmem);
-free_meta:
- kfree(meta);
- meta = NULL;
-out:
- return meta;
-}
-
-void zram_init_device(struct zram *zram, struct zram_meta *meta)
-{
- if (zram->disksize > 2 * (totalram_pages << PAGE_SHIFT)) {
- pr_info(
- "There is little point creating a zram of greater than "
- "twice the size of memory since we expect a 2:1 compression "
- "ratio. Note that zram uses about 0.1%% of the size of "
- "the disk when not in use so a huge zram is "
- "wasteful.\n"
- "\tMemory Size: %lu kB\n"
- "\tSize you selected: %llu kB\n"
- "Continuing anyway ...\n",
- (totalram_pages << PAGE_SHIFT) >> 10, zram->disksize >> 10
- );
- }
-
- /* zram devices sort of resembles non-rotational disks */
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
-
- zram->meta = meta;
- zram->init_done = 1;
-
- pr_debug("Initialization done!\n");
-}
-
-static void zram_slot_free_notify(struct block_device *bdev,
- unsigned long index)
-{
- struct zram *zram;
-
- zram = bdev->bd_disk->private_data;
- down_write(&zram->lock);
- zram_free_page(zram, index);
- up_write(&zram->lock);
- zram_stat64_inc(zram, &zram->stats.notify_free);
-}
-
-static const struct block_device_operations zram_devops = {
- .swap_slot_free_notify = zram_slot_free_notify,
- .owner = THIS_MODULE
-};
-
-static int create_device(struct zram *zram, int device_id)
-{
- int ret = -ENOMEM;
-
- init_rwsem(&zram->lock);
- init_rwsem(&zram->init_lock);
- spin_lock_init(&zram->stat64_lock);
-
- zram->queue = blk_alloc_queue(GFP_KERNEL);
- if (!zram->queue) {
- pr_err("Error allocating disk queue for device %d\n",
- device_id);
- goto out;
- }
-
- blk_queue_make_request(zram->queue, zram_make_request);
- zram->queue->queuedata = zram;
-
- /* gendisk structure */
- zram->disk = alloc_disk(1);
- if (!zram->disk) {
- pr_warn("Error allocating disk structure for device %d\n",
- device_id);
- goto out_free_queue;
- }
-
- zram->disk->major = zram_major;
- zram->disk->first_minor = device_id;
- zram->disk->fops = &zram_devops;
- zram->disk->queue = zram->queue;
- zram->disk->private_data = zram;
- snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
-
- /* Actual capacity set using syfs (/sys/block/zram<id>/disksize */
- set_capacity(zram->disk, 0);
-
- /*
- * To ensure that we always get PAGE_SIZE aligned
- * and n*PAGE_SIZED sized I/O requests.
- */
- blk_queue_physical_block_size(zram->disk->queue, PAGE_SIZE);
- blk_queue_logical_block_size(zram->disk->queue,
- ZRAM_LOGICAL_BLOCK_SIZE);
- blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
- blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
-
- add_disk(zram->disk);
-
- ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
- &zram_disk_attr_group);
- if (ret < 0) {
- pr_warn("Error creating sysfs group");
- goto out_free_disk;
- }
-
- zram->init_done = 0;
- return 0;
-
-out_free_disk:
- del_gendisk(zram->disk);
- put_disk(zram->disk);
-out_free_queue:
- blk_cleanup_queue(zram->queue);
-out:
- return ret;
-}
-
-static void destroy_device(struct zram *zram)
-{
- sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
- &zram_disk_attr_group);
-
- if (zram->disk) {
- del_gendisk(zram->disk);
- put_disk(zram->disk);
- }
-
- if (zram->queue)
- blk_cleanup_queue(zram->queue);
-}
-
-unsigned int zram_get_num_devices(void)
-{
- return num_devices;
-}
-
-static int __init zram_init(void)
-{
- int ret, dev_id;
-
- if (num_devices > max_num_devices) {
- pr_warn("Invalid value for num_devices: %u\n",
- num_devices);
- ret = -EINVAL;
- goto out;
- }
-
- zram_major = register_blkdev(0, "zram");
- if (zram_major <= 0) {
- pr_warn("Unable to get major number\n");
- ret = -EBUSY;
- goto out;
- }
-
- /* Allocate the device array and initialize each one */
- zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
- if (!zram_devices) {
- ret = -ENOMEM;
- goto unregister;
- }
-
- for (dev_id = 0; dev_id < num_devices; dev_id++) {
- ret = create_device(&zram_devices[dev_id], dev_id);
- if (ret)
- goto free_devices;
- }
-
- pr_info("Created %u device(s) ...\n", num_devices);
-
- return 0;
-
-free_devices:
- while (dev_id)
- destroy_device(&zram_devices[--dev_id]);
- kfree(zram_devices);
-unregister:
- unregister_blkdev(zram_major, "zram");
-out:
- return ret;
-}
-
-static void __exit zram_exit(void)
-{
- int i;
- struct zram *zram;
-
- for (i = 0; i < num_devices; i++) {
- zram = &zram_devices[i];
-
- get_disk(zram->disk);
- destroy_device(zram);
- zram_reset_device(zram);
- put_disk(zram->disk);
- }
-
- unregister_blkdev(zram_major, "zram");
-
- kfree(zram_devices);
- pr_debug("Cleanup done!\n");
-}
-
-module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of zram devices");
-
-module_init(zram_init);
-module_exit(zram_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
-MODULE_DESCRIPTION("Compressed RAM Block Device");
+++ /dev/null
-/*
- * Compressed RAM block device
- *
- * Copyright (C) 2008, 2009, 2010 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- *
- * Project home: http://compcache.googlecode.com
- */
-
-#ifndef _ZRAM_DRV_H_
-#define _ZRAM_DRV_H_
-
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-
-#include "../zsmalloc/zsmalloc.h"
-
-/*
- * Some arbitrary value. This is just to catch
- * invalid value for num_devices module parameter.
- */
-static const unsigned max_num_devices = 32;
-
-/*-- Configurable parameters */
-
-/*
- * Pages that compress to size greater than this are stored
- * uncompressed in memory.
- */
-static const size_t max_zpage_size = PAGE_SIZE / 4 * 3;
-
-/*
- * NOTE: max_zpage_size must be less than or equal to:
- * ZS_MAX_ALLOC_SIZE. Otherwise, zs_malloc() would
- * always return failure.
- */
-
-/*-- End of configurable params */
-
-#define SECTOR_SHIFT 9
-#define SECTOR_SIZE (1 << SECTOR_SHIFT)
-#define SECTORS_PER_PAGE_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
-#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT)
-#define ZRAM_LOGICAL_BLOCK_SHIFT 12
-#define ZRAM_LOGICAL_BLOCK_SIZE (1 << ZRAM_LOGICAL_BLOCK_SHIFT)
-#define ZRAM_SECTOR_PER_LOGICAL_BLOCK \
- (1 << (ZRAM_LOGICAL_BLOCK_SHIFT - SECTOR_SHIFT))
-
-/* Flags for zram pages (table[page_no].flags) */
-enum zram_pageflags {
- /* Page consists entirely of zeros */
- ZRAM_ZERO,
-
- __NR_ZRAM_PAGEFLAGS,
-};
-
-/*-- Data structures */
-
-/* Allocated for each disk page */
-struct table {
- unsigned long handle;
- u16 size; /* object size (excluding header) */
- u8 count; /* object ref count (not yet used) */
- u8 flags;
-} __aligned(4);
-
-struct zram_stats {
- u64 compr_size; /* compressed size of pages stored */
- u64 num_reads; /* failed + successful */
- u64 num_writes; /* --do-- */
- u64 failed_reads; /* should NEVER! happen */
- u64 failed_writes; /* can happen when memory is too low */
- u64 invalid_io; /* non-page-aligned I/O requests */
- u64 notify_free; /* no. of swap slot free notifications */
- u32 pages_zero; /* no. of zero filled pages */
- u32 pages_stored; /* no. of pages currently stored */
- u32 good_compress; /* % of pages with compression ratio<=50% */
- u32 bad_compress; /* % of pages with compression ratio>=75% */
-};
-
-struct zram_meta {
- void *compress_workmem;
- void *compress_buffer;
- struct table *table;
- struct zs_pool *mem_pool;
-};
-
-struct zram {
- struct zram_meta *meta;
- spinlock_t stat64_lock; /* protect 64-bit stats */
- struct rw_semaphore lock; /* protect compression buffers, table,
- * 32bit stat counters against concurrent
- * notifications, reads and writes */
- struct request_queue *queue;
- struct gendisk *disk;
- int init_done;
- /* Prevent concurrent execution of device init, reset and R/W request */
- struct rw_semaphore init_lock;
- /*
- * This is the limit on amount of *uncompressed* worth of data
- * we can store in a disk.
- */
- u64 disksize; /* bytes */
-
- struct zram_stats stats;
-};
-
-extern struct zram *zram_devices;
-unsigned int zram_get_num_devices(void);
-#ifdef CONFIG_SYSFS
-extern struct attribute_group zram_disk_attr_group;
-#endif
-
-extern void zram_reset_device(struct zram *zram);
-extern struct zram_meta *zram_meta_alloc(u64 disksize);
-extern void zram_meta_free(struct zram_meta *meta);
-extern void zram_init_device(struct zram *zram, struct zram_meta *meta);
-
-#endif
+++ /dev/null
-/*
- * Compressed RAM block device
- *
- * Copyright (C) 2008, 2009, 2010 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- *
- * Project home: http://compcache.googlecode.com/
- */
-
-#include <linux/device.h>
-#include <linux/genhd.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-
-#include "zram_drv.h"
-
-static u64 zram_stat64_read(struct zram *zram, u64 *v)
-{
- u64 val;
-
- spin_lock(&zram->stat64_lock);
- val = *v;
- spin_unlock(&zram->stat64_lock);
-
- return val;
-}
-
-static struct zram *dev_to_zram(struct device *dev)
-{
- int i;
- struct zram *zram = NULL;
-
- for (i = 0; i < zram_get_num_devices(); i++) {
- zram = &zram_devices[i];
- if (disk_to_dev(zram->disk) == dev)
- break;
- }
-
- return zram;
-}
-
-static ssize_t disksize_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n", zram->disksize);
-}
-
-static ssize_t disksize_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- u64 disksize;
- struct zram_meta *meta;
- struct zram *zram = dev_to_zram(dev);
-
- disksize = memparse(buf, NULL);
- if (!disksize)
- return -EINVAL;
-
- disksize = PAGE_ALIGN(disksize);
- meta = zram_meta_alloc(disksize);
- down_write(&zram->init_lock);
- if (zram->init_done) {
- up_write(&zram->init_lock);
- zram_meta_free(meta);
- pr_info("Cannot change disksize for initialized device\n");
- return -EBUSY;
- }
-
- zram->disksize = disksize;
- set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
- zram_init_device(zram, meta);
- up_write(&zram->init_lock);
-
- return len;
-}
-
-static ssize_t initstate_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%u\n", zram->init_done);
-}
-
-static ssize_t reset_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- int ret;
- unsigned short do_reset;
- struct zram *zram;
- struct block_device *bdev;
-
- zram = dev_to_zram(dev);
- bdev = bdget_disk(zram->disk, 0);
-
- /* Do not reset an active device! */
- if (bdev->bd_holders)
- return -EBUSY;
-
- ret = kstrtou16(buf, 10, &do_reset);
- if (ret)
- return ret;
-
- if (!do_reset)
- return -EINVAL;
-
- /* Make sure all pending I/O is finished */
- if (bdev)
- fsync_bdev(bdev);
-
- zram_reset_device(zram);
- return len;
-}
-
-static ssize_t num_reads_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.num_reads));
-}
-
-static ssize_t num_writes_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.num_writes));
-}
-
-static ssize_t invalid_io_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.invalid_io));
-}
-
-static ssize_t notify_free_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.notify_free));
-}
-
-static ssize_t zero_pages_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%u\n", zram->stats.pages_zero);
-}
-
-static ssize_t orig_data_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- (u64)(zram->stats.pages_stored) << PAGE_SHIFT);
-}
-
-static ssize_t compr_data_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.compr_size));
-}
-
-static ssize_t mem_used_total_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u64 val = 0;
- struct zram *zram = dev_to_zram(dev);
- struct zram_meta *meta = zram->meta;
-
- down_read(&zram->init_lock);
- if (zram->init_done)
- val = zs_get_total_size_bytes(meta->mem_pool);
- up_read(&zram->init_lock);
-
- return sprintf(buf, "%llu\n", val);
-}
-
-static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
- disksize_show, disksize_store);
-static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
-static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
-static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
-static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
-static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
-static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
-static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
-static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
-static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
-static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
-
-static struct attribute *zram_disk_attrs[] = {
- &dev_attr_disksize.attr,
- &dev_attr_initstate.attr,
- &dev_attr_reset.attr,
- &dev_attr_num_reads.attr,
- &dev_attr_num_writes.attr,
- &dev_attr_invalid_io.attr,
- &dev_attr_notify_free.attr,
- &dev_attr_zero_pages.attr,
- &dev_attr_orig_data_size.attr,
- &dev_attr_compr_data_size.attr,
- &dev_attr_mem_used_total.attr,
- NULL,
-};
-
-struct attribute_group zram_disk_attr_group = {
- .attrs = zram_disk_attrs,
-};
+++ /dev/null
-zsmalloc-y := zsmalloc-main.o
-
-obj-$(CONFIG_ZSMALLOC) += zsmalloc.o
+++ /dev/null
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-
-/*
- * This allocator is designed for use with zcache and zram. Thus, the
- * allocator is supposed to work well under low memory conditions. In
- * particular, it never attempts higher order page allocation which is
- * very likely to fail under memory pressure. On the other hand, if we
- * just use single (0-order) pages, it would suffer from very high
- * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy
- * an entire page. This was one of the major issues with its predecessor
- * (xvmalloc).
- *
- * To overcome these issues, zsmalloc allocates a bunch of 0-order pages
- * and links them together using various 'struct page' fields. These linked
- * pages act as a single higher-order page i.e. an object can span 0-order
- * page boundaries. The code refers to these linked pages as a single entity
- * called zspage.
- *
- * Following is how we use various fields and flags of underlying
- * struct page(s) to form a zspage.
- *
- * Usage of struct page fields:
- * page->first_page: points to the first component (0-order) page
- * page->index (union with page->freelist): offset of the first object
- * starting in this page. For the first page, this is
- * always 0, so we use this field (aka freelist) to point
- * to the first free object in zspage.
- * page->lru: links together all component pages (except the first page)
- * of a zspage
- *
- * For _first_ page only:
- *
- * page->private (union with page->first_page): refers to the
- * component page after the first page
- * page->freelist: points to the first free object in zspage.
- * Free objects are linked together using in-place
- * metadata.
- * page->objects: maximum number of objects we can store in this
- * zspage (class->zspage_order * PAGE_SIZE / class->size)
- * page->lru: links together first pages of various zspages.
- * Basically forming list of zspages in a fullness group.
- * page->mapping: class index and fullness group of the zspage
- *
- * Usage of struct page flags:
- * PG_private: identifies the first component page
- * PG_private2: identifies the last component page
- *
- */
-
-#ifdef CONFIG_ZSMALLOC_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-#include <linux/errno.h>
-#include <linux/highmem.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-#include <linux/cpumask.h>
-#include <linux/cpu.h>
-#include <linux/vmalloc.h>
-#include <linux/hardirq.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include "zsmalloc.h"
-
-/*
- * This must be power of 2 and greater than of equal to sizeof(link_free).
- * These two conditions ensure that any 'struct link_free' itself doesn't
- * span more than 1 page which avoids complex case of mapping 2 pages simply
- * to restore link_free pointer values.
- */
-#define ZS_ALIGN 8
-
-/*
- * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
- * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
- */
-#define ZS_MAX_ZSPAGE_ORDER 2
-#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
-
-/*
- * Object location (<PFN>, <obj_idx>) is encoded as
- * as single (void *) handle value.
- *
- * Note that object index <obj_idx> is relative to system
- * page <PFN> it is stored in, so for each sub-page belonging
- * to a zspage, obj_idx starts with 0.
- *
- * This is made more complicated by various memory models and PAE.
- */
-
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
-/*
- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
- * be PAGE_SHIFT
- */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
-#endif
-#endif
-#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
-#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
-#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
-#define ZS_MIN_ALLOC_SIZE \
- MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
-#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
-
-/*
- * On systems with 4K page size, this gives 254 size classes! There is a
- * trader-off here:
- * - Large number of size classes is potentially wasteful as free page are
- * spread across these classes
- * - Small number of size classes causes large internal fragmentation
- * - Probably its better to use specific size classes (empirically
- * determined). NOTE: all those class sizes must be set as multiple of
- * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
- *
- * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
- * (reason above)
- */
-#define ZS_SIZE_CLASS_DELTA (PAGE_SIZE >> 8)
-#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
- ZS_SIZE_CLASS_DELTA + 1)
-
-/*
- * We do not maintain any list for completely empty or full pages
- */
-enum fullness_group {
- ZS_ALMOST_FULL,
- ZS_ALMOST_EMPTY,
- _ZS_NR_FULLNESS_GROUPS,
-
- ZS_EMPTY,
- ZS_FULL
-};
-
-/*
- * We assign a page to ZS_ALMOST_EMPTY fullness group when:
- * n <= N / f, where
- * n = number of allocated objects
- * N = total number of objects zspage can store
- * f = 1/fullness_threshold_frac
- *
- * Similarly, we assign zspage to:
- * ZS_ALMOST_FULL when n > N / f
- * ZS_EMPTY when n == 0
- * ZS_FULL when n == N
- *
- * (see: fix_fullness_group())
- */
-static const int fullness_threshold_frac = 4;
-
-struct size_class {
- /*
- * Size of objects stored in this class. Must be multiple
- * of ZS_ALIGN.
- */
- int size;
- unsigned int index;
-
- /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
- int pages_per_zspage;
-
- spinlock_t lock;
-
- /* stats */
- u64 pages_allocated;
-
- struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
-};
-
-/*
- * Placed within free objects to form a singly linked list.
- * For every zspage, first_page->freelist gives head of this list.
- *
- * This must be power of 2 and less than or equal to ZS_ALIGN
- */
-struct link_free {
- /* Handle of next free chunk (encodes <PFN, obj_idx>) */
- void *next;
-};
-
-struct zs_pool {
- struct size_class size_class[ZS_SIZE_CLASSES];
-
- gfp_t flags; /* allocation flags used when growing pool */
-};
-
-/*
- * A zspage's class index and fullness group
- * are encoded in its (first)page->mapping
- */
-#define CLASS_IDX_BITS 28
-#define FULLNESS_BITS 4
-#define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1)
-#define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1)
-
-/*
- * By default, zsmalloc uses a copy-based object mapping method to access
- * allocations that span two pages. However, if a particular architecture
- * performs VM mapping faster than copying, then it should be added here
- * so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use
- * page table mapping rather than copying for object mapping.
-*/
-#if defined(CONFIG_ARM) && !defined(MODULE)
-#define USE_PGTABLE_MAPPING
-#endif
-
-struct mapping_area {
-#ifdef USE_PGTABLE_MAPPING
- struct vm_struct *vm; /* vm area for mapping object that span pages */
-#else
- char *vm_buf; /* copy buffer for objects that span pages */
-#endif
- char *vm_addr; /* address of kmap_atomic()'ed pages */
- enum zs_mapmode vm_mm; /* mapping mode */
-};
-
-
-/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
-static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
-
-static int is_first_page(struct page *page)
-{
- return PagePrivate(page);
-}
-
-static int is_last_page(struct page *page)
-{
- return PagePrivate2(page);
-}
-
-static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
- enum fullness_group *fullness)
-{
- unsigned long m;
- BUG_ON(!is_first_page(page));
-
- m = (unsigned long)page->mapping;
- *fullness = m & FULLNESS_MASK;
- *class_idx = (m >> FULLNESS_BITS) & CLASS_IDX_MASK;
-}
-
-static void set_zspage_mapping(struct page *page, unsigned int class_idx,
- enum fullness_group fullness)
-{
- unsigned long m;
- BUG_ON(!is_first_page(page));
-
- m = ((class_idx & CLASS_IDX_MASK) << FULLNESS_BITS) |
- (fullness & FULLNESS_MASK);
- page->mapping = (struct address_space *)m;
-}
-
-static int get_size_class_index(int size)
-{
- int idx = 0;
-
- if (likely(size > ZS_MIN_ALLOC_SIZE))
- idx = DIV_ROUND_UP(size - ZS_MIN_ALLOC_SIZE,
- ZS_SIZE_CLASS_DELTA);
-
- return idx;
-}
-
-static enum fullness_group get_fullness_group(struct page *page)
-{
- int inuse, max_objects;
- enum fullness_group fg;
- BUG_ON(!is_first_page(page));
-
- inuse = page->inuse;
- max_objects = page->objects;
-
- if (inuse == 0)
- fg = ZS_EMPTY;
- else if (inuse == max_objects)
- fg = ZS_FULL;
- else if (inuse <= max_objects / fullness_threshold_frac)
- fg = ZS_ALMOST_EMPTY;
- else
- fg = ZS_ALMOST_FULL;
-
- return fg;
-}
-
-static void insert_zspage(struct page *page, struct size_class *class,
- enum fullness_group fullness)
-{
- struct page **head;
-
- BUG_ON(!is_first_page(page));
-
- if (fullness >= _ZS_NR_FULLNESS_GROUPS)
- return;
-
- head = &class->fullness_list[fullness];
- if (*head)
- list_add_tail(&page->lru, &(*head)->lru);
-
- *head = page;
-}
-
-static void remove_zspage(struct page *page, struct size_class *class,
- enum fullness_group fullness)
-{
- struct page **head;
-
- BUG_ON(!is_first_page(page));
-
- if (fullness >= _ZS_NR_FULLNESS_GROUPS)
- return;
-
- head = &class->fullness_list[fullness];
- BUG_ON(!*head);
- if (list_empty(&(*head)->lru))
- *head = NULL;
- else if (*head == page)
- *head = (struct page *)list_entry((*head)->lru.next,
- struct page, lru);
-
- list_del_init(&page->lru);
-}
-
-static enum fullness_group fix_fullness_group(struct zs_pool *pool,
- struct page *page)
-{
- int class_idx;
- struct size_class *class;
- enum fullness_group currfg, newfg;
-
- BUG_ON(!is_first_page(page));
-
- get_zspage_mapping(page, &class_idx, &currfg);
- newfg = get_fullness_group(page);
- if (newfg == currfg)
- goto out;
-
- class = &pool->size_class[class_idx];
- remove_zspage(page, class, currfg);
- insert_zspage(page, class, newfg);
- set_zspage_mapping(page, class_idx, newfg);
-
-out:
- return newfg;
-}
-
-/*
- * We have to decide on how many pages to link together
- * to form a zspage for each size class. This is important
- * to reduce wastage due to unusable space left at end of
- * each zspage which is given as:
- * wastage = Zp - Zp % size_class
- * where Zp = zspage size = k * PAGE_SIZE where k = 1, 2, ...
- *
- * For example, for size class of 3/8 * PAGE_SIZE, we should
- * link together 3 PAGE_SIZE sized pages to form a zspage
- * since then we can perfectly fit in 8 such objects.
- */
-static int get_pages_per_zspage(int class_size)
-{
- int i, max_usedpc = 0;
- /* zspage order which gives maximum used size per KB */
- int max_usedpc_order = 1;
-
- for (i = 1; i <= ZS_MAX_PAGES_PER_ZSPAGE; i++) {
- int zspage_size;
- int waste, usedpc;
-
- zspage_size = i * PAGE_SIZE;
- waste = zspage_size % class_size;
- usedpc = (zspage_size - waste) * 100 / zspage_size;
-
- if (usedpc > max_usedpc) {
- max_usedpc = usedpc;
- max_usedpc_order = i;
- }
- }
-
- return max_usedpc_order;
-}
-
-/*
- * A single 'zspage' is composed of many system pages which are
- * linked together using fields in struct page. This function finds
- * the first/head page, given any component page of a zspage.
- */
-static struct page *get_first_page(struct page *page)
-{
- if (is_first_page(page))
- return page;
- else
- return page->first_page;
-}
-
-static struct page *get_next_page(struct page *page)
-{
- struct page *next;
-
- if (is_last_page(page))
- next = NULL;
- else if (is_first_page(page))
- next = (struct page *)page->private;
- else
- next = list_entry(page->lru.next, struct page, lru);
-
- return next;
-}
-
-/*
- * Encode <page, obj_idx> as a single handle value.
- * On hardware platforms with physical memory starting at 0x0 the pfn
- * could be 0 so we ensure that the handle will never be 0 by adjusting the
- * encoded obj_idx value before encoding.
- */
-static void *obj_location_to_handle(struct page *page, unsigned long obj_idx)
-{
- unsigned long handle;
-
- if (!page) {
- BUG_ON(obj_idx);
- return NULL;
- }
-
- handle = page_to_pfn(page) << OBJ_INDEX_BITS;
- handle |= ((obj_idx + 1) & OBJ_INDEX_MASK);
-
- return (void *)handle;
-}
-
-/*
- * Decode <page, obj_idx> pair from the given object handle. We adjust the
- * decoded obj_idx back to its original value since it was adjusted in
- * obj_location_to_handle().
- */
-static void obj_handle_to_location(unsigned long handle, struct page **page,
- unsigned long *obj_idx)
-{
- *page = pfn_to_page(handle >> OBJ_INDEX_BITS);
- *obj_idx = (handle & OBJ_INDEX_MASK) - 1;
-}
-
-static unsigned long obj_idx_to_offset(struct page *page,
- unsigned long obj_idx, int class_size)
-{
- unsigned long off = 0;
-
- if (!is_first_page(page))
- off = page->index;
-
- return off + obj_idx * class_size;
-}
-
-static void reset_page(struct page *page)
-{
- clear_bit(PG_private, &page->flags);
- clear_bit(PG_private_2, &page->flags);
- set_page_private(page, 0);
- page->mapping = NULL;
- page->freelist = NULL;
- page_mapcount_reset(page);
-}
-
-static void free_zspage(struct page *first_page)
-{
- struct page *nextp, *tmp, *head_extra;
-
- BUG_ON(!is_first_page(first_page));
- BUG_ON(first_page->inuse);
-
- head_extra = (struct page *)page_private(first_page);
-
- reset_page(first_page);
- __free_page(first_page);
-
- /* zspage with only 1 system page */
- if (!head_extra)
- return;
-
- list_for_each_entry_safe(nextp, tmp, &head_extra->lru, lru) {
- list_del(&nextp->lru);
- reset_page(nextp);
- __free_page(nextp);
- }
- reset_page(head_extra);
- __free_page(head_extra);
-}
-
-/* Initialize a newly allocated zspage */
-static void init_zspage(struct page *first_page, struct size_class *class)
-{
- unsigned long off = 0;
- struct page *page = first_page;
-
- BUG_ON(!is_first_page(first_page));
- while (page) {
- struct page *next_page;
- struct link_free *link;
- unsigned int i, objs_on_page;
-
- /*
- * page->index stores offset of first object starting
- * in the page. For the first page, this is always 0,
- * so we use first_page->index (aka ->freelist) to store
- * head of corresponding zspage's freelist.
- */
- if (page != first_page)
- page->index = off;
-
- link = (struct link_free *)kmap_atomic(page) +
- off / sizeof(*link);
- objs_on_page = (PAGE_SIZE - off) / class->size;
-
- for (i = 1; i <= objs_on_page; i++) {
- off += class->size;
- if (off < PAGE_SIZE) {
- link->next = obj_location_to_handle(page, i);
- link += class->size / sizeof(*link);
- }
- }
-
- /*
- * We now come to the last (full or partial) object on this
- * page, which must point to the first object on the next
- * page (if present)
- */
- next_page = get_next_page(page);
- link->next = obj_location_to_handle(next_page, 0);
- kunmap_atomic(link);
- page = next_page;
- off = (off + class->size) % PAGE_SIZE;
- }
-}
-
-/*
- * Allocate a zspage for the given size class
- */
-static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
-{
- int i, error;
- struct page *first_page = NULL, *uninitialized_var(prev_page);
-
- /*
- * Allocate individual pages and link them together as:
- * 1. first page->private = first sub-page
- * 2. all sub-pages are linked together using page->lru
- * 3. each sub-page is linked to the first page using page->first_page
- *
- * For each size class, First/Head pages are linked together using
- * page->lru. Also, we set PG_private to identify the first page
- * (i.e. no other sub-page has this flag set) and PG_private_2 to
- * identify the last page.
- */
- error = -ENOMEM;
- for (i = 0; i < class->pages_per_zspage; i++) {
- struct page *page;
-
- page = alloc_page(flags);
- if (!page)
- goto cleanup;
-
- INIT_LIST_HEAD(&page->lru);
- if (i == 0) { /* first page */
- SetPagePrivate(page);
- set_page_private(page, 0);
- first_page = page;
- first_page->inuse = 0;
- }
- if (i == 1)
- first_page->private = (unsigned long)page;
- if (i >= 1)
- page->first_page = first_page;
- if (i >= 2)
- list_add(&page->lru, &prev_page->lru);
- if (i == class->pages_per_zspage - 1) /* last page */
- SetPagePrivate2(page);
- prev_page = page;
- }
-
- init_zspage(first_page, class);
-
- first_page->freelist = obj_location_to_handle(first_page, 0);
- /* Maximum number of objects we can store in this zspage */
- first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
-
- error = 0; /* Success */
-
-cleanup:
- if (unlikely(error) && first_page) {
- free_zspage(first_page);
- first_page = NULL;
- }
-
- return first_page;
-}
-
-static struct page *find_get_zspage(struct size_class *class)
-{
- int i;
- struct page *page;
-
- for (i = 0; i < _ZS_NR_FULLNESS_GROUPS; i++) {
- page = class->fullness_list[i];
- if (page)
- break;
- }
-
- return page;
-}
-
-#ifdef USE_PGTABLE_MAPPING
-static inline int __zs_cpu_up(struct mapping_area *area)
-{
- /*
- * Make sure we don't leak memory if a cpu UP notification
- * and zs_init() race and both call zs_cpu_up() on the same cpu
- */
- if (area->vm)
- return 0;
- area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
- if (!area->vm)
- return -ENOMEM;
- return 0;
-}
-
-static inline void __zs_cpu_down(struct mapping_area *area)
-{
- if (area->vm)
- free_vm_area(area->vm);
- area->vm = NULL;
-}
-
-static inline void *__zs_map_object(struct mapping_area *area,
- struct page *pages[2], int off, int size)
-{
- BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
- area->vm_addr = area->vm->addr;
- return area->vm_addr + off;
-}
-
-static inline void __zs_unmap_object(struct mapping_area *area,
- struct page *pages[2], int off, int size)
-{
- unsigned long addr = (unsigned long)area->vm_addr;
-
- unmap_kernel_range(addr, PAGE_SIZE * 2);
-}
-
-#else /* USE_PGTABLE_MAPPING */
-
-static inline int __zs_cpu_up(struct mapping_area *area)
-{
- /*
- * Make sure we don't leak memory if a cpu UP notification
- * and zs_init() race and both call zs_cpu_up() on the same cpu
- */
- if (area->vm_buf)
- return 0;
- area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
- if (!area->vm_buf)
- return -ENOMEM;
- return 0;
-}
-
-static inline void __zs_cpu_down(struct mapping_area *area)
-{
- if (area->vm_buf)
- free_page((unsigned long)area->vm_buf);
- area->vm_buf = NULL;
-}
-
-static void *__zs_map_object(struct mapping_area *area,
- struct page *pages[2], int off, int size)
-{
- int sizes[2];
- void *addr;
- char *buf = area->vm_buf;
-
- /* disable page faults to match kmap_atomic() return conditions */
- pagefault_disable();
-
- /* no read fastpath */
- if (area->vm_mm == ZS_MM_WO)
- goto out;
-
- sizes[0] = PAGE_SIZE - off;
- sizes[1] = size - sizes[0];
-
- /* copy object to per-cpu buffer */
- addr = kmap_atomic(pages[0]);
- memcpy(buf, addr + off, sizes[0]);
- kunmap_atomic(addr);
- addr = kmap_atomic(pages[1]);
- memcpy(buf + sizes[0], addr, sizes[1]);
- kunmap_atomic(addr);
-out:
- return area->vm_buf;
-}
-
-static void __zs_unmap_object(struct mapping_area *area,
- struct page *pages[2], int off, int size)
-{
- int sizes[2];
- void *addr;
- char *buf = area->vm_buf;
-
- /* no write fastpath */
- if (area->vm_mm == ZS_MM_RO)
- goto out;
-
- sizes[0] = PAGE_SIZE - off;
- sizes[1] = size - sizes[0];
-
- /* copy per-cpu buffer to object */
- addr = kmap_atomic(pages[0]);
- memcpy(addr + off, buf, sizes[0]);
- kunmap_atomic(addr);
- addr = kmap_atomic(pages[1]);
- memcpy(addr, buf + sizes[0], sizes[1]);
- kunmap_atomic(addr);
-
-out:
- /* enable page faults to match kunmap_atomic() return conditions */
- pagefault_enable();
-}
-
-#endif /* USE_PGTABLE_MAPPING */
-
-static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
- void *pcpu)
-{
- int ret, cpu = (long)pcpu;
- struct mapping_area *area;
-
- switch (action) {
- case CPU_UP_PREPARE:
- area = &per_cpu(zs_map_area, cpu);
- ret = __zs_cpu_up(area);
- if (ret)
- return notifier_from_errno(ret);
- break;
- case CPU_DEAD:
- case CPU_UP_CANCELED:
- area = &per_cpu(zs_map_area, cpu);
- __zs_cpu_down(area);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block zs_cpu_nb = {
- .notifier_call = zs_cpu_notifier
-};
-
-static void zs_exit(void)
-{
- int cpu;
-
- for_each_online_cpu(cpu)
- zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu);
- unregister_cpu_notifier(&zs_cpu_nb);
-}
-
-static int zs_init(void)
-{
- int cpu, ret;
-
- register_cpu_notifier(&zs_cpu_nb);
- for_each_online_cpu(cpu) {
- ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
- if (notifier_to_errno(ret))
- goto fail;
- }
- return 0;
-fail:
- zs_exit();
- return notifier_to_errno(ret);
-}
-
-/**
- * zs_create_pool - Creates an allocation pool to work from.
- * @flags: allocation flags used to allocate pool metadata
- *
- * This function must be called before anything when using
- * the zsmalloc allocator.
- *
- * On success, a pointer to the newly created pool is returned,
- * otherwise NULL.
- */
-struct zs_pool *zs_create_pool(gfp_t flags)
-{
- int i, ovhd_size;
- struct zs_pool *pool;
-
- ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
- pool = kzalloc(ovhd_size, GFP_KERNEL);
- if (!pool)
- return NULL;
-
- for (i = 0; i < ZS_SIZE_CLASSES; i++) {
- int size;
- struct size_class *class;
-
- size = ZS_MIN_ALLOC_SIZE + i * ZS_SIZE_CLASS_DELTA;
- if (size > ZS_MAX_ALLOC_SIZE)
- size = ZS_MAX_ALLOC_SIZE;
-
- class = &pool->size_class[i];
- class->size = size;
- class->index = i;
- spin_lock_init(&class->lock);
- class->pages_per_zspage = get_pages_per_zspage(size);
-
- }
-
- pool->flags = flags;
-
- return pool;
-}
-EXPORT_SYMBOL_GPL(zs_create_pool);
-
-void zs_destroy_pool(struct zs_pool *pool)
-{
- int i;
-
- for (i = 0; i < ZS_SIZE_CLASSES; i++) {
- int fg;
- struct size_class *class = &pool->size_class[i];
-
- for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) {
- if (class->fullness_list[fg]) {
- pr_info("Freeing non-empty class with size "
- "%db, fullness group %d\n",
- class->size, fg);
- }
- }
- }
- kfree(pool);
-}
-EXPORT_SYMBOL_GPL(zs_destroy_pool);
-
-/**
- * zs_malloc - Allocate block of given size from pool.
- * @pool: pool to allocate from
- * @size: size of block to allocate
- *
- * On success, handle to the allocated object is returned,
- * otherwise 0.
- * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
- */
-unsigned long zs_malloc(struct zs_pool *pool, size_t size)
-{
- unsigned long obj;
- struct link_free *link;
- int class_idx;
- struct size_class *class;
-
- struct page *first_page, *m_page;
- unsigned long m_objidx, m_offset;
-
- if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
- return 0;
-
- class_idx = get_size_class_index(size);
- class = &pool->size_class[class_idx];
- BUG_ON(class_idx != class->index);
-
- spin_lock(&class->lock);
- first_page = find_get_zspage(class);
-
- if (!first_page) {
- spin_unlock(&class->lock);
- first_page = alloc_zspage(class, pool->flags);
- if (unlikely(!first_page))
- return 0;
-
- set_zspage_mapping(first_page, class->index, ZS_EMPTY);
- spin_lock(&class->lock);
- class->pages_allocated += class->pages_per_zspage;
- }
-
- obj = (unsigned long)first_page->freelist;
- obj_handle_to_location(obj, &m_page, &m_objidx);
- m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
-
- link = (struct link_free *)kmap_atomic(m_page) +
- m_offset / sizeof(*link);
- first_page->freelist = link->next;
- memset(link, POISON_INUSE, sizeof(*link));
- kunmap_atomic(link);
-
- first_page->inuse++;
- /* Now move the zspage to another fullness group, if required */
- fix_fullness_group(pool, first_page);
- spin_unlock(&class->lock);
-
- return obj;
-}
-EXPORT_SYMBOL_GPL(zs_malloc);
-
-void zs_free(struct zs_pool *pool, unsigned long obj)
-{
- struct link_free *link;
- struct page *first_page, *f_page;
- unsigned long f_objidx, f_offset;
-
- int class_idx;
- struct size_class *class;
- enum fullness_group fullness;
-
- if (unlikely(!obj))
- return;
-
- obj_handle_to_location(obj, &f_page, &f_objidx);
- first_page = get_first_page(f_page);
-
- get_zspage_mapping(first_page, &class_idx, &fullness);
- class = &pool->size_class[class_idx];
- f_offset = obj_idx_to_offset(f_page, f_objidx, class->size);
-
- spin_lock(&class->lock);
-
- /* Insert this object in containing zspage's freelist */
- link = (struct link_free *)((unsigned char *)kmap_atomic(f_page)
- + f_offset);
- link->next = first_page->freelist;
- kunmap_atomic(link);
- first_page->freelist = (void *)obj;
-
- first_page->inuse--;
- fullness = fix_fullness_group(pool, first_page);
-
- if (fullness == ZS_EMPTY)
- class->pages_allocated -= class->pages_per_zspage;
-
- spin_unlock(&class->lock);
-
- if (fullness == ZS_EMPTY)
- free_zspage(first_page);
-}
-EXPORT_SYMBOL_GPL(zs_free);
-
-/**
- * zs_map_object - get address of allocated object from handle.
- * @pool: pool from which the object was allocated
- * @handle: handle returned from zs_malloc
- *
- * Before using an object allocated from zs_malloc, it must be mapped using
- * this function. When done with the object, it must be unmapped using
- * zs_unmap_object.
- *
- * Only one object can be mapped per cpu at a time. There is no protection
- * against nested mappings.
- *
- * This function returns with preemption and page faults disabled.
-*/
-void *zs_map_object(struct zs_pool *pool, unsigned long handle,
- enum zs_mapmode mm)
-{
- struct page *page;
- unsigned long obj_idx, off;
-
- unsigned int class_idx;
- enum fullness_group fg;
- struct size_class *class;
- struct mapping_area *area;
- struct page *pages[2];
-
- BUG_ON(!handle);
-
- /*
- * Because we use per-cpu mapping areas shared among the
- * pools/users, we can't allow mapping in interrupt context
- * because it can corrupt another users mappings.
- */
- BUG_ON(in_interrupt());
-
- obj_handle_to_location(handle, &page, &obj_idx);
- get_zspage_mapping(get_first_page(page), &class_idx, &fg);
- class = &pool->size_class[class_idx];
- off = obj_idx_to_offset(page, obj_idx, class->size);
-
- area = &get_cpu_var(zs_map_area);
- area->vm_mm = mm;
- if (off + class->size <= PAGE_SIZE) {
- /* this object is contained entirely within a page */
- area->vm_addr = kmap_atomic(page);
- return area->vm_addr + off;
- }
-
- /* this object spans two pages */
- pages[0] = page;
- pages[1] = get_next_page(page);
- BUG_ON(!pages[1]);
-
- return __zs_map_object(area, pages, off, class->size);
-}
-EXPORT_SYMBOL_GPL(zs_map_object);
-
-void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
-{
- struct page *page;
- unsigned long obj_idx, off;
-
- unsigned int class_idx;
- enum fullness_group fg;
- struct size_class *class;
- struct mapping_area *area;
-
- BUG_ON(!handle);
-
- obj_handle_to_location(handle, &page, &obj_idx);
- get_zspage_mapping(get_first_page(page), &class_idx, &fg);
- class = &pool->size_class[class_idx];
- off = obj_idx_to_offset(page, obj_idx, class->size);
-
- area = &__get_cpu_var(zs_map_area);
- if (off + class->size <= PAGE_SIZE)
- kunmap_atomic(area->vm_addr);
- else {
- struct page *pages[2];
-
- pages[0] = page;
- pages[1] = get_next_page(page);
- BUG_ON(!pages[1]);
-
- __zs_unmap_object(area, pages, off, class->size);
- }
- put_cpu_var(zs_map_area);
-}
-EXPORT_SYMBOL_GPL(zs_unmap_object);
-
-u64 zs_get_total_size_bytes(struct zs_pool *pool)
-{
- int i;
- u64 npages = 0;
-
- for (i = 0; i < ZS_SIZE_CLASSES; i++)
- npages += pool->size_class[i].pages_allocated;
-
- return npages << PAGE_SHIFT;
-}
-EXPORT_SYMBOL_GPL(zs_get_total_size_bytes);
-
-module_init(zs_init);
-module_exit(zs_exit);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
+++ /dev/null
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _ZS_MALLOC_H_
-#define _ZS_MALLOC_H_
-
-#include <linux/types.h>
-
-/*
- * zsmalloc mapping modes
- *
- * NOTE: These only make a difference when a mapped object spans pages
-*/
-enum zs_mapmode {
- ZS_MM_RW, /* normal read-write mapping */
- ZS_MM_RO, /* read-only (no copy-out at unmap time) */
- ZS_MM_WO /* write-only (no copy-in at map time) */
-};
-
-struct zs_pool;
-
-struct zs_pool *zs_create_pool(gfp_t flags);
-void zs_destroy_pool(struct zs_pool *pool);
-
-unsigned long zs_malloc(struct zs_pool *pool, size_t size);
-void zs_free(struct zs_pool *pool, unsigned long obj);
-
-void *zs_map_object(struct zs_pool *pool, unsigned long handle,
- enum zs_mapmode mm);
-void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
-
-u64 zs_get_total_size_bytes(struct zs_pool *pool);
-
-#endif
* traditional iSCSI block I/O.
*/
if (iscsit_allocate_iovecs(cmd) < 0) {
- return iscsit_add_reject_cmd(cmd,
+ return iscsit_reject_cmd(cmd,
ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}
immed_data = cmd->immediate_data;
return 0;
}
+static void xen_console_update_evtchn(struct xencons_info *info)
+{
+ if (xen_hvm_domain()) {
+ uint64_t v;
+ int err;
+
+ err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
+ if (!err && v)
+ info->evtchn = v;
+ } else
+ info->evtchn = xen_start_info->console.domU.evtchn;
+}
+
void xen_console_resume(void)
{
struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
- if (info != NULL && info->irq)
+ if (info != NULL && info->irq) {
+ if (!xen_initial_domain())
+ xen_console_update_evtchn(info);
rebind_evtchn_irq(info->evtchn, info->irq);
+ }
}
static void xencons_disconnect_backend(struct xencons_info *info)
dw8250_force_idle(p);
writeb(value, p->membase + (UART_LCR << p->regshift));
}
- dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
}
}
dw8250_force_idle(p);
writel(value, p->membase + (UART_LCR << p->regshift));
}
- dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
}
}
{ .compatible = "ibm,qpace-nwp-serial",
.data = (void *)PORT_NWPSERIAL, },
#endif
- { .type = "serial", .data = (void *)PORT_UNKNOWN, },
{ /* end of list */ },
};
case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
dev_dbg(&desc->intf->dev,
"NOTIFY_RESPONSE_AVAILABLE received: index %d len %d",
- dr->wIndex, dr->wLength);
+ le16_to_cpu(dr->wIndex), le16_to_cpu(dr->wLength));
break;
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
clear_bit(WDM_POLL_RUNNING, &desc->flags);
dev_err(&desc->intf->dev,
"unknown notification %d received: index %d len %d\n",
- dr->bNotificationType, dr->wIndex, dr->wLength);
+ dr->bNotificationType,
+ le16_to_cpu(dr->wIndex),
+ le16_to_cpu(dr->wLength));
goto exit;
}
USB_RECIP_INTERFACE);
req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
req->wValue = 0;
- req->wIndex = desc->inum;
+ req->wIndex = desc->inum; /* already converted */
req->wLength = cpu_to_le16(count);
set_bit(WDM_IN_USE, &desc->flags);
desc->outbuf = buf;
rv = usb_translate_errors(rv);
} else {
dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d",
- req->wIndex);
+ le16_to_cpu(req->wIndex));
}
out:
usb_autopm_put_interface(desc->intf);
desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
desc->irq->wValue = 0;
- desc->irq->wIndex = desc->inum;
+ desc->irq->wIndex = desc->inum; /* already converted */
desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
usb_fill_control_urb(
dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
port1, status);
} else {
- /* drive resume for at least 20 msec */
+ /* drive resume for USB_RESUME_TIMEOUT msec */
dev_dbg(&udev->dev, "usb %sresume\n",
(PMSG_IS_AUTO(msg) ? "auto-" : ""));
- msleep(25);
+ msleep(USB_RESUME_TIMEOUT);
/* Virtual root hubs can trigger on GET_PORT_STATUS to
* stop resume signaling. Then finish the resume
config USB_G_ANDROID
boolean "Android Composite Gadget"
+ depends on SND
+ select SND_PCM
+ select SND_RAWMIDI
select USB_F_ACM
select USB_LIBCOMPOSITE
select USB_U_SERIAL
usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
- usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+ usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);
/*
* The Superspeed USB Capability descriptor shall be implemented by all
break;
}
/* host either stalls (value < 0) or reports success */
+ if (value >= 0) {
+ req->length = value;
+ req->zero = value < wLength;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ ERROR(dev, "%s:%d Error!\n", __func__, __LINE__);
+ req->status = 0;
+ }
+ }
return value;
}
spin_unlock_irq(&isp116x->lock);
hcd->state = HC_STATE_RESUMING;
- msleep(20);
+ msleep(USB_RESUME_TIMEOUT);
/* Go operational */
spin_lock_irq(&isp116x->lock);
|| oxu->reset_done[i] != 0)
continue;
- /* start 20 msec resume signaling from this port,
- * and make khubd collect PORT_STAT_C_SUSPEND to
+ /* start USB_RESUME_TIMEOUT resume signaling from this
+ * port, and make hub_wq collect PORT_STAT_C_SUSPEND to
* stop that signaling.
*/
- oxu->reset_done[i] = jiffies + msecs_to_jiffies(20);
+ oxu->reset_done[i] = jiffies +
+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
oxu_dbg(oxu, "port %d remote wakeup\n", i + 1);
mod_timer(&hcd->rh_timer, oxu->reset_done[i]);
}
rh->port &= ~USB_PORT_STAT_SUSPEND;
rh->port |= USB_PORT_STAT_C_SUSPEND << 16;
r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
- msleep(50);
+ msleep(USB_RESUME_TIMEOUT);
r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);
}
sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
mod_timer(&sl811->timer, jiffies
- + msecs_to_jiffies(20));
+ + msecs_to_jiffies(USB_RESUME_TIMEOUT));
break;
case USB_PORT_FEAT_POWER:
port_power(sl811, 0);
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
xhci->quirks |= XHCI_LPM_SUPPORT;
xhci->quirks |= XHCI_INTEL_HOST;
+ xhci->quirks |= XHCI_AVOID_BEI;
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
* PPT chipsets.
*/
xhci->quirks |= XHCI_SPURIOUS_REBOOT;
- xhci->quirks |= XHCI_AVOID_BEI;
}
if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
} else {
xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies +
- msecs_to_jiffies(20);
+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
set_bit(faked_port_index, &bus_state->resuming_ports);
mod_timer(&hcd->rh_timer,
bus_state->resume_done[faked_port_index]);
static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
{
- return res == match_data;
+ struct usb_phy **phy = res;
+
+ return *phy == match_data;
}
/**
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) },
/*
* ELV devices:
*/
{
struct usb_device *udev = serial->dev;
- if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
- (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2")))
+ if (udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems"))
+ return ftdi_jtag_probe(serial);
+
+ if (udev->product &&
+ (!strcmp(udev->product, "BeagleBone/XDS100V2") ||
+ !strcmp(udev->product, "SNAP Connect E10")))
return ftdi_jtag_probe(serial);
return 0;
*/
#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */
+/*
+ * Synapse Wireless product ids (FTDI_VID)
+ * http://www.synapse-wireless.com
+ */
+#define FTDI_SYNAPSE_SS200_PID 0x9090 /* SS200 - SNAP Stick 200 */
+
/********************************/
/** third-party VID/PID combos **/
config VGA_CONSOLE
bool "VGA text console" if EXPERT || !X86
- depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && !ARM64
+ depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \
+ !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \
+ (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \
+ !ARM64
default y
help
Saying Y here will allow you to use Linux in text mode through a
{
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (entry_ino == (u32)(long)dentry->d_fsdata) {
dentry->d_fsdata = (void *)inode->i_ino;
break;
spin_lock(&root->d_lock);
if (prev)
- next = prev->d_u.d_child.next;
+ next = prev->d_child.next;
else {
prev = dget_dlock(root);
next = prev->d_subdirs.next;
return NULL;
}
- q = list_entry(next, struct dentry, d_u.d_child);
+ q = list_entry(next, struct dentry, d_child);
spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Already gone or negative dentry (under construction) - try next */
if (q->d_count == 0 || !simple_positive(q)) {
spin_unlock(&q->d_lock);
- next = q->d_u.d_child.next;
+ next = q->d_child.next;
goto cont;
}
dget_dlock(q);
goto relock;
}
spin_unlock(&p->d_lock);
- next = p->d_u.d_child.next;
+ next = p->d_child.next;
p = parent;
if (next != &parent->d_subdirs)
break;
}
}
- ret = list_entry(next, struct dentry, d_u.d_child);
+ ret = list_entry(next, struct dentry, d_child);
spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
spin_lock(&sbi->lookup_lock);
spin_lock(&expired->d_parent->d_lock);
spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+ list_move(&expired->d_parent->d_subdirs, &expired->d_child);
spin_unlock(&expired->d_lock);
spin_unlock(&expired->d_parent->d_lock);
spin_unlock(&sbi->lookup_lock);
/* only consider parents below dentrys in the root */
if (IS_ROOT(parent->d_parent))
return;
- d_child = &dentry->d_u.d_child;
+ d_child = &dentry->d_child;
/* Set parent managed if it's becoming empty */
if (d_child->next == &parent->d_subdirs &&
d_child->prev == &parent->d_subdirs)
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
unsigned long k, vaddr;
+ unsigned long total_size = 0;
if (elf_ppnt->p_type != PT_LOAD)
continue;
#else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
#endif
+ total_size = total_mapping_size(elf_phdata,
+ loc->elf_ex.e_phnum);
+ if (!total_size) {
+ error = -EINVAL;
+ goto out_free_dentry;
+ }
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
- elf_prot, elf_flags, 0);
+ elf_prot, elf_flags, total_size);
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
retval = IS_ERR((void *)error) ?
return -ENOSPC;
}
- if (btrfs_test_opt(root, DISCARD))
- ret = btrfs_discard_extent(root, start, len, NULL);
-
if (pin)
pin_down_extent(root, cache, start, len, 1);
else {
+ if (btrfs_test_opt(root, DISCARD))
+ ret = btrfs_discard_extent(root, start, len, NULL);
btrfs_add_free_space(cache, start, len);
btrfs_update_reserved_bytes(cache, len, RESERVE_FREE);
}
if (off + len == src->i_size)
len = ALIGN(src->i_size, bs) - off;
+ if (len == 0) {
+ ret = 0;
+ goto out_unlock;
+ }
+
/* verify the end result is block aligned */
if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) ||
!IS_ALIGNED(destoff, bs))
/*
* When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on
- * d_u.d_child when we initially get results back from the MDS, and
+ * d_child when we initially get results back from the MDS, and
* falling back to a "normal" sync readdir if any dentries in the dir
* are dropped.
*
p = parent->d_subdirs.prev;
dout(" initial p %p/%p\n", p->prev, p->next);
} else {
- p = last->d_u.d_child.prev;
+ p = last->d_child.prev;
}
more:
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
while (1) {
dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
!dentry->d_inode ? " null" : "");
spin_unlock(&dentry->d_lock);
p = p->prev;
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
}
spin_lock(&dir->d_lock);
spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&dn->d_u.d_child, &dir->d_subdirs);
+ list_move(&dn->d_child, &dir->d_subdirs);
dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
- dn->d_u.d_child.prev, dn->d_u.d_child.next);
+ dn->d_child.prev, dn->d_child.next);
spin_unlock(&dn->d_lock);
spin_unlock(&dir->d_lock);
}
/* reorder parent's d_subdirs */
spin_lock(&parent->d_lock);
spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&dn->d_u.d_child, &parent->d_subdirs);
+ list_move(&dn->d_child, &parent->d_subdirs);
spin_unlock(&dn->d_lock);
spin_unlock(&parent->d_lock);
}
cifsFileInfo_put(inv_file);
spin_lock(&cifs_file_list_lock);
++refind;
+ inv_file = NULL;
goto refind_writable;
}
}
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
spin_unlock(&inode->i_lock);
return true;
struct dentry *de;
spin_lock(&parent->d_lock);
- list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(de, &parent->d_subdirs, d_child) {
/* don't know what to do with negative dentries */
if (de->d_inode )
coda_flag_inode(de->d_inode, flag);
/*
* Usage:
* dcache->d_inode->i_lock protects:
- * - i_dentry, d_alias, d_inode of aliases
+ * - i_dentry, d_u.d_alias, d_inode of aliases
* dcache_hash_bucket lock protects:
* - the dcache hash table
* s_anon bl list spinlock protects:
* - d_unhashed()
* - d_parent and d_subdirs
* - childrens' d_child and d_parent
- * - d_alias, d_inode
+ * - d_u.d_alias, d_inode
*
* Ordering:
* dentry->d_inode->i_lock
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
- WARN_ON(!hlist_unhashed(&dentry->d_alias));
if (dname_external(dentry))
kfree(dentry->d_name.name);
kmem_cache_free(dentry_cache, dentry);
*/
static void d_free(struct dentry *dentry)
{
+ WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
BUG_ON(dentry->d_count);
this_cpu_dec(nr_dentry);
if (dentry->d_op && dentry->d_op->d_release)
struct inode *inode = dentry->d_inode;
if (inode) {
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
if (!inode->i_nlink)
{
struct inode *inode = dentry->d_inode;
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
__releases(parent->d_lock)
__releases(dentry->d_inode->i_lock)
{
- list_del(&dentry->d_u.d_child);
+ __list_del_entry(&dentry->d_child);
/*
- * Inform try_to_ascend() that we are no longer attached to the
+ * Inform ascending readers that we are no longer attached to the
* dentry tree
*/
dentry->d_flags |= DCACHE_DENTRY_KILLED;
again:
discon_alias = NULL;
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
spin_lock(&alias->d_lock);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
if (IS_ROOT(alias) &&
struct dentry *dentry;
restart:
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!dentry->d_count) {
__dget_dlock(dentry);
/* descend to the first leaf in the current subtree */
while (!list_empty(&dentry->d_subdirs))
dentry = list_entry(dentry->d_subdirs.next,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
/* consume the dentries from this leaf up through its parents
* until we find one with children or run out altogether */
if (IS_ROOT(dentry)) {
parent = NULL;
- list_del(&dentry->d_u.d_child);
+ list_del(&dentry->d_child);
} else {
parent = dentry->d_parent;
parent->d_count--;
- list_del(&dentry->d_u.d_child);
+ list_del(&dentry->d_child);
}
inode = dentry->d_inode;
if (inode) {
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
if (dentry->d_op && dentry->d_op->d_iput)
dentry->d_op->d_iput(dentry, inode);
else
} while (list_empty(&dentry->d_subdirs));
dentry = list_entry(dentry->d_subdirs.next,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
}
}
}
}
-/*
- * This tries to ascend one level of parenthood, but
- * we can race with renaming, so we need to re-check
- * the parenthood after dropping the lock and check
- * that the sequence number still matches.
- */
-static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq)
-{
- struct dentry *new = old->d_parent;
-
- rcu_read_lock();
- spin_unlock(&old->d_lock);
- spin_lock(&new->d_lock);
-
- /*
- * might go back up the wrong parent if we have had a rename
- * or deletion
- */
- if (new != old->d_parent ||
- (old->d_flags & DCACHE_DENTRY_KILLED) ||
- (!locked && read_seqretry(&rename_lock, seq))) {
- spin_unlock(&new->d_lock);
- new = NULL;
- }
- rcu_read_unlock();
- return new;
-}
-
-
/*
* Search for at least 1 mount point in the dentry's subdirs.
* We descend to the next level whenever the d_subdirs
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
/*
* All done at this level ... ascend and resume the search.
*/
+ rcu_read_lock();
+ascend:
if (this_parent != parent) {
struct dentry *child = this_parent;
- this_parent = try_to_ascend(this_parent, locked, seq);
- if (!this_parent)
+ this_parent = child->d_parent;
+
+ spin_unlock(&child->d_lock);
+ spin_lock(&this_parent->d_lock);
+
+ /* might go back up the wrong parent if we have had a rename. */
+ if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
- next = child->d_u.d_child.next;
+ next = child->d_child.next;
+ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ if (next == &this_parent->d_subdirs)
+ goto ascend;
+ child = list_entry(next, struct dentry, d_child);
+ next = next->next;
+ }
+ rcu_read_unlock();
goto resume;
}
- spin_unlock(&this_parent->d_lock);
if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
if (locked)
write_sequnlock(&rename_lock);
return 0; /* No mount points found in tree */
positive:
if (!locked && read_seqretry(&rename_lock, seq))
- goto rename_retry;
+ goto rename_retry_unlocked;
if (locked)
write_sequnlock(&rename_lock);
return 1;
rename_retry:
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
if (locked)
goto again;
+rename_retry_unlocked:
locked = 1;
write_seqlock(&rename_lock);
goto again;
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
*/
if (found && need_resched()) {
spin_unlock(&dentry->d_lock);
+ rcu_read_lock();
goto out;
}
/*
* All done at this level ... ascend and resume the search.
*/
+ rcu_read_lock();
+ascend:
if (this_parent != parent) {
struct dentry *child = this_parent;
- this_parent = try_to_ascend(this_parent, locked, seq);
- if (!this_parent)
+ this_parent = child->d_parent;
+
+ spin_unlock(&child->d_lock);
+ spin_lock(&this_parent->d_lock);
+
+ /* might go back up the wrong parent if we have had a rename. */
+ if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
- next = child->d_u.d_child.next;
+ next = child->d_child.next;
+ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ if (next == &this_parent->d_subdirs)
+ goto ascend;
+ child = list_entry(next, struct dentry, d_child);
+ next = next->next;
+ }
+ rcu_read_unlock();
goto resume;
}
out:
- spin_unlock(&this_parent->d_lock);
if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
if (locked)
write_sequnlock(&rename_lock);
return found;
rename_retry:
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
if (found)
return found;
if (locked)
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
- INIT_HLIST_NODE(&dentry->d_alias);
- INIT_LIST_HEAD(&dentry->d_u.d_child);
+ INIT_HLIST_NODE(&dentry->d_u.d_alias);
+ INIT_LIST_HEAD(&dentry->d_child);
d_set_d_op(dentry, dentry->d_sb->s_d_op);
this_cpu_inc(nr_dentry);
*/
__dget_dlock(parent);
dentry->d_parent = parent;
- list_add(&dentry->d_u.d_child, &parent->d_subdirs);
+ list_add(&dentry->d_child, &parent->d_subdirs);
spin_unlock(&parent->d_lock);
return dentry;
if (inode) {
if (unlikely(IS_AUTOMOUNT(inode)))
dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
- hlist_add_head(&dentry->d_alias, &inode->i_dentry);
+ hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
}
dentry->d_inode = inode;
dentry_rcuwalk_barrier(dentry);
void d_instantiate(struct dentry *entry, struct inode * inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
if (inode)
spin_lock(&inode->i_lock);
__d_instantiate(entry, inode);
return NULL;
}
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
/*
* Don't need alias->d_lock here, because aliases with
* d_parent == entry->d_parent are not subject to name or
{
struct dentry *result;
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
if (inode)
spin_lock(&inode->i_lock);
if (hlist_empty(&inode->i_dentry))
return NULL;
- alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
__dget(alias);
return alias;
}
spin_lock(&tmp->d_lock);
tmp->d_inode = inode;
tmp->d_flags |= DCACHE_DISCONNECTED;
- hlist_add_head(&tmp->d_alias, &inode->i_dentry);
+ hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
hlist_bl_lock(&tmp->d_sb->s_anon);
hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
hlist_bl_unlock(&tmp->d_sb->s_anon);
struct dentry *child;
spin_lock(&dparent->d_lock);
- list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dparent->d_subdirs, d_child) {
if (dentry == child) {
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
__dget_dlock(dentry);
/* Unhash the target: dput() will then get rid of it */
__d_drop(target);
- list_del(&dentry->d_u.d_child);
- list_del(&target->d_u.d_child);
+ list_del(&dentry->d_child);
+ list_del(&target->d_child);
/* Switch the names.. */
switch_names(dentry, target);
if (IS_ROOT(dentry)) {
dentry->d_parent = target->d_parent;
target->d_parent = target;
- INIT_LIST_HEAD(&target->d_u.d_child);
+ INIT_LIST_HEAD(&target->d_child);
} else {
swap(dentry->d_parent, target->d_parent);
/* And add them back to the (new) parent lists */
- list_add(&target->d_u.d_child, &target->d_parent->d_subdirs);
+ list_add(&target->d_child, &target->d_parent->d_subdirs);
}
- list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
write_seqcount_end(&target->d_seq);
write_seqcount_end(&dentry->d_seq);
swap(dentry->d_name.hash, anon->d_name.hash);
dentry->d_parent = dentry;
- list_del_init(&dentry->d_u.d_child);
+ list_del_init(&dentry->d_child);
anon->d_parent = dparent;
- list_move(&anon->d_u.d_child, &dparent->d_subdirs);
+ list_move(&anon->d_child, &dparent->d_subdirs);
write_seqcount_end(&dentry->d_seq);
write_seqcount_end(&anon->d_seq);
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
}
spin_unlock(&dentry->d_lock);
}
+ rcu_read_lock();
+ascend:
if (this_parent != root) {
struct dentry *child = this_parent;
if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
this_parent->d_flags |= DCACHE_GENOCIDE;
this_parent->d_count--;
}
- this_parent = try_to_ascend(this_parent, locked, seq);
- if (!this_parent)
+ this_parent = child->d_parent;
+
+ spin_unlock(&child->d_lock);
+ spin_lock(&this_parent->d_lock);
+
+ /* might go back up the wrong parent if we have had a rename. */
+ if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
- next = child->d_u.d_child.next;
+ next = child->d_child.next;
+ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ if (next == &this_parent->d_subdirs)
+ goto ascend;
+ child = list_entry(next, struct dentry, d_child);
+ next = next->next;
+ }
+ rcu_read_unlock();
goto resume;
}
- spin_unlock(&this_parent->d_lock);
if (!locked && read_seqretry(&rename_lock, seq))
goto rename_retry;
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
if (locked)
write_sequnlock(&rename_lock);
return;
rename_retry:
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
if (locked)
goto again;
locked = 1;
parent = dentry;
down:
mutex_lock(&parent->d_inode->i_mutex);
- list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry_safe(child, next, &parent->d_subdirs, d_child) {
if (!debugfs_positive(child))
continue;
mutex_lock(&parent->d_inode->i_mutex);
if (child != dentry) {
- next = list_entry(child->d_u.d_child.next, struct dentry,
- d_u.d_child);
+ next = list_entry(child->d_child.next, struct dentry,
+ d_child);
goto up;
}
inode = result->d_inode;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
dget(dentry);
spin_unlock(&inode->i_lock);
if (toput)
BUG_ON(end < lblk);
+ if ((status & EXTENT_STATUS_DELAYED) &&
+ (status & EXTENT_STATUS_WRITTEN)) {
+ ext4_warning(inode->i_sb, "Inserting extent [%u/%u] as "
+ " delayed and written which can potentially "
+ " cause data loss.\n", lblk, len);
+ WARN_ON(1);
+ }
+
newes.es_lblk = lblk;
newes.es_len = len;
ext4_es_store_pblock(&newes, pblk);
status = map->m_flags & EXT4_MAP_UNWRITTEN ?
EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+ !(status & EXTENT_STATUS_WRITTEN) &&
ext4_find_delalloc_range(inode, map->m_lblk,
map->m_lblk + map->m_len - 1))
status |= EXTENT_STATUS_DELAYED;
status = map->m_flags & EXT4_MAP_UNWRITTEN ?
EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+ !(status & EXTENT_STATUS_WRITTEN) &&
ext4_find_delalloc_range(inode, map->m_lblk,
map->m_lblk + map->m_len - 1))
status |= EXTENT_STATUS_DELAYED;
ext4_journal_stop(handle);
goto retry_grab;
}
- wait_on_page_writeback(page);
+ /* In case writeback began while the page was unlocked */
+ wait_for_stable_page(page);
if (ext4_should_dioread_nolock(inode))
ret = __block_write_begin(page, pos, len, ext4_get_block_write);
goto retry_grab;
}
/* In case writeback began while the page was unlocked */
- wait_on_page_writeback(page);
+ wait_for_stable_page(page);
ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep);
if (ret < 0) {
struct inode *inode)
{
struct inode *dir = dentry->d_parent->d_inode;
- struct buffer_head *bh;
+ struct buffer_head *bh = NULL;
struct ext4_dir_entry_2 *de;
struct ext4_dir_entry_tail *t;
struct super_block *sb;
return retval;
if (retval == 1) {
retval = 0;
- return retval;
+ goto out;
}
}
if (is_dx(dir)) {
retval = ext4_dx_add_entry(handle, dentry, inode);
if (!retval || (retval != ERR_BAD_DX_DIR))
- return retval;
+ goto out;
ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
dx_fallback++;
ext4_mark_inode_dirty(handle, dir);
return PTR_ERR(bh);
retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
- if (retval != -ENOSPC) {
- brelse(bh);
- return retval;
- }
+ if (retval != -ENOSPC)
+ goto out;
if (blocks == 1 && !dx_fallback &&
- EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
- return make_indexed_dir(handle, dentry, inode, bh);
+ EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+ retval = make_indexed_dir(handle, dentry, inode, bh);
+ bh = NULL; /* make_indexed_dir releases bh */
+ goto out;
+ }
brelse(bh);
}
bh = ext4_append(handle, dir, &block);
}
retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
+out:
brelse(bh);
if (retval == 0)
ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY);
* self "."
*/
filp->f_pos = 1;
- if (filldir(dirent, ".", 1, 0, ip->i_ino,
+ if (filldir(dirent, ".", 1, 1, ip->i_ino,
DT_DIR))
return 0;
}
* parent ".."
*/
filp->f_pos = 2;
- if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR))
+ if (filldir(dirent, "..", 2, 2, PARENT(ip), DT_DIR))
return 0;
/*
spin_lock(&dentry->d_lock);
/* d_lock not required for cursor */
- list_del(&cursor->d_u.d_child);
+ list_del(&cursor->d_child);
p = dentry->d_subdirs.next;
while (n && p != &dentry->d_subdirs) {
struct dentry *next;
- next = list_entry(p, struct dentry, d_u.d_child);
+ next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(next))
n--;
spin_unlock(&next->d_lock);
p = p->next;
}
- list_add_tail(&cursor->d_u.d_child, p);
+ list_add_tail(&cursor->d_child, p);
spin_unlock(&dentry->d_lock);
}
}
{
struct dentry *dentry = filp->f_path.dentry;
struct dentry *cursor = filp->private_data;
- struct list_head *p, *q = &cursor->d_u.d_child;
+ struct list_head *p, *q = &cursor->d_child;
ino_t ino;
int i = filp->f_pos;
for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
struct dentry *next;
- next = list_entry(p, struct dentry, d_u.d_child);
+ next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (!simple_positive(next)) {
spin_unlock(&next->d_lock);
int ret = 0;
spin_lock(&dentry->d_lock);
- list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dentry->d_subdirs, d_child) {
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(child)) {
spin_unlock(&child->d_lock);
if (should_follow_link(inode, follow)) {
if (nd->flags & LOOKUP_RCU) {
- if (unlikely(unlazy_walk(nd, path->dentry))) {
+ if (unlikely(nd->path.mnt != path->mnt ||
+ unlazy_walk(nd, path->dentry))) {
err = -ECHILD;
goto out_err;
}
if (should_follow_link(inode, !symlink_ok)) {
if (nd->flags & LOOKUP_RCU) {
- if (unlikely(unlazy_walk(nd, path->dentry))) {
+ if (unlikely(nd->path.mnt != path->mnt ||
+ unlazy_walk(nd, path->dentry))) {
error = -ECHILD;
goto out;
}
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dent = list_entry(next, struct dentry, d_u.d_child);
+ dent = list_entry(next, struct dentry, d_child);
if ((unsigned long)dent->d_fsdata == fpos) {
if (dent->d_inode)
dget(dent);
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dentry = list_entry(next, struct dentry, d_u.d_child);
+ dentry = list_entry(next, struct dentry, d_child);
if (dentry->d_fsdata == NULL)
ncp_age_dentry(server, dentry);
spin_lock(&parent->d_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
- dentry = list_entry(next, struct dentry, d_u.d_child);
+ dentry = list_entry(next, struct dentry, d_child);
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
next = next->next;
*/
spin_lock(&sb->s_root->d_inode->i_lock);
spin_lock(&sb->s_root->d_lock);
- hlist_del_init(&sb->s_root->d_alias);
+ hlist_del_init(&sb->s_root->d_u.d_alias);
spin_unlock(&sb->s_root->d_lock);
spin_unlock(&sb->s_root->d_inode->i_lock);
}
nchildren = nilfs_btree_node_get_nchildren(node);
if (unlikely(level < NILFS_BTREE_LEVEL_NODE_MIN ||
- level > NILFS_BTREE_LEVEL_MAX ||
+ level >= NILFS_BTREE_LEVEL_MAX ||
nchildren < 0 ||
nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX)) {
pr_crit("NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d\n",
spin_lock(&inode->i_lock);
/* run all of the dentries associated with this inode. Since this is a
* directory, there damn well better only be one item on this list */
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
struct dentry *child;
/* run all of the children of the original inode and fix their
* d_flags to indicate parental interest (their parent is the
* original inode) */
spin_lock(&alias->d_lock);
- list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &alias->d_subdirs, d_child) {
if (!child->d_inode)
continue;
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
trace_ocfs2_find_local_alias(dentry->d_name.len,
if (tmpres) {
spin_unlock(&dlm->spinlock);
spin_lock(&tmpres->spinlock);
+
+ /*
+ * Right after dlm spinlock was released, dlm_thread could have
+ * purged the lockres. Check if lockres got unhashed. If so
+ * start over.
+ */
+ if (hlist_unhashed(&tmpres->hash_node)) {
+ spin_unlock(&tmpres->spinlock);
+ dlm_lockres_put(tmpres);
+ tmpres = NULL;
+ goto lookup;
+ }
+
/* Wait on the thread that is mastering the resource */
if (tmpres->owner == DLM_LOCK_RES_OWNER_UNKNOWN) {
__dlm_wait_on_lockres(tmpres);
/* buffered aio wouldn't have proper lock coverage today */
BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
+ if (unlikely(written <= 0))
+ goto no_sync;
+
if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
((file->f_flags & O_DIRECT) && !direct_io)) {
- ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
- *ppos + count - 1);
+ ret = filemap_fdatawrite_range(file->f_mapping,
+ iocb->ki_pos - written,
+ iocb->ki_pos - 1);
if (ret < 0)
written = ret;
}
if (!ret)
- ret = filemap_fdatawait_range(file->f_mapping, *ppos,
- *ppos + count - 1);
+ ret = filemap_fdatawait_range(file->f_mapping,
+ iocb->ki_pos - written,
+ iocb->ki_pos - 1);
}
+no_sync:
/*
* deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io
* function pointer which is called when o_direct io completes so that
struct address_space *mapping = out->f_mapping;
struct inode *inode = mapping->host;
struct splice_desc sd = {
- .total_len = len,
.flags = flags,
- .pos = *ppos,
.u.file = out,
};
-
+ ret = generic_write_checks(out, ppos, &len, 0);
+ if(ret)
+ return ret;
+ sd.total_len = len;
+ sd.pos = *ppos;
trace_ocfs2_file_splice_write(inode, out, out->f_path.dentry,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
return ret;
}
+static int pagemap_open(struct inode *inode, struct file *file)
+{
+ /* do not disclose physical addresses to unprivileged
+ userspace (closes a rowhammer attack vector) */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
const struct file_operations proc_pagemap_operations = {
.llseek = mem_lseek, /* borrow this */
.read = pagemap_read,
+ .open = pagemap_open,
};
#endif /* CONFIG_PROC_PAGE_MONITOR */
#define MAX_US_INT 0xffff
// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
-#define U32_MAX (~(__u32)0)
-
static inline loff_t max_reiserfs_offset(struct inode *inode)
{
if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
struct address_space *mapping = out->f_mapping;
struct inode *inode = mapping->host;
struct splice_desc sd = {
- .total_len = len,
.flags = flags,
- .pos = *ppos,
.u.file = out,
};
ssize_t ret;
+ ret = generic_write_checks(out, ppos, &len, S_ISBLK(inode->i_mode));
+ if (ret)
+ return ret;
+ sd.total_len = len;
+ sd.pos = *ppos;
+
pipe_lock(pipe);
splice_from_pipe_begin(&sd);
*/
acpi_status acpi_reallocate_root_table(void);
-acpi_status acpi_find_root_pointer(acpi_size *rsdp_address);
+acpi_status acpi_find_root_pointer(acpi_physical_address *rsdp_address);
acpi_status acpi_unload_table_id(acpi_owner_id id);
typedef s32 acpi_native_int;
typedef u32 acpi_size;
+
+#ifdef ACPI_32BIT_PHYSICAL_ADDRESS
+
+/*
+ * OSPMs can define this to shrink the size of the structures for 32-bit
+ * none PAE environment. ASL compiler may always define this to generate
+ * 32-bit OSPM compliant tables.
+ */
typedef u32 acpi_io_address;
typedef u32 acpi_physical_address;
+#else /* ACPI_32BIT_PHYSICAL_ADDRESS */
+
+/*
+ * It is reported that, after some calculations, the physical addresses can
+ * wrap over the 32-bit boundary on 32-bit PAE environment.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=87971
+ */
+typedef u64 acpi_io_address;
+typedef u64 acpi_physical_address;
+
+#endif /* ACPI_32BIT_PHYSICAL_ADDRESS */
+
#define ACPI_MAX_PTR ACPI_UINT32_MAX
#define ACPI_SIZE_MAX ACPI_UINT32_MAX
#define ACPI_LARGE_NAMESPACE_NODE
#define ACPI_DATA_TABLE_DISASSEMBLY
#define ACPI_SINGLE_THREADED
+#define ACPI_32BIT_PHYSICAL_ADDRESS
#endif
/* acpi_exec configuration. Multithreaded with full AML debugger */
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
barrier();
#endif
- if (pmd_none(pmdval))
+ if (pmd_none(pmdval) || pmd_trans_huge(pmdval))
return 1;
if (unlikely(pmd_bad(pmdval))) {
- if (!pmd_trans_huge(pmdval))
- pmd_clear_bad(pmd);
+ pmd_clear_bad(pmd);
return 1;
}
return 0;
/* References to section boundaries */
+#include <linux/compiler.h>
+
extern char _text[], _stext[], _etext[];
extern char _data[], _sdata[], _edata[];
extern char __bss_start[], __bss_stop[];
/* Start and end of .ctors section - used for constructor calls. */
extern char __ctors_start[], __ctors_end[];
+extern __visible const void __nosave_begin, __nosave_end;
+
/* function descriptor handling (if any). Override
* in asm/sections.h */
#ifndef dereference_function_descriptor
__REQ_ELVPRIV, /* elevator private data attached */
__REQ_FAILED, /* set if the request failed */
__REQ_QUIET, /* don't worry about errors */
- __REQ_PREEMPT, /* set for "ide_preempt" requests */
+ __REQ_PREEMPT, /* set for "ide_preempt" requests and also
+ for requests for which the SCSI "quiesce"
+ state must be ignored. */
__REQ_ALLOCED, /* request came from our alloc pool */
__REQ_COPY_USER, /* contains copies of user pages */
__REQ_FLUSH_SEQ, /* request for flush sequence */
#include <linux/ceph/types.h>
-/* This seemed to be the easiest place to define these */
-
-#define U8_MAX ((u8)(~0U))
-#define U16_MAX ((u16)(~0U))
-#define U32_MAX ((u32)(~0U))
-#define U64_MAX ((u64)(~0ULL))
-
-#define S8_MAX ((s8)(U8_MAX >> 1))
-#define S16_MAX ((s16)(U16_MAX >> 1))
-#define S32_MAX ((s32)(U32_MAX >> 1))
-#define S64_MAX ((s64)(U64_MAX >> 1LL))
-
-#define S8_MIN ((s8)(-S8_MAX - 1))
-#define S16_MIN ((s16)(-S16_MAX - 1))
-#define S32_MIN ((s32)(-S32_MAX - 1))
-#define S64_MIN ((s64)(-S64_MAX - 1LL))
-
/*
* in all cases,
* void **p pointer to position pointer
{ .notifier_call = fn, .priority = pri }; \
register_cpu_notifier(&fn##_nb); \
}
+
+#define __cpu_notifier(fn, pri) { \
+ static struct notifier_block fn##_nb = \
+ { .notifier_call = fn, .priority = pri }; \
+ __register_cpu_notifier(&fn##_nb); \
+}
#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
#define cpu_notifier(fn, pri) do { (void)(fn); } while (0)
+#define __cpu_notifier(fn, pri) do { (void)(fn); } while (0)
#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
+
#ifdef CONFIG_HOTPLUG_CPU
extern int register_cpu_notifier(struct notifier_block *nb);
+extern int __register_cpu_notifier(struct notifier_block *nb);
extern void unregister_cpu_notifier(struct notifier_block *nb);
+extern void __unregister_cpu_notifier(struct notifier_block *nb);
#else
#ifndef MODULE
extern int register_cpu_notifier(struct notifier_block *nb);
+extern int __register_cpu_notifier(struct notifier_block *nb);
#else
static inline int register_cpu_notifier(struct notifier_block *nb)
{
return 0;
}
+
+static inline int __register_cpu_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
#endif
static inline void unregister_cpu_notifier(struct notifier_block *nb)
{
}
+
+static inline void __unregister_cpu_notifier(struct notifier_block *nb)
+{
+}
#endif
int cpu_up(unsigned int cpu);
extern void cpu_maps_update_begin(void);
extern void cpu_maps_update_done(void);
+#define cpu_notifier_register_begin cpu_maps_update_begin
+#define cpu_notifier_register_done cpu_maps_update_done
+
#else /* CONFIG_SMP */
#define cpu_notifier(fn, pri) do { (void)(fn); } while (0)
+#define __cpu_notifier(fn, pri) do { (void)(fn); } while (0)
static inline int register_cpu_notifier(struct notifier_block *nb)
{
return 0;
}
+static inline int __register_cpu_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
static inline void unregister_cpu_notifier(struct notifier_block *nb)
{
}
+static inline void __unregister_cpu_notifier(struct notifier_block *nb)
+{
+}
+
static inline void cpu_maps_update_begin(void)
{
}
{
}
+static inline void cpu_notifier_register_begin(void)
+{
+}
+
+static inline void cpu_notifier_register_done(void)
+{
+}
+
#endif /* CONFIG_SMP */
extern struct bus_type cpu_subsys;
extern void cpu_hotplug_disable(void);
extern void cpu_hotplug_enable(void);
#define hotcpu_notifier(fn, pri) cpu_notifier(fn, pri)
+#define __hotcpu_notifier(fn, pri) __cpu_notifier(fn, pri)
#define register_hotcpu_notifier(nb) register_cpu_notifier(nb)
+#define __register_hotcpu_notifier(nb) __register_cpu_notifier(nb)
#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
+#define __unregister_hotcpu_notifier(nb) __unregister_cpu_notifier(nb)
void clear_tasks_mm_cpumask(int cpu);
int cpu_down(unsigned int cpu);
#define cpu_hotplug_disable() do { } while (0)
#define cpu_hotplug_enable() do { } while (0)
#define hotcpu_notifier(fn, pri) do { (void)(fn); } while (0)
+#define __hotcpu_notifier(fn, pri) do { (void)(fn); } while (0)
/* These aren't inline functions due to a GCC bug. */
#define register_hotcpu_notifier(nb) ({ (void)(nb); 0; })
+#define __register_hotcpu_notifier(nb) ({ (void)(nb); 0; })
#define unregister_hotcpu_notifier(nb) ({ (void)(nb); })
+#define __unregister_hotcpu_notifier(nb) ({ (void)(nb); })
#endif /* CONFIG_HOTPLUG_CPU */
#ifdef CONFIG_PM_SLEEP_SMP
void *d_fsdata; /* fs-specific data */
struct list_head d_lru; /* LRU list */
+ struct list_head d_child; /* child of parent list */
+ struct list_head d_subdirs; /* our children */
/*
- * d_child and d_rcu can share memory
+ * d_alias and d_rcu can share memory
*/
union {
- struct list_head d_child; /* child of parent list */
+ struct hlist_node d_alias; /* inode alias list */
struct rcu_head d_rcu;
} d_u;
- struct list_head d_subdirs; /* our children */
- struct hlist_node d_alias; /* inode alias list */
};
/*
#include <linux/irqnr.h>
#include <linux/hardirq.h>
#include <linux/irqflags.h>
-#include <linux/smp.h>
-#include <linux/percpu.h>
#include <linux/hrtimer.h>
#include <linux/kref.h>
#include <linux/workqueue.h>
extern void raise_softirq_irqoff(unsigned int nr);
extern void raise_softirq(unsigned int nr);
-/* This is the worklist that queues up per-cpu softirq work.
- *
- * send_remote_sendirq() adds work to these lists, and
- * the softirq handler itself dequeues from them. The queues
- * are protected by disabling local cpu interrupts and they must
- * only be accessed by the local cpu that they are for.
- */
-DECLARE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
-
DECLARE_PER_CPU(struct task_struct *, ksoftirqd);
static inline struct task_struct *this_cpu_ksoftirqd(void)
return this_cpu_read(ksoftirqd);
}
-/* Try to send a softirq to a remote cpu. If this cannot be done, the
- * work will be queued to the local cpu.
- */
-extern void send_remote_softirq(struct call_single_data *cp, int cpu, int softirq);
-
-/* Like send_remote_softirq(), but the caller must disable local cpu interrupts
- * and compute the current cpu, passed in as 'this_cpu'.
- */
-extern void __send_remote_softirq(struct call_single_data *cp, int cpu,
- int this_cpu, int softirq);
-
/* Tasklets --- multithreaded analogue of BHs.
Main feature differing them of generic softirqs: tasklet
#define ULLONG_MAX (~0ULL)
#define SIZE_MAX (~(size_t)0)
+#define U8_MAX ((u8)~0U)
+#define S8_MAX ((s8)(U8_MAX>>1))
+#define S8_MIN ((s8)(-S8_MAX - 1))
+#define U16_MAX ((u16)~0U)
+#define S16_MAX ((s16)(U16_MAX>>1))
+#define S16_MIN ((s16)(-S16_MAX - 1))
+#define U32_MAX ((u32)~0U)
+#define S32_MAX ((s32)(U32_MAX>>1))
+#define S32_MIN ((s32)(-S32_MAX - 1))
+#define U64_MAX ((u64)~0ULL)
+#define S64_MAX ((s64)(U64_MAX>>1))
+#define S64_MIN ((s64)(-S64_MAX - 1))
+
#define STACK_MAGIC 0xdeadbeef
#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
#define VM_FAULT_WRITE 0x0008 /* Special case for get_user_pages */
#define VM_FAULT_HWPOISON 0x0010 /* Hit poisoned small page */
#define VM_FAULT_HWPOISON_LARGE 0x0020 /* Hit poisoned large page. Index encoded in upper bits */
+#define VM_FAULT_SIGSEGV 0x0040
#define VM_FAULT_NOPAGE 0x0100 /* ->fault installed the pte, not return page */
#define VM_FAULT_LOCKED 0x0200 /* ->fault locked the returned page */
#define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */
-#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
- VM_FAULT_HWPOISON_LARGE)
+#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \
+ VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE)
/* Encode hstate index for a hwpoisoned large page */
#define VM_FAULT_SET_HINDEX(x) ((x) << 12)
/* level */
#define NILFS_BTREE_LEVEL_DATA 0
#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
-#define NILFS_BTREE_LEVEL_MAX 14
+#define NILFS_BTREE_LEVEL_MAX 14 /* Max level (exclusive) */
/**
* struct nilfs_palloc_group_desc - block group descriptor
#define USB_MAXINTERFACES 32
#define USB_MAXIADS (USB_MAXINTERFACES/2)
+/*
+ * USB Resume Timer: Every Host controller driver should drive the resume
+ * signalling on the bus for the amount of time defined by this macro.
+ *
+ * That way we will have a 'stable' behavior among all HCDs supported by Linux.
+ *
+ * Note that the USB Specification states we should drive resume for *at least*
+ * 20 ms, but it doesn't give an upper bound. This creates two possible
+ * situations which we want to avoid:
+ *
+ * (a) sometimes an msleep(20) might expire slightly before 20 ms, which causes
+ * us to fail USB Electrical Tests, thus failing Certification
+ *
+ * (b) Some (many) devices actually need more than 20 ms of resume signalling,
+ * and while we can argue that's against the USB Specification, we don't have
+ * control over which devices a certification laboratory will be using for
+ * certification. If CertLab uses a device which was tested against Windows and
+ * that happens to have relaxed resume signalling rules, we might fall into
+ * situations where we fail interoperability and electrical tests.
+ *
+ * In order to avoid both conditions, we're using a 40 ms resume timeout, which
+ * should cope with both LPJ calibration errors and devices not following every
+ * detail of the USB Specification.
+ */
+#define USB_RESUME_TIMEOUT 40 /* ms */
+
/**
* struct usb_interface_cache - long-term representation of a device interface
* @num_altsetting: number of altsettings defined.
--- /dev/null
+/*
+ * zpool memory storage api
+ *
+ * Copyright (C) 2014 Dan Streetman
+ *
+ * This is a common frontend for the zbud and zsmalloc memory
+ * storage pool implementations. Typically, this is used to
+ * store compressed memory.
+ */
+
+#ifndef _ZPOOL_H_
+#define _ZPOOL_H_
+
+struct zpool;
+
+struct zpool_ops {
+ int (*evict)(struct zpool *pool, unsigned long handle);
+};
+
+/*
+ * Control how a handle is mapped. It will be ignored if the
+ * implementation does not support it. Its use is optional.
+ * Note that this does not refer to memory protection, it
+ * refers to how the memory will be copied in/out if copying
+ * is necessary during mapping; read-write is the safest as
+ * it copies the existing memory in on map, and copies the
+ * changed memory back out on unmap. Write-only does not copy
+ * in the memory and should only be used for initialization.
+ * If in doubt, use ZPOOL_MM_DEFAULT which is read-write.
+ */
+enum zpool_mapmode {
+ ZPOOL_MM_RW, /* normal read-write mapping */
+ ZPOOL_MM_RO, /* read-only (no copy-out at unmap time) */
+ ZPOOL_MM_WO, /* write-only (no copy-in at map time) */
+
+ ZPOOL_MM_DEFAULT = ZPOOL_MM_RW
+};
+
+struct zpool *zpool_create_pool(char *type, gfp_t gfp, struct zpool_ops *ops);
+
+char *zpool_get_type(struct zpool *pool);
+
+void zpool_destroy_pool(struct zpool *pool);
+
+int zpool_malloc(struct zpool *pool, size_t size, gfp_t gfp,
+ unsigned long *handle);
+
+void zpool_free(struct zpool *pool, unsigned long handle);
+
+int zpool_shrink(struct zpool *pool, unsigned int pages,
+ unsigned int *reclaimed);
+
+void *zpool_map_handle(struct zpool *pool, unsigned long handle,
+ enum zpool_mapmode mm);
+
+void zpool_unmap_handle(struct zpool *pool, unsigned long handle);
+
+u64 zpool_get_total_size(struct zpool *pool);
+
+
+/**
+ * struct zpool_driver - driver implementation for zpool
+ * @type: name of the driver.
+ * @list: entry in the list of zpool drivers.
+ * @create: create a new pool.
+ * @destroy: destroy a pool.
+ * @malloc: allocate mem from a pool.
+ * @free: free mem from a pool.
+ * @shrink: shrink the pool.
+ * @map: map a handle.
+ * @unmap: unmap a handle.
+ * @total_size: get total size of a pool.
+ *
+ * This is created by a zpool implementation and registered
+ * with zpool.
+ */
+struct zpool_driver {
+ char *type;
+ struct module *owner;
+ atomic_t refcount;
+ struct list_head list;
+
+ void *(*create)(gfp_t gfp, struct zpool_ops *ops);
+ void (*destroy)(void *pool);
+
+ int (*malloc)(void *pool, size_t size, gfp_t gfp,
+ unsigned long *handle);
+ void (*free)(void *pool, unsigned long handle);
+
+ int (*shrink)(void *pool, unsigned int pages,
+ unsigned int *reclaimed);
+
+ void *(*map)(void *pool, unsigned long handle,
+ enum zpool_mapmode mm);
+ void (*unmap)(void *pool, unsigned long handle);
+
+ u64 (*total_size)(void *pool);
+};
+
+void zpool_register_driver(struct zpool_driver *driver);
+
+int zpool_unregister_driver(struct zpool_driver *driver);
+
+int zpool_evict(void *pool, unsigned long handle);
+
+#endif
--- /dev/null
+/*
+ * zsmalloc memory allocator
+ *
+ * Copyright (C) 2011 Nitin Gupta
+ * Copyright (C) 2012, 2013 Minchan Kim
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the license that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ */
+
+#ifndef _ZS_MALLOC_H_
+#define _ZS_MALLOC_H_
+
+#include <linux/types.h>
+
+/*
+ * zsmalloc mapping modes
+ *
+ * NOTE: These only make a difference when a mapped object spans pages
+*/
+enum zs_mapmode {
+ ZS_MM_RW, /* normal read-write mapping */
+ ZS_MM_RO, /* read-only (no copy-out at unmap time) */
+ ZS_MM_WO /* write-only (no copy-in at map time) */
+};
+
+struct zs_pool;
+
+struct zs_pool *zs_create_pool(gfp_t flags);
+void zs_destroy_pool(struct zs_pool *pool);
+
+unsigned long zs_malloc(struct zs_pool *pool, size_t size);
+void zs_free(struct zs_pool *pool, unsigned long obj);
+
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm);
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
+
+unsigned long zs_get_total_pages(struct zs_pool *pool);
+
+#endif
#define EMUPAGESIZE 4096
#define MAXREQVOICES 8
-#define MAXPAGES 8192
+#define MAXPAGES0 4096 /* 32 bit mode */
+#define MAXPAGES1 8192 /* 31 bit mode */
#define RESERVED 0
#define NUM_MIDI 16
#define NUM_G 64 /* use all channels */
/* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */
#define EMU10K1_DMA_MASK 0x7fffffffUL /* 31bit */
-#define AUDIGY_DMA_MASK 0x7fffffffUL /* 31bit FIXME - 32 should work? */
- /* See ALSA bug #1276 - rlrevell */
+#define AUDIGY_DMA_MASK 0xffffffffUL /* 32bit mode */
#define TMEMSIZE 256*1024
#define TMEMSIZEREG 4
#define MAPB 0x0d /* Cache map B */
-#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */
-#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */
+#define MAP_PTE_MASK0 0xfffff000 /* The 20 MSBs of the PTE indexed by the PTI */
+#define MAP_PTI_MASK0 0x00000fff /* The 12 bit index to one of the 4096 PTE dwords */
+
+#define MAP_PTE_MASK1 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */
+#define MAP_PTI_MASK1 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */
/* 0x0e, 0x0f: Not used */
unsigned short model; /* subsystem id */
unsigned int card_type; /* EMU10K1_CARD_* */
unsigned int ecard_ctrl; /* ecard control bits */
+ unsigned int address_mode; /* address mode */
unsigned long dma_mask; /* PCI DMA mask */
unsigned int delay_pcm_irq; /* in samples */
int max_cache_pages; /* max memory size / PAGE_SIZE */
uptr = compat_ptr(ipck.msgp);
fifth = ipck.msgtyp;
}
- return do_msgrcv(first, uptr, second, fifth, third,
+ return do_msgrcv(first, uptr, second, (s32)fifth, third,
compat_do_msg_fill);
}
case MSGGET:
parent = dentry->d_parent;
spin_lock(&parent->d_lock);
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
- list_del_init(&dentry->d_u.d_child);
+ list_del_init(&dentry->d_child);
spin_unlock(&dentry->d_lock);
spin_unlock(&parent->d_lock);
remove_dir(dentry);
static DEFINE_MUTEX(cpu_add_remove_lock);
/*
- * The following two API's must be used when attempting
- * to serialize the updates to cpu_online_mask, cpu_present_mask.
+ * The following two APIs (cpu_maps_update_begin/done) must be used when
+ * attempting to serialize the updates to cpu_online_mask & cpu_present_mask.
+ * The APIs cpu_notifier_register_begin/done() must be used to protect CPU
+ * hotplug callback (un)registration performed using __register_cpu_notifier()
+ * or __unregister_cpu_notifier().
*/
void cpu_maps_update_begin(void)
{
mutex_lock(&cpu_add_remove_lock);
}
+EXPORT_SYMBOL(cpu_notifier_register_begin);
void cpu_maps_update_done(void)
{
mutex_unlock(&cpu_add_remove_lock);
}
+EXPORT_SYMBOL(cpu_notifier_register_done);
static RAW_NOTIFIER_HEAD(cpu_chain);
return ret;
}
+int __ref __register_cpu_notifier(struct notifier_block *nb)
+{
+ return raw_notifier_chain_register(&cpu_chain, nb);
+}
+
static int __cpu_notify(unsigned long val, void *v, int nr_to_call,
int *nr_calls)
{
BUG_ON(cpu_notify(val, v));
}
EXPORT_SYMBOL(register_cpu_notifier);
+EXPORT_SYMBOL(__register_cpu_notifier);
void __ref unregister_cpu_notifier(struct notifier_block *nb)
{
}
EXPORT_SYMBOL(unregister_cpu_notifier);
+void __ref __unregister_cpu_notifier(struct notifier_block *nb)
+{
+ raw_notifier_chain_unregister(&cpu_chain, nb);
+}
+EXPORT_SYMBOL(__unregister_cpu_notifier);
+
/**
* clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU
* @cpu: a CPU id
*/
struct console_cmdline
{
- char name[8]; /* Name of the driver */
+ char name[16]; /* Name of the driver */
int index; /* Minor dev. to use */
char *options; /* Options for the driver */
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
*/
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
i++) {
+ BUILD_BUG_ON(sizeof(console_cmdline[i].name) !=
+ sizeof(newcon->name));
if (strcmp(console_cmdline[i].name, newcon->name) != 0)
continue;
if (newcon->index >= 0 &&
static int ptrace_resume(struct task_struct *child, long request,
unsigned long data)
{
+ bool need_siglock;
+
if (!valid_signal(data))
return -EIO;
user_disable_single_step(child);
}
+ /*
+ * Change ->exit_code and ->state under siglock to avoid the race
+ * with wait_task_stopped() in between; a non-zero ->exit_code will
+ * wrongly look like another report from tracee.
+ *
+ * Note that we need siglock even if ->exit_code == data and/or this
+ * status was not reported yet, the new status must not be cleared by
+ * wait_task_stopped() after resume.
+ *
+ * If data == 0 we do not care if wait_task_stopped() reports the old
+ * status and clears the code too; this can't race with the tracee, it
+ * takes siglock after resume.
+ */
+ need_siglock = data && !thread_group_empty(current);
+ if (need_siglock)
+ spin_lock_irq(&child->sighand->siglock);
child->exit_code = data;
wake_up_state(child, __TASK_TRACED);
+ if (need_siglock)
+ spin_unlock_irq(&child->sighand->siglock);
return 0;
}
* Distribute under GPLv2.
*
* Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903)
- *
- * Remote softirq infrastructure is by Jens Axboe.
*/
#include <linux/export.h>
}
EXPORT_SYMBOL_GPL(tasklet_hrtimer_init);
-/*
- * Remote softirq bits
- */
-
-DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
-EXPORT_PER_CPU_SYMBOL(softirq_work_list);
-
-static void __local_trigger(struct call_single_data *cp, int softirq)
-{
- struct list_head *head = &__get_cpu_var(softirq_work_list[softirq]);
-
- list_add_tail(&cp->list, head);
-
- /* Trigger the softirq only if the list was previously empty. */
- if (head->next == &cp->list)
- raise_softirq_irqoff(softirq);
-}
-
-#ifdef CONFIG_USE_GENERIC_SMP_HELPERS
-static void remote_softirq_receive(void *data)
-{
- struct call_single_data *cp = data;
- unsigned long flags;
- int softirq;
-
- softirq = *(int *)cp->info;
- local_irq_save(flags);
- __local_trigger(cp, softirq);
- local_irq_restore(flags);
-}
-
-static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq)
-{
- if (cpu_online(cpu)) {
- cp->func = remote_softirq_receive;
- cp->info = &softirq;
- cp->flags = 0;
-
- __smp_call_function_single(cpu, cp, 0);
- return 0;
- }
- return 1;
-}
-#else /* CONFIG_USE_GENERIC_SMP_HELPERS */
-static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq)
-{
- return 1;
-}
-#endif
-
-/**
- * __send_remote_softirq - try to schedule softirq work on a remote cpu
- * @cp: private SMP call function data area
- * @cpu: the remote cpu
- * @this_cpu: the currently executing cpu
- * @softirq: the softirq for the work
- *
- * Attempt to schedule softirq work on a remote cpu. If this cannot be
- * done, the work is instead queued up on the local cpu.
- *
- * Interrupts must be disabled.
- */
-void __send_remote_softirq(struct call_single_data *cp, int cpu, int this_cpu, int softirq)
-{
- if (cpu == this_cpu || __try_remote_softirq(cp, cpu, softirq))
- __local_trigger(cp, softirq);
-}
-EXPORT_SYMBOL(__send_remote_softirq);
-
-/**
- * send_remote_softirq - try to schedule softirq work on a remote cpu
- * @cp: private SMP call function data area
- * @cpu: the remote cpu
- * @softirq: the softirq for the work
- *
- * Like __send_remote_softirq except that disabling interrupts and
- * computing the current cpu is done for the caller.
- */
-void send_remote_softirq(struct call_single_data *cp, int cpu, int softirq)
-{
- unsigned long flags;
- int this_cpu;
-
- local_irq_save(flags);
- this_cpu = smp_processor_id();
- __send_remote_softirq(cp, cpu, this_cpu, softirq);
- local_irq_restore(flags);
-}
-EXPORT_SYMBOL(send_remote_softirq);
-
-static int __cpuinit remote_softirq_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- /*
- * If a CPU goes away, splice its entries to the current CPU
- * and trigger a run of the softirq
- */
- if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
- int cpu = (unsigned long) hcpu;
- int i;
-
- local_irq_disable();
- for (i = 0; i < NR_SOFTIRQS; i++) {
- struct list_head *head = &per_cpu(softirq_work_list[i], cpu);
- struct list_head *local_head;
-
- if (list_empty(head))
- continue;
-
- local_head = &__get_cpu_var(softirq_work_list[i]);
- list_splice_init(head, local_head);
- raise_softirq_irqoff(i);
- }
- local_irq_enable();
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata remote_softirq_cpu_notifier = {
- .notifier_call = remote_softirq_cpu_notify,
-};
-
void __init softirq_init(void)
{
int cpu;
for_each_possible_cpu(cpu) {
- int i;
-
per_cpu(tasklet_vec, cpu).tail =
&per_cpu(tasklet_vec, cpu).head;
per_cpu(tasklet_hi_vec, cpu).tail =
&per_cpu(tasklet_hi_vec, cpu).head;
- for (i = 0; i < NR_SOFTIRQS; i++)
- INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));
}
- register_hotcpu_notifier(&remote_softirq_cpu_notifier);
-
open_softirq(TASKLET_SOFTIRQ, tasklet_action);
open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}
local_irq_disable();
if (local_softirq_pending()) {
__do_softirq();
- rcu_note_context_switch(cpu);
local_irq_enable();
cond_resched();
+
+ preempt_disable();
+ rcu_note_context_switch(cpu);
+ preempt_enable();
+
return;
}
local_irq_enable();
static __always_inline int trace_recursive_lock(void)
{
- unsigned int val = this_cpu_read(current_context);
+ unsigned int val = __this_cpu_read(current_context);
int bit;
if (in_interrupt()) {
return 1;
val |= (1 << bit);
- this_cpu_write(current_context, val);
+ __this_cpu_write(current_context, val);
return 0;
}
static __always_inline void trace_recursive_unlock(void)
{
- unsigned int val = this_cpu_read(current_context);
+ unsigned int val = __this_cpu_read(current_context);
- val--;
- val &= this_cpu_read(current_context);
- this_cpu_write(current_context, val);
+ val &= val & (val - 1);
+ __this_cpu_write(current_context, val);
}
#else
int ret;
/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;
int ret;
/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;
if (dir) {
spin_lock(&dir->d_lock); /* probably unneeded */
- list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dir->d_subdirs, d_child) {
if (child->d_inode) /* probably unneeded */
child->d_inode->i_private = NULL;
}
void memzero_explicit(void *s, size_t count)
{
memset(s, 0, count);
- OPTIMIZER_HIDE_VAR(s);
+ barrier();
}
EXPORT_SYMBOL(memzero_explicit);
messages for every CMA call as well as various messages while
processing calls such as dma_alloc_from_contiguous().
This option does not affect warning and error messages.
+
+config ZPOOL
+ tristate "Common API for compressed memory storage"
+ default n
+ help
+ Compressed memory storage API. This allows using either zbud or
+ zsmalloc.
+
+config ZSMALLOC
+ bool "Memory allocator for compressed pages"
+ depends on MMU
+ default n
+ help
+ zsmalloc is a slab-based memory allocator designed to store
+ compressed RAM pages. zsmalloc uses virtual memory mapping
+ in order to reduce fragmentation. However, this results in a
+ non-standard allocator interface where a handle, not a pointer, is
+ returned by an alloc(). This handle must be mapped in order to
+ access the allocated space.
+
+config PGTABLE_MAPPING
+ bool "Use page table mapping to access object in zsmalloc"
+ depends on ZSMALLOC
+ help
+ By default, zsmalloc uses a copy-based object mapping method to
+ access allocations that span two pages. However, if a particular
+ architecture (ex, ARM) performs VM mapping faster than copying,
+ then you should select this. This causes zsmalloc to use page table
+ mapping rather than copying for object mapping.
+
+ You can check speed with zsmalloc benchmark[1].
+ [1] https://github.com/spartacus06/zsmalloc
obj-$(CONFIG_CLEANCACHE) += cleancache.o
obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o
+obj-$(CONFIG_ZPOOL) += zpool.o
+obj-$(CONFIG_ZSMALLOC) += zsmalloc.o
else
ret = VM_FAULT_WRITE;
put_page(page);
- } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_OOM)));
+ } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM)));
/*
* We must loop because handle_mm_fault() may back out if there's
* any difficulty e.g. if pte accessed bit gets updated concurrently.
* The check (unnecessarily) ignores LRU pages being isolated and
* walked by the page reclaim code, however that's not a big loss.
*/
- if (!PageHuge(p) && !PageTransTail(p)) {
- if (!PageLRU(p))
- shake_page(p, 0);
- if (!PageLRU(p)) {
+ if (!PageHuge(p)) {
+ if (!PageLRU(hpage))
+ shake_page(hpage, 0);
+ if (!PageLRU(hpage)) {
/*
* shake_page could have turned it free.
*/
else
return -EFAULT;
}
- if (ret & VM_FAULT_SIGBUS)
+ if (ret & (VM_FAULT_SIGBUS |
+ VM_FAULT_SIGSEGV))
return i ? i : -EFAULT;
BUG();
}
return -ENOMEM;
if (ret & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE))
return -EHWPOISON;
- if (ret & VM_FAULT_SIGBUS)
+ if (ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV))
return -EFAULT;
BUG();
}
/* Check if we need to add a guard page to the stack */
if (check_stack_guard_page(vma, address) < 0)
- return VM_FAULT_SIGBUS;
+ return VM_FAULT_SIGSEGV;
/* Use the zero-page for reads */
if (!(flags & FAULT_FLAG_WRITE)) {
return NULL;
arch_refresh_nodedata(nid, pgdat);
+ } else {
+ /* Reset the nr_zones and classzone_idx to 0 before reuse */
+ pgdat->nr_zones = 0;
+ pgdat->classzone_idx = 0;
}
/* we can use NODE_DATA(nid) from here */
if (is_vmalloc_addr(zone->wait_table))
vfree(zone->wait_table);
}
-
- /*
- * Since there is no way to guarentee the address of pgdat/zone is not
- * on stack of any kernel threads or used by other kernel objects
- * without reference counting or other symchronizing method, do not
- * reset node_data and free pgdat here. Just reset it to 0 and reuse
- * the memory when the node is online again.
- */
- memset(pgdat, 0, sizeof(*pgdat));
}
EXPORT_SYMBOL(try_offline_node);
* bw * elapsed + write_bandwidth * (period - elapsed)
* write_bandwidth = ---------------------------------------------------
* period
+ *
+ * @written may have decreased due to account_page_redirty().
+ * Avoid underflowing @bw calculation.
*/
- bw = written - bdi->written_stamp;
+ bw = written - min(written, bdi->written_stamp);
bw *= HZ;
if (unlikely(elapsed > period)) {
do_div(bw, elapsed);
unsigned long now)
{
static DEFINE_SPINLOCK(dirty_lock);
- static unsigned long update_time;
+ static unsigned long update_time = INITIAL_JIFFIES;
/*
* check locklessly first to optimize away locking for the most time
--- /dev/null
+/*
+ * zpool memory storage api
+ *
+ * Copyright (C) 2014 Dan Streetman
+ *
+ * This is a common frontend for memory storage pool implementations.
+ * Typically, this is used to store compressed memory.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/zpool.h>
+
+struct zpool {
+ char *type;
+
+ struct zpool_driver *driver;
+ void *pool;
+ struct zpool_ops *ops;
+
+ struct list_head list;
+};
+
+static LIST_HEAD(drivers_head);
+static DEFINE_SPINLOCK(drivers_lock);
+
+static LIST_HEAD(pools_head);
+static DEFINE_SPINLOCK(pools_lock);
+
+/**
+ * zpool_register_driver() - register a zpool implementation.
+ * @driver: driver to register
+ */
+void zpool_register_driver(struct zpool_driver *driver)
+{
+ spin_lock(&drivers_lock);
+ atomic_set(&driver->refcount, 0);
+ list_add(&driver->list, &drivers_head);
+ spin_unlock(&drivers_lock);
+}
+EXPORT_SYMBOL(zpool_register_driver);
+
+/**
+ * zpool_unregister_driver() - unregister a zpool implementation.
+ * @driver: driver to unregister.
+ *
+ * Module usage counting is used to prevent using a driver
+ * while/after unloading, so if this is called from module
+ * exit function, this should never fail; if called from
+ * other than the module exit function, and this returns
+ * failure, the driver is in use and must remain available.
+ */
+int zpool_unregister_driver(struct zpool_driver *driver)
+{
+ int ret = 0, refcount;
+
+ spin_lock(&drivers_lock);
+ refcount = atomic_read(&driver->refcount);
+ WARN_ON(refcount < 0);
+ if (refcount > 0)
+ ret = -EBUSY;
+ else
+ list_del(&driver->list);
+ spin_unlock(&drivers_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(zpool_unregister_driver);
+
+/**
+ * zpool_evict() - evict callback from a zpool implementation.
+ * @pool: pool to evict from.
+ * @handle: handle to evict.
+ *
+ * This can be used by zpool implementations to call the
+ * user's evict zpool_ops struct evict callback.
+ */
+int zpool_evict(void *pool, unsigned long handle)
+{
+ struct zpool *zpool;
+
+ spin_lock(&pools_lock);
+ list_for_each_entry(zpool, &pools_head, list) {
+ if (zpool->pool == pool) {
+ spin_unlock(&pools_lock);
+ if (!zpool->ops || !zpool->ops->evict)
+ return -EINVAL;
+ return zpool->ops->evict(zpool, handle);
+ }
+ }
+ spin_unlock(&pools_lock);
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL(zpool_evict);
+
+static struct zpool_driver *zpool_get_driver(char *type)
+{
+ struct zpool_driver *driver;
+
+ spin_lock(&drivers_lock);
+ list_for_each_entry(driver, &drivers_head, list) {
+ if (!strcmp(driver->type, type)) {
+ bool got = try_module_get(driver->owner);
+
+ if (got)
+ atomic_inc(&driver->refcount);
+ spin_unlock(&drivers_lock);
+ return got ? driver : NULL;
+ }
+ }
+
+ spin_unlock(&drivers_lock);
+ return NULL;
+}
+
+static void zpool_put_driver(struct zpool_driver *driver)
+{
+ atomic_dec(&driver->refcount);
+ module_put(driver->owner);
+}
+
+/**
+ * zpool_create_pool() - Create a new zpool
+ * @type The type of the zpool to create (e.g. zbud, zsmalloc)
+ * @gfp The GFP flags to use when allocating the pool.
+ * @ops The optional ops callback.
+ *
+ * This creates a new zpool of the specified type. The gfp flags will be
+ * used when allocating memory, if the implementation supports it. If the
+ * ops param is NULL, then the created zpool will not be shrinkable.
+ *
+ * Implementations must guarantee this to be thread-safe.
+ *
+ * Returns: New zpool on success, NULL on failure.
+ */
+struct zpool *zpool_create_pool(char *type, gfp_t gfp, struct zpool_ops *ops)
+{
+ struct zpool_driver *driver;
+ struct zpool *zpool;
+
+ pr_info("creating pool type %s\n", type);
+
+ driver = zpool_get_driver(type);
+
+ if (!driver) {
+ request_module("zpool-%s", type);
+ driver = zpool_get_driver(type);
+ }
+
+ if (!driver) {
+ pr_err("no driver for type %s\n", type);
+ return NULL;
+ }
+
+ zpool = kmalloc(sizeof(*zpool), gfp);
+ if (!zpool) {
+ pr_err("couldn't create zpool - out of memory\n");
+ zpool_put_driver(driver);
+ return NULL;
+ }
+
+ zpool->type = driver->type;
+ zpool->driver = driver;
+ zpool->pool = driver->create(gfp, ops);
+ zpool->ops = ops;
+
+ if (!zpool->pool) {
+ pr_err("couldn't create %s pool\n", type);
+ zpool_put_driver(driver);
+ kfree(zpool);
+ return NULL;
+ }
+
+ pr_info("created %s pool\n", type);
+
+ spin_lock(&pools_lock);
+ list_add(&zpool->list, &pools_head);
+ spin_unlock(&pools_lock);
+
+ return zpool;
+}
+
+/**
+ * zpool_destroy_pool() - Destroy a zpool
+ * @pool The zpool to destroy.
+ *
+ * Implementations must guarantee this to be thread-safe,
+ * however only when destroying different pools. The same
+ * pool should only be destroyed once, and should not be used
+ * after it is destroyed.
+ *
+ * This destroys an existing zpool. The zpool should not be in use.
+ */
+void zpool_destroy_pool(struct zpool *zpool)
+{
+ pr_info("destroying pool type %s\n", zpool->type);
+
+ spin_lock(&pools_lock);
+ list_del(&zpool->list);
+ spin_unlock(&pools_lock);
+ zpool->driver->destroy(zpool->pool);
+ zpool_put_driver(zpool->driver);
+ kfree(zpool);
+}
+
+/**
+ * zpool_get_type() - Get the type of the zpool
+ * @pool The zpool to check
+ *
+ * This returns the type of the pool.
+ *
+ * Implementations must guarantee this to be thread-safe.
+ *
+ * Returns: The type of zpool.
+ */
+char *zpool_get_type(struct zpool *zpool)
+{
+ return zpool->type;
+}
+
+/**
+ * zpool_malloc() - Allocate memory
+ * @pool The zpool to allocate from.
+ * @size The amount of memory to allocate.
+ * @gfp The GFP flags to use when allocating memory.
+ * @handle Pointer to the handle to set
+ *
+ * This allocates the requested amount of memory from the pool.
+ * The gfp flags will be used when allocating memory, if the
+ * implementation supports it. The provided @handle will be
+ * set to the allocated object handle.
+ *
+ * Implementations must guarantee this to be thread-safe.
+ *
+ * Returns: 0 on success, negative value on error.
+ */
+int zpool_malloc(struct zpool *zpool, size_t size, gfp_t gfp,
+ unsigned long *handle)
+{
+ return zpool->driver->malloc(zpool->pool, size, gfp, handle);
+}
+
+/**
+ * zpool_free() - Free previously allocated memory
+ * @pool The zpool that allocated the memory.
+ * @handle The handle to the memory to free.
+ *
+ * This frees previously allocated memory. This does not guarantee
+ * that the pool will actually free memory, only that the memory
+ * in the pool will become available for use by the pool.
+ *
+ * Implementations must guarantee this to be thread-safe,
+ * however only when freeing different handles. The same
+ * handle should only be freed once, and should not be used
+ * after freeing.
+ */
+void zpool_free(struct zpool *zpool, unsigned long handle)
+{
+ zpool->driver->free(zpool->pool, handle);
+}
+
+/**
+ * zpool_shrink() - Shrink the pool size
+ * @pool The zpool to shrink.
+ * @pages The number of pages to shrink the pool.
+ * @reclaimed The number of pages successfully evicted.
+ *
+ * This attempts to shrink the actual memory size of the pool
+ * by evicting currently used handle(s). If the pool was
+ * created with no zpool_ops, or the evict call fails for any
+ * of the handles, this will fail. If non-NULL, the @reclaimed
+ * parameter will be set to the number of pages reclaimed,
+ * which may be more than the number of pages requested.
+ *
+ * Implementations must guarantee this to be thread-safe.
+ *
+ * Returns: 0 on success, negative value on error/failure.
+ */
+int zpool_shrink(struct zpool *zpool, unsigned int pages,
+ unsigned int *reclaimed)
+{
+ return zpool->driver->shrink(zpool->pool, pages, reclaimed);
+}
+
+/**
+ * zpool_map_handle() - Map a previously allocated handle into memory
+ * @pool The zpool that the handle was allocated from
+ * @handle The handle to map
+ * @mm How the memory should be mapped
+ *
+ * This maps a previously allocated handle into memory. The @mm
+ * param indicates to the implementation how the memory will be
+ * used, i.e. read-only, write-only, read-write. If the
+ * implementation does not support it, the memory will be treated
+ * as read-write.
+ *
+ * This may hold locks, disable interrupts, and/or preemption,
+ * and the zpool_unmap_handle() must be called to undo those
+ * actions. The code that uses the mapped handle should complete
+ * its operatons on the mapped handle memory quickly and unmap
+ * as soon as possible. As the implementation may use per-cpu
+ * data, multiple handles should not be mapped concurrently on
+ * any cpu.
+ *
+ * Returns: A pointer to the handle's mapped memory area.
+ */
+void *zpool_map_handle(struct zpool *zpool, unsigned long handle,
+ enum zpool_mapmode mapmode)
+{
+ return zpool->driver->map(zpool->pool, handle, mapmode);
+}
+
+/**
+ * zpool_unmap_handle() - Unmap a previously mapped handle
+ * @pool The zpool that the handle was allocated from
+ * @handle The handle to unmap
+ *
+ * This unmaps a previously mapped handle. Any locks or other
+ * actions that the implementation took in zpool_map_handle()
+ * will be undone here. The memory area returned from
+ * zpool_map_handle() should no longer be used after this.
+ */
+void zpool_unmap_handle(struct zpool *zpool, unsigned long handle)
+{
+ zpool->driver->unmap(zpool->pool, handle);
+}
+
+/**
+ * zpool_get_total_size() - The total size of the pool
+ * @pool The zpool to check
+ *
+ * This returns the total size in bytes of the pool.
+ *
+ * Returns: Total size of the zpool in bytes.
+ */
+u64 zpool_get_total_size(struct zpool *zpool)
+{
+ return zpool->driver->total_size(zpool->pool);
+}
+
+static int __init init_zpool(void)
+{
+ pr_info("loaded\n");
+ return 0;
+}
+
+static void __exit exit_zpool(void)
+{
+ pr_info("unloaded\n");
+}
+
+module_init(init_zpool);
+module_exit(exit_zpool);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
+MODULE_DESCRIPTION("Common API for compressed memory storage");
--- /dev/null
+/*
+ * zsmalloc memory allocator
+ *
+ * Copyright (C) 2011 Nitin Gupta
+ * Copyright (C) 2012, 2013 Minchan Kim
+ *
+ * This code is released using a dual license strategy: BSD/GPL
+ * You can choose the license that better fits your requirements.
+ *
+ * Released under the terms of 3-clause BSD License
+ * Released under the terms of GNU General Public License Version 2.0
+ */
+
+
+/*
+ * This allocator is designed for use with zcache and zram. Thus, the
+ * allocator is supposed to work well under low memory conditions. In
+ * particular, it never attempts higher order page allocation which is
+ * very likely to fail under memory pressure. On the other hand, if we
+ * just use single (0-order) pages, it would suffer from very high
+ * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy
+ * an entire page. This was one of the major issues with its predecessor
+ * (xvmalloc).
+ *
+ * To overcome these issues, zsmalloc allocates a bunch of 0-order pages
+ * and links them together using various 'struct page' fields. These linked
+ * pages act as a single higher-order page i.e. an object can span 0-order
+ * page boundaries. The code refers to these linked pages as a single entity
+ * called zspage.
+ *
+ * Following is how we use various fields and flags of underlying
+ * struct page(s) to form a zspage.
+ *
+ * Usage of struct page fields:
+ * page->first_page: points to the first component (0-order) page
+ * page->index (union with page->freelist): offset of the first object
+ * starting in this page. For the first page, this is
+ * always 0, so we use this field (aka freelist) to point
+ * to the first free object in zspage.
+ * page->lru: links together all component pages (except the first page)
+ * of a zspage
+ *
+ * For _first_ page only:
+ *
+ * page->private (union with page->first_page): refers to the
+ * component page after the first page
+ * page->freelist: points to the first free object in zspage.
+ * Free objects are linked together using in-place
+ * metadata.
+ * page->objects: maximum number of objects we can store in this
+ * zspage (class->zspage_order * PAGE_SIZE / class->size)
+ * page->lru: links together first pages of various zspages.
+ * Basically forming list of zspages in a fullness group.
+ * page->mapping: class index and fullness group of the zspage
+ *
+ * Usage of struct page flags:
+ * PG_private: identifies the first component page
+ * PG_private2: identifies the last component page
+ *
+ */
+
+#ifdef CONFIG_ZSMALLOC_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/tlbflush.h>
+#include <asm/pgtable.h>
+#include <linux/cpumask.h>
+#include <linux/cpu.h>
+#include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/zsmalloc.h>
+#include <linux/zpool.h>
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN 8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+ MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 255 size classes! There is a
+ * trader-off here:
+ * - Large number of size classes is potentially wasteful as free page are
+ * spread across these classes
+ * - Small number of size classes causes large internal fragmentation
+ * - Probably its better to use specific size classes (empirically
+ * determined). NOTE: all those class sizes must be set as multiple of
+ * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ * (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA (PAGE_SIZE >> 8)
+#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+ ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+ ZS_ALMOST_FULL,
+ ZS_ALMOST_EMPTY,
+ _ZS_NR_FULLNESS_GROUPS,
+
+ ZS_EMPTY,
+ ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ * n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ * ZS_ALMOST_FULL when n > N / f
+ * ZS_EMPTY when n == 0
+ * ZS_FULL when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct size_class {
+ /*
+ * Size of objects stored in this class. Must be multiple
+ * of ZS_ALIGN.
+ */
+ int size;
+ unsigned int index;
+
+ /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+ int pages_per_zspage;
+
+ spinlock_t lock;
+
+ struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+ /* Handle of next free chunk (encodes <PFN, obj_idx>) */
+ void *next;
+};
+
+struct zs_pool {
+ struct size_class *size_class[ZS_SIZE_CLASSES];
+
+ gfp_t flags; /* allocation flags used when growing pool */
+ atomic_long_t pages_allocated;
+};
+
+/*
+ * A zspage's class index and fullness group
+ * are encoded in its (first)page->mapping
+ */
+#define CLASS_IDX_BITS 28
+#define FULLNESS_BITS 4
+#define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1)
+#define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1)
+
+/*
+ * By default, zsmalloc uses a copy-based object mapping method to access
+ * allocations that span two pages. However, if a particular architecture
+ * performs VM mapping faster than copying, then it should be added here
+ * so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use
+ * page table mapping rather than copying for object mapping.
+*/
+#if defined(CONFIG_ARM) && !defined(MODULE)
+#define USE_PGTABLE_MAPPING
+#endif
+
+struct mapping_area {
+#ifdef USE_PGTABLE_MAPPING
+ struct vm_struct *vm; /* vm area for mapping object that span pages */
+#else
+ char *vm_buf; /* copy buffer for objects that span pages */
+#endif
+ char *vm_addr; /* address of kmap_atomic()'ed pages */
+ enum zs_mapmode vm_mm; /* mapping mode */
+};
+
+/* zpool driver */
+
+#ifdef CONFIG_ZPOOL
+
+static void *zs_zpool_create(gfp_t gfp, struct zpool_ops *zpool_ops)
+{
+ return zs_create_pool(gfp);
+}
+
+static void zs_zpool_destroy(void *pool)
+{
+ zs_destroy_pool(pool);
+}
+
+static int zs_zpool_malloc(void *pool, size_t size, gfp_t gfp,
+ unsigned long *handle)
+{
+ *handle = zs_malloc(pool, size);
+ return *handle ? 0 : -1;
+}
+static void zs_zpool_free(void *pool, unsigned long handle)
+{
+ zs_free(pool, handle);
+}
+
+static int zs_zpool_shrink(void *pool, unsigned int pages,
+ unsigned int *reclaimed)
+{
+ return -EINVAL;
+}
+
+static void *zs_zpool_map(void *pool, unsigned long handle,
+ enum zpool_mapmode mm)
+{
+ enum zs_mapmode zs_mm;
+
+ switch (mm) {
+ case ZPOOL_MM_RO:
+ zs_mm = ZS_MM_RO;
+ break;
+ case ZPOOL_MM_WO:
+ zs_mm = ZS_MM_WO;
+ break;
+ case ZPOOL_MM_RW: /* fallthru */
+ default:
+ zs_mm = ZS_MM_RW;
+ break;
+ }
+
+ return zs_map_object(pool, handle, zs_mm);
+}
+static void zs_zpool_unmap(void *pool, unsigned long handle)
+{
+ zs_unmap_object(pool, handle);
+}
+
+static u64 zs_zpool_total_size(void *pool)
+{
+ return zs_get_total_pages(pool) << PAGE_SHIFT;
+}
+
+static struct zpool_driver zs_zpool_driver = {
+ .type = "zsmalloc",
+ .owner = THIS_MODULE,
+ .create = zs_zpool_create,
+ .destroy = zs_zpool_destroy,
+ .malloc = zs_zpool_malloc,
+ .free = zs_zpool_free,
+ .shrink = zs_zpool_shrink,
+ .map = zs_zpool_map,
+ .unmap = zs_zpool_unmap,
+ .total_size = zs_zpool_total_size,
+};
+
+MODULE_ALIAS("zpool-zsmalloc");
+#endif /* CONFIG_ZPOOL */
+
+/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
+static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
+
+static int is_first_page(struct page *page)
+{
+ return PagePrivate(page);
+}
+
+static int is_last_page(struct page *page)
+{
+ return PagePrivate2(page);
+}
+
+static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
+ enum fullness_group *fullness)
+{
+ unsigned long m;
+ BUG_ON(!is_first_page(page));
+
+ m = (unsigned long)page->mapping;
+ *fullness = m & FULLNESS_MASK;
+ *class_idx = (m >> FULLNESS_BITS) & CLASS_IDX_MASK;
+}
+
+static void set_zspage_mapping(struct page *page, unsigned int class_idx,
+ enum fullness_group fullness)
+{
+ unsigned long m;
+ BUG_ON(!is_first_page(page));
+
+ m = ((class_idx & CLASS_IDX_MASK) << FULLNESS_BITS) |
+ (fullness & FULLNESS_MASK);
+ page->mapping = (struct address_space *)m;
+}
+
+static int get_size_class_index(int size)
+{
+ int idx = 0;
+
+ if (likely(size > ZS_MIN_ALLOC_SIZE))
+ idx = DIV_ROUND_UP(size - ZS_MIN_ALLOC_SIZE,
+ ZS_SIZE_CLASS_DELTA);
+
+ return idx;
+}
+
+static enum fullness_group get_fullness_group(struct page *page)
+{
+ int inuse, max_objects;
+ enum fullness_group fg;
+ BUG_ON(!is_first_page(page));
+
+ inuse = page->inuse;
+ max_objects = page->objects;
+
+ if (inuse == 0)
+ fg = ZS_EMPTY;
+ else if (inuse == max_objects)
+ fg = ZS_FULL;
+ else if (inuse <= max_objects / fullness_threshold_frac)
+ fg = ZS_ALMOST_EMPTY;
+ else
+ fg = ZS_ALMOST_FULL;
+
+ return fg;
+}
+
+static void insert_zspage(struct page *page, struct size_class *class,
+ enum fullness_group fullness)
+{
+ struct page **head;
+
+ BUG_ON(!is_first_page(page));
+
+ if (fullness >= _ZS_NR_FULLNESS_GROUPS)
+ return;
+
+ head = &class->fullness_list[fullness];
+ if (*head)
+ list_add_tail(&page->lru, &(*head)->lru);
+
+ *head = page;
+}
+
+static void remove_zspage(struct page *page, struct size_class *class,
+ enum fullness_group fullness)
+{
+ struct page **head;
+
+ BUG_ON(!is_first_page(page));
+
+ if (fullness >= _ZS_NR_FULLNESS_GROUPS)
+ return;
+
+ head = &class->fullness_list[fullness];
+ BUG_ON(!*head);
+ if (list_empty(&(*head)->lru))
+ *head = NULL;
+ else if (*head == page)
+ *head = (struct page *)list_entry((*head)->lru.next,
+ struct page, lru);
+
+ list_del_init(&page->lru);
+}
+
+static enum fullness_group fix_fullness_group(struct zs_pool *pool,
+ struct page *page)
+{
+ int class_idx;
+ struct size_class *class;
+ enum fullness_group currfg, newfg;
+
+ BUG_ON(!is_first_page(page));
+
+ get_zspage_mapping(page, &class_idx, &currfg);
+ newfg = get_fullness_group(page);
+ if (newfg == currfg)
+ goto out;
+
+ class = pool->size_class[class_idx];
+ remove_zspage(page, class, currfg);
+ insert_zspage(page, class, newfg);
+ set_zspage_mapping(page, class_idx, newfg);
+
+out:
+ return newfg;
+}
+
+/*
+ * We have to decide on how many pages to link together
+ * to form a zspage for each size class. This is important
+ * to reduce wastage due to unusable space left at end of
+ * each zspage which is given as:
+ * wastage = Zp - Zp % size_class
+ * where Zp = zspage size = k * PAGE_SIZE where k = 1, 2, ...
+ *
+ * For example, for size class of 3/8 * PAGE_SIZE, we should
+ * link together 3 PAGE_SIZE sized pages to form a zspage
+ * since then we can perfectly fit in 8 such objects.
+ */
+static int get_pages_per_zspage(int class_size)
+{
+ int i, max_usedpc = 0;
+ /* zspage order which gives maximum used size per KB */
+ int max_usedpc_order = 1;
+
+ for (i = 1; i <= ZS_MAX_PAGES_PER_ZSPAGE; i++) {
+ int zspage_size;
+ int waste, usedpc;
+
+ zspage_size = i * PAGE_SIZE;
+ waste = zspage_size % class_size;
+ usedpc = (zspage_size - waste) * 100 / zspage_size;
+
+ if (usedpc > max_usedpc) {
+ max_usedpc = usedpc;
+ max_usedpc_order = i;
+ }
+ }
+
+ return max_usedpc_order;
+}
+
+/*
+ * A single 'zspage' is composed of many system pages which are
+ * linked together using fields in struct page. This function finds
+ * the first/head page, given any component page of a zspage.
+ */
+static struct page *get_first_page(struct page *page)
+{
+ if (is_first_page(page))
+ return page;
+ else
+ return page->first_page;
+}
+
+static struct page *get_next_page(struct page *page)
+{
+ struct page *next;
+
+ if (is_last_page(page))
+ next = NULL;
+ else if (is_first_page(page))
+ next = (struct page *)page->private;
+ else
+ next = list_entry(page->lru.next, struct page, lru);
+
+ return next;
+}
+
+/*
+ * Encode <page, obj_idx> as a single handle value.
+ * On hardware platforms with physical memory starting at 0x0 the pfn
+ * could be 0 so we ensure that the handle will never be 0 by adjusting the
+ * encoded obj_idx value before encoding.
+ */
+static void *obj_location_to_handle(struct page *page, unsigned long obj_idx)
+{
+ unsigned long handle;
+
+ if (!page) {
+ BUG_ON(obj_idx);
+ return NULL;
+ }
+
+ handle = page_to_pfn(page) << OBJ_INDEX_BITS;
+ handle |= ((obj_idx + 1) & OBJ_INDEX_MASK);
+
+ return (void *)handle;
+}
+
+/*
+ * Decode <page, obj_idx> pair from the given object handle. We adjust the
+ * decoded obj_idx back to its original value since it was adjusted in
+ * obj_location_to_handle().
+ */
+static void obj_handle_to_location(unsigned long handle, struct page **page,
+ unsigned long *obj_idx)
+{
+ *page = pfn_to_page(handle >> OBJ_INDEX_BITS);
+ *obj_idx = (handle & OBJ_INDEX_MASK) - 1;
+}
+
+static unsigned long obj_idx_to_offset(struct page *page,
+ unsigned long obj_idx, int class_size)
+{
+ unsigned long off = 0;
+
+ if (!is_first_page(page))
+ off = page->index;
+
+ return off + obj_idx * class_size;
+}
+
+static void reset_page(struct page *page)
+{
+ clear_bit(PG_private, &page->flags);
+ clear_bit(PG_private_2, &page->flags);
+ set_page_private(page, 0);
+ page->mapping = NULL;
+ page->freelist = NULL;
+ page_mapcount_reset(page);
+}
+
+static void free_zspage(struct page *first_page)
+{
+ struct page *nextp, *tmp, *head_extra;
+
+ BUG_ON(!is_first_page(first_page));
+ BUG_ON(first_page->inuse);
+
+ head_extra = (struct page *)page_private(first_page);
+
+ reset_page(first_page);
+ __free_page(first_page);
+
+ /* zspage with only 1 system page */
+ if (!head_extra)
+ return;
+
+ list_for_each_entry_safe(nextp, tmp, &head_extra->lru, lru) {
+ list_del(&nextp->lru);
+ reset_page(nextp);
+ __free_page(nextp);
+ }
+ reset_page(head_extra);
+ __free_page(head_extra);
+}
+
+/* Initialize a newly allocated zspage */
+static void init_zspage(struct page *first_page, struct size_class *class)
+{
+ unsigned long off = 0;
+ struct page *page = first_page;
+
+ BUG_ON(!is_first_page(first_page));
+ while (page) {
+ struct page *next_page;
+ struct link_free *link;
+ unsigned int i = 1;
+ void *vaddr;
+
+ /*
+ * page->index stores offset of first object starting
+ * in the page. For the first page, this is always 0,
+ * so we use first_page->index (aka ->freelist) to store
+ * head of corresponding zspage's freelist.
+ */
+ if (page != first_page)
+ page->index = off;
+
+ vaddr = kmap_atomic(page);
+ link = (struct link_free *)vaddr + off / sizeof(*link);
+
+ while ((off += class->size) < PAGE_SIZE) {
+ link->next = obj_location_to_handle(page, i++);
+ link += class->size / sizeof(*link);
+ }
+
+ /*
+ * We now come to the last (full or partial) object on this
+ * page, which must point to the first object on the next
+ * page (if present)
+ */
+ next_page = get_next_page(page);
+ link->next = obj_location_to_handle(next_page, 0);
+ kunmap_atomic(vaddr);
+ page = next_page;
+ off %= PAGE_SIZE;
+ }
+}
+
+/*
+ * Allocate a zspage for the given size class
+ */
+static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
+{
+ int i, error;
+ struct page *first_page = NULL, *uninitialized_var(prev_page);
+
+ /*
+ * Allocate individual pages and link them together as:
+ * 1. first page->private = first sub-page
+ * 2. all sub-pages are linked together using page->lru
+ * 3. each sub-page is linked to the first page using page->first_page
+ *
+ * For each size class, First/Head pages are linked together using
+ * page->lru. Also, we set PG_private to identify the first page
+ * (i.e. no other sub-page has this flag set) and PG_private_2 to
+ * identify the last page.
+ */
+ error = -ENOMEM;
+ for (i = 0; i < class->pages_per_zspage; i++) {
+ struct page *page;
+
+ page = alloc_page(flags);
+ if (!page)
+ goto cleanup;
+
+ INIT_LIST_HEAD(&page->lru);
+ if (i == 0) { /* first page */
+ SetPagePrivate(page);
+ set_page_private(page, 0);
+ first_page = page;
+ first_page->inuse = 0;
+ }
+ if (i == 1)
+ first_page->private = (unsigned long)page;
+ if (i >= 1)
+ page->first_page = first_page;
+ if (i >= 2)
+ list_add(&page->lru, &prev_page->lru);
+ if (i == class->pages_per_zspage - 1) /* last page */
+ SetPagePrivate2(page);
+ prev_page = page;
+ }
+
+ init_zspage(first_page, class);
+
+ first_page->freelist = obj_location_to_handle(first_page, 0);
+ /* Maximum number of objects we can store in this zspage */
+ first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
+
+ error = 0; /* Success */
+
+cleanup:
+ if (unlikely(error) && first_page) {
+ free_zspage(first_page);
+ first_page = NULL;
+ }
+
+ return first_page;
+}
+
+static struct page *find_get_zspage(struct size_class *class)
+{
+ int i;
+ struct page *page;
+
+ for (i = 0; i < _ZS_NR_FULLNESS_GROUPS; i++) {
+ page = class->fullness_list[i];
+ if (page)
+ break;
+ }
+
+ return page;
+}
+
+#ifdef USE_PGTABLE_MAPPING
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm)
+ return 0;
+ area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
+ if (!area->vm)
+ return -ENOMEM;
+ return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm)
+ free_vm_area(area->vm);
+ area->vm = NULL;
+}
+
+static inline void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
+ area->vm_addr = area->vm->addr;
+ return area->vm_addr + off;
+}
+
+static inline void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ unsigned long addr = (unsigned long)area->vm_addr;
+
+ unmap_kernel_range(addr, PAGE_SIZE * 2);
+}
+
+#else /* USE_PGTABLE_MAPPING */
+
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm_buf)
+ return 0;
+ area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!area->vm_buf)
+ return -ENOMEM;
+ return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm_buf)
+ free_page((unsigned long)area->vm_buf);
+ area->vm_buf = NULL;
+}
+
+static void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ int sizes[2];
+ void *addr;
+ char *buf = area->vm_buf;
+
+ /* disable page faults to match kmap_atomic() return conditions */
+ pagefault_disable();
+
+ /* no read fastpath */
+ if (area->vm_mm == ZS_MM_WO)
+ goto out;
+
+ sizes[0] = PAGE_SIZE - off;
+ sizes[1] = size - sizes[0];
+
+ /* copy object to per-cpu buffer */
+ addr = kmap_atomic(pages[0]);
+ memcpy(buf, addr + off, sizes[0]);
+ kunmap_atomic(addr);
+ addr = kmap_atomic(pages[1]);
+ memcpy(buf + sizes[0], addr, sizes[1]);
+ kunmap_atomic(addr);
+out:
+ return area->vm_buf;
+}
+
+static void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ int sizes[2];
+ void *addr;
+ char *buf = area->vm_buf;
+
+ /* no write fastpath */
+ if (area->vm_mm == ZS_MM_RO)
+ goto out;
+
+ sizes[0] = PAGE_SIZE - off;
+ sizes[1] = size - sizes[0];
+
+ /* copy per-cpu buffer to object */
+ addr = kmap_atomic(pages[0]);
+ memcpy(addr + off, buf, sizes[0]);
+ kunmap_atomic(addr);
+ addr = kmap_atomic(pages[1]);
+ memcpy(addr, buf + sizes[0], sizes[1]);
+ kunmap_atomic(addr);
+
+out:
+ /* enable page faults to match kunmap_atomic() return conditions */
+ pagefault_enable();
+}
+
+#endif /* USE_PGTABLE_MAPPING */
+
+static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
+ void *pcpu)
+{
+ int ret, cpu = (long)pcpu;
+ struct mapping_area *area;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ area = &per_cpu(zs_map_area, cpu);
+ ret = __zs_cpu_up(area);
+ if (ret)
+ return notifier_from_errno(ret);
+ break;
+ case CPU_DEAD:
+ case CPU_UP_CANCELED:
+ area = &per_cpu(zs_map_area, cpu);
+ __zs_cpu_down(area);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block zs_cpu_nb = {
+ .notifier_call = zs_cpu_notifier
+};
+
+static void zs_unregister_cpu_notifier(void)
+{
+ int cpu;
+
+ cpu_notifier_register_begin();
+
+ for_each_online_cpu(cpu)
+ zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu);
+ __unregister_cpu_notifier(&zs_cpu_nb);
+
+ cpu_notifier_register_done();
+}
+
+static int zs_register_cpu_notifier(void)
+{
+ int cpu, uninitialized_var(ret);
+
+ cpu_notifier_register_begin();
+
+ __register_cpu_notifier(&zs_cpu_nb);
+ for_each_online_cpu(cpu) {
+ ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
+ if (notifier_to_errno(ret))
+ break;
+ }
+
+ cpu_notifier_register_done();
+ return notifier_to_errno(ret);
+}
+
+static void __exit zs_exit(void)
+{
+#ifdef CONFIG_ZPOOL
+ zpool_unregister_driver(&zs_zpool_driver);
+#endif
+ zs_unregister_cpu_notifier();
+}
+
+static int __init zs_init(void)
+{
+ int ret = zs_register_cpu_notifier();
+
+ if (ret) {
+ zs_unregister_cpu_notifier();
+ return ret;
+ }
+
+#ifdef CONFIG_ZPOOL
+ zpool_register_driver(&zs_zpool_driver);
+#endif
+ return 0;
+}
+
+static unsigned int get_maxobj_per_zspage(int size, int pages_per_zspage)
+{
+ return pages_per_zspage * PAGE_SIZE / size;
+}
+
+static bool can_merge(struct size_class *prev, int size, int pages_per_zspage)
+{
+ if (prev->pages_per_zspage != pages_per_zspage)
+ return false;
+
+ if (get_maxobj_per_zspage(prev->size, prev->pages_per_zspage)
+ != get_maxobj_per_zspage(size, pages_per_zspage))
+ return false;
+
+ return true;
+}
+
+/**
+ * zs_create_pool - Creates an allocation pool to work from.
+ * @flags: allocation flags used to allocate pool metadata
+ *
+ * This function must be called before anything when using
+ * the zsmalloc allocator.
+ *
+ * On success, a pointer to the newly created pool is returned,
+ * otherwise NULL.
+ */
+struct zs_pool *zs_create_pool(gfp_t flags)
+{
+ int i, ovhd_size;
+ struct zs_pool *pool;
+
+ ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
+ pool = kzalloc(ovhd_size, GFP_KERNEL);
+ if (!pool)
+ return NULL;
+
+ /*
+ * Iterate reversly, because, size of size_class that we want to use
+ * for merging should be larger or equal to current size.
+ */
+ for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) {
+ int size;
+ int pages_per_zspage;
+ struct size_class *class;
+ struct size_class *prev_class;
+
+ size = ZS_MIN_ALLOC_SIZE + i * ZS_SIZE_CLASS_DELTA;
+ if (size > ZS_MAX_ALLOC_SIZE)
+ size = ZS_MAX_ALLOC_SIZE;
+ pages_per_zspage = get_pages_per_zspage(size);
+
+ /*
+ * size_class is used for normal zsmalloc operation such
+ * as alloc/free for that size. Although it is natural that we
+ * have one size_class for each size, there is a chance that we
+ * can get more memory utilization if we use one size_class for
+ * many different sizes whose size_class have same
+ * characteristics. So, we makes size_class point to
+ * previous size_class if possible.
+ */
+ if (i < ZS_SIZE_CLASSES - 1) {
+ prev_class = pool->size_class[i + 1];
+ if (can_merge(prev_class, size, pages_per_zspage)) {
+ pool->size_class[i] = prev_class;
+ continue;
+ }
+ }
+
+ class = kzalloc(sizeof(struct size_class), GFP_KERNEL);
+ if (!class)
+ goto err;
+
+ class->size = size;
+ class->index = i;
+ class->pages_per_zspage = pages_per_zspage;
+ spin_lock_init(&class->lock);
+ pool->size_class[i] = class;
+ }
+
+ pool->flags = flags;
+
+ return pool;
+
+err:
+ zs_destroy_pool(pool);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(zs_create_pool);
+
+void zs_destroy_pool(struct zs_pool *pool)
+{
+ int i;
+
+ for (i = 0; i < ZS_SIZE_CLASSES; i++) {
+ int fg;
+ struct size_class *class = pool->size_class[i];
+
+ if (!class)
+ continue;
+
+ if (class->index != i)
+ continue;
+
+ for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) {
+ if (class->fullness_list[fg]) {
+ pr_info("Freeing non-empty class with size "
+ "%db, fullness group %d\n",
+ class->size, fg);
+ }
+ }
+ kfree(class);
+ }
+ kfree(pool);
+}
+EXPORT_SYMBOL_GPL(zs_destroy_pool);
+
+/**
+ * zs_malloc - Allocate block of given size from pool.
+ * @pool: pool to allocate from
+ * @size: size of block to allocate
+ *
+ * On success, handle to the allocated object is returned,
+ * otherwise 0.
+ * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
+ */
+unsigned long zs_malloc(struct zs_pool *pool, size_t size)
+{
+ unsigned long obj;
+ struct link_free *link;
+ struct size_class *class;
+ void *vaddr;
+
+ struct page *first_page, *m_page;
+ unsigned long m_objidx, m_offset;
+
+ if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
+ return 0;
+
+ class = pool->size_class[get_size_class_index(size)];
+
+ spin_lock(&class->lock);
+ first_page = find_get_zspage(class);
+
+ if (!first_page) {
+ spin_unlock(&class->lock);
+ first_page = alloc_zspage(class, pool->flags);
+ if (unlikely(!first_page))
+ return 0;
+
+ set_zspage_mapping(first_page, class->index, ZS_EMPTY);
+ atomic_long_add(class->pages_per_zspage,
+ &pool->pages_allocated);
+ spin_lock(&class->lock);
+ }
+
+ obj = (unsigned long)first_page->freelist;
+ obj_handle_to_location(obj, &m_page, &m_objidx);
+ m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
+
+ vaddr = kmap_atomic(m_page);
+ link = (struct link_free *)vaddr + m_offset / sizeof(*link);
+ first_page->freelist = link->next;
+ memset(link, POISON_INUSE, sizeof(*link));
+ kunmap_atomic(vaddr);
+
+ first_page->inuse++;
+ /* Now move the zspage to another fullness group, if required */
+ fix_fullness_group(pool, first_page);
+ spin_unlock(&class->lock);
+
+ return obj;
+}
+EXPORT_SYMBOL_GPL(zs_malloc);
+
+void zs_free(struct zs_pool *pool, unsigned long obj)
+{
+ struct link_free *link;
+ struct page *first_page, *f_page;
+ unsigned long f_objidx, f_offset;
+ void *vaddr;
+
+ int class_idx;
+ struct size_class *class;
+ enum fullness_group fullness;
+
+ if (unlikely(!obj))
+ return;
+
+ obj_handle_to_location(obj, &f_page, &f_objidx);
+ first_page = get_first_page(f_page);
+
+ get_zspage_mapping(first_page, &class_idx, &fullness);
+ class = pool->size_class[class_idx];
+ f_offset = obj_idx_to_offset(f_page, f_objidx, class->size);
+
+ spin_lock(&class->lock);
+
+ /* Insert this object in containing zspage's freelist */
+ vaddr = kmap_atomic(f_page);
+ link = (struct link_free *)(vaddr + f_offset);
+ link->next = first_page->freelist;
+ kunmap_atomic(vaddr);
+ first_page->freelist = (void *)obj;
+
+ first_page->inuse--;
+ fullness = fix_fullness_group(pool, first_page);
+ spin_unlock(&class->lock);
+
+ if (fullness == ZS_EMPTY) {
+ atomic_long_sub(class->pages_per_zspage,
+ &pool->pages_allocated);
+ free_zspage(first_page);
+ }
+}
+EXPORT_SYMBOL_GPL(zs_free);
+
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object.
+ *
+ * Only one object can be mapped per cpu at a time. There is no protection
+ * against nested mappings.
+ *
+ * This function returns with preemption and page faults disabled.
+*/
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm)
+{
+ struct page *page;
+ unsigned long obj_idx, off;
+
+ unsigned int class_idx;
+ enum fullness_group fg;
+ struct size_class *class;
+ struct mapping_area *area;
+ struct page *pages[2];
+
+ BUG_ON(!handle);
+
+ /*
+ * Because we use per-cpu mapping areas shared among the
+ * pools/users, we can't allow mapping in interrupt context
+ * because it can corrupt another users mappings.
+ */
+ BUG_ON(in_interrupt());
+
+ obj_handle_to_location(handle, &page, &obj_idx);
+ get_zspage_mapping(get_first_page(page), &class_idx, &fg);
+ class = pool->size_class[class_idx];
+ off = obj_idx_to_offset(page, obj_idx, class->size);
+
+ area = &get_cpu_var(zs_map_area);
+ area->vm_mm = mm;
+ if (off + class->size <= PAGE_SIZE) {
+ /* this object is contained entirely within a page */
+ area->vm_addr = kmap_atomic(page);
+ return area->vm_addr + off;
+ }
+
+ /* this object spans two pages */
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ return __zs_map_object(area, pages, off, class->size);
+}
+EXPORT_SYMBOL_GPL(zs_map_object);
+
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
+{
+ struct page *page;
+ unsigned long obj_idx, off;
+
+ unsigned int class_idx;
+ enum fullness_group fg;
+ struct size_class *class;
+ struct mapping_area *area;
+
+ BUG_ON(!handle);
+
+ obj_handle_to_location(handle, &page, &obj_idx);
+ get_zspage_mapping(get_first_page(page), &class_idx, &fg);
+ class = pool->size_class[class_idx];
+ off = obj_idx_to_offset(page, obj_idx, class->size);
+
+ area = &__get_cpu_var(zs_map_area);
+ if (off + class->size <= PAGE_SIZE)
+ kunmap_atomic(area->vm_addr);
+ else {
+ struct page *pages[2];
+
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ __zs_unmap_object(area, pages, off, class->size);
+ }
+ put_cpu_var(zs_map_area);
+}
+EXPORT_SYMBOL_GPL(zs_unmap_object);
+
+unsigned long zs_get_total_pages(struct zs_pool *pool)
+{
+ return atomic_long_read(&pool->pages_allocated);
+}
+EXPORT_SYMBOL_GPL(zs_get_total_pages);
+
+module_init(zs_init);
+module_exit(zs_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
struct rtable *rt; /* Route we use */
struct ip_options *opt = &(IPCB(skb)->opt);
+ if (unlikely(skb->sk))
+ goto drop;
+
if (skb_warn_if_lro(skb))
goto drop;
if (sk_hashed(sk)) {
write_lock_bh(&ping_table.lock);
hlist_nulls_del(&sk->sk_nulls_node);
+ sk_nulls_node_init(&sk->sk_nulls_node);
sock_put(sk);
isk->inet_num = 0;
isk->inet_sport = 0;
#define ALPHA_MIN ((3*ALPHA_SCALE)/10) /* ~0.3 */
#define ALPHA_MAX (10*ALPHA_SCALE) /* 10.0 */
#define ALPHA_BASE ALPHA_SCALE /* 1.0 */
-#define U32_MAX ((u32)~0U)
#define RTT_MAX (U32_MAX / ALPHA_MAX) /* 3.3 secs */
#define BETA_SHIFT 6
if (seq_rtt < 0) {
seq_rtt = ca_seq_rtt;
}
- if (!(sacked & TCPCB_SACKED_ACKED))
+ if (!(sacked & TCPCB_SACKED_ACKED)) {
reord = min(pkts_acked, reord);
- if (!after(scb->end_seq, tp->high_seq))
- flag |= FLAG_ORIG_SACK_ACKED;
+ if (!after(scb->end_seq, tp->high_seq))
+ flag |= FLAG_ORIG_SACK_ACKED;
+ }
}
if (sacked & TCPCB_SACKED_ACKED)
skb->sk = sk;
skb->destructor = sock_edemux;
if (sk->sk_state != TCP_TIME_WAIT) {
- struct dst_entry *dst = sk->sk_rx_dst;
+ struct dst_entry *dst = ACCESS_ONCE(sk->sk_rx_dst);
if (dst)
dst = dst_check(dst, 0);
}
}
-/* Send a fin. The caller locks the socket for us. This cannot be
- * allowed to fail queueing a FIN frame under any circumstances.
+/* We allow to exceed memory limits for FIN packets to expedite
+ * connection tear down and (memory) recovery.
+ * Otherwise tcp_send_fin() could be tempted to either delay FIN
+ * or even be forced to close flow without any FIN.
+ */
+static void sk_forced_wmem_schedule(struct sock *sk, int size)
+{
+ int amt, status;
+
+ if (size <= sk->sk_forward_alloc)
+ return;
+ amt = sk_mem_pages(size);
+ sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
+ sk_memory_allocated_add(sk, amt, &status);
+}
+
+/* Send a FIN. The caller locks the socket for us.
+ * We should try to send a FIN packet really hard, but eventually give up.
*/
void tcp_send_fin(struct sock *sk)
{
+ struct sk_buff *skb, *tskb = tcp_write_queue_tail(sk);
struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb = tcp_write_queue_tail(sk);
- int mss_now;
- /* Optimization, tack on the FIN if we have a queue of
- * unsent frames. But be careful about outgoing SACKS
- * and IP options.
+ /* Optimization, tack on the FIN if we have one skb in write queue and
+ * this skb was not yet sent, or we are under memory pressure.
+ * Note: in the latter case, FIN packet will be sent after a timeout,
+ * as TCP stack thinks it has already been transmitted.
*/
- mss_now = tcp_current_mss(sk);
-
- if (tcp_send_head(sk) != NULL) {
- TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN;
- TCP_SKB_CB(skb)->end_seq++;
+ if (tskb && (tcp_send_head(sk) || sk_under_memory_pressure(sk))) {
+coalesce:
+ TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN;
+ TCP_SKB_CB(tskb)->end_seq++;
tp->write_seq++;
+ if (!tcp_send_head(sk)) {
+ /* This means tskb was already sent.
+ * Pretend we included the FIN on previous transmit.
+ * We need to set tp->snd_nxt to the value it would have
+ * if FIN had been sent. This is because retransmit path
+ * does not change tp->snd_nxt.
+ */
+ tp->snd_nxt++;
+ return;
+ }
} else {
- /* Socket is locked, keep trying until memory is available. */
- for (;;) {
- skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation);
- if (skb)
- break;
- yield();
+ skb = alloc_skb_fclone(MAX_TCP_HEADER, sk->sk_allocation);
+ if (unlikely(!skb)) {
+ if (tskb)
+ goto coalesce;
+ return;
}
+ skb_reserve(skb, MAX_TCP_HEADER);
+ sk_forced_wmem_schedule(sk, skb->truesize);
/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
tcp_init_nondata_skb(skb, tp->write_seq,
TCPHDR_ACK | TCPHDR_FIN);
tcp_queue_skb(sk, skb);
}
- __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF);
+ __tcp_push_pending_frames(sk, tcp_current_mss(sk), TCP_NAGLE_OFF);
}
/* We get here when a process closes a file descriptor (either due to
}
#endif
+ /* Do not fool tcpdump (if any), clean our debris */
+ skb->tstamp.tv64 = 0;
return skb;
}
EXPORT_SYMBOL(tcp_make_synack);
goto fallback;
syn_data->ip_summed = CHECKSUM_PARTIAL;
memcpy(syn_data->cb, syn->cb, sizeof(syn->cb));
+ skb_shinfo(syn_data)->gso_segs = 1;
if (unlikely(memcpy_fromiovecend(skb_put(syn_data, space),
fo->data->msg_iov, 0, space))) {
kfree_skb(syn_data);
if (rt)
rt6_set_expires(rt, jiffies + (HZ * lifetime));
if (ra_msg->icmph.icmp6_hop_limit) {
- in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+ /* Only set hop_limit on the interface if it is higher than
+ * the current hop_limit.
+ */
+ if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) {
+ in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
+ } else {
+ ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n");
+ }
if (rt)
dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
ra_msg->icmph.icmp6_hop_limit);
skb->sk = sk;
skb->destructor = sock_edemux;
if (sk->sk_state != TCP_TIME_WAIT) {
- struct dst_entry *dst = sk->sk_rx_dst;
+ struct dst_entry *dst = ACCESS_ONCE(sk->sk_rx_dst);
if (dst)
dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
{
.procname = "ack",
.data = &sysctl_llc2_ack_timeout,
- .maxlen = sizeof(long),
+ .maxlen = sizeof(sysctl_llc2_ack_timeout),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
{
.procname = "busy",
.data = &sysctl_llc2_busy_timeout,
- .maxlen = sizeof(long),
+ .maxlen = sizeof(sysctl_llc2_busy_timeout),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
{
.procname = "p",
.data = &sysctl_llc2_p_timeout,
- .maxlen = sizeof(long),
+ .maxlen = sizeof(sysctl_llc2_p_timeout),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
{
.procname = "rej",
.data = &sysctl_llc2_rej_timeout,
- .maxlen = sizeof(long),
+ .maxlen = sizeof(sysctl_llc2_rej_timeout),
.mode = 0644,
.proc_handler = proc_dointvec_jiffies,
},
static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
+static bool nf_generic_should_process(u8 proto)
+{
+ switch (proto) {
+#ifdef CONFIG_NF_CT_PROTO_SCTP_MODULE
+ case IPPROTO_SCTP:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_DCCP_MODULE
+ case IPPROTO_DCCP:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_GRE_MODULE
+ case IPPROTO_GRE:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_UDPLITE_MODULE
+ case IPPROTO_UDPLITE:
+ return false;
+#endif
+ default:
+ return true;
+ }
+}
+
static inline struct nf_generic_net *generic_pernet(struct net *net)
{
return &net->ct.nf_ct_proto.generic;
static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff, unsigned int *timeouts)
{
- return true;
+ return nf_generic_should_process(nf_ct_protonum(ct));
}
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/suspend.h>
#include <linux/notifier.h>
#include <net/net_namespace.h>
+#include <net/sock.h>
struct idletimer_tg_attr {
struct attribute attr;
bool work_pending;
bool send_nl_msg;
bool active;
+ uid_t uid;
};
static LIST_HEAD(idletimer_tg_list);
char iface_msg[NLMSG_MAX_SIZE];
char state_msg[NLMSG_MAX_SIZE];
char timestamp_msg[NLMSG_MAX_SIZE];
- char *envp[] = { iface_msg, state_msg, timestamp_msg, NULL };
+ char uid_msg[NLMSG_MAX_SIZE];
+ char *envp[] = { iface_msg, state_msg, timestamp_msg, uid_msg, NULL };
int res;
struct timespec ts;
uint64_t time_ns;
return;
}
+ if (state) {
+ res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID=%u", timer->uid);
+ if (NLMSG_MAX_SIZE <= res)
+ pr_err("message too long (%d)", res);
+ } else {
+ res = snprintf(uid_msg, NLMSG_MAX_SIZE, "UID=");
+ if (NLMSG_MAX_SIZE <= res)
+ pr_err("message too long (%d)", res);
+ }
+
time_ns = timespec_to_ns(&ts);
res = snprintf(timestamp_msg, NLMSG_MAX_SIZE, "TIME_NS=%llu", time_ns);
if (NLMSG_MAX_SIZE <= res) {
pr_err("message too long (%d)", res);
}
- pr_debug("putting nlmsg: <%s> <%s>\n", iface_msg, state_msg);
+ pr_debug("putting nlmsg: <%s> <%s> <%s> <%s>\n", iface_msg, state_msg,
+ timestamp_msg, uid_msg);
kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp);
return;
info->timer->delayed_timer_trigger.tv_sec = 0;
info->timer->delayed_timer_trigger.tv_nsec = 0;
info->timer->work_pending = false;
+ info->timer->uid = 0;
get_monotonic_boottime(&info->timer->last_modified_timer);
info->timer->pm_nb.notifier_call = idletimer_resume;
return ret;
}
-static void reset_timer(const struct idletimer_tg_info *info)
+static void reset_timer(const struct idletimer_tg_info *info,
+ struct sk_buff *skb)
{
unsigned long now = jiffies;
struct idletimer_tg *timer = info->timer;
if (!timer_prev || time_before(timer->timer.expires, now)) {
pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n",
timer->timer.expires, now);
+
+ /* Stores the uid resposible for waking up the radio */
+ if (skb && (skb->sk)) {
+ struct sock *sk = skb->sk;
+ read_lock_bh(&sk->sk_callback_lock);
+ if ((sk->sk_socket) && (sk->sk_socket->file) &&
+ (sk->sk_socket->file->f_cred))
+ timer->uid = sk->sk_socket->file->f_cred->uid;
+ read_unlock_bh(&sk->sk_callback_lock);
+ }
+
/* checks if there is a pending inactive notification*/
if (timer->work_pending)
timer->delayed_timer_trigger = timer->last_modified_timer;
}
/* TODO: Avoid modifying timers on each packet */
- reset_timer(info);
+ reset_timer(info, skb);
return XT_CONTINUE;
}
info->timer = __idletimer_tg_find_by_label(info->label);
if (info->timer) {
info->timer->refcnt++;
- reset_timer(info);
+ reset_timer(info, NULL);
pr_debug("increased refcnt of timer %s to %u\n",
info->label, info->timer->refcnt);
} else {
{
.procname = "max_unacked_packets",
.data = &rds_sysctl_max_unacked_packets,
- .maxlen = sizeof(unsigned long),
+ .maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
{
.procname = "max_unacked_bytes",
.data = &rds_sysctl_max_unacked_bytes,
- .maxlen = sizeof(unsigned long),
+ .maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
static void avc_operation_free(struct avc_operation_node *ops_node)
{
- struct avc_operation_decision_node *od_node;
+ struct avc_operation_decision_node *od_node, *tmp;
if (!ops_node)
return;
- list_for_each_entry(od_node, &ops_node->od_head, od_list)
+ list_for_each_entry_safe(od_node, tmp, &ops_node->od_head, od_list) {
+ list_del(&od_node->od_list);
avc_operation_decision_free(od_node);
+ }
kmem_cache_free(avc_operation_node_cachep, ops_node);
}
goto out;
/* No partial writes. */
- length = EINVAL;
+ length = -EINVAL;
if (*ppos != 0)
goto out;
spin_lock(&de->d_lock);
node = de->d_subdirs.next;
while (node != &de->d_subdirs) {
- struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(node, struct dentry, d_child);
spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
list_del_init(node);
list_for_each(class_node, &class_dir->d_subdirs) {
struct dentry *class_subdir = list_entry(class_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
struct list_head *class_subdir_node;
list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
struct dentry *d = list_entry(class_subdir_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
if (d->d_inode)
if (d->d_inode->i_mode & S_IFDIR)
return rc;
if (cur->key.specified & AVTAB_OP) {
+ rc = put_entry(&cur->datum.u.ops->type, sizeof(u8), 1, fp);
+ if (rc)
+ return rc;
for (i = 0; i < ARRAY_SIZE(cur->datum.u.ops->op.perms); i++)
buf32[i] = cpu_to_le32(cur->datum.u.ops->op.perms[i]);
rc = put_entry(buf32, sizeof(u32),
break;
case TMR_ECHO:
- if (seq_mode == SEQ_2)
- seq_copy_to_input(event_rec, 8);
- else
- {
- parm = (parm << 8 | SEQ_ECHO);
- seq_copy_to_input((unsigned char *) &parm, 4);
- }
+ parm = (parm << 8 | SEQ_ECHO);
+ seq_copy_to_input((unsigned char *) &parm, 4);
break;
default:;
int mode = translate_mode(file);
struct synth_info inf;
struct seq_event_rec event_rec;
- unsigned long flags;
int __user *p = arg;
orig_dev = dev = dev >> 4;
case SNDCTL_SEQ_OUTOFBAND:
if (copy_from_user(&event_rec, arg, sizeof(event_rec)))
return -EFAULT;
- spin_lock_irqsave(&lock,flags);
play_event(event_rec.arr);
- spin_unlock_irqrestore(&lock,flags);
return 0;
case SNDCTL_MIDI_INFO:
}
#endif
- strcpy(card->driver, emu->card_capabilities->driver);
- strcpy(card->shortname, emu->card_capabilities->name);
+ strlcpy(card->driver, emu->card_capabilities->driver,
+ sizeof(card->driver));
+ strlcpy(card->shortname, emu->card_capabilities->name,
+ sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),
"%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
card->shortname, emu->revision, emu->serial, emu->port, emu->irq);
snd_emu10k1_ptr_write(hw, Z2, ch, 0);
/* invalidate maps */
- temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK;
+ temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
#if 0
snd_emu10k1_ptr_write(hw, CDF, ch, sample);
/* invalidate maps */
- temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK;
+ temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */
snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */
- silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK;
+ silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
for (ch = 0; ch < NUM_G; ch++) {
snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page);
snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
}
+ if (emu->address_mode == 0) {
+ /* use 16M in 4G */
+ outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG);
+ }
+
return 0;
}
*
*/
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
- .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]",
+ .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0108_chip = 1,
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
- .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]",
+ .driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]",
.id = "Audigy2",
.emu10k2_chip = 1,
.ca0102_chip = 1,
is_audigy = emu->audigy = c->emu10k2_chip;
+ /* set addressing mode */
+ emu->address_mode = is_audigy ? 0 : 1;
/* set the DMA transfer mask */
- emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK;
+ emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK;
if (pci_set_dma_mask(pci, emu->dma_mask) < 0 ||
pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) {
snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask);
emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- 32 * 1024, &emu->ptb_pages) < 0) {
+ (emu->address_mode ? 32 : 16) * 1024, &emu->ptb_pages) < 0) {
err = -ENOMEM;
goto error;
}
/* Clear silent pages and set up pointers */
memset(emu->silent_page.area, 0, PAGE_SIZE);
- silent_page = emu->silent_page.addr << 1;
- for (idx = 0; idx < MAXPAGES; idx++)
+ silent_page = emu->silent_page.addr << emu->address_mode;
+ for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++)
((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx);
/* set up voice indices */
snd_emu10k1_ptr_write(emu, Z1, voice, 0);
snd_emu10k1_ptr_write(emu, Z2, voice, 0);
/* invalidate maps */
- silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK;
+ silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page);
snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page);
/* modulation envelope */
struct snd_emu10k1 *emu = entry->private_data;
u32 value;
u32 value2;
- unsigned long flags;
u32 rate;
if (emu->card_capabilities->emu_model) {
- spin_lock_irqsave(&emu->emu_lock, flags);
snd_emu1010_fpga_read(emu, 0x38, &value);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
if ((value & 0x1) == 0) {
- spin_lock_irqsave(&emu->emu_lock, flags);
snd_emu1010_fpga_read(emu, 0x2a, &value);
snd_emu1010_fpga_read(emu, 0x2b, &value2);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
rate = 0x1770000 / (((value << 5) | value2)+1);
snd_iprintf(buffer, "ADAT Locked : %u\n", rate);
} else {
snd_iprintf(buffer, "ADAT Unlocked\n");
}
- spin_lock_irqsave(&emu->emu_lock, flags);
snd_emu1010_fpga_read(emu, 0x20, &value);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
if ((value & 0x4) == 0) {
- spin_lock_irqsave(&emu->emu_lock, flags);
snd_emu1010_fpga_read(emu, 0x28, &value);
snd_emu1010_fpga_read(emu, 0x29, &value2);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
rate = 0x1770000 / (((value << 5) | value2)+1);
snd_iprintf(buffer, "SPDIF Locked : %d\n", rate);
} else {
{
struct snd_emu10k1 *emu = entry->private_data;
u32 value;
- unsigned long flags;
int i;
snd_iprintf(buffer, "EMU1010 Registers:\n\n");
for(i = 0; i < 0x40; i+=1) {
- spin_lock_irqsave(&emu->emu_lock, flags);
snd_emu1010_fpga_read(emu, i, &value);
- spin_unlock_irqrestore(&emu->emu_lock, flags);
snd_iprintf(buffer, "%02X: %08X, %02X\n", i, value, (value >> 8) & 0x7f);
}
}
* aligned pages in others
*/
#define __set_ptb_entry(emu,page,addr) \
- (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page)))
+ (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << (emu->address_mode)) | (page)))
#define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE)
-#define MAX_ALIGN_PAGES (MAXPAGES / UNIT_PAGES)
+#define MAX_ALIGN_PAGES0 (MAXPAGES0 / UNIT_PAGES)
+#define MAX_ALIGN_PAGES1 (MAXPAGES1 / UNIT_PAGES)
/* get aligned page from offset address */
#define get_aligned_page(offset) ((offset) >> PAGE_SHIFT)
/* get offset address from aligned page */
}
page = blk->mapped_page + blk->pages;
}
- size = MAX_ALIGN_PAGES - page;
+ size = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0) - page;
if (size >= max_size) {
*nextp = pos;
return page;
q = get_emu10k1_memblk(p, mapped_link);
end_page = q->mapped_page;
} else
- end_page = MAX_ALIGN_PAGES;
+ end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0);
/* remove links */
list_del(&blk->mapped_link);
if (snd_BUG_ON(!emu))
return NULL;
if (snd_BUG_ON(runtime->dma_bytes <= 0 ||
- runtime->dma_bytes >= MAXPAGES * EMUPAGESIZE))
+ runtime->dma_bytes >= (emu->address_mode ? MAXPAGES1 : MAXPAGES0) * EMUPAGESIZE))
return NULL;
hdr = emu->memhdr;
if (snd_BUG_ON(!hdr))
}
EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init_stereo);
+/* meta hook to call each driver's vmaster hook */
+static void vmaster_hook(void *private_data, int enabled)
+{
+ struct hda_vmaster_mute_hook *hook = private_data;
+
+ if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER)
+ enabled = hook->mute_mode;
+ hook->hook(hook->codec, enabled);
+}
+
/**
* snd_hda_codec_resume_amp - Resume all AMP commands from the cache
* @codec: HD-audio codec
if (!hook->hook || !hook->sw_kctl)
return 0;
- snd_ctl_add_vmaster_hook(hook->sw_kctl, hook->hook, codec);
hook->codec = codec;
hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER;
+ snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook);
if (!expose_enum_ctl)
return 0;
kctl = snd_ctl_new1(&vmaster_mute_mode, hook);
*/
if (hook->codec->bus->shutdown)
return;
- switch (hook->mute_mode) {
- case HDA_VMUTE_FOLLOW_MASTER:
- snd_ctl_sync_vmaster_hook(hook->sw_kctl);
- break;
- default:
- hook->hook(hook->codec, hook->mute_mode);
- break;
- }
+ snd_ctl_sync_vmaster_hook(hook->sw_kctl);
}
EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook);
{
/* We currently only handle front, HP */
static hda_nid_t pins[] = {
- 0x0f, 0x10, 0x14, 0x15, 0
+ 0x0f, 0x10, 0x14, 0x15, 0x17, 0
};
hda_nid_t *p;
for (p = pins; *p; p++)
ALC269_FIXUP_QUANTA_MUTE,
ALC269_FIXUP_LIFEBOOK,
ALC269_FIXUP_LIFEBOOK_EXTMIC,
+ ALC269_FIXUP_LIFEBOOK_HP_PIN,
ALC269_FIXUP_AMIC,
ALC269_FIXUP_DMIC,
ALC269VB_FIXUP_AMIC,
{ }
},
},
+ [ALC269_FIXUP_LIFEBOOK_HP_PIN] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x21, 0x0221102f }, /* HP out */
+ { }
+ },
+ },
[ALC269_FIXUP_AMIC] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
+ SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
if (snd_BUG_ON(!arg || !emu))
return -ENXIO;
- mutex_lock(&emu->register_mutex);
-
- if (!snd_emux_inc_count(emu)) {
- mutex_unlock(&emu->register_mutex);
+ if (!snd_emux_inc_count(emu))
return -EFAULT;
- }
memset(&callback, 0, sizeof(callback));
callback.owner = THIS_MODULE;
if (p == NULL) {
snd_printk(KERN_ERR "can't create port\n");
snd_emux_dec_count(emu);
- mutex_unlock(&emu->register_mutex);
return -ENOMEM;
}
reset_port_mode(p, arg->seq_mode);
snd_emux_reset_port(p);
-
- mutex_unlock(&emu->register_mutex);
return 0;
}
if (snd_BUG_ON(!emu))
return -ENXIO;
- mutex_lock(&emu->register_mutex);
snd_emux_sounds_off_all(p);
snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
snd_seq_event_port_detach(p->chset.client, p->chset.port);
snd_emux_dec_count(emu);
- mutex_unlock(&emu->register_mutex);
return 0;
}
if (emu->voices)
snd_emux_terminate_all(emu);
- mutex_lock(&emu->register_mutex);
if (emu->client >= 0) {
snd_seq_delete_kernel_client(emu->client);
emu->client = -1;
}
- mutex_unlock(&emu->register_mutex);
}
/*
* increment usage count
*/
-int
-snd_emux_inc_count(struct snd_emux *emu)
+static int
+__snd_emux_inc_count(struct snd_emux *emu)
{
emu->used++;
if (!try_module_get(emu->ops.owner))
return 1;
}
+int snd_emux_inc_count(struct snd_emux *emu)
+{
+ int ret;
+
+ mutex_lock(&emu->register_mutex);
+ ret = __snd_emux_inc_count(emu);
+ mutex_unlock(&emu->register_mutex);
+ return ret;
+}
/*
* decrease usage count
*/
-void
-snd_emux_dec_count(struct snd_emux *emu)
+static void
+__snd_emux_dec_count(struct snd_emux *emu)
{
module_put(emu->card->module);
emu->used--;
module_put(emu->ops.owner);
}
+void snd_emux_dec_count(struct snd_emux *emu)
+{
+ mutex_lock(&emu->register_mutex);
+ __snd_emux_dec_count(emu);
+ mutex_unlock(&emu->register_mutex);
+}
/*
* Routine that is called upon a first use of a particular port
mutex_lock(&emu->register_mutex);
snd_emux_init_port(p);
- snd_emux_inc_count(emu);
+ __snd_emux_inc_count(emu);
mutex_unlock(&emu->register_mutex);
return 0;
}
mutex_lock(&emu->register_mutex);
snd_emux_sounds_off_all(p);
- snd_emux_dec_count(emu);
+ __snd_emux_dec_count(emu);
mutex_unlock(&emu->register_mutex);
return 0;
}
{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */
{ USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */
{ USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */
+ { USB_ID(0x041e, 0x3237), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */
{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */
};
LOCAL_PATH := $(call my-dir)
+
+# Don't use this file if GATOR_DAEMON_PATH is set and we're not under that path
+ifneq ($(and $(GATOR_DAEMON_PATH),$(filter $(patsubst %/,%,$(GATOR_DAEMON_PATH))/%,$(LOCAL_PATH)/)),)
+
include $(CLEAR_VARS)
-XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h)
+XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h SrcMd5.cpp)
LOCAL_SRC_FILES := \
AnnotateListener.cpp \
Buffer.cpp \
CCNDriver.cpp \
- CPUFreqDriver.cpp \
CapturedXML.cpp \
Child.cpp \
Command.cpp \
SessionXML.cpp \
Setup.cpp \
Source.cpp \
+ SrcMd5.cpp \
StreamlineSetup.cpp \
UEvent.cpp \
UserSpaceSource.cpp \
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
+
+endif
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include "OlySocket.h"
+static const char STREAMLINE_ANNOTATE_PARENT[] = "\0streamline-annotate-parent";
+
struct AnnotateClient {
AnnotateClient *next;
int fd;
};
-AnnotateListener::AnnotateListener() : mClients(NULL), mSock(NULL) {
+AnnotateListener::AnnotateListener() : mClients(NULL), mSock(NULL), mUds(NULL) {
}
AnnotateListener::~AnnotateListener() {
close();
+ delete mUds;
delete mSock;
}
void AnnotateListener::setup() {
mSock = new OlyServerSocket(8082);
+ mUds = new OlyServerSocket(STREAMLINE_ANNOTATE_PARENT, sizeof(STREAMLINE_ANNOTATE_PARENT), true);
}
-int AnnotateListener::getFd() {
+int AnnotateListener::getSockFd() {
return mSock->getFd();
}
-void AnnotateListener::handle() {
+void AnnotateListener::handleSock() {
AnnotateClient *const client = new AnnotateClient();
client->fd = mSock->acceptConnection();
client->next = mClients;
mClients = client;
}
+int AnnotateListener::getUdsFd() {
+ return mUds->getFd();
+}
+
+void AnnotateListener::handleUds() {
+ AnnotateClient *const client = new AnnotateClient();
+ client->fd = mUds->acceptConnection();
+ client->next = mClients;
+ mClients = client;
+}
+
void AnnotateListener::close() {
- mSock->closeServerSocket();
+ if (mUds != NULL) {
+ mUds->closeServerSocket();
+ }
+ if (mSock != NULL) {
+ mSock->closeServerSocket();
+ }
while (mClients != NULL) {
::close(mClients->fd);
AnnotateClient *next = mClients->next;
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-class AnnotateClient;
+#ifndef ANNOTATELISTENER_H
+#define ANNOTATELISTENER_H
+
+struct AnnotateClient;
class OlyServerSocket;
class AnnotateListener {
~AnnotateListener();
void setup();
- int getFd();
+ int getSockFd();
+ int getUdsFd();
- void handle();
+ void handleSock();
+ void handleUds();
void close();
void signal();
private:
AnnotateClient *mClients;
OlyServerSocket *mSock;
+ OlyServerSocket *mUds;
// Intentionally unimplemented
AnnotateListener(const AnnotateListener &);
AnnotateListener &operator=(const AnnotateListener &);
};
+
+#endif // ANNOTATELISTENER_H
-APP_PLATFORM := android-8
+APP_PLATFORM := android-9
# Replace armeabi-v7a with arm64-v8a to build an arm64 gatord or with armeabi to build an ARM11 gatord
APP_ABI := armeabi-v7a
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include "SessionData.h"
#define mask (mSize - 1)
+#define FRAME_HEADER_SIZE 3
enum {
- CODE_PEA = 1,
- CODE_KEYS = 2,
- CODE_FORMAT = 3,
- CODE_MAPS = 4,
- CODE_COMM = 5,
- CODE_KEYS_OLD = 6,
- CODE_ONLINE_CPU = 7,
- CODE_OFFLINE_CPU = 8,
- CODE_KALLSYMS = 9,
+ CODE_PEA = 1,
+ CODE_KEYS = 2,
+ CODE_FORMAT = 3,
+ CODE_MAPS = 4,
+ CODE_COMM = 5,
+ CODE_KEYS_OLD = 6,
+ CODE_ONLINE_CPU = 7,
+ CODE_OFFLINE_CPU = 8,
+ CODE_KALLSYMS = 9,
+ CODE_COUNTERS = 10,
};
// Summary Frame Messages
Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mBuf(new char[size]), mReaderSem(readerSem), mCommitTime(gSessionData->mLiveRate), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mCore(core), mBufType(buftype) {
if ((mSize & mask) != 0) {
- logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
+ logg->logError("Buffer size is not a power of 2");
handleException();
}
sem_init(&mWriterSem, 0, 0);
}
}
-void Buffer::commit(const uint64_t time) {
+void Buffer::commit(const uint64_t time, const bool force) {
// post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
int length = mWritePos - mCommitPos;
length += mSize;
}
length = length - typeLength - sizeof(int32_t);
+ if (!force && !mIsDone && length <= FRAME_HEADER_SIZE) {
+ // Nothing to write, only the frame header is present
+ return;
+ }
for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
}
}
}
-void Buffer::pea(const uint64_t currTime, const struct perf_event_attr *const pea, int key) {
+void Buffer::marshalPea(const uint64_t currTime, const struct perf_event_attr *const pea, int key) {
while (!checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
sem_wait(&mWriterSem);
}
check(currTime);
}
-void Buffer::keys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys) {
+void Buffer::marshalKeys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys) {
while (!checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
sem_wait(&mWriterSem);
}
check(currTime);
}
-void Buffer::keysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf) {
+void Buffer::marshalKeysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf) {
while (!checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) {
sem_wait(&mWriterSem);
}
check(currTime);
}
-void Buffer::format(const uint64_t currTime, const int length, const char *const format) {
+void Buffer::marshalFormat(const uint64_t currTime, const int length, const char *const format) {
while (!checkSpace(MAXSIZE_PACK32 + length + 1)) {
sem_wait(&mWriterSem);
}
check(currTime);
}
-void Buffer::maps(const uint64_t currTime, const int pid, const int tid, const char *const maps) {
+void Buffer::marshalMaps(const uint64_t currTime, const int pid, const int tid, const char *const maps) {
const int mapsLen = strlen(maps) + 1;
while (!checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
sem_wait(&mWriterSem);
check(currTime);
}
-void Buffer::comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm) {
+void Buffer::marshalComm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm) {
const int imageLen = strlen(image) + 1;
const int commLen = strlen(comm) + 1;
while (!checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
check(currTime);
}
-void Buffer::onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
+void Buffer::onlineCPU(const uint64_t currTime, const int cpu) {
while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
sem_wait(&mWriterSem);
}
packInt(CODE_ONLINE_CPU);
- packInt64(time);
+ packInt64(currTime);
packInt(cpu);
check(currTime);
}
-void Buffer::offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
+void Buffer::offlineCPU(const uint64_t currTime, const int cpu) {
while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
sem_wait(&mWriterSem);
}
packInt(CODE_OFFLINE_CPU);
- packInt64(time);
+ packInt64(currTime);
packInt(cpu);
check(currTime);
}
-void Buffer::kallsyms(const uint64_t currTime, const char *const kallsyms) {
+void Buffer::marshalKallsyms(const uint64_t currTime, const char *const kallsyms) {
const int kallsymsLen = strlen(kallsyms) + 1;
while (!checkSpace(3 * MAXSIZE_PACK32 + kallsymsLen)) {
sem_wait(&mWriterSem);
check(currTime);
}
+void Buffer::perfCounterHeader(const uint64_t time) {
+ while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
+ sem_wait(&mWriterSem);
+ }
+ packInt(CODE_COUNTERS);
+ packInt64(time);
+}
+
+void Buffer::perfCounter(const int core, const int key, const int64_t value) {
+ while (!checkSpace(2*MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
+ sem_wait(&mWriterSem);
+ }
+ packInt(core);
+ packInt(key);
+ packInt64(value);
+}
+
+void Buffer::perfCounterFooter(const uint64_t currTime) {
+ while (!checkSpace(MAXSIZE_PACK32)) {
+ sem_wait(&mWriterSem);
+ }
+ packInt(-1);
+ check(currTime);
+}
+
void Buffer::setDone() {
mIsDone = true;
commit(0);
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
int bytesAvailable() const;
int contiguousSpaceAvailable() const;
- void commit(const uint64_t time);
+ void commit(const uint64_t time, const bool force = false);
void check(const uint64_t time);
// Summary messages
void event64(int key, int64_t value);
// Perf Attrs messages
- void pea(const uint64_t currTime, const struct perf_event_attr *const pea, int key);
- void keys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys);
- void keysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf);
- void format(const uint64_t currTime, const int length, const char *const format);
- void maps(const uint64_t currTime, const int pid, const int tid, const char *const maps);
- void comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm);
- void onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu);
- void offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu);
- void kallsyms(const uint64_t currTime, const char *const kallsyms);
+ void marshalPea(const uint64_t currTime, const struct perf_event_attr *const pea, int key);
+ void marshalKeys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys);
+ void marshalKeysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf);
+ void marshalFormat(const uint64_t currTime, const int length, const char *const format);
+ void marshalMaps(const uint64_t currTime, const int pid, const int tid, const char *const maps);
+ void marshalComm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm);
+ void onlineCPU(const uint64_t currTime, const int cpu);
+ void offlineCPU(const uint64_t currTime, const int cpu);
+ void marshalKallsyms(const uint64_t currTime, const char *const kallsyms);
+ void perfCounterHeader(const uint64_t time);
+ void perfCounter(const int core, const int key, const int64_t value);
+ void perfCounterFooter(const uint64_t currTime);
void setDone();
bool isDone() const;
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
static const char ATTR_AVERAGE_SELECTION[] = "average_selection";
static const char ATTR_COUNTER[] = "counter";
-static const char ATTR_COUNTER_SET[] = "counter_set";
static const char ATTR_COUNT[] = "count";
static const char ATTR_DESCRIPTION[] = "description";
static const char ATTR_DISPLAY[] = "display";
int type;
if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) {
- logg->logError(__FILE__, __LINE__, "Unable to read CCN-5xx type");
+ logg->logError("Unable to read CCN-5xx type");
handleException();
}
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+++ /dev/null
-/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include "CPUFreqDriver.h"
-
-#include "Buffer.h"
-#include "DriverSource.h"
-#include "Logging.h"
-#include "SessionData.h"
-
-CPUFreqDriver::CPUFreqDriver() : mPrev() {
-}
-
-CPUFreqDriver::~CPUFreqDriver() {
-}
-
-void CPUFreqDriver::readEvents(mxml_node_t *const) {
- // Only for use with perf
- if (!gSessionData->perf.isSetup()) {
- return;
- }
-
- setCounters(new DriverCounter(getCounters(), strdup("Linux_power_cpu_freq")));
-}
-
-void CPUFreqDriver::read(Buffer *const buffer) {
- char buf[64];
- const DriverCounter *const counter = getCounters();
- if ((counter == NULL) || !counter->isEnabled()) {
- return;
- }
-
- const int key = getCounters()->getKey();
- bool resetCores = false;
- for (int i = 0; i < gSessionData->mCores; ++i) {
- snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%i/cpufreq/cpuinfo_cur_freq", i);
- int64_t freq;
- if (DriverSource::readInt64Driver(buf, &freq) != 0) {
- freq = 0;
- }
- if (mPrev[i] != freq) {
- mPrev[i] = freq;
- // Change cores
- buffer->event64(2, i);
- resetCores = true;
- buffer->event64(key, 1000*freq);
- }
- }
- if (resetCores) {
- // Revert cores, UserSpaceSource is all on core 0
- buffer->event64(2, 0);
- }
-}
+++ /dev/null
-/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef CPUFREQDRIVER_H
-#define CPUFREQDRIVER_H
-
-#include "Config.h"
-#include "Driver.h"
-
-class CPUFreqDriver : public PolledDriver {
-private:
- typedef PolledDriver super;
-
-public:
- CPUFreqDriver();
- ~CPUFreqDriver();
-
- void readEvents(mxml_node_t *const root);
- void read(Buffer *const buffer);
-
-private:
- int64_t mPrev[NR_CPUS];
-
- // Intentionally unimplemented
- CPUFreqDriver(const CPUFreqDriver &);
- CPUFreqDriver &operator=(const CPUFreqDriver &);
-};
-
-#endif // CPUFREQDRIVER_H
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
mxmlElementSetAttr(captured, "version", "1");
if (gSessionData->perf.isSetup()) {
mxmlElementSetAttr(captured, "type", "Perf");
- mxmlElementSetAttr(captured, "perf_beta", "yes");
}
mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
if (includeTime) { // Send the following only after the capture is complete
char* xml = getXML(true);
if (util->writeToDisk(file, xml) < 0) {
- logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
+ logg->logError("Error writing %s\nPlease verify the path.", file);
handleException();
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
sem_wait(&haltPipeline);
- while (!primarySource->isDone() ||
- !externalSource->isDone() ||
+ while (!externalSource->isDone() ||
(userSpaceSource != NULL && !userSpaceSource->isDone()) ||
- (ftraceSource != NULL && !ftraceSource->isDone())) {
+ (ftraceSource != NULL && !ftraceSource->isDone()) ||
+ !primarySource->isDone()) {
sem_wait(&senderSem);
- primarySource->write(sender);
externalSource->write(sender);
if (userSpaceSource != NULL) {
userSpaceSource->write(sender);
if (ftraceSource != NULL) {
ftraceSource->write(sender);
}
+ primarySource->write(sender);
}
// write end-of-capture sequence
sender = new Sender(socket);
if (mNumConnections > 1) {
- logg->logError(__FILE__, __LINE__, "Session already in progress");
+ logg->logError("Session already in progress");
handleException();
}
char* xmlString;
xmlString = util->readFromDisk(gSessionData->mSessionXMLPath);
if (xmlString == 0) {
- logg->logError(__FILE__, __LINE__, "Unable to read session xml file: %s", gSessionData->mSessionXMLPath);
+ logg->logError("Unable to read session xml file: %s", gSessionData->mSessionXMLPath);
handleException();
}
gSessionData->parseSessionXML(xmlString);
}
if (gSessionData->kmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) {
- logg->logError(__FILE__, __LINE__, "Mali counters are not supported with Sample Rate: None.");
+ logg->logError("Mali counters are not supported with Sample Rate: None.");
handleException();
}
+ // Initialize ftrace source before child as it's slow and dependens on nothing else
+ // If initialized later, us gator with ftrace has time sync issues
+ if (gSessionData->ftraceDriver.countersEnabled()) {
+ ftraceSource = new FtraceSource(&senderSem);
+ if (!ftraceSource->prepare()) {
+ logg->logError("Unable to prepare userspace source for capture");
+ handleException();
+ }
+ ftraceSource->start();
+ }
+
// Must be after session XML is parsed
if (!primarySource->prepare()) {
if (gSessionData->perf.isSetup()) {
- logg->logError(__FILE__, __LINE__, "Unable to prepare gator driver for capture");
+ logg->logError("Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information.");
} else {
- logg->logError(__FILE__, __LINE__, "Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information.");
+ logg->logError("Unable to prepare gator driver for capture");
}
handleException();
}
// Must be initialized before senderThread is started as senderThread checks externalSource
externalSource = new ExternalSource(&senderSem);
if (!externalSource->prepare()) {
- logg->logError(__FILE__, __LINE__, "Unable to prepare external source for capture");
+ logg->logError("Unable to prepare external source for capture");
handleException();
}
externalSource->start();
if (startUSSource) {
userSpaceSource = new UserSpaceSource(&senderSem);
if (!userSpaceSource->prepare()) {
- logg->logError(__FILE__, __LINE__, "Unable to prepare userspace source for capture");
+ logg->logError("Unable to prepare userspace source for capture");
handleException();
}
userSpaceSource->start();
}
- if (gSessionData->ftraceDriver.countersEnabled()) {
- ftraceSource = new FtraceSource(&senderSem);
- if (!ftraceSource->prepare()) {
- logg->logError(__FILE__, __LINE__, "Unable to prepare userspace source for capture");
- handleException();
- }
- ftraceSource->start();
- }
-
if (gSessionData->mAllowCommands && (gSessionData->mCaptureCommand != NULL)) {
pthread_t thread;
if (pthread_create(&thread, NULL, commandThread, NULL)) {
}
if (!thread_creation_success) {
- logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
+ logg->logError("Failed to create gator threads");
handleException();
}
// Start profiling
primarySource->run();
+ // Wait for the other threads to exit
if (ftraceSource != NULL) {
ftraceSource->join();
}
userSpaceSource->join();
}
externalSource->join();
-
- // Wait for the other threads to exit
pthread_join(senderThreadID, NULL);
// Shutting down the connection should break the stop thread which is stalling on the socket recv() function
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
const int pid = fork();
if (pid < 0) {
- logg->logError(__FILE__, __LINE__, "fork failed");
+ logg->logError("fork failed");
handleException();
}
if (pid == 0) {
const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser;
const int uid = getUid(name);
if (uid < 0) {
- logg->logError(__FILE__, __LINE__, "Unable to lookup the user %s, please double check that the user exists", name);
+ logg->logError("Unable to look up the user %s, please double check that the user exists", name);
handleException();
}
char buf[128];
int pipefd[2];
if (pipe_cloexec(pipefd) != 0) {
- logg->logError(__FILE__, __LINE__, "pipe failed");
+ logg->logError("pipe failed");
handleException();
}
const int pid = fork();
if (pid < 0) {
- logg->logError(__FILE__, __LINE__, "fork failed");
+ logg->logError("fork failed");
handleException();
}
if (pid == 0) {
close(pipefd[1]);
const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
if (bytes > 0) {
- logg->logError(__FILE__, __LINE__, buf);
+ logg->logError("%s", buf);
handleException();
}
close(pipefd[0]);
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
const Counter & counter = gSessionData->mCounters[i];
if (counter.isEnabled()) {
if (strcmp(counter.getType(), "") == 0) {
- logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n event=%d\n", counter.getType(), counter.getEvent());
+ logg->logError("Invalid required attribute in configuration.xml:\n counter=\"%s\"\n event=%d\n", counter.getType(), counter.getEvent());
handleException();
}
if (counter2.isEnabled()) {
// check if the types are the same
if (strcmp(counter.getType(), counter2.getType()) == 0) {
- logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", counter.getType());
+ logg->logError("Duplicate performance counter type in configuration.xml: %s", counter.getType());
handleException();
}
}
for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
if (driver->claimCounter(counter)) {
if (counter.getDriver() != NULL) {
- logg->logError(__FILE__, __LINE__, "More than one driver has claimed %s:%i", counter.getType(), counter.getEvent());
+ logg->logError("More than one driver has claimed %s:%i", counter.getType(), counter.getEvent());
handleException();
}
counter.setDriver(driver);
getPath(path);
if (::remove(path) != 0) {
- logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
+ logg->logError("Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
handleException();
}
logg->logMessage("Invalid configuration.xml file detected and removed");
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
}
if (!mBuf.read("/proc/diskstats")) {
- logg->logError(__FILE__, __LINE__, "Unable to read /proc/diskstats");
+ logg->logError("Unable to read /proc/diskstats");
handleException();
}
char *lastName = NULL;
int lastNameLen = -1;
- char *start = mBuf.getBuf();
- while (*start != '\0') {
- char *end = strchr(start, '\n');
+ char *line = mBuf.getBuf();
+ while (*line != '\0') {
+ char *end = strchr(line, '\n');
if (end != NULL) {
*end = '\0';
}
int nameEnd = -1;
int64_t readBytes = -1;
int64_t writeBytes = -1;
- const int count = sscanf(start, "%*d %*d %n%*s%n %*u %*u %" SCNu64 " %*u %*u %*u %" SCNu64, &nameStart, &nameEnd, &readBytes, &writeBytes);
+ const int count = sscanf(line, "%*d %*d %n%*s%n %*u %*u %" SCNu64 " %*u %*u %*u %" SCNu64, &nameStart, &nameEnd, &readBytes, &writeBytes);
if (count != 2) {
- logg->logError(__FILE__, __LINE__, "Unable to parse /proc/diskstats");
+ logg->logError("Unable to parse /proc/diskstats");
handleException();
}
// Skip partitions which are identified if the name is a substring of the last non-partition
- if ((lastName == NULL) || (strncmp(lastName, start + nameStart, lastNameLen) != 0)) {
- lastName = start + nameStart;
+ if ((lastName == NULL) || (strncmp(lastName, line + nameStart, lastNameLen) != 0)) {
+ lastName = line + nameStart;
lastNameLen = nameEnd - nameStart;
mReadBytes += readBytes;
mWriteBytes += writeBytes;
if (end == NULL) {
break;
}
- start = end + 1;
+ line = end + 1;
}
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem);
if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
- logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
+ logg->logError("Error reading gator driver version");
handleException();
}
if (driver_version != PROTOCOL_VERSION) {
if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
// One of the mismatched versions is development version
- logg->logError(__FILE__, __LINE__,
+ logg->logError(
"DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
">> The following must be synchronized from engineering repository:\n"
">> * gator driver\n"
handleException();
} else {
// Release version mismatch
- logg->logError(__FILE__, __LINE__,
+ logg->logError(
"gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
handleException();
int enable = -1;
if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
- logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress.");
+ logg->logError("Driver already enabled, possibly a session is already in progress.");
handleException();
}
}
if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
- logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
+ logg->logError("Unable to read the driver buffer size");
handleException();
}
}
DynBuf printb;
DynBuf b1;
DynBuf b2;
- const uint64_t currTime = getTime();
+ // MonotonicStarted may not be not assigned yet
+ const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted;
if (!readProcComms(currTime, mBuffer, &printb, &b1, &b2)) {
- logg->logError(__FILE__, __LINE__, "readProcComms failed");
+ logg->logError("readProcComms failed");
handleException();
}
// Set the maximum backtrace depth
if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
- logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
+ logg->logError("Unable to set the driver backtrace depth");
handleException();
}
// open the buffer which calls userspace_buffer_open() in the driver
mBufferFD = open("/dev/gator/buffer", O_RDONLY | O_CLOEXEC);
if (mBufferFD < 0) {
- logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
+ logg->logError("The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
handleException();
}
// set the tick rate of the profiling timer
if (writeReadDriver("/dev/gator/tick", &gSessionData->mSampleRate) != 0) {
- logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
+ logg->logError("Unable to set the driver tick");
handleException();
}
// notify the kernel of the response type
int response_type = gSessionData->mLocalCapture ? 0 : RESPONSE_APC_DATA;
if (writeDriver("/dev/gator/response_type", response_type)) {
- logg->logError(__FILE__, __LINE__, "Unable to write the response type");
+ logg->logError("Unable to write the response type");
handleException();
}
// Set the live rate
if (writeReadDriver("/dev/gator/live_rate", &gSessionData->mLiveRate)) {
- logg->logError(__FILE__, __LINE__, "Unable to set the driver live rate");
+ logg->logError("Unable to set the driver live rate");
handleException();
}
// This command makes the driver start profiling by calling gator_op_start() in the driver
if (writeDriver("/dev/gator/enable", "1") != 0) {
- logg->logError(__FILE__, __LINE__, "The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
+ logg->logError("The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
handleException();
}
pthread_t bootstrapThreadID;
if (pthread_create(&bootstrapThreadID, NULL, bootstrapThreadStatic, this) != 0) {
- logg->logError(__FILE__, __LINE__, "Unable to start the gator_bootstrap thread");
+ logg->logError("Unable to start the gator_bootstrap thread");
handleException();
}
// In one shot mode, stop collection once all the buffers are filled
if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
if (bytesCollected == -1 || mFifo->willFill(bytesCollected)) {
- logg->logMessage("One shot");
+ logg->logMessage("One shot (gator.ko)");
child->endSession();
}
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
const int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
- logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("open failed");
return false;
}
const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
if (capacity < minCapacity) {
if (resize(minCapacity) != 0) {
- logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::resize failed");
goto fail;
}
}
const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
if (bytes < 0) {
- logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("read failed");
goto fail;
} else if (bytes == 0) {
break;
if (capacity <= 0) {
if (resize(2 * MIN_BUFFER_FREE) != 0) {
- logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::resize failed");
return false;
}
}
int bytes = vsnprintf(buf, capacity, format, ap);
va_end(ap);
if (bytes < 0) {
- logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("fsnprintf failed");
return false;
}
if (static_cast<size_t>(bytes) > capacity) {
if (resize(bytes + 1) != 0) {
- logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::resize failed");
return false;
}
bytes = vsnprintf(buf, capacity, format, ap);
va_end(ap);
if (bytes < 0) {
- logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("fsnprintf failed");
return false;
}
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include "OlyUtility.h"
#include "SessionData.h"
+class XMLList {
+public:
+ XMLList(XMLList *const prev, mxml_node_t *const node) : mPrev(prev), mNode(node) {}
+
+ XMLList *getPrev() { return mPrev; }
+ mxml_node_t *getNode() const { return mNode; }
+ void setNode(mxml_node_t *const node) { mNode = node; }
+
+ static void free(XMLList *list) {
+ while (list != NULL) {
+ XMLList *prev = list->getPrev();
+ delete list;
+ list = prev;
+ }
+ }
+
+private:
+ XMLList *const mPrev;
+ mxml_node_t *mNode;
+
+ // Intentionally unimplemented
+ XMLList(const XMLList &);
+ XMLList &operator=(const XMLList &);
+};
+
mxml_node_t *EventsXML::getTree() {
#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
char path[PATH_MAX];
- mxml_node_t *xml;
+ mxml_node_t *xml = NULL;
FILE *fl;
// Avoid unused variable warning
// Load the provided or default events xml
if (gSessionData->mEventsXMLPath) {
strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
- } else {
- util->getApplicationFullPath(path, PATH_MAX);
- strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
+ fl = fopen(path, "r");
+ if (fl) {
+ xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
+ fclose(fl);
+ }
}
- fl = fopen(path, "r");
- if (fl) {
- xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
- fclose(fl);
- } else {
+ if (xml == NULL) {
logg->logMessage("Unable to locate events.xml, using default");
xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
}
+ // Append additional events XML
+ if (gSessionData->mEventsXMLAppend) {
+ fl = fopen(gSessionData->mEventsXMLAppend, "r");
+ if (fl == NULL) {
+ logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend);
+ handleException();
+ }
+ mxml_node_t *append = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
+ fclose(fl);
+
+ mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
+ if (!events) {
+ logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML starts with:\n"
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<events>");
+ handleException();
+ }
+
+ XMLList *categoryList = NULL;
+ XMLList *eventList = NULL;
+ {
+ // Make list of all categories in xml
+ mxml_node_t *node = xml;
+ while (true) {
+ node = mxmlFindElement(node, xml, "category", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ categoryList = new XMLList(categoryList, node);
+ }
+
+ // Make list of all events in xml
+ node = xml;
+ while (true) {
+ node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ eventList = new XMLList(eventList, node);
+ }
+ }
+
+ // Handle events
+ for (mxml_node_t *node = mxmlFindElement(append, append, "event", NULL, NULL, MXML_DESCEND),
+ *next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND);
+ node != NULL;
+ node = next, next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND)) {
+ const char *const category = mxmlElementGetAttr(mxmlGetParent(node), "name");
+ const char *const title = mxmlElementGetAttr(node, "title");
+ const char *const name = mxmlElementGetAttr(node, "name");
+ if (category == NULL || title == NULL || name == NULL) {
+ logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
+ handleException();
+ }
+
+ // Replace any duplicate events
+ for (XMLList *event = eventList; event != NULL; event = event->getPrev()) {
+ const char *const category2 = mxmlElementGetAttr(mxmlGetParent(event->getNode()), "name");
+ const char *const title2 = mxmlElementGetAttr(event->getNode(), "title");
+ const char *const name2 = mxmlElementGetAttr(event->getNode(), "name");
+ if (category2 == NULL || title2 == NULL || name2 == NULL) {
+ logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
+ handleException();
+ }
+
+ if (strcmp(category, category2) == 0 && strcmp(title, title2) == 0 && strcmp(name, name2) == 0) {
+ logg->logMessage("Replacing counter %s %s: %s", category, title, name);
+ mxml_node_t *parent = mxmlGetParent(event->getNode());
+ mxmlDelete(event->getNode());
+ mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
+ event->setNode(node);
+ break;
+ }
+ }
+ }
+
+ // Handle categories
+ for (mxml_node_t *node = strcmp(mxmlGetElement(append), "category") == 0 ? append : mxmlFindElement(append, append, "category", NULL, NULL, MXML_DESCEND),
+ *next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND);
+ node != NULL;
+ node = next, next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND)) {
+ // After replacing duplicate events, a category may be empty
+ if (mxmlGetFirstChild(node) == NULL) {
+ continue;
+ }
+
+ const char *const name = mxmlElementGetAttr(node, "name");
+ if (name == NULL) {
+ logg->logError("Not all event XML categories have the required name attribute");
+ handleException();
+ }
+
+ // Merge identically named categories
+ bool merged = false;
+ for (XMLList *category = categoryList; category != NULL; category = category->getPrev()) {
+ const char *const name2 = mxmlElementGetAttr(category->getNode(), "name");
+ if (name2 == NULL) {
+ logg->logError("Not all event XML categories have the required name attribute");
+ handleException();
+ }
+
+ if (strcmp(name, name2) == 0) {
+ logg->logMessage("Merging category %s", name);
+ while (true) {
+ mxml_node_t *child = mxmlGetFirstChild(node);
+ if (child == NULL) {
+ break;
+ }
+ mxmlAdd(category->getNode(), MXML_ADD_AFTER, mxmlGetLastChild(category->getNode()), child);
+ }
+ merged = true;
+ break;
+ }
+ }
+
+ if (merged) {
+ continue;
+ }
+
+ // Add new categories
+ logg->logMessage("Appending category %s", name);
+ mxmlAdd(events, MXML_ADD_AFTER, mxmlGetLastChild(events), node);
+ }
+
+ XMLList::free(eventList);
+ XMLList::free(categoryList);
+
+ mxmlDelete(append);
+ }
+
return xml;
}
// Add dynamic events from the drivers
mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
if (!events) {
- logg->logError(__FILE__, __LINE__, "Unable to find <events> node in the events.xml");
+ logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML are:\n"
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<events>");
handleException();
}
for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
char *buf = getXML();
if (util->writeToDisk(file, buf) < 0) {
- logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
+ logg->logError("Error writing %s\nPlease verify the path.", file);
handleException();
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
class EventsXML {
public:
+ EventsXML() {}
+
mxml_node_t *getTree();
char *getXML();
void write(const char* path);
+
+private:
+ // Intentionally unimplemented
+ EventsXML(const EventsXML &);
+ EventsXML &operator=(const EventsXML &);
};
#endif // EVENTS_XML
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <sys/prctl.h>
#include <unistd.h>
+#include "Child.h"
#include "Logging.h"
#include "OlySocket.h"
#include "SessionData.h"
+extern Child *child;
+
+static const char STREAMLINE_ANNOTATE[] = "\0streamline-annotate";
static const char MALI_VIDEO[] = "\0mali-video";
static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup";
static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
return true;
}
-ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
+ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) {
sem_init(&mBufferSem, 0, 0);
}
void ExternalSource::waitFor(const int bytes) {
while (mBuffer.bytesAvailable() <= bytes) {
+ if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
+ logg->logMessage("One shot (external)");
+ child->endSession();
+ }
sem_wait(&mBufferSem);
}
}
void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) {
if (!setNonblock(fd)) {
- logg->logError(__FILE__, __LINE__, "Unable to set nonblock on fh");
+ logg->logError("Unable to set nonblock on fh");
handleException();
}
if (!mMonitor.add(fd)) {
- logg->logError(__FILE__, __LINE__, "Unable to add fh to monitor");
+ logg->logError("Unable to add fh to monitor");
handleException();
}
waitFor(Buffer::MAXSIZE_PACK32 + size - 1);
mBuffer.packInt(fd);
mBuffer.writeBytes(handshake, size - 1);
- mBuffer.commit(1);
+ mBuffer.commit(1, true);
}
bool ExternalSource::connectMali() {
!setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) ||
!setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) ||
!setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) ||
+ !setNonblock(mAnnotateUds.getFd()) || !mMonitor.add(mAnnotateUds.getFd()) ||
false) {
return false;
}
prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0);
if (pipe_cloexec(pipefd) != 0) {
- logg->logError(__FILE__, __LINE__, "pipe failed");
+ logg->logError("pipe failed");
handleException();
}
mInterruptFd = pipefd[1];
if (!mMonitor.add(pipefd[0])) {
- logg->logError(__FILE__, __LINE__, "Monitor::add failed");
+ logg->logError("Monitor::add failed");
handleException();
}
// Notify annotate clients to retry connecting to gatord
- gSessionData->annotateListener.signal();
+ uint64_t val = 1;
+ if (::write(gSessionData->mAnnotateStart, &val, sizeof(val)) != sizeof(val)) {
+ logg->logMessage("Writing to annotate pipe failed");
+ }
while (gSessionData->mSessionIsActive) {
struct epoll_event events[16];
while (sem_trywait(&mBufferSem) == 0);
int ready = mMonitor.wait(events, ARRAY_LENGTH(events), -1);
if (ready < 0) {
- logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
+ logg->logError("Monitor::wait failed");
handleException();
}
- const uint64_t currTime = getTime();
+ const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
for (int i = 0; i < ready; ++i) {
const int fd = events[i].data.fd;
// Don't read from this connection, establish a new connection to Mali-V500
close(client);
if (!connectMve()) {
- logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali video connection");
+ logg->logError("Unable to configure incoming Mali video connection");
handleException();
}
} else if (fd == mMaliStartupUds.getFd()) {
// Don't read from this connection, establish a new connection to Mali Graphics
close(client);
if (!connectMali()) {
- logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali graphics connection");
+ logg->logError("Unable to configure incoming Mali graphics connection");
handleException();
}
} else if (fd == mAnnotate.getFd()) {
int client = mAnnotate.acceptConnection();
if (!setNonblock(client) || !mMonitor.add(client)) {
- logg->logError(__FILE__, __LINE__, "Unable to set socket options on incoming annotation connection");
+ logg->logError("Unable to set socket options on incoming annotation connection");
+ handleException();
+ }
+ } else if (fd == mAnnotateUds.getFd()) {
+ int client = mAnnotateUds.acceptConnection();
+ if (!setNonblock(client) || !mMonitor.add(client)) {
+ logg->logError("Unable to set socket options on incoming annotation connection");
handleException();
}
} else if (fd == pipefd[0]) {
if (bytes < 0) {
if (errno == EAGAIN) {
// Nothing left to read
- mBuffer.commit(currTime);
+ mBuffer.commit(currTime, true);
break;
}
// Something else failed, close the socket
- mBuffer.commit(currTime);
+ mBuffer.commit(currTime, true);
mBuffer.packInt(-1);
mBuffer.packInt(fd);
- mBuffer.commit(currTime);
+ // Here and other commits, always force-flush the buffer as this frame don't work like others
+ mBuffer.commit(currTime, true);
close(fd);
break;
} else if (bytes == 0) {
// The other side is closed
- mBuffer.commit(currTime);
+ mBuffer.commit(currTime, true);
mBuffer.packInt(-1);
mBuffer.packInt(fd);
- mBuffer.commit(currTime);
+ mBuffer.commit(currTime, true);
close(fd);
break;
}
mBuffer.advanceWrite(bytes);
- mBuffer.commit(currTime);
+ mBuffer.commit(currTime, true);
// Short reads also mean nothing is left to read
if (bytes < contiguous) {
int8_t c = 0;
// Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
- logg->logError(__FILE__, __LINE__, "write failed");
+ logg->logError("write failed");
handleException();
}
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
OlyServerSocket mMveStartupUds;
OlyServerSocket mMaliStartupUds;
OlyServerSocket mAnnotate;
+ OlyServerSocket mAnnotateUds;
int mInterruptFd;
int mMaliUds;
int mMveUds;
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
if (result != 0) {
char buf[128];
regerror(result, &mReg, buf, sizeof(buf));
- logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf);
+ logg->logError("Invalid regex '%s': %s", regex, buf);
handleException();
}
}
regmatch_t match[2];
int result = regexec(&mReg, buf, 2, match, 0);
if (result != 0) {
- regerror(result, &mReg, buf, sizeof(buf));
- logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, buf);
- handleException();
+ // No match
+ return 0;
}
if (match[1].rm_so < 0) {
- logg->logError(__FILE__, __LINE__, "Parsing %s failed", mPath);
- handleException();
- }
-
- errno = 0;
- value = strtoll(buf + match[1].rm_so, NULL, 0);
- if (errno != 0) {
- logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, strerror(errno));
- handleException();
+ value = 1;
+ } else {
+ errno = 0;
+ value = strtoll(buf + match[1].rm_so, NULL, 0);
+ if (errno != 0) {
+ logg->logError("Parsing %s failed: %s", mPath, strerror(errno));
+ handleException();
+ }
}
} else {
if (DriverSource::readInt64Driver(mPath, &value) != 0) {
return value;
fail:
- logg->logError(__FILE__, __LINE__, "Unable to read %s", mPath);
+ logg->logError("Unable to read %s", mPath);
handleException();
}
}
if (counter[0] == '/') {
- logg->logError(__FILE__, __LINE__, "Old style filesystem counter (%s) detected, please create a new unique counter value and move the filename into the path attribute, see events-Filesystem.xml for examples", counter);
+ logg->logError("Old style filesystem counter (%s) detected, please create a new unique counter value and move the filename into the path attribute, see events-Filesystem.xml for examples", counter);
handleException();
}
const char *path = mxmlElementGetAttr(node, "path");
if (path == NULL) {
- logg->logError(__FILE__, __LINE__, "The filesystem counter %s is missing the required path attribute", counter);
+ logg->logError("The filesystem counter %s is missing the required path attribute", counter);
handleException();
}
const char *regex = mxmlElementGetAttr(node, "regex");
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
mEnd = false;
if (mBuffer == NULL) {
- logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize);
+ logg->logError("failed to allocate %d bytes", bufferSize + singleBufferSize);
handleException();
}
if (sem_init(&mWaitForSpaceSem, 0, 0)) {
- logg->logError(__FILE__, __LINE__, "sem_init() failed");
+ logg->logError("sem_init() failed");
handleException();
}
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include "FtraceDriver.h"
#include <regex.h>
+#include <unistd.h>
+#include "DriverSource.h"
#include "Logging.h"
+#include "Setup.h"
class FtraceCounter : public DriverCounter {
public:
- FtraceCounter(DriverCounter *next, char *name, const char *regex);
+ FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable);
~FtraceCounter();
+ void prepare();
int read(const char *const line, int64_t *values);
+ void stop();
private:
- regex_t reg;
+ regex_t mReg;
+ char *const mEnable;
+ int mWasEnabled;
// Intentionally unimplemented
FtraceCounter(const FtraceCounter &);
FtraceCounter &operator=(const FtraceCounter &);
};
-FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex) : DriverCounter(next, name) {
- int result = regcomp(®, regex, REG_EXTENDED);
+FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
+ int result = regcomp(&mReg, regex, REG_EXTENDED);
if (result != 0) {
char buf[128];
- regerror(result, ®, buf, sizeof(buf));
- logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf);
+ regerror(result, &mReg, buf, sizeof(buf));
+ logg->logError("Invalid regex '%s': %s", regex, buf);
handleException();
}
}
FtraceCounter::~FtraceCounter() {
- regfree(®);
+ regfree(&mReg);
+ if (mEnable != NULL) {
+ free(mEnable);
+ }
+}
+
+void FtraceCounter::prepare() {
+ if (mEnable == NULL) {
+ return;
+ }
+
+ char buf[1<<10];
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+ if ((DriverSource::readIntDriver(buf, &mWasEnabled) != 0) ||
+ (DriverSource::writeDriver(buf, 1) != 0)) {
+ logg->logError("Unable to read or write to %s", buf);
+ handleException();
+ }
}
int FtraceCounter::read(const char *const line, int64_t *values) {
regmatch_t match[2];
- int result = regexec(®, line, 2, match, 0);
+ int result = regexec(&mReg, line, 2, match, 0);
if (result != 0) {
// No match
return 0;
}
+ int64_t value;
if (match[1].rm_so < 0) {
- logg->logError(__FILE__, __LINE__, "Parsing %s failed", getName());
- handleException();
- }
-
- errno = 0;
- int64_t value = strtoll(line + match[1].rm_so, NULL, 0);
- if (errno != 0) {
- logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", getName(), strerror(errno));
- handleException();
+ value = 1;
+ } else {
+ errno = 0;
+ value = strtoll(line + match[1].rm_so, NULL, 0);
+ if (errno != 0) {
+ logg->logError("Parsing %s failed: %s", getName(), strerror(errno));
+ handleException();
+ }
}
values[0] = getKey();
return 1;
}
+void FtraceCounter::stop() {
+ if (mEnable == NULL) {
+ return;
+ }
+
+ char buf[1<<10];
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
+ DriverSource::writeDriver(buf, mWasEnabled);
+}
+
FtraceDriver::FtraceDriver() : mValues(NULL) {
}
}
void FtraceDriver::readEvents(mxml_node_t *const xml) {
+ // Check the kernel version
+ int release[3];
+ if (!getLinuxVersion(release)) {
+ logg->logError("getLinuxVersion failed");
+ handleException();
+ }
+
+ // The perf clock was added in 3.10
+ if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 10, 0)) {
+ logg->logMessage("Unsupported kernel version, to use ftrace please upgrade to Linux 3.10 or later");
+ return;
+ }
+
mxml_node_t *node = xml;
int count = 0;
while (true) {
const char *regex = mxmlElementGetAttr(node, "regex");
if (regex == NULL) {
- logg->logError(__FILE__, __LINE__, "The regex counter %s is missing the required regex attribute", counter);
+ logg->logError("The regex counter %s is missing the required regex attribute", counter);
handleException();
}
- setCounters(new FtraceCounter(getCounters(), strdup(counter), regex));
- ++count;
+ bool addCounter = true;
+ const char *enable = mxmlElementGetAttr(node, "enable");
+ if (enable != NULL) {
+ char buf[1<<10];
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", enable);
+ if (access(buf, W_OK) != 0) {
+ logg->logMessage("Disabling counter %s, %s not found", counter, buf);
+ addCounter = false;
+ }
+ }
+ if (addCounter) {
+ setCounters(new FtraceCounter(getCounters(), strdup(counter), regex, enable));
+ ++count;
+ }
}
mValues = new int64_t[2*count];
}
+void FtraceDriver::prepare() {
+ for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ counter->prepare();
+ }
+}
+
int FtraceDriver::read(const char *line, int64_t **buf) {
int count = 0;
*buf = mValues;
return count;
}
+
+void FtraceDriver::stop() {
+ for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ counter->stop();
+ }
+}
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
void readEvents(mxml_node_t *const xml);
+ void prepare();
int read(const char *line, int64_t **buf);
+ void stop();
private:
int64_t *mValues;
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <sys/syscall.h>
#include <unistd.h>
+#include "Child.h"
#include "DriverSource.h"
#include "Logging.h"
#include "SessionData.h"
+extern Child *child;
+
static void handler(int signum)
{
(void)signum;
act.sa_handler = handler;
act.sa_flags = (int)SA_RESETHAND;
if (sigaction(SIGUSR1, &act, NULL) != 0) {
- logg->logError(__FILE__, __LINE__, "sigaction failed: %s\n", strerror(errno));
+ logg->logError("sigaction failed: %s\n", strerror(errno));
handleException();
}
}
+ gSessionData->ftraceDriver.prepare();
+
if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) {
- logg->logError(__FILE__, __LINE__, "Unable to read if ftrace is enabled");
+ logg->logError("Unable to read if ftrace is enabled");
handleException();
}
if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) {
- logg->logError(__FILE__, __LINE__, "Unable to turn ftrace off before truncating the buffer");
+ logg->logError("Unable to turn ftrace off before truncating the buffer");
handleException();
}
int fd;
fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
if (fd < 0) {
- logg->logError(__FILE__, __LINE__, "Unable truncate ftrace buffer: %s", strerror(errno));
+ logg->logError("Unable truncate ftrace buffer: %s", strerror(errno));
handleException();
}
close(fd);
}
if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) {
- logg->logError(__FILE__, __LINE__, "Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
+ logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later");
handleException();
}
mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb");
if (mFtraceFh == NULL) {
- logg->logError(__FILE__, __LINE__, "Unable to open trace_pipe");
+ logg->logError("Unable to open trace_pipe");
handleException();
}
mTid = syscall(__NR_gettid);
if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) {
- logg->logError(__FILE__, __LINE__, "Unable to turn ftrace on");
+ logg->logError("Unable to turn ftrace on");
handleException();
}
+ // Wait until monotonicStarted is set before sending data
+ int64_t monotonicStarted = 0;
+ while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
+ usleep(10);
+
+ if (gSessionData->perf.isSetup()) {
+ monotonicStarted = gSessionData->mMonotonicStarted;
+ } else {
+ if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
+ logg->logError("Error reading gator driver start time");
+ handleException();
+ }
+ }
+ }
+
while (gSessionData->mSessionIsActive) {
char buf[1<<12];
// Interrupted by interrupt - likely user request to terminate
break;
}
- logg->logError(__FILE__, __LINE__, "Unable read trace data: %s", strerror(errno));
+ logg->logError("Unable read trace data: %s", strerror(errno));
handleException();
}
- const uint64_t currTime = getTime();
+ const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
char *const colon = strstr(buf, ": ");
if (colon == NULL) {
- logg->logError(__FILE__, __LINE__, "Unable find colon: %s", buf);
+ if (strstr(buf, " [LOST ") != NULL) {
+ logg->logError("Ftrace events lost, aborting the capture. It is recommended to discard this report and collect a new capture. If this error occurs often, please reduce the number of ftrace counters selected or the amount of ftrace events generated.");
+ } else {
+ logg->logError("Unable to find colon: %s", buf);
+ }
handleException();
}
*colon = '\0';
char *const space = strrchr(buf, ' ');
if (space == NULL) {
- logg->logError(__FILE__, __LINE__, "Unable find space: %s", buf);
+ logg->logError("Unable to find space: %s", buf);
handleException();
}
*colon = ':';
errno = 0;
const long long time = strtod(space, NULL) * 1000000000;
if (errno != 0) {
- logg->logError(__FILE__, __LINE__, "Unable to parse time: %s", strerror(errno));
+ logg->logError("Unable to parse time: %s", strerror(errno));
handleException();
}
mBuffer.event64(-1, time);
}
mBuffer.check(currTime);
+
+ if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) {
+ logg->logMessage("One shot (ftrace)");
+ child->endSession();
+ }
}
}
DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn);
fclose(mFtraceFh);
DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local");
+ gSessionData->ftraceDriver.stop();
}
void FtraceSource::interrupt() {
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
case SENSORS_FEATURE_CURR: return SENSORS_SUBFEATURE_CURR_INPUT;
case SENSORS_FEATURE_HUMIDITY: return SENSORS_SUBFEATURE_HUMIDITY_INPUT;
default:
- logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", type);
+ logg->logError("Unsupported hwmon feature %i", type);
handleException();
}
};
HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature);
~HwmonCounter();
- const char *getLabel() const { return label; }
- const char *getTitle() const { return title; }
- bool isDuplicate() const { return duplicate; }
- const char *getDisplay() const { return display; }
- const char *getCounterClass() const { return counter_class; }
- const char *getUnit() const { return unit; }
- int getModifier() const { return modifier; }
+ const char *getLabel() const { return mLabel; }
+ const char *getTitle() const { return mTitle; }
+ bool isDuplicate() const { return mDuplicate; }
+ const char *getDisplay() const { return mDisplay; }
+ const char *getCounterClass() const { return mCounterClass; }
+ const char *getUnit() const { return mUnit; }
+ double getMultiplier() const { return mMultiplier; }
int64_t read();
private:
void init(const sensors_chip_name *chip, const sensors_feature *feature);
- const sensors_chip_name *chip;
- const sensors_feature *feature;
- char *label;
- const char *title;
- const char *display;
- const char *counter_class;
- const char *unit;
- double previous_value;
- int modifier;
- int monotonic: 1,
- duplicate : 1;
+ const sensors_chip_name *mChip;
+ const sensors_feature *mFeature;
+ char *mLabel;
+ const char *mTitle;
+ const char *mDisplay;
+ const char *mCounterClass;
+ const char *mUnit;
+ double mPreviousValue;
+ double mMultiplier;
+ int mMonotonic: 1,
+ mDuplicate : 1;
// Intentionally unimplemented
HwmonCounter(const HwmonCounter &);
HwmonCounter &operator=(const HwmonCounter &);
};
-HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature) : DriverCounter(next, name), chip(chip), feature(feature), duplicate(false) {
- label = sensors_get_label(chip, feature);
+HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *const chip, const sensors_feature *feature) : DriverCounter(next, name), mChip(chip), mFeature(feature), mDuplicate(false) {
+ mLabel = sensors_get_label(mChip, mFeature);
- switch (feature->type) {
+ switch (mFeature->type) {
case SENSORS_FEATURE_IN:
- title = "Voltage";
- display = "maximum";
- counter_class = "absolute";
- unit = "V";
- modifier = 1000;
- monotonic = false;
+ mTitle = "Voltage";
+ mDisplay = "maximum";
+ mCounterClass = "absolute";
+ mUnit = "V";
+ mMultiplier = 0.001;
+ mMonotonic = false;
break;
case SENSORS_FEATURE_FAN:
- title = "Fan";
- display = "average";
- counter_class = "absolute";
- unit = "RPM";
- modifier = 1;
- monotonic = false;
+ mTitle = "Fan";
+ mDisplay = "average";
+ mCounterClass = "absolute";
+ mUnit = "RPM";
+ mMultiplier = 1.0;
+ mMonotonic = false;
break;
case SENSORS_FEATURE_TEMP:
- title = "Temperature";
- display = "maximum";
- counter_class = "absolute";
- unit = "°C";
- modifier = 1000;
- monotonic = false;
+ mTitle = "Temperature";
+ mDisplay = "maximum";
+ mCounterClass = "absolute";
+ mUnit = "°C";
+ mMultiplier = 0.001;
+ mMonotonic = false;
break;
case SENSORS_FEATURE_POWER:
- title = "Power";
- display = "maximum";
- counter_class = "absolute";
- unit = "W";
- modifier = 1000000;
- monotonic = false;
+ mTitle = "Power";
+ mDisplay = "maximum";
+ mCounterClass = "absolute";
+ mUnit = "W";
+ mMultiplier = 0.000001;
+ mMonotonic = false;
break;
case SENSORS_FEATURE_ENERGY:
- title = "Energy";
- display = "accumulate";
- counter_class = "delta";
- unit = "J";
- modifier = 1000000;
- monotonic = true;
+ mTitle = "Energy";
+ mDisplay = "accumulate";
+ mCounterClass = "delta";
+ mUnit = "J";
+ mMultiplier = 0.000001;
+ mMonotonic = true;
break;
case SENSORS_FEATURE_CURR:
- title = "Current";
- display = "maximum";
- counter_class = "absolute";
- unit = "A";
- modifier = 1000;
- monotonic = false;
+ mTitle = "Current";
+ mDisplay = "maximum";
+ mCounterClass = "absolute";
+ mUnit = "A";
+ mMultiplier = 0.001;
+ mMonotonic = false;
break;
case SENSORS_FEATURE_HUMIDITY:
- title = "Humidity";
- display = "average";
- counter_class = "absolute";
- unit = "%";
- modifier = 1000;
- monotonic = false;
+ mTitle = "Humidity";
+ mDisplay = "average";
+ mCounterClass = "absolute";
+ mUnit = "%";
+ mMultiplier = 0.001;
+ mMonotonic = false;
break;
default:
- logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
+ logg->logError("Unsupported hwmon feature %i", mFeature->type);
handleException();
}
for (HwmonCounter * counter = static_cast<HwmonCounter *>(next); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
- if (strcmp(label, counter->getLabel()) == 0 && strcmp(title, counter->getTitle()) == 0) {
- duplicate = true;
- counter->duplicate = true;
+ if (strcmp(mLabel, counter->getLabel()) == 0 && strcmp(mTitle, counter->getTitle()) == 0) {
+ mDuplicate = true;
+ counter->mDuplicate = true;
break;
}
}
}
HwmonCounter::~HwmonCounter() {
- free((void *)label);
+ free((void *)mLabel);
}
int64_t HwmonCounter::read() {
const sensors_subfeature *subfeature;
// Keep in sync with the read check in HwmonDriver::readEvents
- subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
+ subfeature = sensors_get_subfeature(mChip, mFeature, getInput(mFeature->type));
if (!subfeature) {
- logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
+ logg->logError("No input value for hwmon sensor %s", mLabel);
handleException();
}
- if (sensors_get_value(chip, subfeature->number, &value) != 0) {
- logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label);
+ if (sensors_get_value(mChip, subfeature->number, &value) != 0) {
+ logg->logError("Can't get input value for hwmon sensor %s", mLabel);
handleException();
}
- result = (monotonic ? value - previous_value : value);
- previous_value = value;
+ result = (mMonotonic ? value - mPreviousValue : value);
+ mPreviousValue = value;
return result;
}
void HwmonDriver::writeEvents(mxml_node_t *root) const {
root = mxmlNewElement(root, "category");
- mxmlElementSetAttr(root, "name", "hwmon");
+ mxmlElementSetAttr(root, "name", "Hardware Monitor");
char buf[1024];
for (HwmonCounter *counter = static_cast<HwmonCounter *>(getCounters()); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
mxmlElementSetAttr(node, "display", counter->getDisplay());
mxmlElementSetAttr(node, "class", counter->getCounterClass());
mxmlElementSetAttr(node, "units", counter->getUnit());
- if (counter->getModifier() != 1) {
- mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
+ if (counter->getMultiplier() != 1.0) {
+ mxmlElementSetAttrf(node, "multiplier", "%lf", counter->getMultiplier());
}
if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
mxmlElementSetAttr(node, "average_selection", "yes");
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
if (access(text, F_OK) == 0) {
int count = counter.getCount();
if (DriverSource::writeReadDriver(text, &count) && counter.getCount() > 0) {
- logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount());
+ logg->logError("Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount());
handleException();
}
counter.setCount(count);
} else if (counter.getCount() > 0) {
ConfigurationXML::remove();
- logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y. The invalid configuration.xml has been removed.\n");
+ logg->logError("Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y. The invalid configuration.xml has been removed.\n");
handleException();
}
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
void LocalCapture::createAPCDirectory(char* target_path) {
gSessionData->mAPCDir = createUniqueDirectory(target_path, ".apc");
if ((removeDirAndAllContents(gSessionData->mAPCDir) != 0 || mkdir(gSessionData->mAPCDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)) {
- logg->logError(__FILE__, __LINE__, "Unable to create directory %s", gSessionData->mAPCDir);
+ logg->logError("Unable to create directory %s", gSessionData->mAPCDir);
handleException();
}
}
// Write the file
if (util->writeToDisk(file, string) < 0) {
- logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
+ logg->logError("Error writing %s\nPlease verify the path.", file);
handleException();
}
// Ensure the path is an absolute path, i.e. starts with a slash
if (initialPath == 0 || strlen(initialPath) == 0) {
- logg->logError(__FILE__, __LINE__, "Missing -o command line option required for a local capture.");
+ logg->logError("Missing -o command line option required for a local capture.");
handleException();
} else if (initialPath[0] != '/') {
if (getcwd(path, PATH_MAX) == 0) {
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
Logging::~Logging() {
}
-void Logging::logError(const char* file, int line, const char* fmt, ...) {
+void Logging::_logError(const char *function, const char *file, int line, const char *fmt, ...) {
va_list args;
MUTEX_LOCK();
if (mDebug) {
- snprintf(mErrBuf, sizeof(mErrBuf), "ERROR[%s:%d]: ", file, line);
+ snprintf(mErrBuf, sizeof(mErrBuf), "ERROR: %s(%s:%i): ", function, file, line);
} else {
mErrBuf[0] = 0;
}
MUTEX_UNLOCK();
}
-void Logging::logMessage(const char* fmt, ...) {
+void Logging::_logMessage(const char *function, const char *file, int line, const char *fmt, ...) {
if (mDebug) {
va_list args;
MUTEX_LOCK();
- strcpy(mLogBuf, "INFO: ");
+ snprintf(mLogBuf, sizeof(mLogBuf), "INFO: %s(%s:%i): ", function, file, line);
va_start(args, fmt);
vsnprintf(mLogBuf + strlen(mLogBuf), sizeof(mLogBuf) - 2 - strlen(mLogBuf), fmt, args); // subtract 2 for \n and \0
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
public:
Logging(bool debug);
~Logging();
- void logError(const char* file, int line, const char* fmt, ...);
- void logMessage(const char* fmt, ...);
- char* getLastError() {return mErrBuf;}
- char* getLastMessage() {return mLogBuf;}
+#define logError(...) _logError(__func__, __FILE__, __LINE__, __VA_ARGS__)
+ __attribute__ ((format (printf, 5, 6)))
+ void _logError(const char *function, const char *file, int line, const char *fmt, ...);
+#define logMessage(...) _logMessage(__func__, __FILE__, __LINE__, __VA_ARGS__)
+ __attribute__ ((format (printf, 5, 6)))
+ void _logMessage(const char *function, const char *file, int line, const char *fmt, ...);
+ char *getLastError() {return mErrBuf;}
+ char *getLastMessage() {return mLogBuf;}
private:
char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
pthread_mutex_t mLoggingMutex;
};
-extern Logging* logg;
+extern Logging *logg;
extern void handleException() __attribute__ ((noreturn));
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
while (written < pos) {
size_t bytes = ::write(mveUds, buf + written, pos - written);
if (bytes <= 0) {
- logg->logMessage("%s(%s:%i): write failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("write failed");
return false;
}
written += bytes;
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
}
if (!mBuf.read("/proc/meminfo")) {
- logg->logError(__FILE__, __LINE__, "Failed to read /proc/meminfo");
+ logg->logError("Failed to read /proc/meminfo");
handleException();
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
mFd = epoll_create(16);
#endif
if (mFd < 0) {
- logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("epoll_create1 failed");
return false;
}
#ifndef EPOLL_CLOEXEC
- int fdf = fcntl(mFd, F_GETFD);
- if ((fdf == -1) || (fcntl(mFd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
- logg->logMessage("%s(%s:%i): fcntl failed", __FUNCTION__, __FILE__, __LINE__);
- ::close(mFd);
- return -1;
- }
+ int fdf = fcntl(mFd, F_GETFD);
+ if ((fdf == -1) || (fcntl(mFd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ logg->logMessage("fcntl failed");
+ ::close(mFd);
+ return -1;
+ }
#endif
return true;
event.data.fd = fd;
event.events = EPOLLIN;
if (epoll_ctl(mFd, EPOLL_CTL_ADD, fd, &event) != 0) {
- logg->logMessage("%s(%s:%i): epoll_ctl failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("epoll_ctl failed");
return false;
}
if (errno == EINTR) {
result = 0;
} else {
- logg->logMessage("%s(%s:%i): epoll_wait failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("epoll_wait failed");
}
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
void NetDriver::start() {
if (!doRead()) {
- logg->logError(__FILE__, __LINE__, "Unable to read network stats");
+ logg->logError("Unable to read network stats");
handleException();
}
// Initialize previous values
void NetDriver::read(Buffer *const buffer) {
if (!doRead()) {
- logg->logError(__FILE__, __LINE__, "Unable to read network stats");
+ logg->logError("Unable to read network stats");
handleException();
}
super::read(buffer);
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
+#include <stddef.h>
#endif
#include "Logging.h"
#ifdef WIN32
WSADATA wsaData;
if (WSAStartup(0x0202, &wsaData) != 0) {
- logg->logError(__FILE__, __LINE__, "Windows socket initialization failed");
+ logg->logError("Windows socket initialization failed");
handleException();
}
#endif
__a > __b ? __b : __a; \
})
-OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) {
+OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize, const bool calculateAddrlen) {
// Create socket
mFDServer = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
if (mFDServer < 0) {
- logg->logError(__FILE__, __LINE__, "Error creating server socket");
+ logg->logError("Error creating server socket");
handleException();
}
sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
// Bind the socket to an address
- if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
- logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
+ if (bind(mFDServer, (const struct sockaddr*)&sockaddr, calculateAddrlen ? offsetof(struct sockaddr_un, sun_path) + pathSize - 1 : sizeof(sockaddr)) < 0) {
+ logg->logError("Binding of server socket failed.");
handleException();
}
// Listen for connections on this socket
if (listen(mFDServer, 1) < 0) {
- logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
+ logg->logError("Listening of server socket failed");
handleException();
}
}
-int OlySocket::connect(const char* path, const size_t pathSize) {
+int OlySocket::connect(const char* path, const size_t pathSize, const bool calculateAddrlen) {
int fd = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
return -1;
memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path)));
sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
- if (::connect(fd, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
+ if (::connect(fd, (const struct sockaddr*)&sockaddr, calculateAddrlen ? offsetof(struct sockaddr_un, sun_path) + pathSize - 1 : sizeof(sockaddr)) < 0) {
close(fd);
return -1;
}
}
void OlyServerSocket::closeServerSocket() {
- if (CLOSE_SOCKET(mFDServer) != 0) {
- logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
+ if (mFDServer > 0 && CLOSE_SOCKET(mFDServer) != 0) {
+ logg->logError("Failed to close server socket.");
handleException();
}
- mFDServer = 0;
+ mFDServer = -1;
}
void OlyServerSocket::createServerSocket(int port) {
family = AF_INET;
mFDServer = socket_cloexec(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (mFDServer < 0) {
- logg->logError(__FILE__, __LINE__, "Error creating server socket");
+ logg->logError("Error creating server socket");
handleException();
}
}
// Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
int on = 1;
if (setsockopt(mFDServer, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
- logg->logError(__FILE__, __LINE__, "Setting server socket options failed");
+ logg->logError("Setting server socket reuse option failed");
handleException();
}
+ // Listen on both IPv4 and IPv6
+ on = 0;
+ if (setsockopt(mFDServer, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) != 0) {
+ logg->logMessage("setsockopt IPV6_V6ONLY failed");
+ }
+
// Create sockaddr_in structure, ensuring non-populated fields are zero
struct sockaddr_in6 sockaddr;
memset((void*)&sockaddr, 0, sizeof(sockaddr));
// Bind the socket to an address
if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
- logg->logError(__FILE__, __LINE__, "Binding of server socket failed.\nIs an instance already running?");
+ logg->logError("Binding of server socket on port %i failed.\nIs an instance already running or is another application using that port?", port);
handleException();
}
// Listen for connections on this socket
if (listen(mFDServer, 1) < 0) {
- logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
+ logg->logError("Listening of server socket failed");
handleException();
}
}
int OlyServerSocket::acceptConnection() {
int socketID;
if (mFDServer <= 0) {
- logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
+ logg->logError("Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
handleException();
}
// Accept a connection, note that this call blocks until a client connects
socketID = accept_cloexec(mFDServer, NULL, NULL);
if (socketID < 0) {
- logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
+ logg->logError("Socket acceptance failed");
handleException();
}
return socketID;
while (size > 0) {
int n = ::send(mSocketID, buffer, size, 0);
if (n < 0) {
- logg->logError(__FILE__, __LINE__, "Socket send error");
+ logg->logError("Socket send error");
handleException();
}
size -= n;
int bytes = recv(mSocketID, buffer, size, 0);
if (bytes < 0) {
- logg->logError(__FILE__, __LINE__, "Socket receive error");
+ logg->logError("Socket receive error");
handleException();
} else if (bytes == 0) {
logg->logMessage("Socket disconnected");
while (size > 0 && buffer != NULL) {
bytes = recv(mSocketID, buffer, size, 0);
if (bytes < 0) {
- logg->logError(__FILE__, __LINE__, "Socket receive error");
+ logg->logError("Socket receive error");
handleException();
} else if (bytes == 0) {
logg->logMessage("Socket disconnected");
// Receive a single character
int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0);
if (bytes < 0) {
- logg->logError(__FILE__, __LINE__, "Socket receive error");
+ logg->logError("Socket receive error");
handleException();
} else if (bytes == 0) {
logg->logMessage("Socket disconnected");
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <stddef.h>
#ifdef WIN32
-typedef socklen_t int;
+typedef int socklen_t;
#else
#include <sys/socket.h>
#endif
class OlySocket {
public:
#ifndef WIN32
- static int connect(const char* path, const size_t pathSize);
+ static int connect(const char* path, const size_t pathSize, const bool calculateAddrlen = false);
#endif
OlySocket(int socketID);
public:
OlyServerSocket(int port);
#ifndef WIN32
- OlyServerSocket(const char* path, const size_t pathSize);
+ OlyServerSocket(const char* path, const size_t pathSize, const bool calculateAddrlen = false);
#endif
~OlyServerSocket();
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
bool PerfBuffer::useFd(const int cpu, const int fd) {
if (mFds[cpu] < 0) {
if (mBuf[cpu] != MAP_FAILED) {
- logg->logMessage("%s(%s:%i): cpu %i already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__, cpu);
+ logg->logMessage("cpu %i already online or not correctly cleaned up", cpu);
return false;
}
// The buffer isn't mapped yet
mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mBuf[cpu] == MAP_FAILED) {
- logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("mmap failed");
return false;
}
mFds[cpu] = fd;
// Check the version
struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
if (pemp->compat_version != 0) {
- logg->logMessage("%s(%s:%i): Incompatible perf_event_mmap_page compat_version", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("Incompatible perf_event_mmap_page compat_version");
return false;
}
} else {
if (mBuf[cpu] == MAP_FAILED) {
- logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("cpu already online or not correctly cleaned up");
return false;
}
if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, mFds[cpu]) < 0) {
- logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("ioctl failed");
return false;
}
}
if (mBuf[cpu] != MAP_FAILED) {
// Take a snapshot of the positions
struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
- const __u64 head = pemp->data_head;
- const __u64 tail = pemp->data_tail;
+ const __u64 head = ACCESS_ONCE(pemp->data_head);
+ const __u64 tail = ACCESS_ONCE(pemp->data_tail);
if (head != tail) {
return false;
return true;
}
-static void compressAndSend(const int cpu, const __u64 head, __u64 tail, const uint8_t *const b, Sender *const sender) {
- // Pick a big size but something smaller than the chunkSize in Sender::writeData which is 100k
- char buf[1<<16];
- int writePos = 0;
- const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
+bool PerfBuffer::isFull() {
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ if (mBuf[cpu] != MAP_FAILED) {
+ // Take a snapshot of the positions
+ struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
+ const __u64 head = ACCESS_ONCE(pemp->data_head);
- while (head > tail) {
- writePos = 0;
- if (!gSessionData->mLocalCapture) {
- buf[writePos++] = RESPONSE_APC_DATA;
+ if (head + 2000 <= (unsigned int)BUF_SIZE) {
+ return true;
+ }
}
- // Reserve space for size
- writePos += sizeof(uint32_t);
- Buffer::packInt(buf, sizeof(buf), writePos, FRAME_PERF);
- Buffer::packInt(buf, sizeof(buf), writePos, cpu);
+ }
+
+ return false;
+}
+
+class PerfFrame {
+public:
+ PerfFrame(Sender *const sender) : mSender(sender), mWritePos(-1), mCpuSizePos(-1) {}
+
+ void add(const int cpu, const __u64 head, __u64 tail, const uint8_t *const b) {
+ cpuHeader(cpu);
while (head > tail) {
const int count = reinterpret_cast<const struct perf_event_header *>(b + (tail & BUF_MASK))->size/sizeof(uint64_t);
// Can this whole message be written as Streamline assumes events are not split between frames
- if (sizeof(buf) <= writePos + count*Buffer::MAXSIZE_PACK64) {
- break;
+ if (sizeof(mBuf) <= mWritePos + count*Buffer::MAXSIZE_PACK64) {
+ send();
+ cpuHeader(cpu);
}
for (int i = 0; i < count; ++i) {
// Must account for message size
- Buffer::packInt64(buf, sizeof(buf), writePos, *reinterpret_cast<const uint64_t *>(b + (tail & BUF_MASK)));
+ Buffer::packInt64(mBuf, sizeof(mBuf), mWritePos, *reinterpret_cast<const uint64_t *>(b + (tail & BUF_MASK)));
tail += sizeof(uint64_t);
}
}
+ }
+
+ void send() {
+ if (mWritePos > 0) {
+ writeFrameSize();
+ mSender->writeData(mBuf, mWritePos, RESPONSE_APC_DATA);
+ mWritePos = -1;
+ mCpuSizePos = -1;
+ }
+ }
- // Write size
- Buffer::writeLEInt(reinterpret_cast<unsigned char *>(buf + typeLength), writePos - typeLength - sizeof(uint32_t));
- sender->writeData(buf, writePos, RESPONSE_APC_DATA);
+private:
+ void writeFrameSize() {
+ writeCpuSize();
+ const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
+ Buffer::writeLEInt(reinterpret_cast<unsigned char *>(mBuf + typeLength), mWritePos - typeLength - sizeof(uint32_t));
}
-}
+
+ void frameHeader() {
+ if (mWritePos < 0) {
+ mWritePos = 0;
+ mCpuSizePos = -1;
+ if (!gSessionData->mLocalCapture) {
+ mBuf[mWritePos++] = RESPONSE_APC_DATA;
+ }
+ // Reserve space for frame size
+ mWritePos += sizeof(uint32_t);
+ Buffer::packInt(mBuf, sizeof(mBuf), mWritePos, FRAME_PERF);
+ }
+ }
+
+ void writeCpuSize() {
+ if (mCpuSizePos >= 0) {
+ Buffer::writeLEInt(reinterpret_cast<unsigned char *>(mBuf + mCpuSizePos), mWritePos - mCpuSizePos - sizeof(uint32_t));
+ }
+ }
+
+ void cpuHeader(const int cpu) {
+ if (sizeof(mBuf) <= mWritePos + Buffer::MAXSIZE_PACK32 + sizeof(uint32_t)) {
+ send();
+ }
+ frameHeader();
+ writeCpuSize();
+ Buffer::packInt(mBuf, sizeof(mBuf), mWritePos, cpu);
+ mCpuSizePos = mWritePos;
+ // Reserve space for cpu size
+ mWritePos += sizeof(uint32_t);
+ }
+
+ // Pick a big size but something smaller than the chunkSize in Sender::writeData which is 100k
+ char mBuf[1<<16];
+ Sender *const mSender;
+ int mWritePos;
+ int mCpuSizePos;
+
+ // Intentionally unimplemented
+ PerfFrame(const PerfFrame &);
+ PerfFrame& operator=(const PerfFrame &);
+};
bool PerfBuffer::send(Sender *const sender) {
+ PerfFrame frame(sender);
+
for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
if (mBuf[cpu] == MAP_FAILED) {
continue;
// Take a snapshot of the positions
struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
- const __u64 head = pemp->data_head;
- const __u64 tail = pemp->data_tail;
+ const __u64 head = ACCESS_ONCE(pemp->data_head);
+ const __u64 tail = ACCESS_ONCE(pemp->data_tail);
if (head > tail) {
const uint8_t *const b = static_cast<uint8_t *>(mBuf[cpu]) + gSessionData->mPageSize;
- compressAndSend(cpu, head, tail, b, sender);
+ frame.add(cpu, head, tail, b);
// Update tail with the data read
pemp->data_tail = head;
mBuf[cpu] = MAP_FAILED;
mDiscard[cpu] = false;
mFds[cpu] = -1;
- logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+ logg->logMessage("Unmaped cpu %i", cpu);
}
}
+ frame.send();
+
return true;
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
bool useFd(const int cpu, const int fd);
void discard(const int cpu);
bool isEmpty();
+ bool isFull();
bool send(Sender *const sender);
private:
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
// From gator_main.c
static const struct gator_cpu gator_cpus[] = {
- { 0xb36, "ARM1136", "ARM_ARM11", 3 },
- { 0xb56, "ARM1156", "ARM_ARM11", 3 },
- { 0xb76, "ARM1176", "ARM_ARM11", 3 },
- { 0xb02, "ARM11MPCore", "ARM_ARM11MPCore", 3 },
- { 0xc05, "Cortex-A5", "ARMv7_Cortex_A5", 2 },
- { 0xc07, "Cortex-A7", "ARMv7_Cortex_A7", 4 },
- { 0xc08, "Cortex-A8", "ARMv7_Cortex_A8", 4 },
- { 0xc09, "Cortex-A9", "ARMv7_Cortex_A9", 6 },
- { 0xc0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 },
- { 0xc0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
- { 0x00f, "Scorpion", "Scorpion", 4 },
- { 0x02d, "ScorpionMP", "ScorpionMP", 4 },
- { 0x049, "KraitSIM", "Krait", 4 },
- { 0x04d, "Krait", "Krait", 4 },
- { 0x06f, "Krait S4 Pro", "Krait", 4 },
- { 0xd03, "Cortex-A53", "ARM_Cortex-A53", 6 },
- { 0xd07, "Cortex-A57", "ARM_Cortex-A57", 6 },
- { 0xd0f, "AArch64", "ARM_AArch64", 6 },
+ { 0x41b36, "ARM1136", "ARM_ARM11", 3 },
+ { 0x41b56, "ARM1156", "ARM_ARM11", 3 },
+ { 0x41b76, "ARM1176", "ARM_ARM11", 3 },
+ { 0x41b02, "ARM11MPCore", "ARM_ARM11MPCore", 3 },
+ { 0x41c05, "Cortex-A5", "ARMv7_Cortex_A5", 2 },
+ { 0x41c07, "Cortex-A7", "ARMv7_Cortex_A7", 4 },
+ { 0x41c08, "Cortex-A8", "ARMv7_Cortex_A8", 4 },
+ { 0x41c09, "Cortex-A9", "ARMv7_Cortex_A9", 6 },
+ { 0x41c0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 },
+ { 0x41c0d, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
+ { 0x41c0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
+ { 0x5100f, "Scorpion", "Scorpion", 4 },
+ { 0x5102d, "ScorpionMP", "ScorpionMP", 4 },
+ { 0x51049, "KraitSIM", "Krait", 4 },
+ { 0x5104d, "Krait", "Krait", 4 },
+ { 0x5106f, "Krait S4 Pro", "Krait", 4 },
+ { 0x41d03, "Cortex-A53", "ARM_Cortex-A53", 6 },
+ { 0x41d07, "Cortex-A57", "ARM_Cortex-A57", 6 },
+ { 0x41d08, "Cortex-A72", "ARM_Cortex-A72", 6 },
};
static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
// gatorfs event name
const char *const gatorName;
const int count;
+ const bool hasCyclesCounter;
};
static const struct uncore_counter uncore_counters[] = {
- { "CCI_400", "CCI_400", 4 },
- { "CCI_400-r1", "CCI_400-r1", 4 },
- { "ccn", "ARM_CCN_5XX", 8 },
+ { "CCI_400", "CCI_400", 4, true },
+ { "CCI_400-r1", "CCI_400-r1", 4, true },
+ { "CCI_500", "CCI_500", 8, false },
+ { "ccn", "ARM_CCN_5XX", 8, true },
};
class PerfCounter : public DriverCounter {
public:
- PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, bool perCpu) : DriverCounter(next, name), mType(type), mCount(0), mConfig(config), mPerCpu(perCpu) {}
+ PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(0) {}
~PerfCounter() {
}
void setCount(const int count) { mCount = count; }
uint64_t getConfig() const { return mConfig; }
void setConfig(const uint64_t config) { mConfig = config; }
- bool isPerCpu() const { return mPerCpu; }
+ uint64_t getSampleType() const { return mSampleType; }
+ uint64_t getFlags() const { return mFlags; }
+ virtual void read(Buffer *const, const int) {}
private:
const uint32_t mType;
- int mCount;
uint64_t mConfig;
- bool mPerCpu;
+ const uint64_t mSampleType;
+ const uint64_t mFlags;
+ int mCount;
+
+ // Intentionally undefined
+ PerfCounter(const PerfCounter &);
+ PerfCounter &operator=(const PerfCounter &);
+};
+
+class CPUFreqDriver : public PerfCounter {
+public:
+ CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU) {}
+
+ void read(Buffer *const buffer, const int cpu) {
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%i/cpufreq/cpuinfo_cur_freq", cpu);
+ int64_t freq;
+ if (DriverSource::readInt64Driver(buf, &freq) != 0) {
+ freq = 0;
+ }
+ buffer->perfCounter(cpu, getKey(), 1000*freq);
+ }
+
+private:
+ // Intentionally undefined
+ CPUFreqDriver(const CPUFreqDriver &);
+ CPUFreqDriver &operator=(const CPUFreqDriver &);
};
PerfDriver::PerfDriver() : mIsSetup(false), mLegacySupport(false) {
int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
char *name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, true));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, true));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
}
}
-void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters) {
- int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
- char *name = new char[len];
- snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, false));
+void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters, const bool hasCyclesCounter) {
+ int len;
+ char *name;
+
+ if (hasCyclesCounter) {
+ len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
+ name = new char[len];
+ snprintf(name, len, "%s_ccnt", counterName);
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+ }
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, false));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
}
}
// Check the kernel version
int release[3];
if (!getLinuxVersion(release)) {
- logg->logMessage("%s(%s:%i): getLinuxVersion failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("getLinuxVersion failed");
return false;
}
if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 4, 0)) {
- logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("Unsupported kernel version");
return false;
}
mLegacySupport = KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0);
if (access(EVENTS_PATH, R_OK) != 0) {
- logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER enabled?", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage(EVENTS_PATH " does not exist, is CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER enabled?");
return false;
}
bool foundCpu = false;
DIR *dir = opendir(PERF_DEVICES);
if (dir == NULL) {
- logg->logMessage("%s(%s:%i): opendif failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("opendir failed");
return false;
}
}
logg->logMessage("Adding uncore counters for %s", uncore_counters[i].gatorName);
- addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count);
+ addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count, uncore_counters[i].hasCyclesCounter);
}
}
closedir(dir);
}
}
- /*
if (!foundCpu) {
- // If all else fails, use the perf architected counters
- // 9 because that's how many are in events-Perf-Hardware.xml - assume they can all be enabled at once
- addCpuCounters("Perf_Hardware", PERF_TYPE_HARDWARE, 9);
+ // If all else fails, use the ARM architected counters
+ logg->logMessage("Using Other cpu");
+ addCpuCounters("Other", PERF_TYPE_RAW, 6);
}
- */
// Add supported software counters
long long id;
id = getTracepointId("irq/softirq_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
}
id = getTracepointId("irq/irq_handler_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
}
id = getTracepointId(SCHED_SWITCH, &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true));
+ setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ }
+
+ id = getTracepointId(CPU_FREQUENCY, &printb);
+ if (id >= 0) {
+ setCounters(new CPUFreqDriver(getCounters(), id));
}
- setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false));
+ setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0));
//Linux_cpu_wait_io
bool PerfDriver::summary(Buffer *const buffer) {
struct utsname utsname;
if (uname(&utsname) != 0) {
- logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("uname failed");
return false;
}
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
- logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("clock_gettime failed");
return false;
}
const int64_t timestamp = (int64_t)ts.tv_sec * NS_PER_S + ts.tv_nsec;
const uint64_t monotonicStarted = getTime();
gSessionData->mMonotonicStarted = monotonicStarted;
+ const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted;
- buffer->summary(monotonicStarted, timestamp, monotonicStarted, monotonicStarted, buf);
+ buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf);
for (int i = 0; i < gSessionData->mCores; ++i) {
- coreName(monotonicStarted, buffer, i);
+ coreName(currTime, buffer, i);
}
- buffer->commit(monotonicStarted);
+ buffer->commit(currTime);
return true;
}
-void PerfDriver::coreName(const uint32_t startTime, Buffer *const buffer, const int cpu) {
+void PerfDriver::coreName(const uint64_t currTime, Buffer *const buffer, const int cpu) {
// Don't send information on a cpu we know nothing about
if (gSessionData->mCpuIds[cpu] == -1) {
return;
break;
}
}
- if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
- buffer->coreName(startTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name);
+ if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
+ buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name);
} else {
char buf[32];
if (gSessionData->mCpuIds[cpu] == -1) {
} else {
snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[cpu]);
}
- buffer->coreName(startTime, cpu, gSessionData->mCpuIds[cpu], buf);
+ buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], buf);
}
}
bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const {
for (PerfCounter *counter = static_cast<PerfCounter *>(getCounters()); counter != NULL; counter = static_cast<PerfCounter *>(counter->getNext())) {
if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
- if (!group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0, counter->isPerCpu() ? PERF_GROUP_PER_CPU : 0)) {
- logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__);
+ int count = counter->getCount();
+ uint64_t sampleType = counter->getSampleType();
+ if (sampleType & PERF_SAMPLE_RAW) {
+ // If raw is enabled, every sample is needed
+ count = 1;
+ }
+ if (!group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), count,
+ // use getCount instead of count as EBS counters need TID and IP but RAW tracepoints don't
+ (counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0) | sampleType,
+ counter->getFlags())) {
+ logg->logMessage("PerfGroup::add failed");
return false;
}
}
return true;
}
+void PerfDriver::read(Buffer *const buffer, const int cpu) {
+ for (PerfCounter *counter = static_cast<PerfCounter *>(getCounters()); counter != NULL; counter = static_cast<PerfCounter *>(counter->getNext())) {
+ if (!counter->isEnabled()) {
+ continue;
+ }
+ counter->read(buffer, cpu);
+ }
+}
+
long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
return -1;
}
int64_t result;
if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
- logg->logMessage("%s(%s:%i): DriverSource::readInt64Driver failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DriverSource::readInt64Driver failed");
return -1;
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#define SCHED_SWITCH "sched/sched_switch"
#define CPU_IDLE "power/cpu_idle"
+#define CPU_FREQUENCY "power/cpu_frequency"
class Buffer;
class DynBuf;
bool setup();
bool summary(Buffer *const buffer);
- void coreName(const uint32_t startTime, Buffer *const buffer, const int cpu);
+ void coreName(const uint64_t currTime, Buffer *const buffer, const int cpu);
bool isSetup() const { return mIsSetup; }
void setupCounter(Counter &counter);
bool enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const;
+ void read(Buffer *const buffer, const int cpu);
static long long getTracepointId(const char *const name, DynBuf *const printb);
private:
void addCpuCounters(const char *const counterName, const int type, const int numCounters);
- void addUncoreCounters(const char *const counterName, const int type, const int numCounters);
+ void addUncoreCounters(const char *const counterName, const int type, const int numCounters, const bool hasCyclesCounter);
bool mIsSetup;
bool mLegacySupport;
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <unistd.h>
#include "Buffer.h"
+#include "DynBuf.h"
#include "Logging.h"
#include "Monitor.h"
#include "PerfBuffer.h"
#include "SessionData.h"
+static const int schedSwitchKey = getEventKey();
+static const int clockKey = getEventKey();
+
#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
pea.size = sizeof(pea); \
/* Emit time, read_format below, group leader id, and raw tracepoint info */ \
pea.sample_type = (gSessionData->perf.getLegacySupport() \
- ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_ID \
- : PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER ) | additionalSampleType; \
+ ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_ID \
+ : PERF_SAMPLE_IDENTIFIER ) | PERF_SAMPLE_TIME | additionalSampleType; \
/* Emit emit value in group format */ \
pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \
/* start out disabled */ \
return fd;
}
-PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) {
+PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb), mSchedSwitchId(-1) {
memset(&mAttrs, 0, sizeof(mAttrs));
- memset(&mPerCpu, 0, sizeof(mPerCpu));
+ memset(&mFlags, 0, sizeof(mFlags));
memset(&mKeys, -1, sizeof(mKeys));
memset(&mFds, -1, sizeof(mFds));
+ memset(&mLeaders, -1, sizeof(mLeaders));
}
PerfGroup::~PerfGroup() {
}
}
-bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
+int PerfGroup::doAdd(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
int i;
for (i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
if (mKeys[i] < 0) {
}
if (i >= ARRAY_LENGTH(mKeys)) {
- logg->logMessage("%s(%s:%i): Too many counters", __FUNCTION__, __FILE__, __LINE__);
- return false;
+ logg->logMessage("Too many counters");
+ return -1;
}
DEFAULT_PEA_ARGS(mAttrs[i], sampleType);
mAttrs[i].config = config;
mAttrs[i].sample_period = sample;
// always be on the CPU but only a group leader can be pinned
- mAttrs[i].pinned = (i == 0 ? 1 : 0);
+ mAttrs[i].pinned = (flags & PERF_GROUP_LEADER ? 1 : 0);
mAttrs[i].mmap = (flags & PERF_GROUP_MMAP ? 1 : 0);
mAttrs[i].comm = (flags & PERF_GROUP_COMM ? 1 : 0);
mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0);
mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0);
mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0);
- mPerCpu[i] = (flags & PERF_GROUP_PER_CPU);
+ mFlags[i] = flags;
mKeys[i] = key;
- buffer->pea(currTime, &mAttrs[i], key);
+ buffer->marshalPea(currTime, &mAttrs[i], key);
+
+ return i;
+}
+
+/* Counters from different hardware PMUs need to be in different
+ * groups. Software counters can be in the same group as the CPU and
+ * should be marked as PERF_GROUP_CPU. The big and little clusters can
+ * be in the same group as only one or the other will be available on
+ * a given CPU.
+ */
+int PerfGroup::getEffectiveType(const int type, const int flags) {
+ const int effectiveType = flags & PERF_GROUP_CPU ? (int)PERF_TYPE_HARDWARE : type;
+ if (effectiveType >= ARRAY_LENGTH(mLeaders)) {
+ logg->logError("perf type is too large, please increase the size of PerfGroup::mLeaders");
+ handleException();
+ }
+ return effectiveType;
+}
+
+bool PerfGroup::createCpuGroup(const uint64_t currTime, Buffer *const buffer) {
+ if (mSchedSwitchId < 0) {
+ DynBuf b;
+ mSchedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &b);
+ if (mSchedSwitchId < 0) {
+ logg->logMessage("Unable to read sched_switch id");
+ return false;
+ }
+ }
+
+ mLeaders[PERF_TYPE_HARDWARE] = doAdd(currTime, buffer, schedSwitchKey, PERF_TYPE_TRACEPOINT, mSchedSwitchId, 1, PERF_SAMPLE_READ | PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL | PERF_GROUP_PER_CPU | PERF_GROUP_LEADER | PERF_GROUP_CPU);
+ if (mLeaders[PERF_TYPE_HARDWARE] < 0) {
+ return false;
+ }
+
+ if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) {
+ return false;
+ }
return true;
}
+bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
+ const int effectiveType = getEffectiveType(type, flags);
+
+ // Does a group exist for this already?
+ if (!(flags & PERF_GROUP_LEADER) && mLeaders[effectiveType] < 0) {
+ // Create it
+ if (effectiveType == PERF_TYPE_HARDWARE) {
+ if (!createCpuGroup(currTime, buffer)) {
+ return false;
+ }
+ } else {
+ // Non-CPU PMUs are sampled every 100ms for Sample Rate: None and EBS, otherwise they would never be sampled
+ const uint64_t timeout = gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS ? 1000000000UL / gSessionData->mSampleRate : 100000000UL;
+ // PERF_SAMPLE_TID | PERF_SAMPLE_IP aren't helpful on non-CPU or 'uncore' PMUs - which CPU is the right one to sample? But removing it causes problems, remove it later.
+ mLeaders[effectiveType] = doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_LEADER);
+ if (mLeaders[effectiveType] < 0) {
+ return false;
+ }
+ }
+ }
+
+ if (!(flags & PERF_GROUP_LEADER) && effectiveType != PERF_TYPE_HARDWARE && (flags & PERF_GROUP_PER_CPU)) {
+ logg->logError("'uncore' counters are not permitted to be per-cpu");
+ handleException();
+ }
+
+ return doAdd(currTime, buffer, key, type, config, sample, sampleType, flags) >= 0;
+}
+
int PerfGroup::prepareCPU(const int cpu, Monitor *const monitor) {
- logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+ logg->logMessage("Onlining cpu %i", cpu);
for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
if (mKeys[i] < 0) {
continue;
}
- if ((cpu != 0) && !mPerCpu[i]) {
+ if ((cpu != 0) && !(mFlags[i] & PERF_GROUP_PER_CPU)) {
continue;
}
- const int offset = i * gSessionData->mCores;
- if (mFds[cpu + offset] >= 0) {
- logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
+ const int offset = i * gSessionData->mCores + cpu;
+ if (mFds[offset] >= 0) {
+ logg->logMessage("cpu already online or not correctly cleaned up");
return PG_FAILURE;
}
- logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: 0x%llx pinned: %i mmap: %i comm: %i freq: %i task: %i sample_id_all: %i", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type, mAttrs[i].pinned, mAttrs[i].mmap, mAttrs[i].comm, mAttrs[i].freq, mAttrs[i].task, mAttrs[i].sample_id_all);
- mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT);
- if (mFds[cpu + offset] < 0) {
- logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno));
+ logg->logMessage("perf_event_open cpu: %i type: %i config: %lli sample: %lli sample_type: 0x%llx pinned: %lli mmap: %lli comm: %lli freq: %lli task: %lli sample_id_all: %lli", cpu, mAttrs[i].type, mAttrs[i].config, mAttrs[i].sample_period, mAttrs[i].sample_type, mAttrs[i].pinned, mAttrs[i].mmap, mAttrs[i].comm, mAttrs[i].freq, mAttrs[i].task, mAttrs[i].sample_id_all);
+ mFds[offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, mAttrs[i].pinned ? -1 : mFds[mLeaders[getEffectiveType(mAttrs[i].type, mFlags[i])] * gSessionData->mCores + cpu], mAttrs[i].pinned ? 0 : PERF_FLAG_FD_OUTPUT);
+ if (mFds[offset] < 0) {
+ logg->logMessage("failed %s", strerror(errno));
if (errno == ENODEV) {
+ // The core is offline
return PG_CPU_OFFLINE;
}
+#ifndef USE_STRICTER_CHECK
continue;
+#else
+ if (errno == ENOENT) {
+ // This event doesn't apply to this CPU but should apply to a different one, ex bL
+ continue;
+ }
+ logg->logMessage("perf_event_open failed");
+ return PG_FAILURE;
+#endif
}
- if (!mPb->useFd(cpu, mFds[cpu + offset])) {
- logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__);
+ if (!mPb->useFd(cpu, mFds[offset])) {
+ logg->logMessage("PerfBuffer::useFd failed");
return PG_FAILURE;
}
- if (!monitor->add(mFds[cpu + offset])) {
- logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
- return PG_FAILURE;
+ if (!monitor->add(mFds[offset])) {
+ logg->logMessage("Monitor::add failed");
+ return PG_FAILURE;
}
}
return PG_SUCCESS;
}
-int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool start, Buffer *const buffer) {
- __u64 ids[ARRAY_LENGTH(mKeys)];
- int coreKeys[ARRAY_LENGTH(mKeys)];
- int idCount = 0;
+static bool readAndSend(const uint64_t currTime, Buffer *const buffer, const int fd, const int keyCount, const int *const keys) {
+ char buf[1024];
+ ssize_t bytes = read(fd, buf, sizeof(buf));
+ if (bytes < 0) {
+ logg->logMessage("read failed");
+ return false;
+ }
+ buffer->marshalKeysOld(currTime, keyCount, keys, bytes, buf);
- for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
- const int fd = mFds[cpu + i * gSessionData->mCores];
- if (fd < 0) {
- continue;
- }
+ return true;
+}
- coreKeys[idCount] = mKeys[i];
- if (!gSessionData->perf.getLegacySupport() && ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0 &&
- // Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works
- ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) {
- logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
- return 0;
- }
- ++idCount;
- }
+int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool enable, Buffer *const buffer) {
+ bool addedEvents = false;
if (!gSessionData->perf.getLegacySupport()) {
- buffer->keys(currTime, idCount, ids, coreKeys);
+ int idCount = 0;
+ int coreKeys[ARRAY_LENGTH(mKeys)];
+ __u64 ids[ARRAY_LENGTH(mKeys)];
+
+ for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ const int fd = mFds[cpu + i * gSessionData->mCores];
+ if (fd < 0) {
+ continue;
+ }
+
+ coreKeys[idCount] = mKeys[i];
+ if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0 &&
+ // Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works
+ ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) {
+ logg->logMessage("ioctl failed");
+ return 0;
+ }
+ ++idCount;
+ addedEvents = true;
+ }
+
+ buffer->marshalKeys(currTime, idCount, ids, coreKeys);
} else {
- char buf[1024];
- ssize_t bytes = read(mFds[cpu], buf, sizeof(buf));
- if (bytes < 0) {
- logg->logMessage("read failed");
- return 0;
+ int idCounts[ARRAY_LENGTH(mLeaders)] = { 0 };
+ int coreKeys[ARRAY_LENGTH(mLeaders)][ARRAY_LENGTH(mKeys)];
+ for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ const int fd = mFds[cpu + i * gSessionData->mCores];
+ if (fd < 0) {
+ continue;
+ }
+
+ const int effectiveType = getEffectiveType(mAttrs[i].type, mFlags[i]);
+ if (mAttrs[i].pinned && mLeaders[effectiveType] != i) {
+ if (!readAndSend(currTime, buffer, fd, 1, mKeys + i)) {
+ return 0;
+ }
+ } else {
+ coreKeys[effectiveType][idCounts[effectiveType]] = mKeys[i];
+ ++idCounts[effectiveType];
+ addedEvents = true;
+ }
+ }
+
+ for (int i = 0; i < ARRAY_LENGTH(mLeaders); ++i) {
+ if (idCounts[i] > 0 && !readAndSend(currTime, buffer, mFds[mLeaders[i] * gSessionData->mCores + cpu], idCounts[i], coreKeys[i])) {
+ return 0;
+ }
}
- buffer->keysOld(currTime, idCount, coreKeys, bytes, buf);
}
- if (start) {
+ if (enable) {
for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
int offset = i * gSessionData->mCores + cpu;
if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE, 0) < 0) {
- logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("ioctl failed");
return 0;
}
}
}
- if (idCount == 0) {
- logg->logMessage("%s(%s:%i): no events came online", __FUNCTION__, __FILE__, __LINE__);
+ if (!addedEvents) {
+ logg->logMessage("no events came online");
}
- return idCount;
+ return 1;
}
bool PerfGroup::offlineCPU(const int cpu) {
- logg->logMessage("%s(%s:%i): Offlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
+ logg->logMessage("Offlining cpu %i", cpu);
- for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ for (int i = ARRAY_LENGTH(mKeys) - 1; i >= 0; --i) {
int offset = i * gSessionData->mCores + cpu;
if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE, 0) < 0) {
- logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("ioctl failed");
return false;
}
}
// Mark the buffer so that it will be released next time it's read
mPb->discard(cpu);
- for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
+ for (int i = ARRAY_LENGTH(mKeys) - 1; i >= 0; --i) {
if (mKeys[i] < 0) {
continue;
}
bool PerfGroup::start() {
for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) {
if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE, 0) < 0) {
- logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("ioctl failed");
goto fail;
}
}
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
PERF_GROUP_TASK = 1 << 3,
PERF_GROUP_SAMPLE_ID_ALL = 1 << 4,
PERF_GROUP_PER_CPU = 1 << 5,
+ PERF_GROUP_LEADER = 1 << 6,
+ PERF_GROUP_CPU = 1 << 7,
};
enum {
PerfGroup(PerfBuffer *const pb);
~PerfGroup();
+ bool createCpuGroup(const uint64_t currTime, Buffer *const buffer);
bool add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
// Safe to call concurrently
int prepareCPU(const int cpu, Monitor *const monitor);
// Not safe to call concurrently. Returns the number of events enabled
- int onlineCPU(const uint64_t currTime, const int cpu, const bool start, Buffer *const buffer);
+ int onlineCPU(const uint64_t currTime, const int cpu, const bool enable, Buffer *const buffer);
bool offlineCPU(int cpu);
bool start();
void stop();
private:
- // +1 for the group leader
- struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1];
- bool mPerCpu[MAX_PERFORMANCE_COUNTERS + 1];
- int mKeys[MAX_PERFORMANCE_COUNTERS + 1];
- int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)];
+ int getEffectiveType(const int type, const int flags);
+ int doAdd(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
+
+ // 2* to be conservative for sched_switch, cpu_idle, hrtimer and non-CPU groups
+ struct perf_event_attr mAttrs[2*MAX_PERFORMANCE_COUNTERS];
PerfBuffer *const mPb;
+ int mFlags[2*MAX_PERFORMANCE_COUNTERS];
+ int mKeys[2*MAX_PERFORMANCE_COUNTERS];
+ int mFds[NR_CPUS * (2*MAX_PERFORMANCE_COUNTERS)];
+ // Offset in mAttrs, mFlags and mKeys of the group leaders for each perf type
+ int mLeaders[16];
+ int mSchedSwitchId;
// Intentionally undefined
PerfGroup(const PerfGroup &);
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
extern Child *child;
+static const int cpuIdleKey = getEventKey();
+
static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
return false;
}
if (!b->read(printb->getBuf())) {
- logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::read failed");
return false;
}
- buffer->format(currTime, b->getLength(), b->getBuf());
+ buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
return true;
}
{
sigset_t set;
if (sigfillset(&set) != 0) {
- logg->logError(__FILE__, __LINE__, "sigfillset failed");
+ logg->logError("sigfillset failed");
handleException();
}
if ((err = pthread_sigmask(SIG_SETMASK, &set, NULL)) != 0) {
- logg->logError(__FILE__, __LINE__, "pthread_sigmask failed");
+ logg->logError("pthread_sigmask failed");
handleException();
}
}
for (;;) {
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
- logg->logError(__FILE__, __LINE__, "clock_gettime failed");
+ logg->logError("clock_gettime failed");
handleException();
}
const int64_t currTime = ts.tv_sec * NS_PER_S + ts.tv_nsec;
static long getMaxCoreNum() {
DIR *dir = opendir("/sys/devices/system/cpu");
if (dir == NULL) {
- logg->logError(__FILE__, __LINE__, "Unable to determine the number of cores on the target, opendir failed");
+ logg->logError("Unable to determine the number of cores on the target, opendir failed");
handleException();
}
closedir(dir);
if (maxCoreNum < 1) {
- logg->logError(__FILE__, __LINE__, "Unable to determine the number of cores on the target, no cpu# directories found");
+ logg->logError("Unable to determine the number of cores on the target, no cpu# directories found");
handleException();
}
if (maxCoreNum >= NR_CPUS) {
- logg->logError(__FILE__, __LINE__, "Too many cores on the target, please increase NR_CPUS in Config.h");
+ logg->logError("Too many cores on the target, please increase NR_CPUS in Config.h");
handleException();
}
return maxCoreNum;
}
-PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mIdleGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) {
+PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(NULL), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) {
long l = sysconf(_SC_PAGE_SIZE);
if (l < 0) {
- logg->logError(__FILE__, __LINE__, "Unable to obtain the page size");
+ logg->logError("Unable to obtain the page size");
handleException();
}
gSessionData->mPageSize = static_cast<int>(l);
}
PerfSource::~PerfSource() {
+ delete mBuffer;
}
bool PerfSource::prepare() {
DynBuf printb;
DynBuf b1;
- long long schedSwitchId;
long long cpuIdleId;
- const uint64_t currTime = getTime();
+ // MonotonicStarted has not yet been assigned!
+ const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted;
+
+ mBuffer = new Buffer(0, FRAME_PERF_ATTRS, gSessionData->mTotalBufferSize*1024*1024, mSenderSem);
// Reread cpuinfo since cores may have changed since startup
gSessionData->readCpuInfo();
|| !mUEvent.init()
|| !mMonitor.add(mUEvent.getFd())
- || (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0
- || !sendTracepointFormat(currTime, &mBuffer, SCHED_SWITCH, &printb, &b1)
+ || !sendTracepointFormat(currTime, mBuffer, SCHED_SWITCH, &printb, &b1)
|| (cpuIdleId = PerfDriver::getTracepointId(CPU_IDLE, &printb)) < 0
- || !sendTracepointFormat(currTime, &mBuffer, CPU_IDLE, &printb, &b1)
+ || !sendTracepointFormat(currTime, mBuffer, CPU_IDLE, &printb, &b1)
- // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID
- || !mCountersGroup.add(currTime, &mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL | PERF_GROUP_PER_CPU)
- || !mIdleGroup.add(currTime, &mBuffer, 101/**/, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_PER_CPU)
+ || !sendTracepointFormat(currTime, mBuffer, CPU_FREQUENCY, &printb, &b1)
- // Only want TID and IP but not RAW on timer
- || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(currTime, &mBuffer, 102/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, PERF_GROUP_PER_CPU))
+ || !mCountersGroup.createCpuGroup(currTime, mBuffer)
+ || !mCountersGroup.add(currTime, mBuffer, cpuIdleKey, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU)
- || !gSessionData->perf.enable(currTime, &mCountersGroup, &mBuffer)
+ || !gSessionData->perf.enable(currTime, &mCountersGroup, mBuffer)
|| 0) {
- logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.4 or later?", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("perf setup failed, are you running Linux 3.4 or later?");
return false;
}
for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
const int result = mCountersGroup.prepareCPU(cpu, &mMonitor);
if ((result != PG_SUCCESS) && (result != PG_CPU_OFFLINE)) {
- logg->logError(__FILE__, __LINE__, "PerfGroup::prepareCPU on mCountersGroup failed");
- handleException();
- }
- }
- for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- const int result = mIdleGroup.prepareCPU(cpu, &mMonitor);
- if ((result != PG_SUCCESS) && (result != PG_CPU_OFFLINE)) {
- logg->logError(__FILE__, __LINE__, "PerfGroup::prepareCPU on mIdleGroup failed");
+ logg->logError("PerfGroup::prepareCPU on mCountersGroup failed");
handleException();
}
}
int numEvents = 0;
for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- numEvents += mCountersGroup.onlineCPU(currTime, cpu, false, &mBuffer);
- }
- for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
- numEvents += mIdleGroup.onlineCPU(currTime, cpu, false, &mBuffer);
+ numEvents += mCountersGroup.onlineCPU(currTime, cpu, false, mBuffer);
}
if (numEvents <= 0) {
- logg->logMessage("%s(%s:%i): PerfGroup::onlineCPU failed on all cores", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("PerfGroup::onlineCPU failed on all cores");
return false;
}
// Send the summary right before the start so that the monotonic delta is close to the start time
if (!gSessionData->perf.summary(&mSummary)) {
- logg->logError(__FILE__, __LINE__, "PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__);
- handleException();
+ logg->logError("PerfDriver::summary failed");
+ handleException();
}
// Start the timer thread to used to sync perf and monotonic raw times
pthread_t syncThread;
if (pthread_create(&syncThread, NULL, syncFunc, NULL)) {
- logg->logError(__FILE__, __LINE__, "pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
- handleException();
+ logg->logError("pthread_create failed");
+ handleException();
}
struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (pthread_setschedparam(syncThread, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) {
- logg->logError(__FILE__, __LINE__, "pthread_setschedparam failed");
- handleException();
+ logg->logError("pthread_setschedparam failed");
+ handleException();
}
- mBuffer.commit(currTime);
+ mBuffer->commit(currTime);
return true;
}
// Gator runs at a high priority, reset the priority to the default
if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), 0) == -1) {
- logg->logError(__FILE__, __LINE__, "setpriority failed");
+ logg->logError("setpriority failed");
handleException();
}
if (!readProcMaps(args->mCurrTime, args->mBuffer, &printb, &b)) {
- logg->logError(__FILE__, __LINE__, "readProcMaps failed");
+ logg->logError("readProcMaps failed");
handleException();
}
- args->mBuffer->commit(args->mCurrTime);
if (!readKallsyms(args->mCurrTime, args->mBuffer, &args->mIsDone)) {
- logg->logError(__FILE__, __LINE__, "readKallsyms failed");
+ logg->logError("readKallsyms failed");
handleException();
}
args->mBuffer->commit(args->mCurrTime);
pthread_t procThread;
ProcThreadArgs procThreadArgs;
+ if (pipe_cloexec(pipefd) != 0) {
+ logg->logError("pipe failed");
+ handleException();
+ }
+ mInterruptFd = pipefd[1];
+
+ if (!mMonitor.add(pipefd[0])) {
+ logg->logError("Monitor::add failed");
+ handleException();
+ }
+
{
DynBuf printb;
DynBuf b1;
DynBuf b2;
- const uint64_t currTime = getTime();
+ const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
// Start events before reading proc to avoid race conditions
- if (!mCountersGroup.start() || !mIdleGroup.start()) {
- logg->logError(__FILE__, __LINE__, "PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__);
+ if (!mCountersGroup.start()) {
+ logg->logError("PerfGroup::start failed");
handleException();
}
- if (!readProcComms(currTime, &mBuffer, &printb, &b1, &b2)) {
- logg->logError(__FILE__, __LINE__, "readProcComms failed");
+ mBuffer->perfCounterHeader(currTime);
+ for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
+ gSessionData->perf.read(mBuffer, cpu);
+ }
+ mBuffer->perfCounterFooter(currTime);
+
+ if (!readProcComms(currTime, mBuffer, &printb, &b1, &b2)) {
+ logg->logError("readProcComms failed");
handleException();
}
- mBuffer.commit(currTime);
+ mBuffer->commit(currTime);
// Postpone reading kallsyms as on android adb gets too backed up and data is lost
- procThreadArgs.mBuffer = &mBuffer;
+ procThreadArgs.mBuffer = mBuffer;
procThreadArgs.mCurrTime = currTime;
procThreadArgs.mIsDone = false;
if (pthread_create(&procThread, NULL, procFunc, &procThreadArgs)) {
- logg->logError(__FILE__, __LINE__, "pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logError("pthread_create failed");
handleException();
}
}
- if (pipe_cloexec(pipefd) != 0) {
- logg->logError(__FILE__, __LINE__, "pipe failed");
- handleException();
- }
- mInterruptFd = pipefd[1];
-
- if (!mMonitor.add(pipefd[0])) {
- logg->logError(__FILE__, __LINE__, "Monitor::add failed");
- handleException();
- }
-
- int timeout = -1;
- if (gSessionData->mLiveRate > 0) {
- timeout = gSessionData->mLiveRate/NS_PER_MS;
- }
-
sem_post(mStartProfile);
+ const uint64_t NO_RATE = ~0ULL;
+ const uint64_t rate = gSessionData->mLiveRate > 0 && gSessionData->mSampleRate > 0 ? gSessionData->mLiveRate : NO_RATE;
+ uint64_t nextTime = 0;
+ int timeout = rate != NO_RATE ? 0 : -1;
while (gSessionData->mSessionIsActive) {
// +1 for uevents, +1 for pipe
struct epoll_event events[NR_CPUS + 2];
int ready = mMonitor.wait(events, ARRAY_LENGTH(events), timeout);
if (ready < 0) {
- logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
+ logg->logError("Monitor::wait failed");
handleException();
}
- const uint64_t currTime = getTime();
+ const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted;
for (int i = 0; i < ready; ++i) {
if (events[i].data.fd == mUEvent.getFd()) {
if (!handleUEvent(currTime)) {
- logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed");
+ logg->logError("PerfSource::handleUEvent failed");
handleException();
}
break;
sem_post(mSenderSem);
// In one shot mode, stop collection once all the buffers are filled
- // Assume timeout == 0 in this case
- if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
- logg->logMessage("%s(%s:%i): One shot", __FUNCTION__, __FILE__, __LINE__);
+ if (gSessionData->mOneShot && gSessionData->mSessionIsActive && ((mSummary.bytesAvailable() <= 0) || (mBuffer->bytesAvailable() <= 0) || mCountersBuf.isFull())) {
+ logg->logMessage("One shot (perf)");
child->endSession();
}
+
+ if (rate != NO_RATE) {
+ while (currTime > nextTime) {
+ nextTime += rate;
+ }
+ // + NS_PER_MS - 1 to ensure always rounding up
+ timeout = max(0, (int)((nextTime + NS_PER_MS - 1 - getTime() + gSessionData->mMonotonicStarted)/NS_PER_MS));
+ }
}
procThreadArgs.mIsDone = true;
pthread_join(procThread, NULL);
- mIdleGroup.stop();
mCountersGroup.stop();
- mBuffer.setDone();
+ mBuffer->setDone();
mIsDone = true;
// send a notification that data is ready
bool PerfSource::handleUEvent(const uint64_t currTime) {
UEventResult result;
if (!mUEvent.read(&result)) {
- logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("UEvent::Read failed");
return false;
}
if (strcmp(result.mSubsystem, "cpu") == 0) {
if (strncmp(result.mDevPath, CPU_DEVPATH, sizeof(CPU_DEVPATH) - 1) != 0) {
- logg->logMessage("%s(%s:%i): Unexpected cpu DEVPATH format", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("Unexpected cpu DEVPATH format");
return false;
}
char *endptr;
errno = 0;
int cpu = strtol(result.mDevPath + sizeof(CPU_DEVPATH) - 1, &endptr, 10);
if (errno != 0 || *endptr != '\0') {
- logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("strtol failed");
return false;
}
if (cpu >= gSessionData->mCores) {
- logg->logError(__FILE__, __LINE__, "Only %i cores are expected but core %i reports %s", gSessionData->mCores, cpu, result.mAction);
+ logg->logError("Only %i cores are expected but core %i reports %s", gSessionData->mCores, cpu, result.mAction);
handleException();
}
if (strcmp(result.mAction, "online") == 0) {
- mBuffer.onlineCPU(currTime, currTime - gSessionData->mMonotonicStarted, cpu);
+ mBuffer->onlineCPU(currTime, cpu);
// Only call onlineCPU if prepareCPU succeeded
- bool result = false;
+ bool ret = false;
int err = mCountersGroup.prepareCPU(cpu, &mMonitor);
if (err == PG_CPU_OFFLINE) {
- result = true;
+ ret = true;
} else if (err == PG_SUCCESS) {
- if (mCountersGroup.onlineCPU(currTime, cpu, true, &mBuffer)) {
- err = mIdleGroup.prepareCPU(cpu, &mMonitor);
- if (err == PG_CPU_OFFLINE) {
- result = true;
- } else if (err == PG_SUCCESS) {
- if (mIdleGroup.onlineCPU(currTime, cpu, true, &mBuffer)) {
- result = true;
- }
- }
+ if (mCountersGroup.onlineCPU(currTime, cpu, true, mBuffer) > 0) {
+ mBuffer->perfCounterHeader(currTime);
+ gSessionData->perf.read(mBuffer, cpu);
+ mBuffer->perfCounterFooter(currTime);
+ ret = true;
}
}
- mBuffer.commit(currTime);
+ mBuffer->commit(currTime);
gSessionData->readCpuInfo();
gSessionData->perf.coreName(currTime, &mSummary, cpu);
mSummary.commit(currTime);
- return result;
+ return ret;
} else if (strcmp(result.mAction, "offline") == 0) {
- const bool result = mCountersGroup.offlineCPU(cpu) && mIdleGroup.offlineCPU(cpu);
- mBuffer.offlineCPU(currTime, currTime - gSessionData->mMonotonicStarted, cpu);
- return result;
+ const bool ret = mCountersGroup.offlineCPU(cpu);
+ mBuffer->offlineCPU(currTime, cpu);
+ return ret;
}
}
int8_t c = 0;
// Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
- logg->logError(__FILE__, __LINE__, "write failed");
+ logg->logError("write failed");
handleException();
}
}
}
bool PerfSource::isDone () {
- return mBuffer.isDone() && mIsDone && mCountersBuf.isEmpty();
+ return mBuffer->isDone() && mIsDone && mCountersBuf.isEmpty();
}
void PerfSource::write (Sender *sender) {
mSummary.write(sender);
gSessionData->mSentSummary = true;
}
- if (!mBuffer.isDone()) {
- mBuffer.write(sender);
+ if (!mBuffer->isDone()) {
+ mBuffer->write(sender);
}
if (!mCountersBuf.send(sender)) {
- logg->logError(__FILE__, __LINE__, "PerfBuffer::send failed");
+ logg->logError("PerfBuffer::send failed");
handleException();
}
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
bool handleUEvent(const uint64_t currTime);
Buffer mSummary;
- Buffer mBuffer;
+ Buffer *mBuffer;
PerfBuffer mCountersBuf;
PerfGroup mCountersGroup;
- PerfGroup mIdleGroup;
Monitor mMonitor;
UEvent mUEvent;
sem_t *const mSenderSem;
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
if (!b->read(pathname)) {
- logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::read failed, likely because the thread exited");
// This is not a fatal error - the thread just doesn't exist any more
return true;
}
char *comm = strchr(b->getBuf(), '(');
if (comm == NULL) {
- logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("parsing stat failed");
return false;
}
++comm;
char *const str = strrchr(comm, ')');
if (str == NULL) {
- logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("parsing stat failed");
return false;
}
*str = '\0';
const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads);
if (count != 1) {
- logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("sscanf failed");
return false;
}
static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) {
if (tid == -1 ? !printb->printf("/proc/%i/exe", pid)
: !printb->printf("/proc/%i/task/%i/exe", pid, tid)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
return NULL;
}
// readlink /proc/[pid]/exe returns ENOENT for kernel threads
image = "\0";
} else {
- logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::readlink failed");
return NULL;
}
if (tid == -1 ? !printb->printf("/proc/%i/cmdline", pid)
: !printb->printf("/proc/%i/task/%i/cmdline", pid, tid)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
return NULL;
}
if (!b->read(printb->getBuf())) {
- logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::read failed, likely because the thread exited");
return NULL;
}
bool result = false;
if (!b1->printf("/proc/%i/task", pid)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
return result;
}
DIR *task = opendir(b1->getBuf());
if (task == NULL) {
- logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("opendir failed");
// This is not a fatal error - the thread just doesn't exist any more
return true;
}
}
if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
goto fail;
}
ProcStat ps;
if (!readProcStat(&ps, printb->getBuf(), b1)) {
- logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("readProcStat failed");
goto fail;
}
const char *const image = readProcExe(printb, pid, tid, b2);
if (image == NULL) {
- logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("readImage failed");
goto fail;
}
- buffer->comm(currTime, pid, tid, image, ps.comm);
+ buffer->marshalComm(currTime, pid, tid, image, ps.comm);
}
result = true;
DIR *proc = opendir("/proc");
if (proc == NULL) {
- logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("opendir failed");
return result;
}
}
if (!printb->printf("/proc/%i/stat", pid)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
goto fail;
}
ProcStat ps;
if (!readProcStat(&ps, printb->getBuf(), b1)) {
- logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("readProcStat failed");
goto fail;
}
if (ps.numThreads <= 1) {
const char *const image = readProcExe(printb, pid, -1, b1);
if (image == NULL) {
- logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("readImage failed");
goto fail;
}
- buffer->comm(currTime, pid, pid, image, ps.comm);
+ buffer->marshalComm(currTime, pid, pid, image, ps.comm);
} else {
if (!readProcTask(currTime, buffer, pid, printb, b1, b2)) {
- logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("readProcTask failed");
goto fail;
}
}
DIR *proc = opendir("/proc");
if (proc == NULL) {
- logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("opendir failed");
return result;
}
}
if (!printb->printf("/proc/%i/maps", pid)) {
- logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::printf failed");
goto fail;
}
if (!b->read(printb->getBuf())) {
- logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("DynBuf::read failed, likely because the process exited");
// This is not a fatal error - the process just doesn't exist any more
continue;
}
- buffer->maps(currTime, pid, pid, b->getBuf());
+ buffer->marshalMaps(currTime, pid, pid, b->getBuf());
}
result = true;
int fd = ::open("/proc/kallsyms", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
- logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("open failed");
return true;
};
while (gSessionData->mSessionIsActive && !ACCESS_ONCE(*isDone)) {
// Assert there is still space in the buffer
if (sizeof(buf) - pos - 1 == 0) {
- logg->logError(__FILE__, __LINE__, "no space left in buffer");
+ logg->logError("no space left in buffer");
handleException();
}
// -1 to reserve space for \0
const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1);
if (bytes < 0) {
- logg->logError(__FILE__, __LINE__, "read failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logError("read failed");
handleException();
}
if (bytes == 0) {
// Assert the buffer is empty
if (pos != 0) {
- logg->logError(__FILE__, __LINE__, "buffer not empty on eof");
+ logg->logError("buffer not empty on eof");
handleException();
}
break;
if (buf[newline] == '\n') {
const char was = buf[newline + 1];
buf[newline + 1] = '\0';
- buffer->kallsyms(currTime, buf);
+ buffer->marshalKallsyms(currTime, buf);
// Sleep 3 ms to avoid sending out too much data too quickly
usleep(3000);
buf[0] = was;
// Assert the memory regions do not overlap
if (pos - newline >= newline + 1) {
- logg->logError(__FILE__, __LINE__, "memcpy src and dst overlap");
+ logg->logError("memcpy src and dst overlap");
handleException();
}
if (pos - newline - 2 > 0) {
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
// Streamline will send data prior to the magic sequence for legacy support, which should be ignored for v4+
while (strcmp("STREAMLINE", streamline) != 0) {
if (mDataSocket->receiveString(streamline, sizeof(streamline)) == -1) {
- logg->logError(__FILE__, __LINE__, "Socket disconnected");
+ logg->logError("Socket disconnected");
handleException();
}
}
sprintf(mDataFileName, "%s/0000000000", apcDir);
mDataFile = fopen_cloexec(mDataFileName, "wb");
if (!mDataFile) {
- logg->logError(__FILE__, __LINE__, "Failed to open binary file: %s", mDataFileName);
+ logg->logError("Failed to open binary file: %s", mDataFileName);
handleException();
}
}
logg->logMessage("Writing data with length %d", length);
// Send data to the data file
if (fwrite(data, 1, length, mDataFile) != (unsigned int)length) {
- logg->logError(__FILE__, __LINE__, "Failed writing binary file %s", mDataFileName);
+ logg->logError("Failed writing binary file %s", mDataFileName);
handleException();
}
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <sys/mman.h>
#include <unistd.h>
-#include "CPUFreqDriver.h"
#include "DiskIODriver.h"
#include "FSDriver.h"
#include "HwmonDriver.h"
usDrivers[1] = new FSDriver();
usDrivers[2] = new MemInfoDriver();
usDrivers[3] = new NetDriver();
- usDrivers[4] = new CPUFreqDriver();
- usDrivers[5] = new DiskIODriver();
+ usDrivers[4] = new DiskIODriver();
initialize();
}
// Share mCpuIds across all instances of gatord
mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (mCpuIds == MAP_FAILED) {
- logg->logError(__FILE__, __LINE__, "Unable to mmap shared memory for cpuids");
+ logg->logError("Unable to mmap shared memory for cpuids");
handleException();
}
memset(mCpuIds, -1, cpuIdSize);
mConfigurationXMLPath = NULL;
mSessionXMLPath = NULL;
mEventsXMLPath = NULL;
+ mEventsXMLAppend = NULL;
mTargetPath = NULL;
mAPCDir = NULL;
mCaptureWorkingDir = NULL;
// sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
mCores = 1;
mPageSize = 0;
+ mAnnotateStart = -1;
}
void SessionData::parseSessionXML(char* xmlString) {
} else if (strcmp(session.parameters.sample_rate, "none") == 0) {
mSampleRate = 0;
} else {
- logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
+ logg->logError("Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
handleException();
}
mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
} else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
mTotalBufferSize = 16;
} else {
- logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml.");
+ logg->logError("Invalid value for buffer mode in session xml.");
handleException();
}
}
if (!mAllowCommands && (mCaptureCommand != NULL)) {
- logg->logError(__FILE__, __LINE__, "Running a command during a capture is not currently allowed. Please restart gatord with the -a flag.");
+ logg->logError("Running a command during a capture is not currently allowed. Please restart gatord with the -a flag.");
handleException();
}
}
fclose(fh);
}
+static void setImplementer(int &cpuId, const int implementer) {
+ if (cpuId == -1) {
+ cpuId = 0;
+ }
+ cpuId |= implementer << 12;
+}
+
+static void setPart(int &cpuId, const int part) {
+ if (cpuId == -1) {
+ cpuId = 0;
+ }
+ cpuId |= part;
+}
+
void SessionData::readCpuInfo() {
char temp[256]; // arbitrarily large amount
mMaxCpuId = -1;
return;
}
- bool foundCoreName = false;
+ bool foundCoreName = (strcmp(mCoreName, CORE_NAME_UNKNOWN) != 0);
int processor = -1;
while (fgets(temp, sizeof(temp), f)) {
const size_t len = strlen(temp);
temp[len - 1] = '\0';
}
- const bool foundHardware = strstr(temp, "Hardware") != 0;
+ const bool foundHardware = !foundCoreName && strstr(temp, "Hardware") != 0;
+ const bool foundCPUImplementer = strstr(temp, "CPU implementer") != 0;
const bool foundCPUPart = strstr(temp, "CPU part") != 0;
const bool foundProcessor = strstr(temp, "processor") != 0;
- if (foundHardware || foundCPUPart || foundProcessor) {
+ if (foundHardware || foundCPUImplementer || foundCPUPart || foundProcessor) {
char* position = strchr(temp, ':');
if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
logg->logMessage("Unknown format of /proc/cpuinfo\n"
}
position += 2;
- if (foundHardware && (strcmp(mCoreName, CORE_NAME_UNKNOWN) == 0)) {
+ if (foundHardware) {
strncpy(mCoreName, position, sizeof(mCoreName));
mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
foundCoreName = true;
}
+ if (foundCPUImplementer) {
+ const int implementer = strtol(position, NULL, 0);
+ if (processor >= NR_CPUS) {
+ logg->logMessage("Too many processors, please increase NR_CPUS");
+ } else if (processor >= 0) {
+ setImplementer(mCpuIds[processor], implementer);
+ } else {
+ setImplementer(mMaxCpuId, implementer);
+ }
+ }
+
if (foundCPUPart) {
const int cpuId = strtol(position, NULL, 0);
- // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
- if (cpuId > mMaxCpuId) {
- mMaxCpuId = cpuId;
- }
if (processor >= NR_CPUS) {
logg->logMessage("Too many processors, please increase NR_CPUS");
} else if (processor >= 0) {
- mCpuIds[processor] = cpuId;
+ setPart(mCpuIds[processor], cpuId);
+ } else {
+ setPart(mMaxCpuId, cpuId);
}
}
}
}
+ // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
+ for (int i = 0; i < NR_CPUS; ++i) {
+ if (mCpuIds[i] > mMaxCpuId) {
+ mMaxCpuId = mCpuIds[i];
+ }
+ }
+
if (!foundCoreName) {
logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
"The core name in the captured xml file will be 'unknown'.");
uint64_t getTime() {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
- logg->logError(__FILE__, __LINE__, "Failed to get uptime");
+ logg->logError("Failed to get uptime");
handleException();
}
return (NS_PER_S*ts.tv_sec + ts.tv_nsec);
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <stdint.h>
-#include "AnnotateListener.h"
#include "Config.h"
#include "Counter.h"
#include "FtraceDriver.h"
#include "MaliVideoDriver.h"
#include "PerfDriver.h"
-#define PROTOCOL_VERSION 20
+#define PROTOCOL_VERSION 21
// Differentiates development versions (timestamp) from release versions
#define PROTOCOL_DEV 1000
void readModel();
void readCpuInfo();
- PolledDriver *usDrivers[6];
+ PolledDriver *usDrivers[5];
KMod kmod;
PerfDriver perf;
MaliVideoDriver maliVideo;
FtraceDriver ftraceDriver;
- AnnotateListener annotateListener;
char mCoreName[MAX_STRING_LEN];
struct ImageLinkList *mImages;
char *mConfigurationXMLPath;
char *mSessionXMLPath;
char *mEventsXMLPath;
+ char *mEventsXMLAppend;
char *mTargetPath;
char *mAPCDir;
char *mCaptureWorkingDir;
int mPageSize;
int *mCpuIds;
int mMaxCpuId;
+ int mAnnotateStart;
// PMU Counters
int mCounterOverflow;
};
extern SessionData* gSessionData;
+extern const char *const gSrcMd5;
uint64_t getTime();
int getEventKey();
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
parameters.call_stack_unwinding = false;
parameters.live_rate = 0;
mSessionXML = str;
- logg->logMessage(mSessionXML);
+ logg->logMessage("%s", mSessionXML);
}
SessionXML::~SessionXML() {
return;
}
- logg->logError(__FILE__, __LINE__, "No session tag found in the session.xml file");
+ logg->logError("No session tag found in the session.xml file");
handleException();
}
int version = 0;
if (mxmlElementGetAttr(node, ATTR_VERSION)) version = strtol(mxmlElementGetAttr(node, ATTR_VERSION), NULL, 10);
if (version != 1) {
- logg->logError(__FILE__, __LINE__, "Invalid session.xml version: %d", version);
+ logg->logError("Invalid session.xml version: %d", version);
handleException();
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mount.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include "Config.h"
#include "DynBuf.h"
#include "Logging.h"
+#include "SessionData.h"
+
+#define GATOR_MSG "gator: "
+#define GATOR_ERROR "gator: error: "
+#define GATOR_CONFIRM "gator: confirm: "
bool getLinuxVersion(int version[3]) {
// Check the kernel version
struct utsname utsname;
if (uname(&utsname) != 0) {
- logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("uname failed");
return false;
}
DIR *proc = opendir("/proc");
if (proc == NULL) {
- logg->logError(__FILE__, __LINE__, "gator: error: opendir failed");
+ logg->logError(GATOR_ERROR "opendir failed");
handleException();
}
}
if (!printb->printf("/proc/%i/stat", pid)) {
- logg->logError(__FILE__, __LINE__, "gator: error: DynBuf::printf failed");
+ logg->logError(GATOR_ERROR "DynBuf::printf failed");
handleException();
}
char *comm = strchr(b.getBuf(), '(');
if (comm == NULL) {
- logg->logError(__FILE__, __LINE__, "gator: error: parsing stat begin failed");
+ logg->logError(GATOR_ERROR "parsing stat comm begin failed");
handleException();
}
++comm;
char *const str = strrchr(comm, ')');
if (str == NULL) {
- logg->logError(__FILE__, __LINE__, "gator: error: parsing stat end failed");
+ logg->logError(GATOR_ERROR "parsing stat comm end failed");
handleException();
}
*str = '\0';
- if (strncmp(comm, "gator", 5) == 0) {
- // Assume there is only one gator process
- return pid;
+ if (strncmp(comm, "gator", 5) != 0) {
+ continue;
+ }
+
+ char state;
+ const int count = sscanf(str + 2, " %c ", &state);
+ if (count != 1) {
+ logg->logError(GATOR_ERROR "parsing stat state failed");
+ handleException();
+ }
+
+ if (state == 'Z') {
+ // This gator is a zombie, ignore
+ continue;
}
+
+ // Assume there is only one gator process
+ return pid;
}
closedir(proc);
return -1;
}
-int update(const char *const gatorPath) {
- printf("gator: starting\n");
+static bool confirm(const char *const message) {
+ char buf[1<<10];
+
+ printf(GATOR_CONFIRM "%s\n", message);
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ if (strcmp(buf, "y\n") == 0) {
+ return true;
+ }
+ if (strcmp(buf, "n\n") == 0) {
+ return false;
+ }
+ // Ignore unrecognized input
+ }
+
+ return false;
+}
+
+void update(const char *const gatorPath) {
+ printf(GATOR_MSG "starting\n");
int version[3];
if (!getLinuxVersion(version)) {
- logg->logError(__FILE__, __LINE__, "gator: error: getLinuxVersion failed");
+ logg->logError(GATOR_ERROR "getLinuxVersion failed");
handleException();
}
if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) {
- logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
+ logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
handleException();
}
if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) {
- logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
- handleException();
- }
-
- if (access("/sys/module/gator", F_OK) == 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: Streamline has detected that the gator kernel module is loaded on your device. Please build an updated version of gator.ko and gatord and install them on your device.");
+ logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
handleException();
}
if (geteuid() != 0) {
- printf("gator: trying sudo\n");
+ printf(GATOR_MSG "trying sudo\n");
execlp("sudo", "sudo", gatorPath, "-u", NULL);
// Streamline will provide the password if needed
- printf("gator: trying su\n");
+ printf(GATOR_MSG "trying su\n");
char buf[1<<10];
- snprintf(buf, sizeof(buf), "%s -u", gatorPath);
- execlp("su", "su", "-", "-c", buf, NULL);
+ /*
+ * Different versions of su handle additional -c command line options differently and expect the
+ * arguments in different ways. Try both ways wrapped in a shell.
+ *
+ * Then invoke another shell after su as it avoids odd failures on some Android systems
+ */
+ snprintf(buf, sizeof(buf), "su -c \"sh -c '%s -u'\" || su -c sh -c '%s -u'", gatorPath, gatorPath);
+ execlp("sh", "sh", "-c", buf, NULL);
// Streamline will provide the password if needed
- logg->logError(__FILE__, __LINE__, "gator: error: Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username.");
+ logg->logError(GATOR_ERROR "Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username.");
handleException();
}
- printf("gator: now root\n");
+ printf(GATOR_MSG "now root\n");
+
+ if (access("/sys/module/gator", F_OK) == 0) {
+ if (!confirm("Streamline has detected that the gator kernel module is loaded on your device. Click yes to switch to user space gator, click no to abort the install.")) {
+ printf("gator: cancel\n");
+ exit(-1);
+ }
+ }
// setenforce 0 not needed for userspace gator
// Kill existing gator
- DynBuf gatorStatPath;
- int gator_main = pgrep_gator(&gatorStatPath);
+ DynBuf printb;
+ int gator_main = pgrep_gator(&printb);
if (gator_main > 0) {
if (kill(gator_main, SIGTERM) != 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: kill SIGTERM failed");
+ logg->logError(GATOR_ERROR "kill SIGTERM failed");
+ handleException();
+ }
+ if (!printb.printf("/proc/%i/exe", gator_main)) {
+ logg->logError(GATOR_ERROR "DynBuf::printf failed");
handleException();
}
for (int i = 0; ; ++i) {
- if (access(gatorStatPath.getBuf(), F_OK) != 0) {
+ // /proc/<pid>/exe exists but will not be accessible for zombies
+ if (access(printb.getBuf(), F_OK) != 0) {
break;
}
if (i == 5) {
if (kill(gator_main, SIGKILL) != 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: kill SIGKILL failed");
+ logg->logError(GATOR_ERROR "kill SIGKILL failed");
handleException();
}
} else if (i >= 10) {
- logg->logError(__FILE__, __LINE__, "gator: error: unable to kill running gator");
+ logg->logError(GATOR_ERROR "unable to kill running gator");
handleException();
}
sleep(1);
}
}
- printf("gator: no gatord running\n");
+ printf(GATOR_MSG "no gatord running\n");
+
+ umount("/dev/gator");
+ syscall(__NR_delete_module, "gator", O_NONBLOCK);
rename("gatord", "gatord.old");
rename("gator.ko", "gator.ko.old");
if (dot != NULL) {
*dot = '\0';
if (rename(gatorPath, newGatorPath) != 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: rename failed");
+ logg->logError(GATOR_ERROR "rename failed");
handleException();
}
}
- // Fork and start gatord (redirect stdout and stderr)
+ char buf[128];
+ int pipefd[2];
+ if (pipe_cloexec(pipefd) != 0) {
+ logg->logError(GATOR_ERROR "pipe failed");
+ handleException();
+ }
+
+ // Fork and start gatord (redirect stdin, stdout and stderr so shell can close)
int child = fork();
if (child < 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: fork failed");
+ logg->logError(GATOR_ERROR "fork failed");
handleException();
} else if (child == 0) {
- int inFd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+ int inFd;
+ int outFd;
+ int errFd;
+ int result = -1;
+
+ buf[0] = '\0';
+ close(pipefd[0]);
+
+ inFd = open("/dev/null", O_RDONLY | O_CLOEXEC);
if (inFd < 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: open of /dev/null failed");
- handleException();
+ snprintf(buf, sizeof(buf), GATOR_ERROR "open of /dev/null failed");
+ goto fail_exit;
}
- int outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
+ outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (outFd < 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.out failed");
- handleException();
+ snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.out failed");
+ goto fail_exit;
}
- int errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
+ errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (errFd < 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.err failed");
- handleException();
+ snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.err failed");
+ goto fail_exit;
}
if (dup2(inFd, STDIN_FILENO) < 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdin failed");
- handleException();
+ snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdin failed");
+ goto fail_exit;
}
+ fflush(stdout);
if (dup2(outFd, STDOUT_FILENO) < 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdout failed");
- handleException();
+ snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdout failed");
+ goto fail_exit;
}
+ fflush(stderr);
if (dup2(errFd, STDERR_FILENO) < 0) {
- logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stderr failed");
- handleException();
+ snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stderr failed");
+ goto fail_exit;
}
- execlp(newGatorPath, newGatorPath, "-a", NULL);
- logg->logError(__FILE__, __LINE__, "gator: error: execlp failed");
- handleException();
+
+ snprintf(buf, sizeof(buf), GATOR_MSG "done");
+ result = 0;
+
+ fail_exit:
+ if (buf[0] != '\0') {
+ const ssize_t bytes = write(pipefd[1], buf, sizeof(buf));
+ // Can't do anything if this fails
+ (void)bytes;
+ }
+ close(pipefd[1]);
+
+ if (result == 0) {
+ // Continue to execute gator normally
+ return;
+ }
+ exit(-1);
}
- printf("gator: done\n");
+ close(pipefd[1]);
+ const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
+ if (bytes > 0) {
+ logg->logError("%s", buf);
+ handleException();
+ }
+ close(pipefd[0]);
- return 0;
+ // Exit so parent shell can move on
+ exit(0);
}
/**
- * Copyright (C) ARM Limited 2014. All rights reserved.
+ * Copyright (C) ARM Limited 2014-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
bool getLinuxVersion(int version[3]);
-int update(const char *const gatorPath);
+void update(const char *const gatorPath);
#endif // SETUP_H
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
void Source::start() {
if (pthread_create(&mThreadID, NULL, runStatic, this)) {
- logg->logError(__FILE__, __LINE__, "Failed to create source thread");
+ logg->logError("Failed to create source thread");
handleException();
}
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2011-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2011-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
sendData(NULL, 0, RESPONSE_ACK);
break;
default:
- logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
+ logg->logError("Target error: Unknown command type, %d", type);
handleException();
}
}
if (gSessionData->mCounterOverflow > 0) {
- logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+ logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
handleException();
}
}
gSessionData->mWaitingOnCommand = false;
if (response < 0) {
- logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ logg->logError("Target error: Unexpected socket disconnect");
handleException();
}
// add artificial limit
if ((length < 0) || length > 1024 * 1024) {
- logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
+ logg->logError("Target error: Invalid length received, %d", length);
handleException();
}
// allocate memory to contain the xml file, size of zero returns a zero size object
data = (char*)calloc(length + 1, 1);
if (data == NULL) {
- logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
+ logg->logError("Unable to allocate memory for xml");
handleException();
}
// receive data
response = mSocket->receiveNBytes(data, length);
if (response < 0) {
- logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
+ logg->logError("Target error: Unexpected socket disconnect");
handleException();
}
// Artificial size restriction
if (size > 1024*1024) {
- logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
+ logg->logError("Corrupt default configuration file");
handleException();
}
}
if (count == 0) {
- logg->logError(__FILE__, __LINE__, "No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
+ logg->logError("No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
handleException();
}
ConfigurationXML::getPath(path);
if (util->writeToDisk(path, xml) < 0) {
- logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path);
+ logg->logError("Error writing %s\nPlease verify write permissions to this path.", path);
handleException();
}
{ ConfigurationXML configuration; }
if (gSessionData->mCounterOverflow > 0) {
- logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
+ logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
handleException();
}
}
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
bool UEvent::init() {
mFd = socket_cloexec(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
if (mFd < 0) {
- logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("socket failed");
return false;
}
sockaddr.nl_groups = 1; // bitmask: (1 << 0) == kernel events, (1 << 1) == udev events
sockaddr.nl_pid = 0;
if (bind(mFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
- logg->logMessage("%s(%s:%i): bind failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("bind failed");
return false;
}
bool UEvent::read(UEventResult *const result) {
ssize_t bytes = recv(mFd, result->mBuf, sizeof(result->mBuf), 0);
if (bytes <= 0) {
- logg->logMessage("%s(%s:%i): recv failed", __FUNCTION__, __FILE__, __LINE__);
+ logg->logMessage("recv failed");
return false;
}
for (int pos = 0; pos < bytes; pos += strlen(result->mBuf + pos) + 1) {
char *const str = result->mBuf + pos;
+ logg->logMessage("uevent + %i: %s", pos, str);
if (strncmp(str, ACTION, sizeof(ACTION) - 1) == 0) {
result->mAction = str + sizeof(ACTION) - 1;
} else if (strncmp(str, DEVPATH, sizeof(DEVPATH) - 1) == 0) {
/**
- * Copyright (C) ARM Limited 2013-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2013-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#define __STDC_FORMAT_MACROS
+
#include "UserSpaceSource.h"
+#include <inttypes.h>
#include <sys/prctl.h>
#include <unistd.h>
gSessionData->usDrivers[i]->start();
}
- int64_t monotonic_started = 0;
- while (monotonic_started <= 0) {
+ int64_t monotonicStarted = 0;
+ while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) {
usleep(10);
if (gSessionData->perf.isSetup()) {
- monotonic_started = gSessionData->mMonotonicStarted;
+ monotonicStarted = gSessionData->mMonotonicStarted;
} else {
- if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
- logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
+ if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) {
+ logg->logError("Error reading gator driver start time");
handleException();
}
- gSessionData->mMonotonicStarted = monotonic_started;
+ gSessionData->mMonotonicStarted = monotonicStarted;
}
}
- uint64_t next_time = 0;
+ uint64_t nextTime = 0;
while (gSessionData->mSessionIsActive) {
- const uint64_t curr_time = getTime() - monotonic_started;
+ const uint64_t currTime = getTime() - monotonicStarted;
// Sample ten times a second ignoring gSessionData->mSampleRate
- next_time += NS_PER_S/10;//gSessionData->mSampleRate;
- if (next_time < curr_time) {
- logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
- next_time = curr_time;
+ nextTime += NS_PER_S/10;//gSessionData->mSampleRate;
+ if (nextTime < currTime) {
+ logg->logMessage("Too slow, currTime: %" PRIi64 " nextTime: %" PRIi64, currTime, nextTime);
+ nextTime = currTime;
}
- if (mBuffer.eventHeader(curr_time)) {
+ if (mBuffer.eventHeader(currTime)) {
for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) {
gSessionData->usDrivers[i]->read(&mBuffer);
}
// Only check after writing all counters so that time and corresponding counters appear in the same frame
- mBuffer.check(curr_time);
+ mBuffer.check(currTime);
}
- if (mBuffer.bytesAvailable() <= 0) {
+ if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) {
logg->logMessage("One shot (counters)");
child->endSession();
}
- usleep((next_time - curr_time)/NS_PER_US);
+ usleep((nextTime - currTime)/NS_PER_US);
}
mBuffer.setDone();
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
/**
* Minimal set of C++ functions so that libstdc++ is not required
*
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
# -std=c++0x is the planned new c++ standard
# -std=c++98 is the 1998 c++ standard
CPPFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors
-CXXFLAGS += -fno-rtti -Wextra # -Weffc++
+CXXFLAGS += -fno-rtti -Wextra -Wshadow # -Weffc++
ifeq ($(WERROR),1)
CPPFLAGS += -Werror
endif
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
-$(TARGET): $(CXX_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o)
+SrcMd5.cpp: $(wildcard *.cpp *.h mxml/*.c mxml/*.h libsensors/*.c libsensors/*.h)
+ echo 'extern const char *const gSrcMd5 = "'`ls $^ | grep -Ev '^(.*_xml\.h|$@)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32`'";' > $@
+
+$(TARGET): $(CXX_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) SrcMd5.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
# Intentionally ignore CC as a native binary is required
gcc $^ -o $@
clean:
- rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h
+ rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h SrcMd5.cpp
<configuration counter="ARM_Cortex-A57_cnt1" event="0x16"/>
<configuration counter="ARM_Cortex-A57_cnt2" event="0x10"/>
<configuration counter="ARM_Cortex-A57_cnt3" event="0x19"/>
+ <configuration counter="ARM_Cortex-A72_ccnt" event="0x11"/>
+ <configuration counter="ARM_Cortex-A72_cnt0" event="0x8"/>
+ <configuration counter="ARM_Cortex-A72_cnt1" event="0x16"/>
+ <configuration counter="ARM_Cortex-A72_cnt2" event="0x10"/>
+ <configuration counter="ARM_Cortex-A72_cnt3" event="0x19"/>
<configuration counter="Scorpion_ccnt" event="0xff"/>
<configuration counter="Scorpion_cnt0" event="0x08"/>
<configuration counter="Scorpion_cnt1" event="0x10"/>
<configuration counter="ARM_Mali-Midgard_fragment" cores="1"/>
<configuration counter="ARM_Mali-Midgard_vertex" cores="1"/>
<configuration counter="ARM_Mali-Midgard_opencl" cores="1"/>
- <configuration counter="ARM_Mali-T60x_GPU_ACTIVE"/>
- <configuration counter="ARM_Mali-T60x_JS0_ACTIVE"/>
- <configuration counter="ARM_Mali-T60x_JS1_ACTIVE"/>
- <configuration counter="ARM_Mali-T60x_JS2_ACTIVE"/>
- <configuration counter="ARM_Mali-T62x_GPU_ACTIVE"/>
- <configuration counter="ARM_Mali-T62x_JS0_ACTIVE"/>
- <configuration counter="ARM_Mali-T62x_JS1_ACTIVE"/>
- <configuration counter="ARM_Mali-T62x_JS2_ACTIVE"/>
- <configuration counter="ARM_Mali-T72x_GPU_ACTIVE"/>
- <configuration counter="ARM_Mali-T72x_JS0_ACTIVE"/>
- <configuration counter="ARM_Mali-T72x_JS1_ACTIVE"/>
- <configuration counter="ARM_Mali-T72x_JS2_ACTIVE"/>
- <configuration counter="ARM_Mali-T76x_GPU_ACTIVE"/>
- <configuration counter="ARM_Mali-T76x_JS0_ACTIVE"/>
- <configuration counter="ARM_Mali-T76x_JS1_ACTIVE"/>
- <configuration counter="ARM_Mali-T76x_JS2_ACTIVE"/>
<configuration counter="L2C-310_cnt0" event="0x1"/>
</configurations>
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
<event event="0x0d" title="Program Counter" name="SW change" description="Software changed the PC"/>
<event event="0x0f" title="Cache " name="TLB miss" description="Main TLB miss (unused on ARM1156)"/>
<event event="0x10" title="External" name="Access" description="Explicit external data or peripheral access"/>
- <event event="0x11" title="Cache" name="Data miss" description="Stall because of Load Store Unit request queue being full"/>
+ <event event="0x11" title="Cache" name="Stall" description="Stall because of Load Store Unit request queue being full"/>
<event event="0x12" title="Write Buffer" name="Drains" description="The number of times the Write Buffer was drained because of a Data Synchronization Barrier command or Strongly Ordered operation"/>
<event event="0x13" title="Disable Interrupts" name="FIQ" description="The number of cycles which FIQ interrupts are disabled (ARM1156 only)"/>
<event event="0x14" title="Disable Interrupts" name="IRQ" description="The number of cycles which IRQ interrupts are disabled (ARM1156 only)"/>
<counter_set name="CCI_400_cnt" count="4"/>
- <category name="CCI-400" counter_set="CCI_400_cnt" per_cpu="no" supports_event_based_sampling="yes">
+ <category name="CCI-400" counter_set="CCI_400_cnt" per_cpu="no">
<event counter="CCI_400_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
<option_set name="Slave">
<option event_delta="0x00" name="S0" description="Slave interface 0"/>
<event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
</category>
<counter_set name="CCI_400-r1_cnt" count="4"/>
- <category name="CCI-400" counter_set="CCI_400-r1_cnt" per_cpu="no" supports_event_based_sampling="yes">
+ <category name="CCI-400" counter_set="CCI_400-r1_cnt" per_cpu="no">
<event counter="CCI_400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
<option_set name="Slave">
<option event_delta="0x00" name="S0" description="Slave interface 0"/>
--- /dev/null
+ <counter_set name="CCI_500_cnt" count="8"/>
+ <category name="CCI-500" counter_set="CCI_500_cnt" per_cpu="no">
+ <option_set name="Slave">
+ <option event_delta="0x00" name="S0" description="Slave interface 0"/>
+ <option event_delta="0x20" name="S1" description="Slave interface 1"/>
+ <option event_delta="0x40" name="S2" description="Slave interface 2"/>
+ <option event_delta="0x60" name="S3" description="Slave interface 3"/>
+ <option event_delta="0x80" name="S4" description="Slave interface 4"/>
+ <option event_delta="0xa0" name="S5" description="Slave interface 5"/>
+ <option event_delta="0xc0" name="S6" description="Slave interface 6"/>
+ </option_set>
+ <event event="0x00" option_set="Slave" title="CCI-500" name="Read ARVALID" description="Read request handshake: any ARVALID, ARREADY HIGH"/>
+ <event event="0x01" option_set="Slave" title="CCI-500" name="Read device" description="Read request: device"/>
+ <event event="0x02" option_set="Slave" title="CCI-500" name="Read non-shareable" description="Read request handshake: normal, non-shareable"/>
+ <event event="0x03" option_set="Slave" title="CCI-500" name="Read non-allocating" description="Read request handshake: normal, shareable, non-allocating, for example ReadOnce"/>
+ <event event="0x04" option_set="Slave" title="CCI-500" name="Read other" description="Read request handshake: normal, shareable allocating, for example ReadClean, ReadShared, ReadNotSharedDirty, ReadUnique"/>
+ <event event="0x05" option_set="Slave" title="CCI-500" name="Read invalidation" description="Read request handshake: invalidation, for example MakeUnique, CleanUnique"/>
+ <event event="0x06" option_set="Slave" title="CCI-500" name="Read maintenance" description="Read request handshake: cache maintenance operation, for example CleanInvalid, MakeInvalid, CleanShared"/>
+ <event event="0x07" option_set="Slave" title="CCI-500" name="Read DVM" description="Read request handshake: DVM message, any"/>
+ <event event="0x08" option_set="Slave" title="CCI-500" name="Read RVALID" description="Read data handshake: any RVALID, RREADY HIGH"/>
+ <event event="0x09" option_set="Slave" title="CCI-500" name="Read RLAST" description="Read data handshake with RLAST set, for a snoop hit"/>
+ <event event="0x0a" option_set="Slave" title="CCI-500" name="Write AWVALID" description="Write request: any AWVALID, AWREADY HIGH"/>
+ <event event="0x0b" option_set="Slave" title="CCI-500" name="Write device" description="Write request: device"/>
+ <event event="0x0c" option_set="Slave" title="CCI-500" name="Write non-shareable" description="Write request: non-shareable"/>
+ <event event="0x0d" option_set="Slave" title="CCI-500" name="Write shareable a" description="Write request handshake: shareable, for example WriteBack, WriteClean"/>
+ <event event="0x0e" option_set="Slave" title="CCI-500" name="Write shareable b" description="Write request handshake: shareable, for example WriteLineUnique"/>
+ <event event="0x0f" option_set="Slave" title="CCI-500" name="Write shareable c" description="Write request handshake: shareable, for example WriteUnique"/>
+ <event event="0x10" option_set="Slave" title="CCI-500" name="Write evict" description="Write request handshake, for example Evict"/>
+ <!--event event="0x11" option_set="Slave" title="CCI-500" name="Write evict ?" description="Write request handshake, for example WriteEvict. WriteEvict is not supported in the CCI-500, so does not fire."/-->
+ <event event="0x12" option_set="Slave" title="CCI-500" name="Write WVALID" description="Write data beat: any WVALID, WREADY HIGH"/>
+ <event event="0x13" option_set="Slave" title="CCI-500" name="Snoop ACVLID" description="Snoop request: any ACVALID, ACREADY HIGH"/>
+ <event event="0x14" option_set="Slave" title="CCI-500" name="Snoop read" description="Snoop request: read, for example ReadOnce, ReadClean, ReadNotSharedDirty, ReadShared, ReadUnique"/>
+ <event event="0x15" option_set="Slave" title="CCI-500" name="Snoop invalidate" description="Snoop request: clean or invalidate, for example MakeInvalid, CleanInvalid, CleanShared"/>
+ <event event="0x16" option_set="Slave" title="CCI-500" name="Snoop CRRESP" description="Snoop request: Data Transfer bit CRRESP[0] LOW"/>
+ <event event="0x17" option_set="Slave" title="CCI-500" name="Read request stall" description="Read request stall: ARVALID HIGH ARREADY LOW"/>
+ <event event="0x18" option_set="Slave" title="CCI-500" name="Read data stall" description="Read data stall: RVALID HIGH RREADY LOW"/>
+ <event event="0x19" option_set="Slave" title="CCI-500" name="Write request stall" description="Write request stall: AWVALID HIGH AWREADY LOW"/>
+ <event event="0x1a" option_set="Slave" title="CCI-500" name="Write data stall" description="Write data stall: WVALID HIGH WREADY LOW"/>
+ <event event="0x1b" option_set="Slave" title="CCI-500" name="Write response stall" description="Write response stall: BVALID HIGH BREADY LOW"/>
+ <event event="0x1c" option_set="Slave" title="CCI-500" name="Snoop request stall" description="Snoop request stall: ACVALID HIGH ACREADY LOW"/>
+ <event event="0x1d" option_set="Slave" title="CCI-500" name="Snoop data stall" description="Snoop data stall: CDVALID HIGH CDREADY LOW"/>
+ <event event="0x1e" option_set="Slave" title="CCI-500" name="Request stall" description="Request stall cycle because of OT transaction limit"/>
+ <event event="0x1f" option_set="Slave" title="CCI-500" name="Read stall" description="Read stall because of arbitration"/>
+ <option_set name="Master">
+ <option event_delta="0x100" name="M0" description="Master interface 0"/>
+ <option event_delta="0x120" name="M1" description="Master interface 1"/>
+ <option event_delta="0x140" name="M2" description="Master interface 2"/>
+ <option event_delta="0x160" name="M3" description="Master interface 3"/>
+ <option event_delta="0x180" name="M4" description="Master interface 4"/>
+ <option event_delta="0x1a0" name="M5" description="Master interface 5"/>
+ </option_set>
+ <event event="0x00" option_set="Master" title="CCI-500" name="Read data beat" description="Read data beat: any"/>
+ <event event="0x01" option_set="Master" title="CCI-500" name="Write data beat" description="Write data beat: any"/>
+ <event event="0x02" option_set="Master" title="CCI-500" name="Read request stall" description="Read request stall: ARVALID HIGH ARREADY LOW"/>
+ <event event="0x03" option_set="Master" title="CCI-500" name="Read data stall" description="Read data stall: RVALID HIGH RREADY LOW"/>
+ <event event="0x04" option_set="Master" title="CCI-500" name="Write request stall" description="Write request stall: AWVALID HIGH AWREADY LOW"/>
+ <event event="0x05" option_set="Master" title="CCI-500" name="Write data stall" description="Write data stall: WVALID HIGH WREADY LOW"/>
+ <event event="0x06" option_set="Master" title="CCI-500" name="Write response stall" description="Write response stall: BVALID HIGH BREADY LOW"/>
+ <event event="0x1e0" title="CCI-500" name="Snoop response 0/1" description="Access to snoop filter bank 0 or 1, any response"/>
+ <event event="0x1e1" title="CCI-500" name="Snoop response 2/3" description="Access to snoop filter bank 2 or 3, any response"/>
+ <event event="0x1e2" title="CCI-500" name="Snoop response 3/4" description="Access to snoop filter bank 4 or 5, any response"/>
+ <event event="0x1e3" title="CCI-500" name="Snoop response 6/7" description="Access to snoop filter bank 6 or 7, any response"/>
+ <event event="0x1e4" title="CCI-500" name="Snoop miss 0/1" description="Access to snoop filter bank 0 or 1, miss response"/>
+ <event event="0x1e5" title="CCI-500" name="Snoop miss 2/3" description="Access to snoop filter bank 2 or 3, miss response"/>
+ <event event="0x1e6" title="CCI-500" name="Snoop miss 4/5" description="Access to snoop filter bank 4 or 5, miss response"/>
+ <event event="0x1e7" title="CCI-500" name="Snoop miss 6/7" description="Access to snoop filter bank 6 or 7, miss response"/>
+ <event event="0x1e8" title="CCI-500" name="Snoop invalidation" description="Back invalidation from snoop filter"/>
+ <event event="0x1e9" title="CCI-500" name="Snoop small" description="Requests that allocate into a snoop filter bank might be stalled because all ways are used. The snoop filter RAM might be too small."/>
+ <event event="0x1ea" title="CCI-500" name="TT stall" description="Stall because TT full, increase TT_DEPTH parameter to avoid performance degradation"/>
+ <event event="0x1eb" title="CCI-500" name="Write request" description="CCI-generated write request"/>
+ <event event="0x1ec" title="CCI-500" name="Snoop handshake" description="CD handshake in snoop network, use this to measure snoop data bandwidth. Each event corresponds to 16 bytes of snoop data."/>
+ <event event="0x1ed" title="CCI-500" name="Address hazard" description="Request stall because of address hazard"/>
+ <event event="0x1ee" title="CCI-500" name="TT full" description="Snoop request stall because of snoop TT being full"/>
+ <event event="0x1ef" title="CCI-500" name="Snoop override" description="Snoop request type override for TZMP1 protection"/>
+ </category>
<counter_set name="ARMv7_Cortex_A15_cnt" count="6"/>
<category name="Cortex-A15" counter_set="ARMv7_Cortex_A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
<event counter="ARMv7_Cortex_A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
- <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
+ <event event="0x00" title="Software" name="Increment" description="Instruction architecturally executed, condition code check pass, software increment"/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
<event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
<event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
<event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
<event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
- <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
- <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
- <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Instruction architecturally executed, condition code check pass, exception return"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction architecturally executed, condition code check pass, write to CONTEXTIDR"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Mispredicted or not predicted branch speculatively executed"/>
<event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
<event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
- <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
- <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache write-back"/>
<event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
<event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
- <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
- <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache write-back"/>
+ <event event="0x19" title="Bus" name="Access" description="Bus access"/>
<event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
<event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
- <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/>
- <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
- <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
- <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
- <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
- <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
- <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-Back - Victim"/>
- <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-Back - Cleaning and coherency"/>
+ <event event="0x1c" title="Memory" name="Translation table" description="Instruction architecturally executed, condition code check pass, write to TTBR"/>
+ <event event="0x1d" title="Bus" name="Cycle" description="Bus cycle"/>
+ <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access, read"/>
+ <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access, write"/>
+ <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill, read"/>
+ <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill, write"/>
+ <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache write-back, victim"/>
+ <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache write-back, cleaning and coherency"/>
<event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
- <event event="0x4c" title="TLB" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
- <event event="0x4d" title="TLB" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
- <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
- <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
- <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
- <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
- <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/>
- <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-Back - Cleaning and coherency"/>
+ <event event="0x4c" title="Cache" name="L1 TLB refill read" description="Level 1 data TLB refill, read"/>
+ <event event="0x4d" title="Cache" name="L1 TLB refill write" description="Level 1 data TLB refill, write"/>
+ <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access, read"/>
+ <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access, write"/>
+ <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill, read"/>
+ <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill, write"/>
+ <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache write-back, victim"/>
+ <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache write-back, cleaning and coherency"/>
<event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
- <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
- <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
- <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
- <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
- <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
- <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
- <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
- <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
+ <event event="0x60" title="Bus" name="Read" description="Bus access, read"/>
+ <event event="0x61" title="Bus" name="Write" description="Bus access, write"/>
+ <event event="0x62" title="Bus" name="Cacheable normal" description="Bus access, Normal, Cacheable, Shareable"/>
+ <event event="0x63" title="Bus" name="Not normal" description="Bus access, not Normal, Cacheable, Shareable"/>
+ <event event="0x64" title="Bus" name="Access normal" description="Bus access, normal"/>
+ <event event="0x65" title="Bus" name="Peripheral" description="Bus access, peripheral"/>
+ <event event="0x66" title="Memory" name="Read" description="Data memory access, read"/>
+ <event event="0x67" title="Memory" name="Write" description="Data memory access, write"/>
+ <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access, read"/>
+ <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access, write"/>
<event event="0x6a" title="Memory" name="Unaligned" description="Unaligned access"/>
- <event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive instruction speculatively executed - LDREX"/>
- <event event="0x6d" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
- <event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive instruction speculatively executed - STREX fail"/>
- <event event="0x70" title="Instruction" name="Load" description="Instruction speculatively executed - Load"/>
- <event event="0x71" title="Instruction" name="Store" description="Instruction speculatively executed - Store"/>
- <event event="0x72" title="Instruction" name="Load/Store" description="Instruction speculatively executed - Load or store"/>
- <event event="0x73" title="Instruction" name="Integer" description="Instruction speculatively executed - Integer data processing"/>
- <event event="0x74" title="Instruction" name="Advanced SIMD" description="Instruction speculatively executed - Advanced SIMD"/>
- <event event="0x75" title="Instruction" name="VFP" description="Instruction speculatively executed - VFP"/>
- <event event="0x76" title="Instruction" name="Software change" description="Instruction speculatively executed - Software change of the PC"/>
- <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
- <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
- <event event="0x7a" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
- <event event="0x7c" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
- <event event="0x7d" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
- <event event="0x7e" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
+ <event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive instruction speculatively executed, LDREX"/>
+ <event event="0x6d" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed, STREX pass"/>
+ <event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive instruction speculatively executed, STREX fail"/>
+ <event event="0x70" title="Instruction" name="Load" description="Instruction speculatively executed, load"/>
+ <event event="0x71" title="Instruction" name="Store" description="Instruction speculatively executed, store"/>
+ <event event="0x72" title="Instruction" name="Load/Store" description="Instruction speculatively executed, load or store"/>
+ <event event="0x73" title="Instruction" name="Integer" description="Instruction speculatively executed, integer data processing"/>
+ <event event="0x74" title="Instruction" name="Advanced SIMD" description="Instruction speculatively executed, Advanced SIMD Extension"/>
+ <event event="0x75" title="Instruction" name="VFP" description="Instruction speculatively executed, Floating-point Extension"/>
+ <event event="0x76" title="Instruction" name="Software change" description="Instruction speculatively executed, software change of the PC"/>
+ <event event="0x78" title="Branch" name="Immediate" description="Branch speculatively executed, immediate branch"/>
+ <event event="0x79" title="Procedure" name="Return" description="Branch speculatively executed, procedure return"/>
+ <event event="0x7a" title="Branch" name="Indirect" description="Branch speculatively executed, indirect branch"/>
+ <event event="0x7c" title="Instruction" name="ISB" description="Barrier speculatively executed, ISB"/>
+ <event event="0x7d" title="Instruction" name="DSB" description="Barrier speculatively executed, DSB"/>
+ <event event="0x7e" title="Instruction" name="DMB" description="Barrier speculatively executed, DMB"/>
</category>
<counter_set name="ARMv7_Cortex_A17_cnt" count="6"/>
<category name="Cortex-A17" counter_set="ARMv7_Cortex_A17_cnt" per_cpu="yes" supports_event_based_sampling="yes">
<event counter="ARMv7_Cortex_A17_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
- <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
- <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
- <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
- <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
- <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill at (at least) the lowest level of instruction or unified cache. Includes the speculative linefills in the count."/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill at (at least) the lowest level of TLB. Includes the speculative requests in the count."/>
+ <event event="0x03" title="Cache" name="Data refill" description="Data read or write operation that causes a refill at (at least) the lowest level of data or unified cache. Counts the number of allocations performed in the Data Cache because of a read or a write."/>
+ <event event="0x04" title="Cache" name="Data access" description="Data read or write operation that causes a cache access at (at least) the lowest level of data or unified cache. This includes speculative reads."/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Data read or write operation that causes a TLB refill at (at least) the lowest level of TLB. This does not include micro TLB misses because of PLD, PLI, CP15 Cache operation by MVA and CP15 VA to PA operations."/>
<event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken. Counts the number of exceptions architecturally taken."/>
<event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
- <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
- <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
- <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
- <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
- <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
- <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Change to ContextID retired. Counts the number of instructions architecturally executed writing into the ContextID register."/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted. Counts the number of mispredicted or not-predicted branches executed. This includes the branches which are flushed because of a previous load/store which aborts late."/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branches or other change in program flow that could have been predicted by the branch prediction resources of the processor. This includes the branches which are flushed because of a previous load/store which aborts late."/>
+ <event event="0x13" title="Memory" name="Memory access" description="Level 1 data memory access"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache eviction"/>
<event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
<event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
- <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
- <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
- <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
- <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/>
- <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache write-back. Data transfers made as a result of a coherency request from the Level 2 caches to outside of the Level 1 and Level 2 caches are not counted. Write-backs made as a result of CP15 cache maintenance operations are counted."/>
+ <event event="0x19" title="Bus" name="Access" description="Bus accesses. Single transfer bus accesses on either of the ACE read or write channels might increment twice in one cycle if both the read and write channels are active simultaneously.Operations that utilise the bus that do not explicitly transfer data, such as barrier or coherency operations are counted as bus accesses."/>
+ <event event="0x1b" title="Instruction" name="Speculative" description="Instructions speculatively executed"/>
+ <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table register (TTBR0 or TTBR1)"/>
+ <event event="0x1d" title="Bus" name="Cycle" description="Bus cycle"/>
<event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
<event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
<event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
<event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
- <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/>
- <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-Back - Cleaning and coherency"/>
+ <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache write-back - Victim"/>
+ <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache write-back - Cleaning and coherency"/>
<event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
- <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
- <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/>
- <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/>
+ <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal Cacheable"/>
+ <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not Cacheable"/>
<event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
<event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
<event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
<event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive instruction speculatively executed - LDREX"/>
<event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive instruction speculatively executed - STREX fail"/>
<event event="0x6f" title="Intrinsic" name="STREX" description="Exclusive instruction speculatively executed - STREX"/>
- <event event="0x70" title="Instruction" name="Load" description="Instruction speculatively executed - Load"/>
- <event event="0x71" title="Instruction" name="Store" description="Instruction speculatively executed - Store"/>
+ <event event="0x70" title="Instruction" name="Load" description="Load instruction speculatively executed"/>
+ <event event="0x71" title="Instruction" name="Store" description="Store instruction speculatively executed"/>
<event event="0x72" title="Instruction" name="Load/Store" description="Instruction speculatively executed - Load or store"/>
- <event event="0x73" title="Instruction" name="Integer" description="Instruction speculatively executed - Integer data processing"/>
+ <event event="0x73" title="Instruction" name="Integer" description="Instruction speculatively executed - Data processing"/>
<event event="0x74" title="Instruction" name="Advanced SIMD" description="Instruction speculatively executed - Advanced SIMD"/>
<event event="0x75" title="Instruction" name="VFP" description="Instruction speculatively executed - VFP"/>
<event event="0x76" title="Instruction" name="Software change" description="Instruction speculatively executed - Software change of the PC"/>
- <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
- <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
- <event event="0x7a" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
+ <event event="0x78" title="Branch" name="Immediate" description="Branch speculatively executed - Immediate branch"/>
+ <event event="0x79" title="Procedure" name="Return" description="Branch speculatively executed - Procedure return"/>
+ <event event="0x7a" title="Branch" name="Indirect" description="Branch speculatively executed - Indirect branch"/>
<event event="0x7c" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
<event event="0x7d" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
<event event="0x7e" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
- <event event="0x81" title="Exception" name="Undefined" description="Exception taken, other synchronous"/>
- <event event="0x8a" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
- <event event="0xc0" title="Instruction" name="Stalled Linefill" description="Instruction side stalled due to a Linefill"/>
- <event event="0xc1" title="Instruction" name="Stalled Page Table Walk" description="Instruction Side stalled due to a Page Table Walk"/>
+ <event event="0x81" title="Exception" name="Undefined" description="Exception taken - Undefined Instruction"/>
+ <event event="0x8a" title="Exception" name="Hypervisor call" description="Exception taken - Hypervisor Call"/>
+ <event event="0xc0" title="Instruction" name="Stalled Linefill" description="Instruction side stalled due to a linefill"/>
+ <event event="0xc1" title="Instruction" name="Stalled Page Table Walk" description="Instruction side stalled due to a translation table walk"/>
<event event="0xc2" title="Cache" name="4 Ways Read" description="Number of set of 4 ways read in the instruction cache - Tag RAM"/>
<event event="0xc3" title="Cache" name="Ways Read" description="Number of ways read in the instruction cache - Data RAM"/>
<event event="0xc4" title="Cache" name="BATC Read" description="Number of ways read in the instruction BTAC RAM"/>
- <event event="0xca" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local Cortex-A17 cluster, rather than accessing the L2 cache or issuing an external read. It increments on each transaction, rather than on each beat of data"/>
+ <event event="0xca" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local Cortex-A17 cluster, rather than accessing the L2 cache or issuing an external read. It increments on each transaction, rather than on each beat of data."/>
<event event="0xd3" title="Slots" name="Load-Store Unit" description="Duration during which all slots in the Load-Store Unit are busy"/>
<event event="0xd8" title="Slots" name="Load-Store Issue Queue" description="Duration during which all slots in the Load-Store Issue queue are busy"/>
<event event="0xd9" title="Slots" name="Data Processing Issue Queue" description="Duration during which all slots in the Data Processing issue queue are busy"/>
<event event="0xdc" title="Hypervisor" name="Traps" description="Number of Trap to hypervisor"/>
<event event="0xde" title="PTM" name="EXTOUT 0" description="PTM EXTOUT 0"/>
<event event="0xdf" title="PTM" name="EXTOUT 1" description="PTM EXTOUT 1"/>
- <event event="0xe0" title="MMU" name="Table Walk" description="Duration during which the MMU handle a Page table walk"/>
- <event event="0xe1" title="MMU" name="Stage1 Table Walk" description="Duration during which the MMU handle a Stage1 Page table walk"/>
- <event event="0xe2" title="MMU" name="Stage2 Table Walk" description="Duration during which the MMU handle a Stage2 Page table walk"/>
- <event event="0xe3" title="MMU" name="LSU Table Walk" description="Duration during which the MMU handle a Page table walk requested by the Load Store Unit"/>
- <event event="0xe4" title="MMU" name="Instruction Table Walk" description="Duration during which the MMU handle a Page table walk requested by the Instruction side"/>
- <event event="0xe5" title="MMU" name="Preload Table Walk" description="Duration during which the MMU handle a Page table walk requested by a Preload instruction or Prefetch request"/>
- <event event="0xe6" title="MMU" name="cp15 Table Walk" description="Duration during which the MMU handle a Page table walk requested by a cp15 operation (maintenance by MVA and VA-to-PA operation)"/>
+ <event event="0xe0" title="MMU" name="Table Walk" description="Duration during which the MMU handle a translation table walk"/>
+ <event event="0xe1" title="MMU" name="Stage1 Table Walk" description="Duration during which the MMU handle a Stage1 translation table walk"/>
+ <event event="0xe2" title="MMU" name="Stage2 Table Walk" description="Duration during which the MMU handle a Stage2 translation table walk"/>
+ <event event="0xe3" title="MMU" name="LSU Table Walk" description="Duration during which the MMU handle a translation table walk requested by the Load Store Unit"/>
+ <event event="0xe4" title="MMU" name="Instruction Table Walk" description="Duration during which the MMU handle a translation table walk requested by the Instruction side"/>
+ <event event="0xe5" title="MMU" name="Preload Table Walk" description="Duration during which the MMU handle a translation table walk requested by a Preload instruction or Prefetch request"/>
+ <event event="0xe6" title="MMU" name="cp15 Table Walk" description="Duration during which the MMU handle a translation table walk requested by a CP15 operation (maintenance by MVA and VA-to-PA operation)"/>
<event event="0xe7" title="Cache" name="L1 PLD TLB refill" description="Level 1 PLD TLB refill"/>
<event event="0xe8" title="Cache" name="L1 CP15 TLB refill" description="Level 1 CP15 TLB refill"/>
<event event="0xe9" title="Cache" name="L1 TLB flush" description="Level 1 TLB flush"/>
<counter_set name="ARMv7_Cortex_A5_cnt" count="2"/>
<category name="Cortex-A5" counter_set="ARMv7_Cortex_A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
<event counter="ARMv7_Cortex_A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
- <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
- <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
- <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
- <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
- <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
- <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
- <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
- <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
+ <event event="0x00" title="Software" name="Increment" description="Software increment. The register is incremented only on writes to the Software Increment Register."/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill at (at least) the lowest level of instruction or unified cache. Includes the speculative linefills in the count."/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill at (at least) the lowest level of TLB. Includes the speculative requests in the count."/>
+ <event event="0x03" title="Cache" name="Data refill" description="Data read or write operation that causes a refill at (at least) the lowest level of data or unified cache. Counts the number of allocations performed in the Data Cache because of a read or a write."/>
+ <event event="0x04" title="Cache" name="Data access" description="Data read or write operation that causes a cache access at (at least) the lowest level of data or unified cache. This includes speculative reads."/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Data read or write operation that causes a TLB refill at (at least) the lowest level of TLB. This does not include micro TLB misses because of PLD, PLI, CP15 Cache operation by MVA and CP15 VA to PA operations."/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Data read architecturally executed. Counts the number of data read instructions accepted by the Load Store Unit. This includes counting the speculative and aborted LDR/LDM, and the reads because of the SWP instructions."/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Data write architecturally executed. Counts the number of data write instructions accepted by the Load Store Unit. This includes counting the speculative and aborted STR/STM, and the writes because of the SWP instructions."/>
<event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken. Counts the number of exceptions architecturally taken."/>
<event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
- <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
- <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
- <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
- <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
- <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
- <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
- <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Change to ContextID retired. Counts the number of instructions architecturally executed writing into the ContextID Register."/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of PC"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed (taken or not taken). This includes the branches which are flushed due to a previous load/store which aborts late."/>
+ <event event="0x0e" title="Procedure" name="Return" description="Procedure return (other than exception returns) architecturally executed"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned load-store"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted/not predicted. Counts the number of mispredicted or not-predicted branches executed. This includes the branches which are flushed because of a previous load/store which aborts late."/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branches or other change in program flow that could have been predicted by the branch prediction resources of the processor. This includes the branches which are flushed because of a previous load/store which aborts late."/>
<event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
- <event event="0x14" title="Cache" name="Instruction access" description="Instruction cache access"/>
+ <event event="0x14" title="Cache" name="Instruction access" description="Instruction Cache access"/>
<event event="0x15" title="Cache" name="Data eviction" description="Data cache eviction"/>
<event event="0x86" title="Interrupts" name="IRQ" description="IRQ exception taken"/>
<event event="0x87" title="Interrupts" name="FIQ" description="FIQ exception taken"/>
- <event event="0xC0" title="Memory" name="External request" description="External memory request"/>
- <event event="0xC1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
- <event event="0xC2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
- <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
- <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
- <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
- <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description="ETM - ETM Ext Out[0]"/>
- <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description="ETM - ETM Ext Out[1]"/>
- <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
+ <event event="0xc0" title="Memory" name="External request" description="External memory request"/>
+ <event event="0xc1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
+ <event event="0xc2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
+ <event event="0xc3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
+ <event event="0xc4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
+ <event event="0xc5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
+ <event event="0xc7" title="ETM" name="ETM Ext Out[0]" description="ETM Ext Out[0]"/>
+ <event event="0xc8" title="ETM" name="ETM Ext Out[1]" description="ETM Ext Out[1]"/>
+ <event event="0xc9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
</category>
<counter_set name="ARM_Cortex-A53_cnt" count="6"/>
<category name="Cortex-A53" counter_set="ARM_Cortex-A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
<event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
- <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x00" title="Software" name="Increment" description="Software increment. The register is incremented only on writes to the Software Increment Register."/>
<event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
<event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
<event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
<event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
<event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x06" title="Instruction" name="Data Read" description="Instruction architecturally executed, condition check pass - load"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Instruction architecturally executed, condition check pass - store"/>
<event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
- <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
- <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
- <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Change to Context ID retired"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Instruction architecturally executed, condition check pass, software change of the PC"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Instruction architecturally executed, immediate branch"/>
+ <event event="0x0e" title="Procedure" name="Return" description="Instruction architecturally executed, condition code check pass, procedure return"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Instruction architecturally executed, condition check pass, unaligned load or store"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Mispredicted or not predicted branch speculatively executed"/>
<event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
<event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
- <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
- <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
- <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
- <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
- <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="L1 Instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data write" description="L1 Data cache Write-Back"/>
+ <event event="0x16" title="Cache" name="L2 data access" description="L2 Data cache access"/>
+ <event event="0x17" title="Cache" name="L2 data refill" description="L2 Data cache refill"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="L2 Data cache Write-Back"/>
<event event="0x19" title="Bus" name="Access" description="Bus access"/>
- <event event="0x1A" title="Memory" name="Error" description="Local memory error"/>
- <event event="0x1B" title="Instruction" name="Speculative" description="Operation speculatively executed"/>
- <event event="0x1C" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/>
- <event event="0x1D" title="Bus" name="Cycle" description="Bus cycle"/>
- <event event="0x1E" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/>
- <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
- <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
- <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
- <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
- <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-back - Victim"/>
- <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-back - Cleaning and coherency"/>
- <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
- <event event="0x4C" title="Cache" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
- <event event="0x4D" title="Cache" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
- <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
- <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
- <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
- <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
- <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-back - Victim"/>
- <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-back - Cleaning and coherency"/>
- <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
+ <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
+ <event event="0x1d" title="Bus" name="Cycle" description="Bus cycle"/>
+ <event event="0x1e" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/>
<event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
<event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
- <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/>
- <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/>
- <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
- <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
- <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
- <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
- <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
- <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
- <event event="0x6A" title="Memory" name="Unaligned" description="Unaligned access"/>
- <event event="0x6C" title="Intrinsic" name="LDREX" description="Exclusive operation speculatively executed - LDREX"/>
- <event event="0x6D" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
- <event event="0x6E" title="Intrinsic" name="STREX fail" description="Exclusive operation speculatively executed - STREX fail"/>
- <event event="0x70" title="Instruction" name="Load" description="Operation speculatively executed - Load"/>
- <event event="0x71" title="Instruction" name="Store" description="Operation speculatively executed - Store"/>
- <event event="0x72" title="Instruction" name="Load/Store" description="Operation speculatively executed - Load or store"/>
- <event event="0x73" title="Instruction" name="Integer" description="Operation speculatively executed - Integer data processing"/>
- <event event="0x74" title="Instruction" name="Advanced SIMD" description="Operation speculatively executed - Advanced SIMD"/>
- <event event="0x75" title="Instruction" name="VFP" description="Operation speculatively executed - VFP"/>
- <event event="0x76" title="Instruction" name="Software change" description="Operation speculatively executed - Software change of the PC"/>
- <event event="0x77" title="Instruction" name="Crypto" description="Operation speculatively executed, crypto data processing"/>
- <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
- <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
- <event event="0x7A" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
- <event event="0x7C" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
- <event event="0x7D" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
- <event event="0x7E" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
- <event event="0x81" title="Exception" name="Undefined" description="Exception taken, other synchronous"/>
- <event event="0x82" title="Exception" name="Supervisor" description="Exception taken, Supervisor Call"/>
- <event event="0x83" title="Exception" name="Instruction abort" description="Exception taken, Instruction Abort"/>
- <event event="0x84" title="Exception" name="Data abort" description="Exception taken, Data Abort or SError"/>
+ <event event="0x7a" title="Branch" name="Indirect" description="Branch speculatively executed - Indirect branch"/>
<event event="0x86" title="Interrupts" name="IRQ" description="Exception taken, IRQ"/>
<event event="0x87" title="Interrupts" name="FIQ" description="Exception taken, FIQ"/>
- <event event="0x88" title="Exception" name="Secure monitor call" description="Exception taken, Secure Monitor Call"/>
- <event event="0x8A" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
- <event event="0x8B" title="Exception" name="Instruction abort non-local" description="Exception taken, Instruction Abort not taken locally"/>
- <event event="0x8C" title="Exception" name="Data abort non-local" description="Exception taken, Data Abort or SError not taken locally"/>
- <event event="0x8D" title="Exception" name="Other non-local" description="Exception taken - Other traps not taken locally"/>
- <event event="0x8E" title="Exception" name="IRQ non-local" description="Exception taken, IRQ not taken locally"/>
- <event event="0x8F" title="Exception" name="FIQ non-local" description="Exception taken, FIQ not taken locally"/>
- <event event="0x90" title="Release Consistency" name="Load" description="Release consistency instruction speculatively executed - Load Acquire"/>
- <event event="0x91" title="Release Consistency" name="Store" description="Release consistency instruction speculatively executed - Store Release"/>
+ <event event="0xc0" title="Memory" name="External request" description="External memory request"/>
+ <event event="0xc1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
+ <event event="0xc2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
+ <event event="0xc3" title="Cache" name="Throttle" description="Instruction Cache Throttle occurred"/>
+ <event event="0xc4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
+ <event event="0xc5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
+ <event event="0xc6" title="Pre-decode" name="error" description="Pre-decode error"/>
+ <event event="0xc7" title="Memory" name="Write stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
+ <event event="0xc8" title="Memory" name="Snoop" description="SCU Snooped data from another CPU for this CPU"/>
+ <event event="0xc9" title="Branch" name="Taken" description="Conditional branch executed"/>
+ <!--
+ <event event="0xca" title="Branch" name="Mispredicted a" description="Indirect branch mispredicted"/>
+ <event event="0xcb" title="Branch" name="Mispredicted b" description="Indirect branch mispredicted because of address miscompare"/>
+ <event event="0xcc" title="Branch" name="Mispredicted c" description="Conditional branch mispredicted"/>
+ -->
+ <event event="0xd0" title="Cache" name="L1 inst error" description="L1 Instruction Cache (data or tag) memory error"/>
+ <event event="0xd1" title="Cache" name="L1 data error" description="L1 Data Cache (data, tag or dirty) memory error, correctable or non-correctable"/>
+ <event event="0xd2" title="Cache" name="TLB error" description="TLB memory error"/>
+ <event event="0xe0" title="Stall" name="DPU IP empty" description="Attributable Performance Impact Event. Counts every cycle that the DPU IQ is empty and that is not because of a recent micro-TLB miss, instruction cache miss or pre-decode error."/>
+ <event event="0xe1" title="Stall" name="Cache miss" description="Attributable Performance Impact Event. Counts every cycle the DPU IQ is empty and there is an instruction cache miss being processed."/>
+ <event event="0xe2" title="Stall" name="TLB miss" description="Attributable Performance Impact Event. Counts every cycle the DPU IQ is empty and there is an instruction micro-TLB miss being processed."/>
+ <event event="0xe3" title="Stall" name="Pre-decode error" description="Attributable Performance Impact Event. Counts every cycle the DPU IQ is empty and there is a pre-decode error being processed."/>
+ <event event="0xe4" title="Stall" name="Interlock other" description="Attributable Performance Impact Event. Counts every cycle there is an interlock that is not because of an Advanced SIMD or Floating-point instruction, and not because of a load/store instruction waiting for data to calculate the address in the AGU. Stall cycles because of a stall in Wr, typically awaiting load data, are excluded."/>
+ <event event="0xe5" title="Stall" name="Interlock address" description="Attributable Performance Impact Event. Counts every cycle there is an interlock that is because of a load/store instruction waiting for data to calculate the address in the AGU. Stall cycles because of a stall in Wr, typically awaiting load data, are excluded."/>
+ <event event="0xe6" title="Stall" name="Interlock SIMD/FPU" description="Attributable Performance Impact Event. Counts every cycle there is an interlock that is because of an Advanced SIMD or Floating-point instruction. Stall cycles because of a stall in the Wr stage, typically awaiting load data, are excluded."/>
+ <event event="0xe7" title="Stall" name="Load miss" description="Attributable Performance Impact Event. Counts every cycle there is a stall in the Wr stage because of a load miss"/>
+ <event event="0xe8" title="Stall" name="Store" description="Attributable Performance Impact Event. Counts every cycle there is a stall in the Wr stage because of a store."/>
</category>
<event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
<event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
<event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
- <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
- <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
- <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Instruction architecturally executed (condition check pass) - Exception return"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction architecturally executed (condition check pass) - Write to CONTEXTIDR"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Mispredicted or not predicted branch speculatively executed"/>
<event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
<event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
<event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
<event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
<event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
<event event="0x19" title="Bus" name="Access" description="Bus access"/>
- <event event="0x1A" title="Memory" name="Error" description="Local memory error"/>
- <event event="0x1B" title="Instruction" name="Speculative" description="Operation speculatively executed"/>
- <event event="0x1C" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/>
- <event event="0x1D" title="Bus" name="Cycle" description="Bus cycle"/>
- <event event="0x1E" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/>
+ <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
+ <event event="0x1b" title="Instruction" name="Speculative" description="Operation speculatively executed"/>
+ <event event="0x1c" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/>
+ <event event="0x1d" title="Bus" name="Cycle" description="Bus cycle"/>
+ <event event="0x1e" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/>
<event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
<event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
<event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
<event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-back - Victim"/>
<event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-back - Cleaning and coherency"/>
<event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
- <event event="0x4C" title="Cache" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
- <event event="0x4D" title="Cache" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
+ <event event="0x4c" title="Cache" name="L1 TLB refill read" description="Level 1 data TLB refill - Read"/>
+ <event event="0x4d" title="Cache" name="L1 TLB refill write" description="Level 1 data TLB refill - Write"/>
<event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
<event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
<event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
<event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
<event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
<event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
- <event event="0x6A" title="Memory" name="Unaligned" description="Unaligned access"/>
- <event event="0x6C" title="Intrinsic" name="LDREX" description="Exclusive operation speculatively executed - LDREX"/>
- <event event="0x6D" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
- <event event="0x6E" title="Intrinsic" name="STREX fail" description="Exclusive operation speculatively executed - STREX fail"/>
+ <event event="0x6a" title="Memory" name="Unaligned" description="Unaligned access"/>
+ <event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive operation speculatively executed - LDREX"/>
+ <event event="0x6d" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
+ <event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive operation speculatively executed - STREX fail"/>
<event event="0x70" title="Instruction" name="Load" description="Operation speculatively executed - Load"/>
<event event="0x71" title="Instruction" name="Store" description="Operation speculatively executed - Store"/>
<event event="0x72" title="Instruction" name="Load/Store" description="Operation speculatively executed - Load or store"/>
<event event="0x75" title="Instruction" name="VFP" description="Operation speculatively executed - VFP"/>
<event event="0x76" title="Instruction" name="Software change" description="Operation speculatively executed - Software change of the PC"/>
<event event="0x77" title="Instruction" name="Crypto" description="Operation speculatively executed, crypto data processing"/>
- <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
- <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
- <event event="0x7A" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
- <event event="0x7C" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
- <event event="0x7D" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
- <event event="0x7E" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
+ <event event="0x78" title="Branch" name="Immediate" description="Branch speculatively executed - Immediate branch"/>
+ <event event="0x79" title="Procedure" name="Return" description="Branch speculatively executed - Procedure return"/>
+ <event event="0x7a" title="Branch" name="Indirect" description="Branch speculatively executed - Indirect branch"/>
+ <event event="0x7c" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
+ <event event="0x7d" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
+ <event event="0x7e" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
<event event="0x81" title="Exception" name="Undefined" description="Exception taken, other synchronous"/>
<event event="0x82" title="Exception" name="Supervisor" description="Exception taken, Supervisor Call"/>
<event event="0x83" title="Exception" name="Instruction abort" description="Exception taken, Instruction Abort"/>
<event event="0x86" title="Interrupts" name="IRQ" description="Exception taken, IRQ"/>
<event event="0x87" title="Interrupts" name="FIQ" description="Exception taken, FIQ"/>
<event event="0x88" title="Exception" name="Secure monitor call" description="Exception taken, Secure Monitor Call"/>
- <event event="0x8A" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
- <event event="0x8B" title="Exception" name="Instruction abort non-local" description="Exception taken, Instruction Abort not taken locally"/>
- <event event="0x8C" title="Exception" name="Data abort non-local" description="Exception taken, Data Abort or SError not taken locally"/>
- <event event="0x8D" title="Exception" name="Other non-local" description="Exception taken - Other traps not taken locally"/>
- <event event="0x8E" title="Exception" name="IRQ non-local" description="Exception taken, IRQ not taken locally"/>
- <event event="0x8F" title="Exception" name="FIQ non-local" description="Exception taken, FIQ not taken locally"/>
- <event event="0x90" title="Release Consistency" name="Load" description="Release consistency instruction speculatively executed - Load Acquire"/>
- <event event="0x91" title="Release Consistency" name="Store" description="Release consistency instruction speculatively executed - Store Release"/>
+ <event event="0x8a" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
+ <event event="0x8b" title="Exception" name="Instruction abort non-local" description="Exception taken, Instruction Abort not taken locally"/>
+ <event event="0x8c" title="Exception" name="Data abort non-local" description="Exception taken, Data Abort, or SError not taken locally"/>
+ <event event="0x8d" title="Exception" name="Other non-local" description="Exception taken - Other traps not taken locally"/>
+ <event event="0x8e" title="Exception" name="IRQ non-local" description="Exception taken, IRQ not taken locally"/>
+ <event event="0x8f" title="Exception" name="FIQ non-local" description="Exception taken, FIQ not taken locally"/>
+ <event event="0x90" title="Release Consistency" name="Load" description="Release consistency instruction speculatively executed - Load-Acquire"/>
+ <event event="0x91" title="Release Consistency" name="Store" description="Release consistency instruction speculatively executed - Store-Release"/>
</category>
<counter_set name="ARMv7_Cortex_A7_cnt" count="4"/>
<category name="Cortex-A7" counter_set="ARMv7_Cortex_A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
<event counter="ARMv7_Cortex_A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
- <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
- <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
- <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
- <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
- <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
- <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
- <event event="0x06" title="Memory" name="Data Read" description="Data read architecturally executed"/>
- <event event="0x07" title="Memory" name="Data Write" description="Data write architecturally executed"/>
+ <event event="0x00" title="Software" name="Increment" description="Software increment. The register is incremented only on writes to the Software Increment Register."/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill at (at least) the lowest level of instruction or unified cache. Includes the speculative linefills in the count."/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill at (at least) the lowest level of TLB. Includes the speculative requests in the count."/>
+ <event event="0x03" title="Cache" name="Data refill" description="Data read or write operation that causes a refill at (at least) the lowest level of data or unified cache. Counts the number of allocations performed in the Data Cache because of a read or a write."/>
+ <event event="0x04" title="Cache" name="Data access" description="Data read or write operation that causes a cache access at (at least) the lowest level of data or unified cache. This includes speculative reads."/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Data read or write operation that causes a TLB refill at (at least) the lowest level of TLB. This does not include micro TLB misses because of PLD, PLI, CP15 Cache operation by MVA and CP15 VA to PA operations."/>
+ <event event="0x06" title="Instruction" name="Memory Read" description="Data read architecturally executed. Counts the number of data read instructions accepted by the Load Store Unit. This includes counting the speculative and aborted LDR/LDM, and the reads because of the SWP instructions."/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Data write architecturally executed. Counts the number of data write instructions accepted by the Load Store Unit. This includes counting the speculative and aborted STR/STM, and the writes because of the SWP instructions."/>
<event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken. Counts the number of exceptions architecturally taken."/>
<event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
- <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
- <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
- <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
- <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
- <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
- <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Change to ContextID retired. Counts the number of instructions architecturally executed writing into the ContextID Register."/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of PC"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed (taken or not taken). This includes the branches which are flushed due to a previous load/store which aborts late."/>
+ <event event="0x0e" title="Procedure" name="Return" description="Procedure return (other than exception returns) architecturally executed"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned load-store"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted/not predicted. Counts the number of mispredicted or not-predicted branches executed. This includes the branches which are flushed because of a previous load/store which aborts late."/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branches or other change in program flow that could have been predicted by the branch prediction resources of the processor. This includes the branches which are flushed because of a previous load/store which aborts late."/>
<event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
- <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
- <event event="0x15" title="Cache" name="L1 data eviction" description="Level 1 data cache eviction"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Instruction Cache access"/>
+ <event event="0x15" title="Cache" name="L1 data eviction" description="Data cache eviction"/>
<event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
<event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
- <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
- <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
- <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
- <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
- <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache write-back. Data transfers made as a result of a coherency request from the Level 2 caches to outside of the Level 1 and Level 2 caches are not counted. Write-backs made as a result of CP15 cache maintenance operations are counted."/>
+ <event event="0x19" title="Bus" name="Access" description="Bus accesses. Single transfer bus accesses on either of the ACE read or write channels might increment twice in one cycle if both the read and write channels are active simultaneously. Operations that utilise the bus that do not explicitly transfer data, such as barrier or coherency operations are counted as bus accesses."/>
+ <event event="0x1d" title="Bus" name="Cycle" description="Bus cycle"/>
+ <event event="0x60" title="Bus" name="Read" description="Bus access, read"/>
+ <event event="0x61" title="Bus" name="Write" description="Bus access, write"/>
<event event="0x86" title="Exception" name="IRQ" description="IRQ exception taken"/>
<event event="0x87" title="Exception" name="FIQ" description="FIQ exception taken"/>
- <event event="0xC0" title="Memory" name="External request" description="External memory request"/>
- <event event="0xC1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
- <event event="0xC2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
- <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
- <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
- <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
- <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description="ETM - ETM Ext Out[0]"/>
- <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description="ETM - ETM Ext Out[1]"/>
- <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
- <event event="0xCA" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local cluster, rather than accessing the L2 cache or issuing an external read."/>
+ <event event="0xc0" title="Memory" name="External request" description="External memory request"/>
+ <event event="0xc1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
+ <event event="0xc2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
+ <event event="0xc3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
+ <event event="0xc4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
+ <event event="0xc5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
+ <event event="0xc7" title="ETM" name="ETM Ext Out[0]" description="ETM Ext Out[0]"/>
+ <event event="0xc8" title="ETM" name="ETM Ext Out[1]" description="ETM Ext Out[1]"/>
+ <event event="0xc9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
+ <event event="0xca" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local Cortex-A7 cluster, rather than accessing the L2 cache or issuing an external read. It increments on each transaction, rather than on each beat of data."/>
</category>
--- /dev/null
+ <counter_set name="ARM_Cortex_A72_cnt" count="6"/>
+ <category name="Cortex-A72" counter_set="ARM_Cortex_A72_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="ARM_Cortex_A72_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
+ <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
+ <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
+ <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
+ <event event="0x19" title="Bus" name="Access" description="Bus access"/>
+ <event event="0x1A" title="Memory" name="Error" description="Local memory error"/>
+ <event event="0x1B" title="Instruction" name="Speculative" description="Operation speculatively executed"/>
+ <event event="0x1C" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/>
+ <event event="0x1D" title="Bus" name="Cycle" description="Bus cycle"/>
+ <event event="0x1E" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/>
+ <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
+ <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
+ <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
+ <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
+ <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-back - Victim"/>
+ <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-back - Cleaning and coherency"/>
+ <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
+ <event event="0x4C" title="Cache" name="L1 TLB refill read" description="Level 1 data TLB refill - Read"/>
+ <event event="0x4D" title="Cache" name="L1 TLB refill write" description="Level 1 data TLB refill - Write"/>
+ <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
+ <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
+ <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
+ <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
+ <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-back - Victim"/>
+ <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-back - Cleaning and coherency"/>
+ <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
+ <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
+ <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
+ <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/>
+ <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/>
+ <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
+ <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
+ <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
+ <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
+ <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
+ <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
+ <event event="0x6A" title="Memory" name="Unaligned" description="Unaligned access"/>
+ <event event="0x6C" title="Intrinsic" name="LDREX" description="Exclusive operation speculatively executed - LDREX"/>
+ <event event="0x6D" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
+ <event event="0x6E" title="Intrinsic" name="STREX fail" description="Exclusive operation speculatively executed - STREX fail"/>
+ <event event="0x70" title="Instruction" name="Load" description="Operation speculatively executed - Load"/>
+ <event event="0x71" title="Instruction" name="Store" description="Operation speculatively executed - Store"/>
+ <event event="0x72" title="Instruction" name="Load/Store" description="Operation speculatively executed - Load or store"/>
+ <event event="0x73" title="Instruction" name="Integer" description="Operation speculatively executed - Integer data processing"/>
+ <event event="0x74" title="Instruction" name="Advanced SIMD" description="Operation speculatively executed - Advanced SIMD"/>
+ <event event="0x75" title="Instruction" name="VFP" description="Operation speculatively executed - VFP"/>
+ <event event="0x76" title="Instruction" name="Software change" description="Operation speculatively executed - Software change of the PC"/>
+ <event event="0x77" title="Instruction" name="Crypto" description="Operation speculatively executed, crypto data processing"/>
+ <event event="0x78" title="Branch" name="Immediate" description="Branch speculatively executed - Immediate branch"/>
+ <event event="0x79" title="Procedure" name="Return" description="Branch speculatively executed - Procedure return"/>
+ <event event="0x7A" title="Branch" name="Indirect" description="Branch speculatively executed - Indirect branch"/>
+ <event event="0x7C" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
+ <event event="0x7D" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
+ <event event="0x7E" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
+ <event event="0x81" title="Exception" name="Undefined" description="Exception taken, other synchronous"/>
+ <event event="0x82" title="Exception" name="Supervisor" description="Exception taken, Supervisor Call"/>
+ <event event="0x83" title="Exception" name="Instruction abort" description="Exception taken, Instruction Abort"/>
+ <event event="0x84" title="Exception" name="Data abort" description="Exception taken, Data Abort or SError"/>
+ <event event="0x86" title="Interrupts" name="IRQ" description="Exception taken, IRQ"/>
+ <event event="0x87" title="Interrupts" name="FIQ" description="Exception taken, FIQ"/>
+ <event event="0x88" title="Exception" name="Secure monitor call" description="Exception taken, Secure Monitor Call"/>
+ <event event="0x8A" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
+ <event event="0x8B" title="Exception" name="Instruction abort non-local" description="Exception taken, Instruction Abort not taken locally"/>
+ <event event="0x8C" title="Exception" name="Data abort non-local" description="Exception taken, Data Abort or SError not taken locally"/>
+ <event event="0x8D" title="Exception" name="Other non-local" description="Exception taken - Other traps not taken locally"/>
+ <event event="0x8E" title="Exception" name="IRQ non-local" description="Exception taken, IRQ not taken locally"/>
+ <event event="0x8F" title="Exception" name="FIQ non-local" description="Exception taken, FIQ not taken locally"/>
+ <event event="0x90" title="Release Consistency" name="Load" description="Release consistency instruction speculatively executed - Load Acquire"/>
+ <event event="0x91" title="Release Consistency" name="Store" description="Release consistency instruction speculatively executed - Store Release"/>
+ </category>
<category name="Cortex-A8" counter_set="ARMv7_Cortex_A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
<event counter="ARMv7_Cortex_A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
<event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
- <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
- <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
- <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
- <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
- <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
- <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
- <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
- <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
- <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
- <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
- <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
- <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
- <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
- <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
- <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
- <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill at the lowest level of instruction or unified cache. Each instruction fetch from normal cacheable memory that causes a refill from outside of the cache is counted. Accesses that do not cause a new cache refill, but are satisfied from refilling data of a previous miss are not counted. Where instruction fetches consist of multiple instructions, these accesses count as single events. CP15 cache maintenance operations do not count as events. This counter increments for speculative instruction fetches and for fetches of instructions that reach execution."/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill at the lowest level of TLB. Each instruction fetch that causes a translation table walk or an access to another level of TLB caching is counted. CP15 TLB maintenance operations do not count as events. This counter increments for speculative instruction fetches and for fetches of instructions that reach execution."/>
+ <event event="0x03" title="Cache" name="Data refill" description="Data read or write operation that causes a refill at the lowest level of data or unified cache. Each data read from or write to normal cacheable memory that causes a refill from outside of the cache is counted. Accesses that do not cause a new cache refill, but are satisfied from refilling data of a previous miss are not counted. Each access to a cache line to normal cacheable memory that causes a new linefill is counted, including the multiple transaction of instructions such as LDM or STM, PUSH and POP. Write-through writes that hit in the cache do not cause a linefill and so are not counted. CP15 cache maintenance operations do not count as events. This counter increments for speculative data accesses and for data accesses that are explicitly made by instructions."/>
+ <event event="0x04" title="Cache" name="Data access" description="Data read or write operation that causes a cache access at the lowest level of data or unified cache. Each access to a cache line to normal cacheable memory is counted including the multiple transaction of instructions such as LDM or STM. CP15 cache maintenance operations do not count as events. This counter increments for speculative data accesses and for data accesses that are explicitly made by instructions."/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Data read or write operation that causes a TLB refill at the lowest level of TLB. Each data read or write operation that causes a translation table walk or an access to another level of TLB caching is counted. CP15 TLB maintenance operations do not count as events. This counter increments for speculative data accesses and for data accesses that are explicitly made by instructions."/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Data read architecturally executed. This counter increments for every instruction that explicitly read data, including SWP. This counter only increments for instructions that are unconditional or that pass their condition codes."/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Data write architecturally executed. The counter increments for every instruction that explicitly wrote data, including SWP. This counter only increments for instructions that are unconditional or that pass their condition codes."/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed. This counter counts for all instructions, including conditional instructions that fail their condition codes."/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken. This counts for each exception taken."/>
+ <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed. This counter only increments for instructions that are unconditional or that pass their condition codes."/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the Context ID Register architecturally executed. This counter only increments for instructions that are unconditional or that pass their condition codes."/>
+ <event event="0x0c" title="Branch" name="PC change" description="Software change of PC, except by an exception, architecturally executed. This counter only increments for instructions that are unconditional or that pass their condition codes."/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed, taken or not taken. This includes B{L}, BLX, CB{N}Z, HB{L}, and HBLP. This counter counts for all immediate branch instructions that are architecturally executed, including conditional instructions that fail their condition codes."/>
+ <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception returns, architecturally executed. This counter only increments for instructions that are unconditional or that pass their condition codes."/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed. This counts each instruction that is an access to an unaligned address. This counter only increments for instructions that are unconditional or that pass their condition codes."/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted. This counts for every pipeline flush because of a misprediction from the program flow prediction resources."/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Branches or other change in the program flow that could have been predicted by the branch prediction resources of the processor"/>
<event event="0x40" title="Cache" name="Write buffer full" description="Any write buffer full cycle"/>
<event event="0x41" title="Cache" name="L2 store" description="Any store that is merged in the L2 memory system"/>
<event event="0x42" title="Cache" name="Bufferable transaction" description="Any bufferable store transaction from load/store to L2 cache, excluding eviction or cast out data"/>
<event event="0x46" title="AXI" name="Write" description="The number of AXI write data transfers"/>
<event event="0x47" title="Memory" name="Replay event" description="Any replay event in the memory system"/>
<event event="0x48" title="Memory" name="Unaligned access replay" description="Any unaligned memory access that results in a replay"/>
- <event event="0x49" title="Cache" name="L1 data hash miss" description="Any L1 data memory access that misses in the cache as a result of the hashing algorithm"/>
- <event event="0x4a" title="Cache" name="L1 inst hash miss" description="Any L1 instruction memory access that misses in the cache as a result of the hashing algorithm"/>
- <event event="0x4b" title="Cache" name="L1 page coloring" description="Any L1 data memory access in which a page coloring alias occurs"/>
+ <event event="0x49" title="Cache" name="L1 data hash miss" description="Any L1 data memory access that misses in the cache as a result of the hashing algorithm. The cases covered are: hash hit and physical address miss, hash hit and physical address hit in another way and hash miss and physical address hit."/>
+ <event event="0x4a" title="Cache" name="L1 inst hash miss" description="Any L1 instruction memory access that misses in the cache as a result of the hashing algorithm. The cases covered are: hash hit and physical address miss, hash hit and physical address hit in another way and hash miss and physical address hit."/>
+ <event event="0x4b" title="Cache" name="L1 page coloring" description="Any L1 data memory access in which a page coloring alias occurs. alias = virtual address [12] ! = physical address [12]. This behavior results in a data memory eviction or cast out."/>
<event event="0x4c" title="NEON" name="L1 cache hit" description="Any NEON access that hits in the L1 data cache"/>
<event event="0x4d" title="NEON" name="L1 cache access" description="Any NEON cacheable data accesses for L1 data cache"/>
<event event="0x4e" title="NEON" name="L2 cache access" description="Any L2 cache accesses as a result of a NEON memory access"/>
<event event="0x4f" title="NEON" name="L2 cache hit" description="Any NEON hit in the L2 cache"/>
<event event="0x50" title="Cache" name="L1 inst access" description="Any L1 instruction cache access, excluding CP15 cache accesses"/>
<event event="0x51" title="Branch" name="Return stack misprediction" description="Any return stack misprediction because of incorrect target address for a taken return stack pop"/>
- <event event="0x52" title="Branch" name="Direction misprediction" description="Branch direction misprediction"/>
+ <event event="0x52" title="Branch" name="Direction misprediction" description="Two forms of branch direction misprediction: branch predicted taken, but was not taken and branch predicted not taken, but was taken"/>
<event event="0x53" title="Branch" name="Taken prediction" description="Any predictable branch that is predicted to be taken"/>
<event event="0x54" title="Branch" name="Executed and taken prediction" description="Any predictable branch that is executed and taken"/>
<event event="0x55" title="Core" name="Operations issued" description="Number of operations issued, where an operation is either: an instruction or one operation in a sequence of operations that make up a multi-cycle instruction"/>
<event event="0x56" title="Core" name="No issue cycles" description="Increment for every cycle that no instructions are available for issue"/>
- <event event="0x57" title="Core" name="Issue cycles" description="For every cycle, this event counts the number of instructions issued in that cycle. Multi-cycle instructions are only counted once"/>
+ <event event="0x57" title="Core" name="Issue cycles" description="For every cycle, this event counts the number of instructions issued in that cycle. Multi-cycle instructions are only counted once."/>
<event event="0x58" title="NEON" name="MRC data wait" description="Number of cycles the processor stalls waiting on MRC data from NEON"/>
<event event="0x59" title="NEON" name="Full queue" description="Number of cycles that the processor stalls as a result of a full NEON instruction queue or NEON load queue"/>
<event event="0x5a" title="NEON" name="Idle" description="Number of cycles that NEON and integer processors are both not idle"/>
<event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
<event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
<event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
- <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken"/>
<event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
<event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
<event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
<event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
<event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
<event event="0x40" title="Java" name="Bytecode execute" description="Counts the number of Java bytecodes being decoded, including speculative ones"/>
- <event event="0x41" title="Java" name="SW bytecode execute" description="Counts the number of software java bytecodes being decoded, including speculative ones"/>
- <event event="0x42" title="Jazelle" name="Backward branch execute" description="Counts the number of Jazelle taken branches being executed"/>
- <event event="0x50" title="Cache" name="Coherency miss" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which also miss in all the other Cortex-A9 processors, meaning that the request is sent to the external memory"/>
- <event event="0x51" title="Cache" name="Coherency hit" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which hit in another Cortex-A9 processor, meaning that the linefill data is fetched directly from the relevant Cortex-A9 cache"/>
- <event event="0x60" title="Cache" name="Inst dependent stall" description="Counts the number of cycles where the processor is ready to accept new instructions, but does not receive any because of the instruction side not being able to provide any and the instruction cache is currently performing at least one linefill"/>
- <event event="0x61" title="Cache" name="Data dependent stall" description="Counts the number of cycles where the core has some instructions that it cannot issue to any pipeline, and the Load Store unit has at least one pending linefill request, and no pending TLB requests"/>
- <event event="0x62" title="Cache" name="TLB stall" description="Counts the number of cycles where the processor is stalled waiting for the completion of translation table walks from the main TLB"/>
+ <event event="0x41" title="Java" name="SW bytecode execute" description="Counts the number of software Java bytecodes being decoded, including speculative ones"/>
+ <event event="0x42" title="Jazelle" name="Backward branch execute" description="Counts the number of Jazelle taken branches being executed. This includes the branches that are flushed because of a previous load/store that aborts late."/>
+ <event event="0x50" title="Cache" name="Coherency miss" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor that also miss in all the other Cortex-A9 processors. This means that the request is sent to the external memory."/>
+ <event event="0x51" title="Cache" name="Coherency hit" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor that hit in another Cortex-A9 processor. This means that the linefill data is fetched directly from the relevant Cortex-A9 cache."/>
+ <event event="0x60" title="Cache" name="Inst dependent stall" description="Counts the number of cycles where the processor: is ready to accept new instructions, does not receive a new instruction, because: the instruction side is unable to provide one or the instruction cache is performing at least one linefill"/>
+ <event event="0x61" title="Cache" name="Data dependent stall" description="Counts the number of cycles where the processor has some instructions that it cannot issue to any pipeline, and the Load Store unit has at least one pending linefill request, and no pending TLB requests"/>
+ <event event="0x62" title="Cache" name="TLB stall" description="Counts the number of cycles where the processor is stalled waiting for the completion of translation table walks from the main TLB. The processor stalls because the instruction side is not able to provide the instructions, or the data side is not able to provide the necessary data."/>
<event event="0x63" title="Intrinsic" name="STREX pass" description="Counts the number of STREX instructions architecturally executed and passed"/>
<event event="0x64" title="Intrinsic" name="STREX fail" description="Counts the number of STREX instructions architecturally executed and failed"/>
<event event="0x65" title="Cache" name="Data eviction" description="Counts the number of eviction requests because of a linefill in the data cache"/>
<event event="0x66" title="Pipeline" name="Issue stage no dispatch" description="Counts the number of cycles where the issue stage does not dispatch any instruction because it is empty or cannot dispatch any instructions"/>
<event event="0x67" title="Pipeline" name="Issue stage empty" description="Counts the number of cycles where the issue stage is empty"/>
- <event event="0x68" title="Instruction" name="Executed" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
- <event event="0x69" title="Cache" name="Data linefills" description="Counts the number of linefills performed on the external AXI bus"/>
- <event event="0x6A" title="Cache" name="Prefetch linefills" description="Counts the number of data linefills caused by prefetcher requests"/>
- <event event="0x6B" title="Cache" name="Prefetch hits" description="Counts the number of cache hits in a line that belongs to a stream followed by the prefetcher"/>
- <event event="0x6E" title="Core" name="Functions" description="Counts the number of procedure returns whose condition codes do not fail, excluding all returns from exception"/>
- <event event="0x70" title="Instruction" name="Main execution unit" description="Counts the number of instructions being executed in the main execution pipeline of the processor, the multiply pipeline and arithmetic logic unit pipeline"/>
- <event event="0x71" title="Instruction" name="Second execution unit" description="Counts the number of instructions being executed in the processor second execution pipeline (ALU)"/>
- <event event="0x72" title="Instruction" name="Load/Store" description="Counts the number of instructions being executed in the Load/Store unit"/>
- <event event="0x73" title="Instruction" name="Floating point" description="Counts the number of Floating-point instructions going through the Register Rename stage"/>
- <event event="0x74" title="Instruction" name="NEON" description="Counts the number of NEON instructions going through the Register Rename stage"/>
+ <event event="0x68" title="Instruction" name="Executed" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and an even more approximate number of the total number of instructions architecturally executed. The approximation depends mainly on the branch misprediction rate."/>
+ <event event="0x69" title="Cache" name="Data linefills" description="Counts the number of linefills performed on the external AXI bus. This event counts all data linefill requests, caused by: loads, including speculative ones, stores, PLD, prefetch or page table walk."/>
+ <event event="0x6a" title="Cache" name="Prefetch linefills" description="Counts the number of data linefills caused by prefetcher requests"/>
+ <event event="0x6b" title="Cache" name="Prefetch hits" description="Counts the number of cache hits in a line that belongs to a stream followed by the prefetcher. This includes: lines that have been prefetched by the automatic data prefetcher and lines already present in the cache, before the prefetcher action."/>
+ <event event="0x6e" title="Procedure" name="Return" description="Counts the number of procedure returns whose condition codes do not fail, excluding all returns from exception. This count includes procedure returns that are flushed because of a previous load/store that aborts late."/>
+ <event event="0x70" title="Instruction" name="Main execution unit" description="Counts the number of instructions being executed in the main execution pipeline of the processor, the multiply pipeline and arithmetic logic unit pipeline. The counted instructions are still speculative."/>
+ <event event="0x71" title="Instruction" name="Second execution unit" description="Counts the number of instructions being executed in the processor second execution pipeline (ALU). The counted instructions are still speculative."/>
+ <event event="0x72" title="Instruction" name="Load/Store" description="Counts the number of instructions being executed in the Load/Store unit. The counted instructions are still speculative."/>
+ <event event="0x73" title="Instruction" name="Floating point" description="Counts the number of floating-point instructions going through the Register Rename stage. Instructions are still speculative in this stage."/>
+ <event event="0x74" title="Instruction" name="NEON" description="Counts the number of NEON instructions going through the Register Rename stage. Instructions are still speculative in this stage."/>
<event event="0x80" title="Stalls" name="PLD" description="Counts the number of cycles where the processor is stalled because PLD slots are all full"/>
- <event event="0x81" title="Stalls" name="Memory write" description="Counts the number of cycles when the processor is stalled and the data side is stalled too because it is full and executing writes to the external memory"/>
+ <event event="0x81" title="Stalls" name="Memory write" description="Counts the number of cycles when the processor is stalled. The data side is stalled also, because it is full and executes writes to the external memory."/>
<event event="0x82" title="Stalls" name="Inst main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the instruction side"/>
<event event="0x83" title="Stalls" name="Data main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the data side"/>
- <event event="0x84" title="Stalls" name="Inst micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the instruction side"/>
- <event event="0x85" title="Stalls" name="Data micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the data side"/>
- <event event="0x86" title="Stalls" name="DMB" description="Counts the number of stall cycles because of the execution of a DMB memory barrier"/>
- <event event="0x8A" title="Clock" name="Integer core" description="Counts the number of cycles during which the integer core clock is enabled"/>
- <event event="0x8B" title="Clock" name="Data engine" description="Counts the number of cycles during which the Data Engine clock is enabled"/>
- <event event="0x8C" title="Clock" name="NEON" description="Counts the number of cycles when the NEON SIMD clock is enabled"/>
- <event event="0x8D" title="Memory" name="TLB inst allocations" description="Counts the number of TLB allocations because of Instruction requests"/>
- <event event="0x8E" title="Memory" name="TLB data allocations" description="Counts the number of TLB allocations because of Data requests"/>
+ <event event="0x84" title="Stalls" name="Inst micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the instruction side. This event does not include main TLB miss stall cycles that are already counted in the corresponding main TLB event."/>
+ <event event="0x85" title="Stalls" name="Data micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the data side. This event does not include main TLB miss stall cycles that are already counted in the corresponding main TLB event."/>
+ <event event="0x86" title="Stalls" name="DMB" description="Counts the number of stall cycles because of the execution of a DMB. This includes all DMB instructions being executed, even speculatively."/>
+ <event event="0x8a" title="Clock" name="Integer core" description="Counts the number of cycles when the integer core clock is enabled"/>
+ <event event="0x8b" title="Clock" name="Data engine" description="Counts the number of cycles when the data engine clock is enabled"/>
+ <event event="0x8c" title="Clock" name="NEON" description="Counts the number of cycles when the NEON SIMD clock is enabled"/>
+ <event event="0x8d" title="Memory" name="TLB inst allocations" description="Counts the number of TLB allocations because of Instruction requests"/>
+ <event event="0x8e" title="Memory" name="TLB data allocations" description="Counts the number of TLB allocations because of Data requests"/>
<event event="0x90" title="Instruction" name="ISB" description="Counts the number of ISB instructions architecturally executed"/>
<event event="0x91" title="Instruction" name="DSB" description="Counts the number of DSB instructions architecturally executed"/>
<event event="0x92" title="Instruction" name="DMB" description="Counts the number of DMB instructions speculatively executed"/>
<event event="0x93" title="External" name="Interrupts" description="Counts the number of external interrupts executed by the processor"/>
- <event event="0xA0" title="PLE" name="Cache line rq completed" description="Counts the number of PLE cache line requests completed"/>
- <event event="0xA1" title="PLE" name="Cache line rq skipped" description="Counts the number of PLE cache line requests skipped"/>
- <event event="0xA2" title="PLE" name="FIFO flush" description="Counts the number of PLE FIFO flush requests"/>
- <event event="0xA3" title="PLE" name="Request completed" description="Counts the number of PLE FIFO flush completed"/>
- <event event="0xA4" title="PLE" name="FIFO overflow" description="Counts the number of PLE FIFO flush overflowed"/>
- <event event="0xA5" title="PLE" name="Request programmed" description="Counts the number of PLE FIFO flush program requests"/>
+ <event event="0xa0" title="PLE" name="Cache line rq completed" description="Counts the number of PLE cache line requests completed"/>
+ <event event="0xa1" title="PLE" name="Cache line rq skipped" description="Counts the number of PLE cache line requests skipped"/>
+ <event event="0xa2" title="PLE" name="FIFO flush" description="Counts the number of PLE FIFO flush requests"/>
+ <event event="0xa3" title="PLE" name="Request completed" description="Counts the number of PLE FIFO flush completed"/>
+ <event event="0xa4" title="PLE" name="FIFO overflow" description="Counts the number of PLE FIFO flush overflowed"/>
+ <event event="0xa5" title="PLE" name="Request programmed" description="Counts the number of PLE FIFO flush program requests"/>
</category>
<category name="Filesystem">
<!-- counter attribute must start with filesystem_ and be unique -->
- <!-- regex item in () is the value shown -->
+ <!-- regex item in () is the value shown or, if the parentheses are missing, the number of times the regex matches is counted -->
<!--
- <event counter="filesystem_cpu1_online" path="/sys/devices/system/cpu/cpu1/online" title="online" name="cpu 1" class="absolute" description="If cpu 1 is online"/>
<event counter="filesystem_loginuid" path="/proc/self/loginuid" title="loginuid" name="loginuid" class="absolute" description="loginuid"/>
<event counter="filesystem_gatord_rss" path="/proc/self/stat" title="stat" name="rss" class="absolute" regex="-?[0-9]+ \(.*\) . -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ (-?[0-9]+)" units="pages" description="resident set size"/>
<event counter="filesystem_processes" path="/proc/stat" title="proc-stat" name="processes" class="absolute" regex="processes ([0-9]+)" description="Number of processes and threads created"/>
<event event="0x8" title="L2 Cache" name="Instruction Read Request" description="Instruction read lookup to the L2 cache. Subsequently results in a hit or miss"/>
<event event="0x9" title="L2 Cache" name="Write Allocate Miss" description="Allocation into the L2 cache caused by a write, with Write-Allocate attribute, miss"/>
<event event="0xa" title="L2 Cache" name="Internal Prefetch Allocate" description="Allocation of a prefetch generated by L2C-310 into the L2 cache"/>
- <event event="0xb" title="L2 Cache" name="Prefitch Hit" description="Prefetch hint hits in the L2 cache"/>
- <event event="0xc" title="L2 Cache" name="Prefitch Allocate" description="Prefetch hint allocated into the L2 cache"/>
+ <event event="0xb" title="L2 Cache" name="Prefetch Hit" description="Prefetch hint hits in the L2 cache"/>
+ <event event="0xc" title="L2 Cache" name="Prefetch Allocate" description="Prefetch hint allocated into the L2 cache"/>
<event event="0xd" title="L2 Cache" name="Speculative Read Received" description="Speculative read received"/>
<event event="0xe" title="L2 Cache" name="Speculative Read Confirmed" description="Speculative read confirmed"/>
<event event="0xf" title="L2 Cache" name="Prefetch Hint Received" description="Prefetch hint received"/>
<event counter="Linux_meminfo_memfree" title="Memory" name="Free" class="absolute" display="minimum" units="B" description="Available memory size"/>
<event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" class="absolute" units="B" description="Memory used by OS disk buffers"/>
<event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" class="absolute" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
- <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x003c96fb" description="One or more threads are runnable but waiting due to CPU contention"/>
- <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x00b30000" description="One or more threads are blocked on an I/O resource"/>
+ <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" multiplier="0.0001" color="0x003c96fb" description="One or more threads are runnable but waiting due to CPU contention"/>
+ <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" multiplier="0.0001" color="0x00b30000" description="One or more threads are blocked on an I/O resource"/>
<event counter="Linux_power_cpu" title="CPU Status" name="Activity" class="activity" activity1="Off" activity_color1="0x0000ff00" activity2="WFI" activity_color2="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" description="CPU Status"/>
</category>
<event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" class="absolute" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
</category>
<category name="ARM_Mali-4xx_Frequency" per_cpu="no">
- <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/>
+ <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" class="absolute" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/>
</category>
- <category name="Mali-4xx Activity" counter_set="ARM_Mali-4xx_Activity_cnt">
+ <category name="Mali-4xx Activity" counter_set="ARM_Mali-4xx_Activity_cnt" per_cpu="yes">
<event counter="ARM_Mali-4xx_fragment" title="GPU Fragment" name="Activity" class="activity" activity1="Activity" activity_color1="0x00006fcc" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" description="GPU Fragment Activity"/>
<event counter="ARM_Mali-4xx_vertex" title="GPU Vertex" name="Activity" class="activity" activity1="Activity" activity_color1="0x00eda000" rendering_type="bar" average_selection="yes" percentage="yes" description="GPU Vertex Activity"/>
</category>
<category name="Mali-Midgard Software Counters" per_cpu="no">
<event counter="ARM_Mali-Midgard_TOTAL_ALLOC_PAGES" title="Mali Total Alloc Pages" name="Total number of allocated pages" description="Mali total number of allocated pages."/>
</category>
+<!--
+power management is disabled during profiling so these counters are not useful as they always return zero
<category name="Mali-Midgard PM Shader" per_cpu="no">
<event counter="ARM_Mali-Midgard_PM_SHADER_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
<event counter="ARM_Mali-Midgard_PM_SHADER_1" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
<event counter="ARM_Mali-Midgard_PM_SHADER_7" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
</category>
<category name="Mali-Midgard PM Tiler" per_cpu="no">
- <event counter="ARM_Mali-Midgard_PM_TILER_0" display="average" average_selection="yes" percentage="yes" title="Mali PM Tiler" name="PM Tiler Core 0" description="Mali PM Tiler: PM Tiler Core 0."/>
+ <event counter="ARM_Mali-Midgard_PM_TILER_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Tiler" name="PM Tiler Core 0" description="Mali PM Tiler: PM Tiler Core 0."/>
</category>
<category name="Mali-Midgard PM L2" per_cpu="no">
- <event counter="ARM_Mali-Midgard_PM_L2_0" display="average" average_selection="yes" percentage="yes" title="Mali PM L2" name="PM L2 Core 0" description="Mali PM L2: PM L2 Core 0."/>
- <event counter="ARM_Mali-Midgard_PM_L2_1" display="average" average_selection="yes" percentage="yes" title="Mali PM L2" name="PM L2 Core 1" description="Mali PM L2: PM L2 Core 1."/>
+ <event counter="ARM_Mali-Midgard_PM_L2_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM L2" name="PM L2 Core 0" description="Mali PM L2: PM L2 Core 0."/>
+ <event counter="ARM_Mali-Midgard_PM_L2_1" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM L2" name="PM L2 Core 1" description="Mali PM L2: PM L2 Core 1."/>
</category>
+-->
<category name="Mali-Midgard MMU Address Space" per_cpu="no">
- <event counter="ARM_Mali-Midgard_MMU_AS_0" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 0" description="Mali MMU Address Space 0 usage."/>
- <event counter="ARM_Mali-Midgard_MMU_AS_1" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 1" description="Mali MMU Address Space 1 usage."/>
- <event counter="ARM_Mali-Midgard_MMU_AS_2" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 2" description="Mali MMU Address Space 2 usage."/>
- <event counter="ARM_Mali-Midgard_MMU_AS_3" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 3" description="Mali MMU Address Space 3 usage."/>
+ <event counter="ARM_Mali-Midgard_MMU_AS_0" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 0" description="Mali MMU Address Space 0 usage."/>
+ <event counter="ARM_Mali-Midgard_MMU_AS_1" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 1" description="Mali MMU Address Space 1 usage."/>
+ <event counter="ARM_Mali-Midgard_MMU_AS_2" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 2" description="Mali MMU Address Space 2 usage."/>
+ <event counter="ARM_Mali-Midgard_MMU_AS_3" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 3" description="Mali MMU Address Space 3 usage."/>
</category>
<category name="Mali-Midgard MMU Page Fault" per_cpu="no">
<event counter="ARM_Mali-Midgard_MMU_PAGE_FAULT_0" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 0" description="Reports the number of newly allocated pages after a MMU page fault in address space 0."/>
+<!-- this file is valid for Midgard r4p0 and earlier and replaced with the core-specific files in r5p0 -->
<category name="Mali-Midgard Job Manager" per_cpu="no">
<event counter="ARM_Mali-Midgard_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles the GPU was active"/>
<event counter="ARM_Mali-Midgard_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles the GPU had a pending interrupt"/>
<event counter="ARM_Mali-Midgard_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) was active"/>
<event counter="ARM_Mali-Midgard_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) was active"/>
<event counter="ARM_Mali-Midgard_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) was active"/>
- <event counter="ARM_Mali-Midgard_JS0_JOBS" title="Mali Job Manager Work" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
- <event counter="ARM_Mali-Midgard_JS0_TASKS" title="Mali Job Manager Work" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
- <event counter="ARM_Mali-Midgard_JS1_JOBS" title="Mali Job Manager Work" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
- <event counter="ARM_Mali-Midgard_JS1_TASKS" title="Mali Job Manager Work" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
- <event counter="ARM_Mali-Midgard_JS2_TASKS" title="Mali Job Manager Work" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
- <event counter="ARM_Mali-Midgard_JS2_JOBS" title="Mali Job Manager Work" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-Midgard_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-Midgard_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-Midgard_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-Midgard_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-Midgard_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-Midgard_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
</category>
<category name="Mali-Midgard Tiler" per_cpu="no">
<event counter="ARM_Mali-Midgard_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
<event counter="ARM_Mali-Midgard_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
<event counter="ARM_Mali-Midgard_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
<event counter="ARM_Mali-Midgard_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
+
<event counter="ARM_Mali-Midgard_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
<event counter="ARM_Mali-Midgard_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
<event counter="ARM_Mali-Midgard_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
<event counter="ARM_Mali-Midgard_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
<event counter="ARM_Mali-Midgard_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
+
<event counter="ARM_Mali-Midgard_LEVEL0" title="Mali Tiler Hierarchy" name="L0 prims" description="Number of primitives in hierarchy level 0"/>
<event counter="ARM_Mali-Midgard_LEVEL1" title="Mali Tiler Hierarchy" name="L1 prims" description="Number of primitives in hierarchy level 1"/>
<event counter="ARM_Mali-Midgard_LEVEL2" title="Mali Tiler Hierarchy" name="L2 prims" description="Number of primitives in hierarchy level 2"/>
<event counter="ARM_Mali-Midgard_LEVEL5" title="Mali Tiler Hierarchy" name="L5 prims" description="Number of primitives in hierarchy level 5"/>
<event counter="ARM_Mali-Midgard_LEVEL6" title="Mali Tiler Hierarchy" name="L6 prims" description="Number of primitives in hierarchy level 6"/>
<event counter="ARM_Mali-Midgard_LEVEL7" title="Mali Tiler Hierarchy" name="L7 prims" description="Number of primitives in hierarchy level 7"/>
- <event counter="ARM_Mali-Midgard_COMMAND_1" title="Mali Tiler Commands" name="Prims in 1 command" description="Number of primitives producing 1 command"/>
- <event counter="ARM_Mali-Midgard_COMMAND_2" title="Mali Tiler Commands" name="Prims in 2 command" description="Number of primitives producing 2 commands"/>
- <event counter="ARM_Mali-Midgard_COMMAND_3" title="Mali Tiler Commands" name="Prims in 3 command" description="Number of primitives producing 3 commands"/>
- <event counter="ARM_Mali-Midgard_COMMAND_4" title="Mali Tiler Commands" name="Prims in 4 command" description="Number of primitives producing 4 commands"/>
- <event counter="ARM_Mali-Midgard_COMMAND_4_7" title="Mali Tiler Commands" name="Prims in 4-7 commands" description="Number of primitives producing 4-7 commands"/>
- <event counter="ARM_Mali-Midgard_COMMAND_5_7" title="Mali Tiler Commands" name="Prims in 5-7 commands" description="Number of primitives producing 5-7 commands"/>
- <event counter="ARM_Mali-Midgard_COMMAND_8_15" title="Mali Tiler Commands" name="Prims in 8-15 commands" description="Number of primitives producing 8-15 commands"/>
- <event counter="ARM_Mali-Midgard_COMMAND_16_63" title="Mali Tiler Commands" name="Prims in 16-63 commands" description="Number of primitives producing 16-63 commands"/>
- <event counter="ARM_Mali-Midgard_COMMAND_64" title="Mali Tiler Commands" name="Prims in >= 64 commands" description="Number of primitives producing >= 64 commands"/>
</category>
<category name="Mali-Midgard Shader Core" per_cpu="no">
<event counter="ARM_Mali-Midgard_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles the Tripipe was active"/>
<event counter="ARM_Mali-Midgard_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
<event counter="ARM_Mali-Midgard_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
<event counter="ARM_Mali-Midgard_FRAG_CYCLE_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
+
<event counter="ARM_Mali-Midgard_FRAG_THREADS" title="Mali Core Threads" name="Fragment threads" description="Number of fragment threads started"/>
<event counter="ARM_Mali-Midgard_FRAG_DUMMY_THREADS" title="Mali Core Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
- <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
- <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
+ <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS quads" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-Midgard_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS quads" description="Number of threads killed by late ZS test"/>
<event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
<event counter="ARM_Mali-Midgard_FRAG_THREADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
+
<event counter="ARM_Mali-Midgard_COMPUTE_TASKS" title="Mali Compute Threads" name="Compute tasks" description="Number of compute tasks"/>
<event counter="ARM_Mali-Midgard_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads started" description="Number of compute threads started"/>
<event counter="ARM_Mali-Midgard_COMPUTE_CYCLES_DESC" title="Mali Compute Threads" name="Compute cycles awaiting descriptors" description="Number of compute cycles spent waiting for descriptors"/>
+
<event counter="ARM_Mali-Midgard_FRAG_PRIMATIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
<event counter="ARM_Mali-Midgard_FRAG_PRIMATIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
<event counter="ARM_Mali-Midgard_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
<event counter="ARM_Mali-Midgard_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
+
<event counter="ARM_Mali-Midgard_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
<event counter="ARM_Mali-Midgard_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
<event counter="ARM_Mali-Midgard_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
+
<event counter="ARM_Mali-Midgard_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
<event counter="ARM_Mali-Midgard_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
+
<event counter="ARM_Mali-Midgard_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of instructions completed by the the A-pipe (normalized per pipeline)"/>
+
<event counter="ARM_Mali-Midgard_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
<event counter="ARM_Mali-Midgard_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
+
<event counter="ARM_Mali-Midgard_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
<event counter="ARM_Mali-Midgard_TEX_THREADS" title="Mali Texture Pipe" name="T instruction issues" description="Number of instructions issused to the T-pipe, including restarts"/>
<event counter="ARM_Mali-Midgard_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
- <event counter="ARM_Mali-Midgard_LSC_READ_HITS" title="Mali Load/Store Cache" name="Read hits" description="Number of read hits in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_READ_MISSES" title="Mali Load/Store Cache" name="Read misses" description="Number of read misses in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_WRITE_HITS" title="Mali Load/Store Cache" name="Write hits" description="Number of write hits in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_WRITE_MISSES" title="Mali Load/Store Cache" name="Write misses" description="Number of write misses in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_ATOMIC_HITS" title="Mali Load/Store Cache" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_LINE_FETCHES" title="Mali Load/Store Cache" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_DIRTY_LINE" title="Mali Load/Store Cache" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
- <event counter="ARM_Mali-Midgard_LSC_SNOOPS" title="Mali Load/Store Cache" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+
+ <event counter="ARM_Mali-Midgard_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_READ_MISSES" title="Mali Load/Store Cache Reads" name="Read misses" description="Number of read misses in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_WRITE_MISSES" title="Mali Load/Store Cache Writes" name="Write misses" description="Number of write misses in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache Atomics" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+ <event counter="ARM_Mali-Midgard_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
</category>
<category name="Mali-Midgard L2 and MMU" per_cpu="no">
- <event counter="ARM_Mali-Midgard_L2_WRITE_BEATS" title="Mali L2 Cache" name="External write beats" description="Number of external bus write beats"/>
- <event counter="ARM_Mali-Midgard_L2_READ_BEATS" title="Mali L2 Cache" name="External read beats" description="Number of external bus read beats"/>
- <event counter="ARM_Mali-Midgard_L2_READ_SNOOP" title="Mali L2 Cache" name="Read snoops" description="Number of read transaction snoops"/>
- <event counter="ARM_Mali-Midgard_L2_READ_HIT" title="Mali L2 Cache" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
- <event counter="ARM_Mali-Midgard_L2_WRITE_SNOOP" title="Mali L2 Cache" name="Write snoops" description="Number of write transaction snoops"/>
- <event counter="ARM_Mali-Midgard_L2_WRITE_HIT" title="Mali L2 Cache" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
- <event counter="ARM_Mali-Midgard_L2_EXT_AR_STALL" title="Mali L2 Cache" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-Midgard_L2_EXT_W_STALL" title="Mali L2 Cache" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-Midgard_L2_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-Midgard_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+
+ <event counter="ARM_Mali-Midgard_L2_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-Midgard_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+
+ <event counter="ARM_Mali-Midgard_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-Midgard_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+ <event counter="ARM_Mali-Midgard_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-Midgard_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
</category>
<event counter="ARM_Mali-T60x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
<event counter="ARM_Mali-T60x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
- <event counter="ARM_Mali-T60x_JS0_JOBS" title="Mali Job Manager Work" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
- <event counter="ARM_Mali-T60x_JS0_TASKS" title="Mali Job Manager Work" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
- <event counter="ARM_Mali-T60x_JS1_JOBS" title="Mali Job Manager Work" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
- <event counter="ARM_Mali-T60x_JS1_TASKS" title="Mali Job Manager Work" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
- <event counter="ARM_Mali-T60x_JS2_TASKS" title="Mali Job Manager Work" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
- <event counter="ARM_Mali-T60x_JS2_JOBS" title="Mali Job Manager Work" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+ <event counter="ARM_Mali-T60x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T60x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T60x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T60x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T60x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T60x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
</category>
<event counter="ARM_Mali-T60x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
<event counter="ARM_Mali-T60x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
- <event counter="ARM_Mali-T60x_LSC_READ_HITS" title="Mali Load/Store Cache" name="Read hits" description="Number of read hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_READ_MISSES" title="Mali Load/Store Cache" name="Read misses" description="Number of read misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_WRITE_HITS" title="Mali Load/Store Cache" name="Write hits" description="Number of write hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_WRITE_MISSES" title="Mali Load/Store Cache" name="Write misses" description="Number of write misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_LINE_FETCHES" title="Mali Load/Store Cache" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_DIRTY_LINE" title="Mali Load/Store Cache" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
- <event counter="ARM_Mali-T60x_LSC_SNOOPS" title="Mali Load/Store Cache" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+ <event counter="ARM_Mali-T60x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T60x_LSC_READ_MISSES" title="Mali Load/Store Cache Reads" name="Read misses" description="Number of read misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T60x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T60x_LSC_WRITE_MISSES" title="Mali Load/Store Cache Writes" name="Write misses" description="Number of write misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T60x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T60x_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache Atomics" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T60x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T60x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T60x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
</category>
<category name="Mali L2 Cache" per_cpu="no">
- <event counter="ARM_Mali-T60x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache" name="External write beats" description="Number of external bus write beats"/>
- <event counter="ARM_Mali-T60x_L2_EXT_READ_BEATS" title="Mali L2 Cache" name="External read beats" description="Number of external bus read beats"/>
- <event counter="ARM_Mali-T60x_L2_READ_SNOOP" title="Mali L2 Cache" name="Read snoops" description="Number of read transaction snoops"/>
- <event counter="ARM_Mali-T60x_L2_READ_HIT" title="Mali L2 Cache" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
- <event counter="ARM_Mali-T60x_L2_WRITE_SNOOP" title="Mali L2 Cache" name="Write snoops" description="Number of write transaction snoops"/>
- <event counter="ARM_Mali-T60x_L2_WRITE_HIT" title="Mali L2 Cache" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
- <event counter="ARM_Mali-T60x_L2_EXT_AR_STALL" title="Mali L2 Cache" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T60x_L2_EXT_W_STALL" title="Mali L2 Cache" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T60x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
- <event counter="ARM_Mali-T60x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
- <event counter="ARM_Mali-T60x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
- <event counter="ARM_Mali-T60x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
- <event counter="ARM_Mali-T60x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+ <event counter="ARM_Mali-T60x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T60x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T60x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
- </category>
+ <event counter="ARM_Mali-T60x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T60x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T60x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T60x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T60x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T60x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T60x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T60x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T60x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T60x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
\ No newline at end of file
<event counter="ARM_Mali-T62x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
<event counter="ARM_Mali-T62x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
- <event counter="ARM_Mali-T62x_JS0_JOBS" title="Mali Job Manager Work" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
- <event counter="ARM_Mali-T62x_JS0_TASKS" title="Mali Job Manager Work" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
- <event counter="ARM_Mali-T62x_JS1_JOBS" title="Mali Job Manager Work" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
- <event counter="ARM_Mali-T62x_JS1_TASKS" title="Mali Job Manager Work" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
- <event counter="ARM_Mali-T62x_JS2_TASKS" title="Mali Job Manager Work" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
- <event counter="ARM_Mali-T62x_JS2_JOBS" title="Mali Job Manager Work" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+ <event counter="ARM_Mali-T62x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T62x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T62x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T62x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T62x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T62x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
</category>
<event counter="ARM_Mali-T62x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
<event counter="ARM_Mali-T62x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
- <event counter="ARM_Mali-T62x_LSC_READ_HITS" title="Mali Load/Store Cache" name="Read hits" description="Number of read hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_READ_MISSES" title="Mali Load/Store Cache" name="Read misses" description="Number of read misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_WRITE_HITS" title="Mali Load/Store Cache" name="Write hits" description="Number of write hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_WRITE_MISSES" title="Mali Load/Store Cache" name="Write misses" description="Number of write misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_LINE_FETCHES" title="Mali Load/Store Cache" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_DIRTY_LINE" title="Mali Load/Store Cache" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
- <event counter="ARM_Mali-T62x_LSC_SNOOPS" title="Mali Load/Store Cache" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+ <event counter="ARM_Mali-T62x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T62x_LSC_READ_MISSES" title="Mali Load/Store Cache Reads" name="Read misses" description="Number of read misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T62x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T62x_LSC_WRITE_MISSES" title="Mali Load/Store Cache Writes" name="Write misses" description="Number of write misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T62x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T62x_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache Atomics" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T62x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T62x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+ <event counter="ARM_Mali-T62x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
</category>
<category name="Mali L2 Cache" per_cpu="no">
- <event counter="ARM_Mali-T62x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache" name="External write beats" description="Number of external bus write beats"/>
- <event counter="ARM_Mali-T62x_L2_EXT_READ_BEATS" title="Mali L2 Cache" name="External read beats" description="Number of external bus read beats"/>
- <event counter="ARM_Mali-T62x_L2_READ_SNOOP" title="Mali L2 Cache" name="Read snoops" description="Number of read transaction snoops"/>
- <event counter="ARM_Mali-T62x_L2_READ_HIT" title="Mali L2 Cache" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
- <event counter="ARM_Mali-T62x_L2_WRITE_SNOOP" title="Mali L2 Cache" name="Write snoops" description="Number of write transaction snoops"/>
- <event counter="ARM_Mali-T62x_L2_WRITE_HIT" title="Mali L2 Cache" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
- <event counter="ARM_Mali-T62x_L2_EXT_AR_STALL" title="Mali L2 Cache" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T62x_L2_EXT_W_STALL" title="Mali L2 Cache" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T62x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
- <event counter="ARM_Mali-T62x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
- <event counter="ARM_Mali-T62x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
- <event counter="ARM_Mali-T62x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
- <event counter="ARM_Mali-T62x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+ <event counter="ARM_Mali-T62x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T62x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T62x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
- </category>
+ <event counter="ARM_Mali-T62x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T62x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T62x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T62x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T62x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T62x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T62x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T62x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T62x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T62x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
\ No newline at end of file
<event counter="ARM_Mali-T72x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
<event counter="ARM_Mali-T72x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
- <event counter="ARM_Mali-T72x_JS0_JOBS" title="Mali Job Manager Work" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
- <event counter="ARM_Mali-T72x_JS0_TASKS" title="Mali Job Manager Work" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
- <event counter="ARM_Mali-T72x_JS1_JOBS" title="Mali Job Manager Work" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
- <event counter="ARM_Mali-T72x_JS1_TASKS" title="Mali Job Manager Work" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
- <event counter="ARM_Mali-T72x_JS2_TASKS" title="Mali Job Manager Work" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
- <event counter="ARM_Mali-T72x_JS2_JOBS" title="Mali Job Manager Work" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+ <event counter="ARM_Mali-T72x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T72x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T72x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T72x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T72x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T72x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
</category>
<event counter="ARM_Mali-T72x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
<event counter="ARM_Mali-T72x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
- <event counter="ARM_Mali-T72x_LSC_READ_HITS" title="Mali Load/Store Cache" name="Read hits" description="Number of read hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_READ_MISSES" title="Mali Load/Store Cache" name="Read misses" description="Number of read misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_WRITE_HITS" title="Mali Load/Store Cache" name="Write hits" description="Number of write hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_WRITE_MISSES" title="Mali Load/Store Cache" name="Write misses" description="Number of write misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_LINE_FETCHES" title="Mali Load/Store Cache" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_DIRTY_LINE" title="Mali Load/Store Cache" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
- <event counter="ARM_Mali-T72x_LSC_SNOOPS" title="Mali Load/Store Cache" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T72x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T72x_LSC_READ_MISSES" title="Mali Load/Store Cache Reads" name="Read misses" description="Number of read misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T72x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T72x_LSC_WRITE_MISSES" title="Mali Load/Store Cache Writes" name="Write misses" description="Number of write misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T72x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+ <event counter="ARM_Mali-T72x_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache Atomics" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T72x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T72x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+ <event counter="ARM_Mali-T72x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
</category>
<category name="Mali L2 Cache" per_cpu="no">
- <event counter="ARM_Mali-T72x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache" name="External write beats" description="Number of external bus write beats"/>
- <event counter="ARM_Mali-T72x_L2_EXT_READ_BEATS" title="Mali L2 Cache" name="External read beats" description="Number of external bus read beats"/>
- <event counter="ARM_Mali-T72x_L2_READ_SNOOP" title="Mali L2 Cache" name="Read snoops" description="Number of read transaction snoops"/>
- <event counter="ARM_Mali-T72x_L2_READ_HIT" title="Mali L2 Cache" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
- <event counter="ARM_Mali-T72x_L2_WRITE_SNOOP" title="Mali L2 Cache" name="Write snoops" description="Number of write transaction snoops"/>
- <event counter="ARM_Mali-T72x_L2_WRITE_HIT" title="Mali L2 Cache" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
- <event counter="ARM_Mali-T72x_L2_EXT_AR_STALL" title="Mali L2 Cache" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T72x_L2_EXT_W_STALL" title="Mali L2 Cache" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T72x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
- <event counter="ARM_Mali-T72x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+ <event counter="ARM_Mali-T72x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T72x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T72x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T72x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T72x_L2_EXT_READ_BEAT" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T72x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+
+ <event counter="ARM_Mali-T72x_L2_EXT_WRITE_BEAT" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T72x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
</category>
<event counter="ARM_Mali-T76x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
<event counter="ARM_Mali-T76x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
- <event counter="ARM_Mali-T76x_JS0_JOBS" title="Mali Job Manager Work" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
- <event counter="ARM_Mali-T76x_JS0_TASKS" title="Mali Job Manager Work" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
- <event counter="ARM_Mali-T76x_JS1_JOBS" title="Mali Job Manager Work" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
- <event counter="ARM_Mali-T76x_JS1_TASKS" title="Mali Job Manager Work" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
- <event counter="ARM_Mali-T76x_JS2_TASKS" title="Mali Job Manager Work" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
- <event counter="ARM_Mali-T76x_JS2_JOBS" title="Mali Job Manager Work" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+ <event counter="ARM_Mali-T76x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T76x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T76x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T76x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T76x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T76x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
</category>
<event counter="ARM_Mali-T76x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
<event counter="ARM_Mali-T76x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
- <event counter="ARM_Mali-T76x_LSC_READ_HITS" title="Mali Load/Store Cache" name="Read hits" description="Number of read hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_READ_MISSES" title="Mali Load/Store Cache" name="Read misses" description="Number of read misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_WRITE_HITS" title="Mali Load/Store Cache" name="Write hits" description="Number of write hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_WRITE_MISSES" title="Mali Load/Store Cache" name="Write misses" description="Number of write misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_LINE_FETCHES" title="Mali Load/Store Cache" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_DIRTY_LINE" title="Mali Load/Store Cache" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
- <event counter="ARM_Mali-T76x_LSC_SNOOPS" title="Mali Load/Store Cache" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+ <event counter="ARM_Mali-T76x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T76x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T76x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T76x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T76x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T76x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T76x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T76x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T76x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
</category>
<category name="Mali L2 Cache" per_cpu="no">
- <event counter="ARM_Mali-T76x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache" name="External write beats" description="Number of external bus write beats"/>
- <event counter="ARM_Mali-T76x_L2_EXT_READ_BEATS" title="Mali L2 Cache" name="External read beats" description="Number of external bus read beats"/>
- <event counter="ARM_Mali-T76x_L2_READ_SNOOP" title="Mali L2 Cache" name="Read snoops" description="Number of read transaction snoops"/>
- <event counter="ARM_Mali-T76x_L2_READ_HIT" title="Mali L2 Cache" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
- <event counter="ARM_Mali-T76x_L2_WRITE_SNOOP" title="Mali L2 Cache" name="Write snoops" description="Number of write transaction snoops"/>
- <event counter="ARM_Mali-T76x_L2_WRITE_HIT" title="Mali L2 Cache" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
- <event counter="ARM_Mali-T76x_L2_EXT_AR_STALL" title="Mali L2 Cache" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T76x_L2_EXT_W_STALL" title="Mali L2 Cache" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
- <event counter="ARM_Mali-T76x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
- <event counter="ARM_Mali-T76x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
- <event counter="ARM_Mali-T76x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
- <event counter="ARM_Mali-T76x_L2_READ_LOOKUP" title="Mali L2 Cache" name="L2 read lookups" description="Number of reads into the L2 cache"/>
- <event counter="ARM_Mali-T76x_L2_WRITE_LOOKUP" title="Mali L2 Cache" name="L2 write lookups" description="Number of writes into the L2 cache"/>
- </category>
+ <event counter="ARM_Mali-T76x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T76x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T76x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T76x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T76x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T76x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T76x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T76x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T76x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T76x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T76x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T76x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T76x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
\ No newline at end of file
--- /dev/null
+\r
+ <category name="Mali Job Manager" per_cpu="no">\r
+\r
+ <event counter="ARM_Mali-T82x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>\r
+ <event counter="ARM_Mali-T82x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>\r
+ <event counter="ARM_Mali-T82x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>\r
+ <event counter="ARM_Mali-T82x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>\r
+ <event counter="ARM_Mali-T82x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>\r
+\r
+ <event counter="ARM_Mali-T82x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>\r
+ <event counter="ARM_Mali-T82x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>\r
+ <event counter="ARM_Mali-T82x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>\r
+\r
+ <event counter="ARM_Mali-T82x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>\r
+ <event counter="ARM_Mali-T82x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>\r
+ <event counter="ARM_Mali-T82x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>\r
+\r
+ </category>\r
+\r
+ <category name="Mali Tiler" per_cpu="no">\r
+\r
+ <event counter="ARM_Mali-T82x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>\r
+\r
+ <event counter="ARM_Mali-T82x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>\r
+ <event counter="ARM_Mali-T82x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>\r
+ <event counter="ARM_Mali-T82x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>\r
+ <event counter="ARM_Mali-T82x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>\r
+ <event counter="ARM_Mali-T82x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>\r
+\r
+ <event counter="ARM_Mali-T82x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>\r
+ <event counter="ARM_Mali-T82x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>\r
+ <event counter="ARM_Mali-T82x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>\r
+ <event counter="ARM_Mali-T82x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>\r
+ <event counter="ARM_Mali-T82x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>\r
+\r
+ </category>\r
+\r
+ <category name="Mali Shader Core" per_cpu="no">\r
+\r
+ <event counter="ARM_Mali-T82x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>\r
+ <event counter="ARM_Mali-T82x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>\r
+\r
+ <event counter="ARM_Mali-T82x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>\r
+\r
+ <event counter="ARM_Mali-T82x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>\r
+ <event counter="ARM_Mali-T82x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>\r
+\r
+ <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>\r
+\r
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>\r
+\r
+ <event counter="ARM_Mali-T82x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>\r
+ <event counter="ARM_Mali-T82x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>\r
+\r
+ <event counter="ARM_Mali-T82x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of batched instructions executed by the A-pipe (normalized per pipe)"/>\r
+\r
+ <event counter="ARM_Mali-T82x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>\r
+ <event counter="ARM_Mali-T82x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>\r
+\r
+ <event counter="ARM_Mali-T82x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>\r
+ <event counter="ARM_Mali-T82x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>\r
+ <event counter="ARM_Mali-T82x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>\r
+\r
+ <event counter="ARM_Mali-T82x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>\r
+ <event counter="ARM_Mali-T82x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>\r
+\r
+ <event counter="ARM_Mali-T82x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>\r
+ <event counter="ARM_Mali-T82x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>\r
+\r
+ <event counter="ARM_Mali-T82x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>\r
+ <event counter="ARM_Mali-T82x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>\r
+\r
+ <event counter="ARM_Mali-T82x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>\r
+ <event counter="ARM_Mali-T82x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>\r
+\r
+ <event counter="ARM_Mali-T82x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>\r
+\r
+ </category>\r
+\r
+ <category name="Mali L2 Cache" per_cpu="no">\r
+\r
+ <event counter="ARM_Mali-T82x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>\r
+ <event counter="ARM_Mali-T82x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>\r
+ <event counter="ARM_Mali-T82x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>\r
+\r
+ <event counter="ARM_Mali-T82x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>\r
+ <event counter="ARM_Mali-T82x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>\r
+ <event counter="ARM_Mali-T82x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>\r
+\r
+ <event counter="ARM_Mali-T82x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>\r
+ <event counter="ARM_Mali-T82x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>\r
+ <event counter="ARM_Mali-T82x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>\r
+ <event counter="ARM_Mali-T82x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>\r
+\r
+ <event counter="ARM_Mali-T82x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>\r
+ <event counter="ARM_Mali-T82x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>\r
+ <event counter="ARM_Mali-T82x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>\r
+\r
+ </category>\r
--- /dev/null
+
+ <category name="Mali Job Manager" per_cpu="no">
+
+ <event counter="ARM_Mali-T83x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
+ <event counter="ARM_Mali-T83x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
+ <event counter="ARM_Mali-T83x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
+ <event counter="ARM_Mali-T83x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
+ <event counter="ARM_Mali-T83x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
+
+ <event counter="ARM_Mali-T83x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T83x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T83x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T83x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T83x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T83x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
+
+ </category>
+
+ <category name="Mali Tiler" per_cpu="no">
+
+ <event counter="ARM_Mali-T83x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>
+
+ <event counter="ARM_Mali-T83x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
+ <event counter="ARM_Mali-T83x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
+ <event counter="ARM_Mali-T83x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
+ <event counter="ARM_Mali-T83x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
+ <event counter="ARM_Mali-T83x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
+
+ <event counter="ARM_Mali-T83x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
+ <event counter="ARM_Mali-T83x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
+ <event counter="ARM_Mali-T83x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
+ <event counter="ARM_Mali-T83x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
+ <event counter="ARM_Mali-T83x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
+
+ </category>
+
+ <category name="Mali Shader Core" per_cpu="no">
+
+ <event counter="ARM_Mali-T83x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>
+ <event counter="ARM_Mali-T83x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
+ <event counter="ARM_Mali-T83x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
+ <event counter="ARM_Mali-T83x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
+ <event counter="ARM_Mali-T83x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>
+
+ <event counter="ARM_Mali-T83x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>
+ <event counter="ARM_Mali-T83x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
+ <event counter="ARM_Mali-T83x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-T83x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>
+
+ <event counter="ARM_Mali-T83x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>
+ <event counter="ARM_Mali-T83x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>
+
+ <event counter="ARM_Mali-T83x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
+ <event counter="ARM_Mali-T83x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
+
+ <event counter="ARM_Mali-T83x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
+ <event counter="ARM_Mali-T83x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
+ <event counter="ARM_Mali-T83x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
+
+ <event counter="ARM_Mali-T83x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
+ <event counter="ARM_Mali-T83x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
+
+ <event counter="ARM_Mali-T83x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of batched instructions executed by the A-pipe (normalized per pipe)"/>
+
+ <event counter="ARM_Mali-T83x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
+ <event counter="ARM_Mali-T83x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
+
+ <event counter="ARM_Mali-T83x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
+ <event counter="ARM_Mali-T83x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
+ <event counter="ARM_Mali-T83x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
+
+ <event counter="ARM_Mali-T83x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T83x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T83x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T83x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T83x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T83x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T83x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T83x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T83x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+
+ </category>
+
+ <category name="Mali L2 Cache" per_cpu="no">
+
+ <event counter="ARM_Mali-T83x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T83x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T83x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T83x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T83x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T83x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T83x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T83x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T83x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T83x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T83x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T83x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T83x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
--- /dev/null
+
+ <category name="Mali Job Manager" per_cpu="no">
+
+ <event counter="ARM_Mali-T86x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
+ <event counter="ARM_Mali-T86x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
+ <event counter="ARM_Mali-T86x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
+ <event counter="ARM_Mali-T86x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
+ <event counter="ARM_Mali-T86x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
+
+ <event counter="ARM_Mali-T86x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T86x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T86x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T86x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T86x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T86x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
+
+ </category>
+
+ <category name="Mali Tiler" per_cpu="no">
+
+ <event counter="ARM_Mali-T86x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>
+
+ <event counter="ARM_Mali-T86x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
+ <event counter="ARM_Mali-T86x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
+ <event counter="ARM_Mali-T86x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
+ <event counter="ARM_Mali-T86x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
+ <event counter="ARM_Mali-T86x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
+
+ <event counter="ARM_Mali-T86x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
+ <event counter="ARM_Mali-T86x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
+ <event counter="ARM_Mali-T86x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
+ <event counter="ARM_Mali-T86x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
+ <event counter="ARM_Mali-T86x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
+
+ <event counter="ARM_Mali-T86x_TI_LEVEL0" title="Mali Tiler Hierarchy" name="L0 prims" description="Number of primitives in hierarchy level 0"/>
+ <event counter="ARM_Mali-T86x_TI_LEVEL1" title="Mali Tiler Hierarchy" name="L1 prims" description="Number of primitives in hierarchy level 1"/>
+ <event counter="ARM_Mali-T86x_TI_LEVEL2" title="Mali Tiler Hierarchy" name="L2 prims" description="Number of primitives in hierarchy level 2"/>
+ <event counter="ARM_Mali-T86x_TI_LEVEL3" title="Mali Tiler Hierarchy" name="L3 prims" description="Number of primitives in hierarchy level 3"/>
+ <event counter="ARM_Mali-T86x_TI_LEVEL4" title="Mali Tiler Hierarchy" name="L4 prims" description="Number of primitives in hierarchy level 4"/>
+ <event counter="ARM_Mali-T86x_TI_LEVEL5" title="Mali Tiler Hierarchy" name="L5 prims" description="Number of primitives in hierarchy level 5"/>
+ <event counter="ARM_Mali-T86x_TI_LEVEL6" title="Mali Tiler Hierarchy" name="L6 prims" description="Number of primitives in hierarchy level 6"/>
+ <event counter="ARM_Mali-T86x_TI_LEVEL7" title="Mali Tiler Hierarchy" name="L7 prims" description="Number of primitives in hierarchy level 7"/>
+
+ </category>
+
+ <category name="Mali Shader Core" per_cpu="no">
+
+ <event counter="ARM_Mali-T86x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>
+ <event counter="ARM_Mali-T86x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
+ <event counter="ARM_Mali-T86x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
+ <event counter="ARM_Mali-T86x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
+ <event counter="ARM_Mali-T86x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>
+
+ <event counter="ARM_Mali-T86x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>
+ <event counter="ARM_Mali-T86x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
+ <event counter="ARM_Mali-T86x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-T86x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>
+
+ <event counter="ARM_Mali-T86x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>
+ <event counter="ARM_Mali-T86x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>
+
+ <event counter="ARM_Mali-T86x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
+ <event counter="ARM_Mali-T86x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
+
+ <event counter="ARM_Mali-T86x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
+ <event counter="ARM_Mali-T86x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
+ <event counter="ARM_Mali-T86x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
+
+ <event counter="ARM_Mali-T86x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
+ <event counter="ARM_Mali-T86x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
+
+ <event counter="ARM_Mali-T86x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of instructions completed by the the A-pipe (normalized per pipeline)"/>
+
+ <event counter="ARM_Mali-T86x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
+ <event counter="ARM_Mali-T86x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
+
+ <event counter="ARM_Mali-T86x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
+ <event counter="ARM_Mali-T86x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
+ <event counter="ARM_Mali-T86x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
+
+ <event counter="ARM_Mali-T86x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T86x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T86x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T86x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T86x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T86x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T86x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T86x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T86x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+
+ </category>
+
+ <category name="Mali L2 Cache" per_cpu="no">
+
+ <event counter="ARM_Mali-T86x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T86x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T86x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T86x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T86x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T86x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T86x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T86x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T86x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T86x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T86x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T86x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T86x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
--- /dev/null
+
+ <category name="Mali Job Manager" per_cpu="no">
+
+ <event counter="ARM_Mali-T88x_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles GPU active"/>
+ <event counter="ARM_Mali-T88x_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles GPU interrupt pending"/>
+ <event counter="ARM_Mali-T88x_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) active"/>
+ <event counter="ARM_Mali-T88x_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) active"/>
+ <event counter="ARM_Mali-T88x_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) active"/>
+
+ <event counter="ARM_Mali-T88x_JS0_JOBS" title="Mali Job Manager Jobs" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
+ <event counter="ARM_Mali-T88x_JS1_JOBS" title="Mali Job Manager Jobs" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
+ <event counter="ARM_Mali-T88x_JS2_JOBS" title="Mali Job Manager Jobs" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
+
+ <event counter="ARM_Mali-T88x_JS0_TASKS" title="Mali Job Manager Tasks" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
+ <event counter="ARM_Mali-T88x_JS1_TASKS" title="Mali Job Manager Tasks" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
+ <event counter="ARM_Mali-T88x_JS2_TASKS" title="Mali Job Manager Tasks" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
+
+ </category>
+
+ <category name="Mali Tiler" per_cpu="no">
+
+ <event counter="ARM_Mali-T88x_TI_ACTIVE" title="Mali Tiler Cycles" name="Tiler cycles" description="Number of cycles Tiler active"/>
+
+ <event counter="ARM_Mali-T88x_TI_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
+ <event counter="ARM_Mali-T88x_TI_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
+ <event counter="ARM_Mali-T88x_TI_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
+ <event counter="ARM_Mali-T88x_TI_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
+ <event counter="ARM_Mali-T88x_TI_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
+
+ <event counter="ARM_Mali-T88x_TI_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
+ <event counter="ARM_Mali-T88x_TI_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
+ <event counter="ARM_Mali-T88x_TI_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
+ <event counter="ARM_Mali-T88x_TI_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
+ <event counter="ARM_Mali-T88x_TI_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
+
+ <event counter="ARM_Mali-T88x_TI_LEVEL0" title="Mali Tiler Hierarchy" name="L0 prims" description="Number of primitives in hierarchy level 0"/>
+ <event counter="ARM_Mali-T88x_TI_LEVEL1" title="Mali Tiler Hierarchy" name="L1 prims" description="Number of primitives in hierarchy level 1"/>
+ <event counter="ARM_Mali-T88x_TI_LEVEL2" title="Mali Tiler Hierarchy" name="L2 prims" description="Number of primitives in hierarchy level 2"/>
+ <event counter="ARM_Mali-T88x_TI_LEVEL3" title="Mali Tiler Hierarchy" name="L3 prims" description="Number of primitives in hierarchy level 3"/>
+ <event counter="ARM_Mali-T88x_TI_LEVEL4" title="Mali Tiler Hierarchy" name="L4 prims" description="Number of primitives in hierarchy level 4"/>
+ <event counter="ARM_Mali-T88x_TI_LEVEL5" title="Mali Tiler Hierarchy" name="L5 prims" description="Number of primitives in hierarchy level 5"/>
+ <event counter="ARM_Mali-T88x_TI_LEVEL6" title="Mali Tiler Hierarchy" name="L6 prims" description="Number of primitives in hierarchy level 6"/>
+ <event counter="ARM_Mali-T88x_TI_LEVEL7" title="Mali Tiler Hierarchy" name="L7 prims" description="Number of primitives in hierarchy level 7"/>
+
+ </category>
+
+ <category name="Mali Shader Core" per_cpu="no">
+
+ <event counter="ARM_Mali-T88x_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles tripipe was active"/>
+ <event counter="ARM_Mali-T88x_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
+ <event counter="ARM_Mali-T88x_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
+ <event counter="ARM_Mali-T88x_FRAG_CYCLES_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
+ <event counter="ARM_Mali-T88x_FRAG_CYCLES_FPKQ_ACTIVE" title="Mali Core Cycles" name="Fragment cycles pre-pipe buffer not empty" description="Number of cycles the pre-pipe queue contains quads"/>
+
+ <event counter="ARM_Mali-T88x_FRAG_THREADS" title="Mali Fragment Threads" name="Fragment threads" description="Number of fragment threads started"/>
+ <event counter="ARM_Mali-T88x_FRAG_DUMMY_THREADS" title="Mali Fragment Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
+ <event counter="ARM_Mali-T88x_FRAG_THREADS_LZS_TEST" title="Mali Fragment Threads" name="Fragment threads doing late ZS" description="Number of threads doing late ZS test"/>
+ <event counter="ARM_Mali-T88x_FRAG_THREADS_LZS_KILLED" title="Mali Fragment Threads" name="Fragment threads killed late ZS" description="Number of threads killed by late ZS test"/>
+
+ <event counter="ARM_Mali-T88x_COMPUTE_TASKS" title="Mali Compute Tasks" name="Compute tasks" description="Number of compute tasks"/>
+ <event counter="ARM_Mali-T88x_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads" description="Number of compute threads started"/>
+
+ <event counter="ARM_Mali-T88x_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
+ <event counter="ARM_Mali-T88x_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
+
+ <event counter="ARM_Mali-T88x_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
+ <event counter="ARM_Mali-T88x_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
+ <event counter="ARM_Mali-T88x_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
+
+ <event counter="ARM_Mali-T88x_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
+ <event counter="ARM_Mali-T88x_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
+
+ <event counter="ARM_Mali-T88x_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of instructions completed by the the A-pipe (normalized per pipeline)"/>
+
+ <event counter="ARM_Mali-T88x_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
+ <event counter="ARM_Mali-T88x_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
+
+ <event counter="ARM_Mali-T88x_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
+ <event counter="ARM_Mali-T88x_TEX_ISSUES" title="Mali Texture Pipe" name="T instruction issues" description="Number of threads through loop 2 address calculation"/>
+ <event counter="ARM_Mali-T88x_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
+
+ <event counter="ARM_Mali-T88x_LSC_READ_OP" title="Mali Load/Store Cache Reads" name="Read operations" description="Number of read operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T88x_LSC_READ_HITS" title="Mali Load/Store Cache Reads" name="Read hits" description="Number of read hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T88x_LSC_WRITE_OP" title="Mali Load/Store Cache Writes" name="Write operations" description="Number of write operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T88x_LSC_WRITE_HITS" title="Mali Load/Store Cache Writes" name="Write hits" description="Number of write hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T88x_LSC_ATOMIC_OP" title="Mali Load/Store Cache Atomics" name="Atomic operations" description="Number of atomic operations in the Load/Store cache"/>
+ <event counter="ARM_Mali-T88x_LSC_ATOMIC_HITS" title="Mali Load/Store Cache Atomics" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T88x_LSC_LINE_FETCHES" title="Mali Load/Store Cache Bus" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
+ <event counter="ARM_Mali-T88x_LSC_DIRTY_LINE" title="Mali Load/Store Cache Bus" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
+
+ <event counter="ARM_Mali-T88x_LSC_SNOOPS" title="Mali Load/Store Cache Bus" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
+
+ </category>
+
+ <category name="Mali L2 Cache" per_cpu="no">
+
+ <event counter="ARM_Mali-T88x_L2_READ_LOOKUP" title="Mali L2 Cache Reads" name="L2 read lookups" description="Number of reads into the L2 cache"/>
+ <event counter="ARM_Mali-T88x_L2_READ_SNOOP" title="Mali L2 Cache Reads" name="Read snoops" description="Number of read transaction snoops"/>
+ <event counter="ARM_Mali-T88x_L2_READ_HIT" title="Mali L2 Cache Reads" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
+
+ <event counter="ARM_Mali-T88x_L2_WRITE_SNOOP" title="Mali L2 Cache Writes" name="Write snoops" description="Number of write transaction snoops"/>
+ <event counter="ARM_Mali-T88x_L2_WRITE_HIT" title="Mali L2 Cache Writes" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
+ <event counter="ARM_Mali-T88x_L2_WRITE_LOOKUP" title="Mali L2 Cache Writes" name="L2 write lookups" description="Number of writes into the L2 cache"/>
+
+ <event counter="ARM_Mali-T88x_L2_EXT_READ_BEATS" title="Mali L2 Cache Ext Reads" name="External read beats" description="Number of external bus read beats"/>
+ <event counter="ARM_Mali-T88x_L2_EXT_AR_STALL" title="Mali L2 Cache Ext Reads" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T88x_L2_EXT_R_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus response buffer full" description="Number of cycles a valid request is blocked by a full response buffer"/>
+ <event counter="ARM_Mali-T88x_L2_EXT_RD_BUF_FULL" title="Mali L2 Cache Ext Reads" name="External bus read data buffer full" description="Number of cycles a valid request is blocked by a full read data buffer"/>
+
+ <event counter="ARM_Mali-T88x_L2_EXT_WRITE_BEATS" title="Mali L2 Cache Ext Writes" name="External write beats" description="Number of external bus write beats"/>
+ <event counter="ARM_Mali-T88x_L2_EXT_W_STALL" title="Mali L2 Cache Ext Writes" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
+ <event counter="ARM_Mali-T88x_L2_EXT_W_BUF_FULL" title="Mali L2 Cache Ext Writes" name="External bus write buffer full" description="Number of cycles a valid request is blocked by a full write buffer"/>
+
+ </category>
--- /dev/null
+ <counter_set name="Other_cnt" count="6"/>
+ <category name="Other" counter_set="Other_cnt" per_cpu="yes" supports_event_based_sampling="yes">
+ <event counter="Other_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
+ <event event="0x00" title="Software" name="Increment" description="Instruction architecturally executed, condition code check pass, software increment"/>
+ <event event="0x01" title="Cache" name="Instruction refill" description="Level 1 instruction cache refill"/>
+ <event event="0x02" title="Cache" name="Inst TLB refill" description="Level 1 instruction TLB refill"/>
+ <event event="0x03" title="Cache" name="Data refill" description="Level 1 data cache refill"/>
+ <event event="0x04" title="Cache" name="Data access" description="Level 1 data cache access"/>
+ <event event="0x05" title="Cache" name="Data TLB refill" description="Level 1 data TLB refill"/>
+ <event event="0x06" title="Instruction" name="Memory read" description="Instruction architecturally executed, condition code check pass, load"/>
+ <event event="0x07" title="Instruction" name="Memory write" description="Instruction architecturally executed, condition code check pass, store"/>
+ <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
+ <event event="0x09" title="Exception" name="Taken" description="Exception taken"/>
+ <event event="0x0a" title="Exception" name="Return" description="Instruction architecturally executed, condition code check pass, exception return"/>
+ <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction architecturally executed, condition code check pass, write to CONTEXTIDR"/>
+ <event event="0x0c" title="Branch" name="PC change" description="Instruction architecturally executed, condition code check pass, software change of the PC"/>
+ <event event="0x0d" title="Branch" name="Immediate" description="Instruction architecturally executed, immediate branch"/>
+ <event event="0x0e" title="Procedure" name="Return" description="Instruction architecturally executed, condition code check pass, procedure return"/>
+ <event event="0x0f" title="Memory" name="Unaligned access" description="Instruction architecturally executed, condition code check pass, unaligned load or store"/>
+ <event event="0x10" title="Branch" name="Mispredicted" description="Mispredicted or not predicted branch speculatively executed"/>
+ <event event="0x12" title="Branch" name="Potential prediction" description="Predictable branch speculatively executed"/>
+ <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
+ <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
+ <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache write-back"/>
+ <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
+ <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
+ <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache write-back"/>
+ <event event="0x19" title="Bus" name="Access" description="Bus access"/>
+ <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
+ <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
+ <event event="0x1c" title="Memory" name="Translation table" description="Instruction architecturally executed, condition code check pass, write to TTBR"/>
+ <event event="0x1d" title="Bus" name="Cycle" description="Bus cycle"/>
+ </category>
<category name="Ftrace">
- <!-- counter attribute must start with ftrace_ and be unique -->
- <!-- regex item in () is the value shown -->
<!--
- <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" class="absolute" regex="([0-9]+)" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
+ Ftrace counters require Linux 3.10 or later. If you do you see ftrace counters in counter configuration, please check your Linux version.
+ 'counter' attribute must start with ftrace_ and be unique
+ the regex item in () is the value shown or, if the parentheses are missing, the number of regex matches is counted
+ 'enable' (optional) is the ftrace event to enable associated with the gator event
-->
+ <!--
+ <event counter="ftrace_trace_marker_numbers" title="ftrace" name="trace_marker" regex="^tracing_mark_write: ([0-9]+)\s$" class="absolute" description="Numbers written to /sys/kernel/debug/tracing/trace_marker, ex: echo 42 > /sys/kernel/debug/tracing/trace_marker"/>
+ -->
+
+ <!-- ftrace counters -->
+ <event counter="ftrace_kmem_kmalloc" title="Kmem" name="kmalloc" regex="^kmalloc:.* bytes_alloc=([0-9]+) " enable="kmem/kmalloc" class="incident" description="Number of bytes allocated in the kernel using kmalloc"/>
+ <event counter="ftrace_ext4_ext4_da_write" title="Ext4" name="ext4_da_write" regex="^ext4_da_write_end:.* len ([0-9]+) " enable="ext4/ext4_da_write_end" class="incident" description="Number of bytes written to an ext4 filesystem"/>
+ <event counter="ftrace_f2fs_f2fs_write" title="F2FS" name="f2fs_write" regex="^f2fs_write_end:.* len ([0-9]+), " enable="f2fs/f2fs_write_end" class="incident" description="Number of bytes written to an f2fs filesystem"/>
+ <event counter="ftrace_power_clock_set_rate" title="Power" name="clock_set_rate" regex="^clock_set_rate:.* state=([0-9]+) " enable="power/clock_set_rate" class="absolute" description="Clock rate state"/>
+
+ <!-- counting ftrace counters -->
+ <event counter="ftrace_block_block_rq_complete" title="Block" name="block_rq_complete" regex="^block_rq_complete: " enable="block/block_rq_complete" class="delta" description="Number of block IO operations completed by device driver"/>
+ <event counter="ftrace_block_block_rq_issue" title="Block" name="block_rq_issue" regex="^block_rq_issue: " enable="block/block_rq_issue" class="delta" description="Number of block IO operations issued to device driver"/>
+ <event counter="ftrace_power_cpu_idle" title="Power" name="cpu_idle" regex="^cpu_idle: " enable="power/cpu_idle" class="delta" description="Number of times cpu_idle is entered or exited"/>
</category>
/**
- * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ * Copyright (C) ARM Limited 2010-2015. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <sys/wait.h>
#include <unistd.h>
+#include "AnnotateListener.h"
#include "CCNDriver.h"
#include "Child.h"
#include "EventsXML.h"
memset(&mDstAns, 0, sizeof(mDstAns));
memcpy(mDstAns.rviHeader, "STR_ANS ", sizeof(mDstAns.rviHeader));
if (gethostname(mDstAns.dhcpName, sizeof(mDstAns.dhcpName) - 1) != 0) {
- logg->logError(__FILE__, __LINE__, "gethostname failed");
+ logg->logError("gethostname failed");
handleException();
}
// Subvert the defaultGateway field for the port number
addrlen = sizeof(sockaddr);
read = recvfrom(mReq, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen);
if (read < 0) {
- logg->logError(__FILE__, __LINE__, "recvfrom failed");
+ logg->logError("recvfrom failed");
handleException();
} else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) {
// Don't care if sendto fails - gatord shouldn't exit because of it and Streamline will retry
family = AF_INET;
s = socket_cloexec(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) {
- logg->logError(__FILE__, __LINE__, "socket failed");
+ logg->logError("socket failed");
handleException();
}
}
on = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
- logg->logError(__FILE__, __LINE__, "setsockopt failed");
+ logg->logError("setsockopt REUSEADDR failed");
handleException();
}
+ // Listen on both IPv4 and IPv6
+ on = 0;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) != 0) {
+ logg->logMessage("setsockopt IPV6_V6ONLY failed");
+ }
+
memset((void*)&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin6_family = family;
sockaddr.sin6_port = htons(port);
sockaddr.sin6_addr = in6addr_any;
if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
- logg->logError(__FILE__, __LINE__, "socket failed");
+ logg->logError("socket failed");
handleException();
}
// if still mounted
if (access("/dev/gator/buffer", F_OK) == 0) {
- logg->logError(__FILE__, __LINE__, "Unable to remove the running gator.ko. Manually remove the module or use the running module by not specifying one on the commandline");
+ logg->logError("Unable to remove the running gator.ko. Manually remove the module or use the running module by not specifying one on the commandline");
handleException();
}
}
return false;
} else {
// gator location specified on the command line but it was not found
- logg->logError(__FILE__, __LINE__, "gator module not found at %s", location);
+ logg->logError("gator module not found at %s", location);
handleException();
}
}
snprintf(command, sizeof(command), "insmod %s >/dev/null 2>&1", location);
if (system(command) != 0) {
logg->logMessage("Unable to load gator.ko driver with command: %s", command);
- logg->logError(__FILE__, __LINE__, "Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
+ logg->logError("Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
handleException();
}
}
if (mountGatorFS() == -1) {
- logg->logError(__FILE__, __LINE__, "Unable to mount the gator filesystem needed for profiling.");
+ logg->logError("Unable to mount the gator filesystem needed for profiling.");
handleException();
}
}
return 0; // success
}
-static const char OPTSTRING[] = "hvudap:s:c:e:m:o:";
+static const char OPTSTRING[] = "hvVudap:s:c:e:E:m:o:";
static bool hasDebugFlag(int argc, char** argv) {
int c;
case 'e':
gSessionData->mEventsXMLPath = optarg;
break;
+ case 'E':
+ gSessionData->mEventsXMLAppend = optarg;
+ break;
case 'm':
cmdline.module = optarg;
break;
case 'p':
cmdline.port = strtol(optarg, NULL, 10);
+ if ((cmdline.port == 8082) || (cmdline.port == 8083)) {
+ logg->logError("Gator can't use port %i, as it already uses ports 8082 and 8083 for annotations. Please select a different port.", cmdline.port);
+ handleException();
+ }
break;
case 's':
gSessionData->mSessionXMLPath = optarg;
break;
case 'h':
case '?':
- logg->logError(__FILE__, __LINE__,
+ logg->logError(
"%s. All parameters are optional:\n"
- "-c config_xml path and filename of the configuration.xml to use\n"
- "-e events_xml path and filename of the events.xml to use\n"
+ "-c config_xml path and filename of the configuration XML to use\n"
+ "-e events_xml path and filename of the events XML to use\n"
+ "-E events_xml path and filename of events XML to append\n"
"-h this help page\n"
"-m module path and filename of gator.ko\n"
"-p port_number port upon which the server listens; default is 8080\n"
"-o apc_dir path and name of the output for a local capture\n"
"-v version information\n"
"-d enable debug messages\n"
- "-a allow the user user to provide a command to run at the start of a capture"
+ "-a allow the user to issue a command from Streamline"
, version_string);
handleException();
break;
case 'v':
- logg->logError(__FILE__, __LINE__, version_string);
+ logg->logError("%s", version_string);
+ handleException();
+ break;
+ case 'V':
+ logg->logError("%s\nSRC_MD5: %s", version_string, gSrcMd5);
handleException();
break;
}
// Error checking
if (cmdline.port != DEFAULT_PORT && gSessionData->mSessionXMLPath != NULL) {
- logg->logError(__FILE__, __LINE__, "Only a port or a session xml can be specified, not both");
+ logg->logError("Only a port or a session xml can be specified, not both");
handleException();
}
if (gSessionData->mTargetPath != NULL && gSessionData->mSessionXMLPath == NULL) {
- logg->logError(__FILE__, __LINE__, "Missing -s command line option required for a local capture.");
+ logg->logError("Missing -s command line option required for a local capture.");
handleException();
}
if (optind < argc) {
- logg->logError(__FILE__, __LINE__, "Unknown argument: %s. Use '-h' for help.", argv[optind]);
+ logg->logError("Unknown argument: %s. Use '-h' for help.", argv[optind]);
handleException();
}
return cmdline;
}
+static AnnotateListener annotateListener;
+
static void handleClient() {
OlySocket client(sock->acceptConnection());
int pid = fork();
if (pid < 0) {
// Error
- logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists.");
+ logg->logError("Fork process failed. Please power cycle the target device if this error persists.");
} else if (pid == 0) {
// Child
sock->closeServerSocket();
udpListener.close();
monitor.close();
+ annotateListener.close();
child = new Child(&client, numSessions + 1);
child->run();
delete child;
struct cmdline_t cmdline = parseCommandLine(argc, argv);
if (cmdline.update) {
- return update(argv[0]);
+ update(argv[0]);
+ cmdline.update = false;
+ gSessionData->mAllowCommands = true;
}
// Verify root permissions
uid_t euid = geteuid();
if (euid) {
- logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
+ logg->logError("gatord must be launched with root privileges");
handleException();
}
// Call before setting up the SIGCHLD handler, as system() spawns child processes
if (!setupFilesystem(cmdline.module)) {
- logg->logMessage("Unable to setup gatorfs, trying perf");
+ logg->logMessage("Unable to set up gatorfs, trying perf");
if (!gSessionData->perf.setup()) {
- logg->logError(__FILE__, __LINE__,
+ logg->logError(
"Unable to locate gator.ko driver:\n"
" >>> gator.ko should be co-located with gatord in the same directory\n"
" >>> OR insmod gator.ko prior to launching gatord\n"
child->run();
delete child;
} else {
- gSessionData->annotateListener.setup();
+ annotateListener.setup();
+ int pipefd[2];
+ if (pipe_cloexec(pipefd) != 0) {
+ logg->logError("Unable to set up annotate pipe");
+ handleException();
+ }
+ gSessionData->mAnnotateStart = pipefd[1];
sock = new OlyServerSocket(cmdline.port);
udpListener.setup(cmdline.port);
if (!monitor.init() ||
!monitor.add(sock->getFd()) ||
!monitor.add(udpListener.getReq()) ||
- !monitor.add(gSessionData->annotateListener.getFd()) ||
+ !monitor.add(annotateListener.getSockFd()) ||
+ !monitor.add(annotateListener.getUdsFd()) ||
+ !monitor.add(pipefd[0]) ||
false) {
- logg->logError(__FILE__, __LINE__, "Monitor setup failed");
+ logg->logError("Monitor setup failed");
handleException();
}
// Forever loop, can be exited via a signal or exception
logg->logMessage("Waiting on connection...");
int ready = monitor.wait(events, ARRAY_LENGTH(events), -1);
if (ready < 0) {
- logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
+ logg->logError("Monitor::wait failed");
handleException();
}
for (int i = 0; i < ready; ++i) {
handleClient();
} else if (events[i].data.fd == udpListener.getReq()) {
udpListener.handle();
- } else if (events[i].data.fd == gSessionData->annotateListener.getFd()) {
- gSessionData->annotateListener.handle();
+ } else if (events[i].data.fd == annotateListener.getSockFd()) {
+ annotateListener.handleSock();
+ } else if (events[i].data.fd == annotateListener.getUdsFd()) {
+ annotateListener.handleUds();
+ } else if (events[i].data.fd == pipefd[0]) {
+ uint64_t val;
+ if (read(pipefd[0], &val, sizeof(val)) != sizeof(val)) {
+ logg->logMessage("Reading annotate pipe failed");
+ }
+ annotateListener.signal();
}
}
}
CC = $(CROSS_COMPILE)gcc
-BUILD_OUTPUT := $(PWD)
+BUILD_OUTPUT := $(CURDIR)
PREFIX := /usr
DESTDIR :=
+ifeq ("$(origin O)", "command line")
+ BUILD_OUTPUT := $(O)
+endif
+
turbostat : turbostat.c
CFLAGS += -Wall
CFLAGS += -DMSRHEADER='"../../../../arch/x86/include/uapi/asm/msr-index.h"'
ghc->generation = slots->generation;
ghc->len = len;
ghc->memslot = gfn_to_memslot(kvm, start_gfn);
- ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, &nr_pages_avail);
- if (!kvm_is_error_hva(ghc->hva) && nr_pages_avail >= nr_pages_needed) {
+ ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, NULL);
+ if (!kvm_is_error_hva(ghc->hva) && nr_pages_needed <= 1) {
ghc->hva += offset;
} else {
/*