summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMandar padmawar <mpadmawar@nvidia.com>2014-05-29 23:28:18 -0700
committerMandar padmawar <mpadmawar@nvidia.com>2014-05-29 23:28:18 -0700
commitabf9c41277d27ad35cb2dc036dd9c427e8d316e7 (patch)
tree7a7502259b67a5ef54a168099165ffa19159aa22
parenta39d4a70d52df4a9d4a74c818880b73d684db8c7 (diff)
parent75c1032e7b6215de41e451a01033a342372105d4 (diff)
Merge commit 'refs/changes/16/411516/5' of ssh://git-master:12001/linux-3.10 into promotion_build
-rw-r--r--android/configs/android-base.cfg3
-rw-r--r--android/configs/android-recommended.cfg1
-rw-r--r--arch/arm/common/Kconfig46
-rw-r--r--arch/arm/common/Makefile1
-rw-r--r--arch/arm64/Kconfig33
-rw-r--r--arch/arm64/Makefile8
-rw-r--r--arch/arm64/boot/.gitignore1
-rw-r--r--arch/arm64/boot/Makefile14
-rw-r--r--arch/arm64/boot/dts/Makefile12
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c51
-rw-r--r--drivers/hid/hid-debug.c15
-rw-r--r--drivers/hid/hid-input.c17
-rw-r--r--drivers/input/Kconfig10
-rw-r--r--drivers/input/Makefile3
-rw-r--r--drivers/input/keycombo.c261
-rw-r--r--drivers/input/keyreset.c206
-rw-r--r--drivers/of/fdt.c68
-rw-r--r--drivers/staging/android/Kconfig2
-rw-r--r--drivers/staging/android/Makefile1
-rw-r--r--drivers/staging/android/binder.c13
-rw-r--r--drivers/staging/android/fiq_debugger/Kconfig49
-rw-r--r--drivers/staging/android/fiq_debugger/Makefile4
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_debugger.c (renamed from arch/arm/common/fiq_debugger.c)592
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_debugger.h (renamed from arch/arm/include/asm/fiq_debugger.h)2
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_debugger_arm.c240
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c202
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_debugger_priv.h37
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h (renamed from arch/arm/common/fiq_debugger_ringbuf.h)2
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_watchdog.c56
-rw-r--r--drivers/staging/android/fiq_debugger/fiq_watchdog.h20
-rw-r--r--drivers/tty/n_tty.c4
-rw-r--r--drivers/usb/gadget/f_accessory.c16
-rw-r--r--drivers/usb/gadget/f_mtp.c16
-rw-r--r--drivers/video/adf/adf.c22
-rw-r--r--drivers/video/adf/adf_fbdev.c36
-rw-r--r--drivers/video/adf/adf_fops.c4
-rw-r--r--drivers/video/adf/adf_fops32.h2
-rw-r--r--drivers/video/adf/adf_memblock.c17
-rw-r--r--fs/pstore/ram.c6
-rw-r--r--include/linux/keycombo.h36
-rw-r--r--include/linux/keyreset.h3
-rw-r--r--include/linux/of_fdt.h21
-rw-r--r--include/linux/pstore_ram.h2
-rw-r--r--include/linux/wakeup_reason.h23
-rw-r--r--include/uapi/linux/input.h40
-rw-r--r--include/uapi/linux/prctl.h6
-rw-r--r--include/uapi/video/adf.h12
-rw-r--r--include/video/adf.h18
-rw-r--r--include/video/adf_fbdev.h67
-rw-r--r--kernel/power/Makefile2
-rw-r--r--kernel/power/wakeup_reason.c139
-rw-r--r--kernel/sys.c19
-rw-r--r--net/ipv4/ping.c15
-rw-r--r--net/netfilter/xt_IDLETIMER.c170
-rw-r--r--net/netfilter/xt_qtaguid.c14
-rw-r--r--net/netfilter/xt_quota2.c4
-rw-r--r--security/selinux/avc.c7
-rw-r--r--security/selinux/hooks.c5
-rw-r--r--security/selinux/include/avc.h4
59 files changed, 1988 insertions, 712 deletions
diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg
index 00c99e1f3b1f..04c7148cf637 100644
--- a/android/configs/android-base.cfg
+++ b/android/configs/android-base.cfg
@@ -16,6 +16,7 @@ CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_SCHED=y
CONFIG_DM_CRYPT=y
+CONFIG_DM_VERITY=y
CONFIG_EMBEDDED=y
CONFIG_FB=y
CONFIG_HIGH_RES_TIMERS=y
@@ -34,8 +35,8 @@ CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_NF_ARPFILTER=y
diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg
index aceee62a3e0b..960b9de2860d 100644
--- a/android/configs/android-recommended.cfg
+++ b/android/configs/android-recommended.cfg
@@ -13,6 +13,7 @@ CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_COMPACTION=y
CONFIG_DM_UEVENT=y
CONFIG_DRAGONRISE_FF=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FUSE_FS=y
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 3e6e2180643e..709d85388621 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -22,52 +22,6 @@ config FIQ_GLUE
bool
select FIQ
-config FIQ_DEBUGGER
- bool "FIQ Mode Serial Debugger"
- select FIQ
- select FIQ_GLUE
- default n
- help
- The FIQ serial debugger can accept commands even when the
- kernel is unresponsive due to being stuck with interrupts
- disabled.
-
-
-config FIQ_DEBUGGER_NO_SLEEP
- bool "Keep serial debugger active"
- depends on FIQ_DEBUGGER
- default n
- help
- Enables the serial debugger at boot. Passing
- fiq_debugger.no_sleep on the kernel commandline will
- override this config option.
-
-config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
- bool "Don't disable wakeup IRQ when debugger is active"
- depends on FIQ_DEBUGGER
- default n
- help
- Don't disable the wakeup irq when enabling the uart clock. This will
- cause extra interrupts, but it makes the serial debugger usable with
- on some MSM radio builds that ignore the uart clock request in power
- collapse.
-
-config FIQ_DEBUGGER_CONSOLE
- bool "Console on FIQ Serial Debugger port"
- depends on FIQ_DEBUGGER
- default n
- help
- Enables a console so that printk messages are displayed on
- the debugger serial port as the occur.
-
-config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE
- bool "Put the FIQ debugger into console mode by default"
- depends on FIQ_DEBUGGER_CONSOLE
- default n
- help
- If enabled, this puts the fiq debugger into console mode by default.
- Otherwise, the fiq debugger will start out in debug mode.
-
config GIC_SET_MULTIPLE_CPUS
bool "Use affinity hint to allow multiple CPUs for IRQ"
depends on ARM_GIC && SMP
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 384abdc09b62..0a0821fa9a90 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -4,7 +4,6 @@
obj-y += firmware.o
-obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o
obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o
obj-$(CONFIG_ICST) += icst.o
obj-$(CONFIG_SA1111) += sa1111.o
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 056a3f9fcb38..61cd81cad4d8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -357,6 +357,23 @@ config CMDLINE
entering them here. As a minimum, you should specify the the
root device (e.g. root=/dev/nfs).
+choice
+ prompt "Kernel command line type" if CMDLINE != ""
+ default CMDLINE_FROM_BOOTLOADER
+
+config CMDLINE_FROM_BOOTLOADER
+ bool "Use bootloader kernel arguments if available"
+ help
+ Uses the command-line options passed by the boot loader. If
+ the boot loader doesn't provide any, the default kernel command
+ string provided in CMDLINE will be used.
+
+config CMDLINE_EXTEND
+ bool "Extend bootloader kernel arguments"
+ help
+ The command-line arguments provided by the boot loader will be
+ appended to the default kernel command string.
+
config CMDLINE_FORCE
bool "Always use the default kernel command string"
help
@@ -364,6 +381,22 @@ config CMDLINE_FORCE
loader passes other arguments to the kernel.
This is useful if you cannot or don't want to change the
command-line options your boot loader passes to the kernel.
+endchoice
+
+config BUILD_ARM64_APPENDED_DTB_IMAGE
+ bool "Build a concatenated Image.gz/dtb by default"
+ depends on OF
+ help
+ Enabling this option will cause a concatenated Image.gz and list of
+ DTBs to be built by default (instead of a standalone Image.gz.)
+ The image will built in arch/arm64/boot/Image.gz-dtb
+
+config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
+ string "Default dtb names"
+ depends on BUILD_ARM64_APPENDED_DTB_IMAGE
+ help
+ Space separated list of names of dtbs to append when
+ building a concatenated Image.gz-dtb.
endmenu
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index c68d8cb8985d..bf0d94c3ce25 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -53,7 +53,12 @@ libs-y := arch/arm64/lib/ $(libs-y)
libs-y += $(LIBGCC)
# Default target when executing plain make
+ifeq ($(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),y)
+KBUILD_IMAGE := Image.gz-dtb
+else
KBUILD_IMAGE := Image.gz
+endif
+
KBUILD_DTBS := dtbs
all: $(KBUILD_IMAGE) $(KBUILD_DTBS) zImage
@@ -76,6 +81,9 @@ zinstall install: vmlinux
dtbs: scripts
$(Q)$(MAKE) $(build)=$(boot)/dts dtbs
+Image.gz-dtb: vmlinux scripts dtbs
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
# We use MRPROPER_FILES and CLEAN_FILES now
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
diff --git a/arch/arm64/boot/.gitignore b/arch/arm64/boot/.gitignore
index 8dab0bb6ae66..eb3551131b1e 100644
--- a/arch/arm64/boot/.gitignore
+++ b/arch/arm64/boot/.gitignore
@@ -1,2 +1,3 @@
Image
Image.gz
+Image.gz-dtb
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index 985f046586d0..b4cd97d41a11 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -14,17 +14,29 @@
# Based on the ia64 boot/Makefile.
#
+include $(srctree)/arch/arm64/boot/dts/Makefile
targets := Image Image.gz zImage
+DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES))
+ifneq ($(DTB_NAMES),)
+DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
+else
+DTB_LIST := $(dtb-y)
+endif
+DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST))
+
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/Image.gz: $(obj)/Image FORCE
$(call if_changed,gzip)
-$(obj)/zImage: $(obj)/Image FORCE
+$(obj)/zImage: $(obj)/Image
$(call if_changed,gzip)
+$(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE
+ $(call if_changed,cat)
+
install: $(obj)/Image
$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
$(obj)/Image System.map "$(INSTALL_PATH)"
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 42609a0df121..a97dbddad121 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -17,10 +17,18 @@ dtb-$(CONFIG_MACH_T132REF) += tegra132-tn8-p1761-1270-a03-battery.dtb
dtb-$(CONFIG_MACH_T132REF) += tegra132-tn8-p1761-1270-a03.dtb
targets += $(dtb-y)
+DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES))
+ifneq ($(DTB_NAMES),)
+DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
+else
+DTB_LIST := $(dtb-y)
+endif
+targets += $(DTB_LIST)
+
+dtbs: $(addprefix $(obj)/, $(DTB_LIST))
+
DTC_FLAGS := -i $(srctree)/arch/arm/boot/dts
DTCCPP_FLAGS := -I$(srctree)/arch/arm/boot/dts
-dtbs: $(addprefix $(obj)/, $(dtb-y))
-
clean-files := *.dtb
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 9c62003a19a8..98e71417f884 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -48,8 +48,10 @@ struct cpufreq_interactive_cpuinfo {
unsigned int io_consecutive;
struct cpufreq_policy *policy;
struct cpufreq_frequency_table *freq_table;
+ spinlock_t target_freq_lock; /*protects target freq */
unsigned int target_freq;
unsigned int floor_freq;
+ unsigned int max_freq;
u64 floor_validate_time;
u64 hispeed_validate_time;
struct rw_semaphore enable_sem;
@@ -407,6 +409,7 @@ static void cpufreq_interactive_timer(unsigned long data)
if (WARN_ON_ONCE(!delta_time))
goto rearm;
+ 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;
@@ -428,6 +431,7 @@ static void cpufreq_interactive_timer(unsigned long data)
trace_cpufreq_interactive_notyet(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
+ spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
goto rearm;
}
@@ -435,8 +439,10 @@ static void cpufreq_interactive_timer(unsigned long data)
if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
new_freq, CPUFREQ_RELATION_L,
- &index))
+ &index)) {
+ spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
goto rearm;
+ }
new_freq = pcpu->freq_table[index].frequency;
@@ -450,6 +456,7 @@ static void cpufreq_interactive_timer(unsigned long data)
trace_cpufreq_interactive_notyet(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
+ spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
goto rearm;
}
}
@@ -476,6 +483,7 @@ static void cpufreq_interactive_timer(unsigned long data)
trace_cpufreq_interactive_already(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
+ spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
goto rearm_if_notmax;
}
@@ -483,6 +491,7 @@ static void cpufreq_interactive_timer(unsigned long data)
pcpu->policy->cur, new_freq);
pcpu->target_freq = new_freq;
+ spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
spin_lock_irqsave(&speedchange_cpumask_lock, flags);
cpumask_set_cpu(data, &speedchange_cpumask);
spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
@@ -626,16 +635,17 @@ static void cpufreq_interactive_boost(void)
{
int i;
int anyboost = 0;
- unsigned long flags;
+ unsigned long flags[2];
struct cpufreq_interactive_cpuinfo *pcpu;
struct cpufreq_interactive_tunables *tunables;
- spin_lock_irqsave(&speedchange_cpumask_lock, flags);
+ spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]);
for_each_online_cpu(i) {
pcpu = &per_cpu(cpuinfo, i);
tunables = pcpu->policy->governor_data;
+ spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]);
if (pcpu->target_freq < tunables->hispeed_freq) {
pcpu->target_freq = tunables->hispeed_freq;
cpumask_set_cpu(i, &speedchange_cpumask);
@@ -651,9 +661,10 @@ static void cpufreq_interactive_boost(void)
pcpu->floor_freq = tunables->hispeed_freq;
pcpu->floor_validate_time = ktime_to_us(ktime_get());
+ spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]);
}
- spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]);
if (anyboost)
wake_up_process(speedchange_task);
@@ -965,6 +976,7 @@ static ssize_t store_boost(struct cpufreq_interactive_tunables *tunables,
trace_cpufreq_interactive_boost("on");
cpufreq_interactive_boost();
} else {
+ tunables->boostpulse_endtime = ktime_to_us(ktime_get());
trace_cpufreq_interactive_unboost("off");
}
@@ -1198,6 +1210,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
struct cpufreq_interactive_cpuinfo *pcpu;
struct cpufreq_frequency_table *freq_table;
struct cpufreq_interactive_tunables *tunables;
+ unsigned long flags;
if (have_governor_per_policy())
tunables = policy->governor_data;
@@ -1292,7 +1305,10 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
ktime_to_us(ktime_get());
pcpu->hispeed_validate_time =
pcpu->floor_validate_time;
+ pcpu->max_freq = policy->max;
down_write(&pcpu->enable_sem);
+ del_timer_sync(&pcpu->cpu_timer);
+ del_timer_sync(&pcpu->cpu_slack_timer);
cpufreq_interactive_timer_start(tunables, j);
pcpu->governor_enabled = 1;
up_write(&pcpu->enable_sem);
@@ -1325,29 +1341,37 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
for_each_cpu(j, policy->cpus) {
pcpu = &per_cpu(cpuinfo, j);
- /* hold write semaphore to avoid race */
- down_write(&pcpu->enable_sem);
+ down_read(&pcpu->enable_sem);
if (pcpu->governor_enabled == 0) {
- up_write(&pcpu->enable_sem);
+ up_read(&pcpu->enable_sem);
continue;
}
- /* update target_freq firstly */
+ spin_lock_irqsave(&pcpu->target_freq_lock, flags);
if (policy->max < pcpu->target_freq)
pcpu->target_freq = policy->max;
else if (policy->min > pcpu->target_freq)
pcpu->target_freq = policy->min;
- /* Reschedule timer.
+ spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
+ up_read(&pcpu->enable_sem);
+
+ /* Reschedule timer only if policy->max is raised.
* Delete the timers, else the timer callback may
* return without re-arm the timer when failed
* acquire the semaphore. This race may cause timer
* stopped unexpectedly.
*/
- del_timer_sync(&pcpu->cpu_timer);
- del_timer_sync(&pcpu->cpu_slack_timer);
- cpufreq_interactive_timer_start(tunables, j);
- up_write(&pcpu->enable_sem);
+
+ if (policy->max > pcpu->max_freq) {
+ down_write(&pcpu->enable_sem);
+ del_timer_sync(&pcpu->cpu_timer);
+ del_timer_sync(&pcpu->cpu_slack_timer);
+ cpufreq_interactive_timer_start(tunables, j);
+ up_write(&pcpu->enable_sem);
+ }
+
+ pcpu->max_freq = policy->max;
}
break;
}
@@ -1384,6 +1408,7 @@ static int __init cpufreq_interactive_init(void)
init_timer(&pcpu->cpu_slack_timer);
pcpu->cpu_slack_timer.function = cpufreq_interactive_nop_timer;
spin_lock_init(&pcpu->load_lock);
+ spin_lock_init(&pcpu->target_freq_lock);
init_rwsem(&pcpu->enable_sem);
}
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 8453214ec376..941ab3c287ec 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -768,6 +768,8 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel",
[KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
[KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown",
+ [BTN_DPAD_UP] = "BtnDPadUp", [BTN_DPAD_DOWN] = "BtnDPadDown",
+ [BTN_DPAD_LEFT] = "BtnDPadLeft", [BTN_DPAD_RIGHT] = "BtnDPadRight",
[BTN_0] = "Btn0", [BTN_1] = "Btn1",
[BTN_2] = "Btn2", [BTN_3] = "Btn3",
[BTN_4] = "Btn4", [BTN_5] = "Btn5",
@@ -797,7 +799,8 @@ static const char *keys[KEY_MAX + 1] = {
[BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens",
[BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus",
[BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
- [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
+ [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_TOOL_QUADTAP] = "ToolQuadrupleTap",
+ [BTN_GEAR_DOWN] = "WheelBtn",
[BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok",
[KEY_SELECT] = "Select", [KEY_GOTO] = "Goto",
[KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2",
@@ -852,6 +855,16 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
[KEY_KBDILLUMUP] = "KbdIlluminationUp",
[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+ [KEY_BUTTONCONFIG] = "ButtonConfig",
+ [KEY_TASKMANAGER] = "TaskManager",
+ [KEY_JOURNAL] = "Journal",
+ [KEY_CONTROLPANEL] = "ControlPanel",
+ [KEY_APPSELECT] = "AppSelect",
+ [KEY_SCREENSAVER] = "ScreenSaver",
+ [KEY_VOICECOMMAND] = "VoiceCommand",
+ [KEY_BRIGHTNESS_MIN] = "BrightnessMin",
+ [KEY_BRIGHTNESS_MAX] = "BrightnessMax",
+ [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
};
static const char *relatives[REL_MAX + 1] = {
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index bbb546ad985f..198fb3358cb6 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -730,6 +730,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x06c: map_key_clear(KEY_YELLOW); break;
case 0x06d: map_key_clear(KEY_ZOOM); break;
+ case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break;
+ case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break;
+ case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break;
+ case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break;
+ case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break;
+ case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); break;
+
case 0x082: map_key_clear(KEY_VIDEO_NEXT); break;
case 0x083: map_key_clear(KEY_LAST); break;
case 0x084: map_key_clear(KEY_ENTER); break;
@@ -770,6 +777,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0bf: map_key_clear(KEY_SLOW); break;
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
+ case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break;
case 0x0e0: map_abs_clear(ABS_VOLUME); break;
case 0x0e2: map_key_clear(KEY_MUTE); break;
case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
@@ -777,6 +785,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
case 0x0f5: map_key_clear(KEY_SLOW); break;
+ case 0x181: map_key_clear(KEY_BUTTONCONFIG); break;
case 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
@@ -790,6 +799,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x18c: map_key_clear(KEY_VOICEMAIL); break;
case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
case 0x18e: map_key_clear(KEY_CALENDAR); break;
+ case 0x18f: map_key_clear(KEY_TASKMANAGER); break;
+ case 0x190: map_key_clear(KEY_JOURNAL); break;
case 0x191: map_key_clear(KEY_FINANCE); break;
case 0x192: map_key_clear(KEY_CALC); break;
case 0x193: map_key_clear(KEY_PLAYER); break;
@@ -798,10 +809,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x199: map_key_clear(KEY_CHAT); break;
case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break;
+ case 0x19f: map_key_clear(KEY_CONTROLPANEL); break;
+ case 0x1a2: map_key_clear(KEY_APPSELECT); break;
+ case 0x1a3: map_key_clear(KEY_NEXT); break;
+ case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
+ case 0x1b1: map_key_clear(KEY_SCREENSAVER); break;
+ case 0x1b4: map_key_clear(KEY_FILE); break;
case 0x1b6: map_key_clear(KEY_IMAGES); break;
case 0x1b7: map_key_clear(KEY_AUDIO); break;
case 0x1b8: map_key_clear(KEY_VIDEO); break;
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 67543a8f4443..24bb04ae7aec 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -177,12 +177,22 @@ config INPUT_APMPOWER
config INPUT_KEYRESET
tristate "Reset key"
depends on INPUT
+ select INPUT_KEYCOMBO
---help---
Say Y here if you want to reboot when some keys are pressed;
To compile this driver as a module, choose M here: the
module will be called keyreset.
+config INPUT_KEYCOMBO
+ tristate "Key combo"
+ depends on INPUT
+ ---help---
+ Say Y here if you want to take action when some keys are pressed;
+
+ To compile this driver as a module, choose M here: the
+ module will be called keycombo.
+
config INPUT_CFBOOST
tristate "Input event CPU frequency booster"
depends on INPUT && CPU_FREQ
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 827e7a372d6f..0d0e36c31238 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -28,5 +28,8 @@ obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o
+obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o
obj-$(CONFIG_INPUT_CFBOOST) += input-cfboost.o
+
+
diff --git a/drivers/input/keycombo.c b/drivers/input/keycombo.c
new file mode 100644
index 000000000000..2fba451b91d5
--- /dev/null
+++ b/drivers/input/keycombo.c
@@ -0,0 +1,261 @@
+/* drivers/input/keycombo.c
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/keycombo.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+struct keycombo_state {
+ struct input_handler input_handler;
+ unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+ unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+ unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+ spinlock_t lock;
+ struct workqueue_struct *wq;
+ int key_down_target;
+ int key_down;
+ int key_up;
+ struct delayed_work key_down_work;
+ int delay;
+ struct work_struct key_up_work;
+ void (*key_up_fn)(void *);
+ void (*key_down_fn)(void *);
+ void *priv;
+ int key_is_down;
+ struct wakeup_source combo_held_wake_source;
+ struct wakeup_source combo_up_wake_source;
+};
+
+static void do_key_down(struct work_struct *work)
+{
+ struct delayed_work *dwork = container_of(work, struct delayed_work,
+ work);
+ struct keycombo_state *state = container_of(dwork,
+ struct keycombo_state, key_down_work);
+ if (state->key_down_fn)
+ state->key_down_fn(state->priv);
+}
+
+static void do_key_up(struct work_struct *work)
+{
+ struct keycombo_state *state = container_of(work, struct keycombo_state,
+ key_up_work);
+ if (state->key_up_fn)
+ state->key_up_fn(state->priv);
+ __pm_relax(&state->combo_up_wake_source);
+}
+
+static void keycombo_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+{
+ unsigned long flags;
+ struct keycombo_state *state = handle->private;
+
+ if (type != EV_KEY)
+ return;
+
+ if (code >= KEY_MAX)
+ return;
+
+ if (!test_bit(code, state->keybit))
+ return;
+
+ spin_lock_irqsave(&state->lock, flags);
+ if (!test_bit(code, state->key) == !value)
+ goto done;
+ __change_bit(code, state->key);
+ if (test_bit(code, state->upbit)) {
+ if (value)
+ state->key_up++;
+ else
+ state->key_up--;
+ } else {
+ if (value)
+ state->key_down++;
+ else
+ state->key_down--;
+ }
+ if (state->key_down == state->key_down_target && state->key_up == 0) {
+ __pm_stay_awake(&state->combo_held_wake_source);
+ state->key_is_down = 1;
+ if (queue_delayed_work(state->wq, &state->key_down_work,
+ state->delay))
+ pr_debug("Key down work already queued!");
+ } else if (state->key_is_down) {
+ if (!cancel_delayed_work(&state->key_down_work)) {
+ __pm_stay_awake(&state->combo_up_wake_source);
+ queue_work(state->wq, &state->key_up_work);
+ }
+ __pm_relax(&state->combo_held_wake_source);
+ state->key_is_down = 0;
+ }
+done:
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+
+static int keycombo_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ int i;
+ int ret;
+ struct input_handle *handle;
+ struct keycombo_state *state =
+ container_of(handler, struct keycombo_state, input_handler);
+ for (i = 0; i < KEY_MAX; i++) {
+ if (test_bit(i, state->keybit) && test_bit(i, dev->keybit))
+ break;
+ }
+ if (i == KEY_MAX)
+ return -ENODEV;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = KEYCOMBO_NAME;
+ handle->private = state;
+
+ ret = input_register_handle(handle);
+ if (ret)
+ goto err_input_register_handle;
+
+ ret = input_open_device(handle);
+ if (ret)
+ goto err_input_open_device;
+
+ return 0;
+
+err_input_open_device:
+ input_unregister_handle(handle);
+err_input_register_handle:
+ kfree(handle);
+ return ret;
+}
+
+static void keycombo_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ kfree(handle);
+}
+
+static const struct input_device_id keycombo_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(input, keycombo_ids);
+
+static int keycombo_probe(struct platform_device *pdev)
+{
+ int ret;
+ int key, *keyp;
+ struct keycombo_state *state;
+ struct keycombo_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ spin_lock_init(&state->lock);
+ keyp = pdata->keys_down;
+ while ((key = *keyp++)) {
+ if (key >= KEY_MAX)
+ continue;
+ state->key_down_target++;
+ __set_bit(key, state->keybit);
+ }
+ if (pdata->keys_up) {
+ keyp = pdata->keys_up;
+ while ((key = *keyp++)) {
+ if (key >= KEY_MAX)
+ continue;
+ __set_bit(key, state->keybit);
+ __set_bit(key, state->upbit);
+ }
+ }
+
+ state->wq = alloc_ordered_workqueue("keycombo", 0);
+ if (!state->wq)
+ return -ENOMEM;
+
+ state->priv = pdata->priv;
+
+ if (pdata->key_down_fn)
+ state->key_down_fn = pdata->key_down_fn;
+ INIT_DELAYED_WORK(&state->key_down_work, do_key_down);
+
+ if (pdata->key_up_fn)
+ state->key_up_fn = pdata->key_up_fn;
+ INIT_WORK(&state->key_up_work, do_key_up);
+
+ wakeup_source_init(&state->combo_held_wake_source, "key combo");
+ wakeup_source_init(&state->combo_up_wake_source, "key combo up");
+ state->delay = msecs_to_jiffies(pdata->key_down_delay);
+
+ state->input_handler.event = keycombo_event;
+ state->input_handler.connect = keycombo_connect;
+ state->input_handler.disconnect = keycombo_disconnect;
+ state->input_handler.name = KEYCOMBO_NAME;
+ state->input_handler.id_table = keycombo_ids;
+ ret = input_register_handler(&state->input_handler);
+ if (ret) {
+ kfree(state);
+ return ret;
+ }
+ platform_set_drvdata(pdev, state);
+ return 0;
+}
+
+int keycombo_remove(struct platform_device *pdev)
+{
+ struct keycombo_state *state = platform_get_drvdata(pdev);
+ input_unregister_handler(&state->input_handler);
+ destroy_workqueue(state->wq);
+ kfree(state);
+ return 0;
+}
+
+
+struct platform_driver keycombo_driver = {
+ .driver.name = KEYCOMBO_NAME,
+ .probe = keycombo_probe,
+ .remove = keycombo_remove,
+};
+
+static int __init keycombo_init(void)
+{
+ return platform_driver_register(&keycombo_driver);
+}
+
+static void __exit keycombo_exit(void)
+{
+ return platform_driver_unregister(&keycombo_driver);
+}
+
+module_init(keycombo_init);
+module_exit(keycombo_exit);
diff --git a/drivers/input/keyreset.c b/drivers/input/keyreset.c
index 36208fe0baae..eaaccde82210 100644
--- a/drivers/input/keyreset.c
+++ b/drivers/input/keyreset.c
@@ -1,6 +1,6 @@
/* drivers/input/keyreset.c
*
- * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2014 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -21,200 +21,104 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
-
+#include <linux/keycombo.h>
struct keyreset_state {
- struct input_handler input_handler;
- unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
- unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
- unsigned long key[BITS_TO_LONGS(KEY_CNT)];
- spinlock_t lock;
- int key_down_target;
- int key_down;
- int key_up;
- int restart_disabled;
+ int restart_requested;
int (*reset_fn)(void);
+ struct platform_device *pdev_child;
};
-int restart_requested;
-static void deferred_restart(struct work_struct *dummy)
+static void do_restart(void)
{
- restart_requested = 2;
sys_sync();
- restart_requested = 3;
kernel_restart(NULL);
}
-static DECLARE_WORK(restart_work, deferred_restart);
-static void keyreset_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int value)
+static void do_reset_fn(void *priv)
{
- unsigned long flags;
- struct keyreset_state *state = handle->private;
-
- if (type != EV_KEY)
- return;
-
- if (code >= KEY_MAX)
- return;
-
- if (!test_bit(code, state->keybit))
- return;
-
- spin_lock_irqsave(&state->lock, flags);
- if (!test_bit(code, state->key) == !value)
- goto done;
- __change_bit(code, state->key);
- if (test_bit(code, state->upbit)) {
- if (value) {
- state->restart_disabled = 1;
- state->key_up++;
- } else
- state->key_up--;
+ struct keyreset_state *state = priv;
+ if (state->restart_requested)
+ panic("keyboard reset failed, %d", state->restart_requested);
+ if (state->reset_fn) {
+ state->restart_requested = state->reset_fn();
} else {
- if (value)
- state->key_down++;
- else
- state->key_down--;
+ pr_info("keyboard reset\n");
+ do_restart();
+ state->restart_requested = 1;
}
- if (state->key_down == 0 && state->key_up == 0)
- state->restart_disabled = 0;
-
- pr_debug("reset key changed %d %d new state %d-%d-%d\n", code, value,
- state->key_down, state->key_up, state->restart_disabled);
-
- if (value && !state->restart_disabled &&
- state->key_down == state->key_down_target) {
- state->restart_disabled = 1;
- if (restart_requested)
- panic("keyboard reset failed, %d", restart_requested);
- if (state->reset_fn) {
- restart_requested = state->reset_fn();
- } else {
- pr_info("keyboard reset\n");
- schedule_work(&restart_work);
- restart_requested = 1;
- }
- }
-done:
- spin_unlock_irqrestore(&state->lock, flags);
}
-static int keyreset_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
-{
- int i;
- int ret;
- struct input_handle *handle;
- struct keyreset_state *state =
- container_of(handler, struct keyreset_state, input_handler);
-
- for (i = 0; i < KEY_MAX; i++) {
- if (test_bit(i, state->keybit) && test_bit(i, dev->keybit))
- break;
- }
- if (i == KEY_MAX)
- return -ENODEV;
-
- handle = kzalloc(sizeof(*handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
-
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "keyreset";
- handle->private = state;
-
- ret = input_register_handle(handle);
- if (ret)
- goto err_input_register_handle;
-
- ret = input_open_device(handle);
- if (ret)
- goto err_input_open_device;
-
- pr_info("using input dev %s for key reset\n", dev->name);
-
- return 0;
-
-err_input_open_device:
- input_unregister_handle(handle);
-err_input_register_handle:
- kfree(handle);
- return ret;
-}
-
-static void keyreset_disconnect(struct input_handle *handle)
-{
- input_close_device(handle);
- input_unregister_handle(handle);
- kfree(handle);
-}
-
-static const struct input_device_id keyreset_ids[] = {
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
- .evbit = { BIT_MASK(EV_KEY) },
- },
- { },
-};
-MODULE_DEVICE_TABLE(input, keyreset_ids);
-
static int keyreset_probe(struct platform_device *pdev)
{
- int ret;
+ int ret = -ENOMEM;
+ struct keycombo_platform_data *pdata_child;
+ struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+ int up_size = 0, down_size = 0, size;
int key, *keyp;
struct keyreset_state *state;
- struct keyreset_platform_data *pdata = pdev->dev.platform_data;
if (!pdata)
return -EINVAL;
-
- state = kzalloc(sizeof(*state), GFP_KERNEL);
+ state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
- spin_lock_init(&state->lock);
+ state->pdev_child = platform_device_alloc(KEYCOMBO_NAME,
+ PLATFORM_DEVID_AUTO);
+ if (!state->pdev_child)
+ return -ENOMEM;
+ state->pdev_child->dev.parent = &pdev->dev;
+
keyp = pdata->keys_down;
while ((key = *keyp++)) {
if (key >= KEY_MAX)
continue;
- state->key_down_target++;
- __set_bit(key, state->keybit);
+ down_size++;
}
if (pdata->keys_up) {
keyp = pdata->keys_up;
while ((key = *keyp++)) {
if (key >= KEY_MAX)
continue;
- __set_bit(key, state->keybit);
- __set_bit(key, state->upbit);
+ up_size++;
}
}
-
- if (pdata->reset_fn)
- state->reset_fn = pdata->reset_fn;
-
- state->input_handler.event = keyreset_event;
- state->input_handler.connect = keyreset_connect;
- state->input_handler.disconnect = keyreset_disconnect;
- state->input_handler.name = KEYRESET_NAME;
- state->input_handler.id_table = keyreset_ids;
- ret = input_register_handler(&state->input_handler);
- if (ret) {
- kfree(state);
- return ret;
+ size = sizeof(struct keycombo_platform_data)
+ + sizeof(int) * (down_size + 1);
+ pdata_child = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!pdata_child)
+ goto error;
+ memcpy(pdata_child->keys_down, pdata->keys_down,
+ sizeof(int) * down_size);
+ if (up_size > 0) {
+ pdata_child->keys_up = devm_kzalloc(&pdev->dev, up_size + 1,
+ GFP_KERNEL);
+ if (!pdata_child->keys_up)
+ goto error;
+ memcpy(pdata_child->keys_up, pdata->keys_up,
+ sizeof(int) * up_size);
+ if (!pdata_child->keys_up)
+ goto error;
}
+ state->reset_fn = pdata->reset_fn;
+ pdata_child->key_down_fn = do_reset_fn;
+ pdata_child->priv = state;
+ pdata_child->key_down_delay = pdata->key_down_delay;
+ ret = platform_device_add_data(state->pdev_child, pdata_child, size);
+ if (ret)
+ goto error;
platform_set_drvdata(pdev, state);
- return 0;
+ return platform_device_add(state->pdev_child);
+error:
+ platform_device_put(state->pdev_child);
+ return ret;
}
int keyreset_remove(struct platform_device *pdev)
{
struct keyreset_state *state = platform_get_drvdata(pdev);
- input_unregister_handler(&state->input_handler);
- kfree(state);
+ platform_device_put(state->pdev_child);
return 0;
}
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index a6287c6ad6c2..9da44890b56c 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -667,36 +667,66 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
return 0;
}
+/*
+ * Convert configs to something easy to use in C code
+ */
+#if defined(CONFIG_CMDLINE_FORCE)
+static const int overwrite_incoming_cmdline = 1;
+static const int read_dt_cmdline;
+static const int concat_cmdline;
+#elif defined(CONFIG_CMDLINE_EXTEND)
+static const int overwrite_incoming_cmdline;
+static const int read_dt_cmdline = 1;
+static const int concat_cmdline = 1;
+#else /* CMDLINE_FROM_BOOTLOADER */
+static const int overwrite_incoming_cmdline;
+static const int read_dt_cmdline = 1;
+static const int concat_cmdline;
+#endif
+
+#ifdef CONFIG_CMDLINE
+static const char *config_cmdline = CONFIG_CMDLINE;
+#else
+static const char *config_cmdline = "";
+#endif
+
int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data)
{
- unsigned long l;
- char *p;
+ unsigned long l = 0;
+ char *p = NULL;
+ char *cmdline = data;
pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
- if (depth != 1 || !data ||
+ if (depth != 1 || !cmdline ||
(strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
return 0;
early_init_dt_check_for_initrd(node);
- /* Retrieve command line */
- p = of_get_flat_dt_prop(node, "bootargs", &l);
- if (p != NULL && l > 0)
- strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
-
- /*
- * CONFIG_CMDLINE is meant to be a default in case nothing else
- * managed to set the command line, unless CONFIG_CMDLINE_FORCE
- * is set in which case we override whatever was found earlier.
- */
-#ifdef CONFIG_CMDLINE
-#ifndef CONFIG_CMDLINE_FORCE
- if (!((char *)data)[0])
-#endif
- strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif /* CONFIG_CMDLINE */
+ /* Put CONFIG_CMDLINE in if forced or if data had nothing in it to start */
+ if (overwrite_incoming_cmdline || !cmdline[0])
+ strlcpy(cmdline, config_cmdline, COMMAND_LINE_SIZE);
+
+ /* Retrieve command line unless forcing */
+ if (read_dt_cmdline)
+ p = of_get_flat_dt_prop(node, "bootargs", &l);
+
+ if (p != NULL && l > 0) {
+ if (concat_cmdline) {
+ int cmdline_len;
+ int copy_len;
+ strlcat(cmdline, " ", COMMAND_LINE_SIZE);
+ cmdline_len = strlen(cmdline);
+ copy_len = COMMAND_LINE_SIZE - cmdline_len - 1;
+ copy_len = min((int)l, copy_len);
+ strncpy(cmdline + cmdline_len, p, copy_len);
+ cmdline[cmdline_len + copy_len] = '\0';
+ } else {
+ strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE));
+ }
+ }
pr_debug("Command line is: %s\n", (char*)data);
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index af80e05dd78f..c303acbe05cc 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -127,6 +127,8 @@ config SW_SYNC_USER
source "drivers/staging/android/ion/Kconfig"
+source "drivers/staging/android/fiq_debugger/Kconfig"
+
endif # if ANDROID
endmenu
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 0a01e1914905..907b62f56203 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -1,6 +1,7 @@
ccflags-y += -I$(src) # needed for trace events
obj-y += ion/
+obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 6aec8509d7b0..d4e529001934 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -792,7 +792,7 @@ static void binder_delete_free_buffer(struct binder_proc *proc,
list_del(&buffer->entry);
if (free_page_start || free_page_end) {
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %p do not share page%s%s with with %p or %p\n",
+ "%d: merge free, buffer %p do not share page%s%s with %p or %p\n",
proc->pid, buffer, free_page_start ? "" : " end",
free_page_end ? "" : " start", prev, next);
binder_update_page_range(proc, 0, free_page_start ?
@@ -1306,6 +1306,7 @@ static void binder_transaction(struct binder_proc *proc,
struct binder_transaction *t;
struct binder_work *tcomplete;
binder_size_t *offp, *off_end;
+ binder_size_t off_min;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
@@ -1504,17 +1505,23 @@ static void binder_transaction(struct binder_proc *proc,
goto err_bad_offset;
}
off_end = (void *)offp + tr->offsets_size;
+ off_min = 0;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
if (*offp > t->buffer->data_size - sizeof(*fp) ||
+ *offp < off_min ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(u32))) {
- binder_user_error("%d:%d got transaction with invalid offset, %lld\n",
- proc->pid, thread->pid, (u64)*offp);
+ binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n",
+ proc->pid, thread->pid, (u64)*offp,
+ (u64)off_min,
+ (u64)(t->buffer->data_size -
+ sizeof(*fp)));
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
+ off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
diff --git a/drivers/staging/android/fiq_debugger/Kconfig b/drivers/staging/android/fiq_debugger/Kconfig
new file mode 100644
index 000000000000..56f7f999377e
--- /dev/null
+++ b/drivers/staging/android/fiq_debugger/Kconfig
@@ -0,0 +1,49 @@
+config FIQ_DEBUGGER
+ bool "FIQ Mode Serial Debugger"
+ default n
+ depends on ARM || ARM64
+ help
+ The FIQ serial debugger can accept commands even when the
+ kernel is unresponsive due to being stuck with interrupts
+ disabled.
+
+config FIQ_DEBUGGER_NO_SLEEP
+ bool "Keep serial debugger active"
+ depends on FIQ_DEBUGGER
+ default n
+ help
+ Enables the serial debugger at boot. Passing
+ fiq_debugger.no_sleep on the kernel commandline will
+ override this config option.
+
+config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
+ bool "Don't disable wakeup IRQ when debugger is active"
+ depends on FIQ_DEBUGGER
+ default n
+ help
+ Don't disable the wakeup irq when enabling the uart clock. This will
+ cause extra interrupts, but it makes the serial debugger usable with
+ on some MSM radio builds that ignore the uart clock request in power
+ collapse.
+
+config FIQ_DEBUGGER_CONSOLE
+ bool "Console on FIQ Serial Debugger port"
+ depends on FIQ_DEBUGGER
+ default n
+ help
+ Enables a console so that printk messages are displayed on
+ the debugger serial port as the occur.
+
+config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE
+ bool "Put the FIQ debugger into console mode by default"
+ depends on FIQ_DEBUGGER_CONSOLE
+ default n
+ help
+ If enabled, this puts the fiq debugger into console mode by default.
+ Otherwise, the fiq debugger will start out in debug mode.
+
+config FIQ_WATCHDOG
+ bool
+ select FIQ_DEBUGGER
+ select PSTORE_RAM
+ default n
diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile
new file mode 100644
index 000000000000..a7ca4871cad3
--- /dev/null
+++ b/drivers/staging/android/fiq_debugger/Makefile
@@ -0,0 +1,4 @@
+obj-y += fiq_debugger.o
+obj-$(CONFIG_ARM) += fiq_debugger_arm.o
+obj-$(CONFIG_ARM64) += fiq_debugger_arm64.o
+obj-$(CONFIG_FIQ_WATCHDOG) += fiq_watchdog.o
diff --git a/arch/arm/common/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c
index 759204eed0f1..7d6b4ae8a2cd 100644
--- a/arch/arm/common/fiq_debugger.c
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/common/fiq_debugger.c
+ * drivers/staging/android/fiq_debugger.c
*
* Serial Debugger Interface accessed through an FIQ interrupt.
*
@@ -35,12 +35,14 @@
#include <linux/tty_flip.h>
#include <linux/wakelock.h>
-#include <asm/fiq_debugger.h>
+#ifdef CONFIG_FIQ_GLUE
#include <asm/fiq_glue.h>
-#include <asm/stacktrace.h>
+#endif
#include <linux/uaccess.h>
+#include "fiq_debugger.h"
+#include "fiq_debugger_priv.h"
#include "fiq_debugger_ringbuf.h"
#define DEBUG_MAX 64
@@ -48,11 +50,11 @@
#define MAX_FIQ_DEBUGGER_PORTS 4
-#define THREAD_INFO(sp) ((struct thread_info *) \
- ((unsigned long)(sp) & ~(THREAD_SIZE - 1)))
-
struct fiq_debugger_state {
+#ifdef CONFIG_FIQ_GLUE
struct fiq_glue_handler handler;
+#endif
+ struct fiq_debugger_output output;
int fiq;
int uart_irq;
@@ -75,7 +77,6 @@ struct fiq_debugger_state {
bool ignore_next_wakeup_irq;
struct timer_list sleep_timer;
spinlock_t sleep_timer_lock;
- spinlock_t debug_fiq_lock;
bool uart_enabled;
struct wake_lock debugger_wake_lock;
bool console_enable;
@@ -125,10 +126,13 @@ module_param_named(console_enable, initial_console_enable, bool, 0644);
module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644);
#ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
-static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {}
-static inline void disable_wakeup_irq(struct fiq_debugger_state *state) {}
+static inline
+void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) {}
+static inline
+void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) {}
#else
-static inline void enable_wakeup_irq(struct fiq_debugger_state *state)
+static inline
+void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state)
{
if (state->wakeup_irq < 0)
return;
@@ -136,7 +140,8 @@ static inline void enable_wakeup_irq(struct fiq_debugger_state *state)
if (!state->wakeup_irq_no_set_wake)
enable_irq_wake(state->wakeup_irq);
}
-static inline void disable_wakeup_irq(struct fiq_debugger_state *state)
+static inline
+void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state)
{
if (state->wakeup_irq < 0)
return;
@@ -146,16 +151,17 @@ static inline void disable_wakeup_irq(struct fiq_debugger_state *state)
}
#endif
-static bool inline debug_have_fiq(struct fiq_debugger_state *state)
+static inline bool fiq_debugger_have_fiq(struct fiq_debugger_state *state)
{
return (state->fiq >= 0);
}
-static void debug_force_irq(struct fiq_debugger_state *state)
+#ifdef CONFIG_FIQ_GLUE
+static void fiq_debugger_force_irq(struct fiq_debugger_state *state)
{
unsigned int irq = state->signal_irq;
- if (WARN_ON(!debug_have_fiq(state)))
+ if (WARN_ON(!fiq_debugger_have_fiq(state)))
return;
if (state->pdata->force_irq) {
state->pdata->force_irq(state->pdev, irq);
@@ -165,8 +171,9 @@ static void debug_force_irq(struct fiq_debugger_state *state)
chip->irq_retrigger(irq_get_irq_data(irq));
}
}
+#endif
-static void debug_uart_enable(struct fiq_debugger_state *state)
+static void fiq_debugger_uart_enable(struct fiq_debugger_state *state)
{
if (state->clk)
clk_enable(state->clk);
@@ -174,7 +181,7 @@ static void debug_uart_enable(struct fiq_debugger_state *state)
state->pdata->uart_enable(state->pdev);
}
-static void debug_uart_disable(struct fiq_debugger_state *state)
+static void fiq_debugger_uart_disable(struct fiq_debugger_state *state)
{
if (state->pdata->uart_disable)
state->pdata->uart_disable(state->pdev);
@@ -182,33 +189,33 @@ static void debug_uart_disable(struct fiq_debugger_state *state)
clk_disable(state->clk);
}
-static void debug_uart_flush(struct fiq_debugger_state *state)
+static void fiq_debugger_uart_flush(struct fiq_debugger_state *state)
{
if (state->pdata->uart_flush)
state->pdata->uart_flush(state->pdev);
}
-static void debug_putc(struct fiq_debugger_state *state, char c)
+static void fiq_debugger_putc(struct fiq_debugger_state *state, char c)
{
state->pdata->uart_putc(state->pdev, c);
}
-static void debug_puts(struct fiq_debugger_state *state, char *s)
+static void fiq_debugger_puts(struct fiq_debugger_state *state, char *s)
{
unsigned c;
while ((c = *s++)) {
if (c == '\n')
- debug_putc(state, '\r');
- debug_putc(state, c);
+ fiq_debugger_putc(state, '\r');
+ fiq_debugger_putc(state, c);
}
}
-static void debug_prompt(struct fiq_debugger_state *state)
+static void fiq_debugger_prompt(struct fiq_debugger_state *state)
{
- debug_puts(state, "debug> ");
+ fiq_debugger_puts(state, "debug> ");
}
-static void dump_kernel_log(struct fiq_debugger_state *state)
+static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state)
{
char buf[512];
size_t len;
@@ -219,40 +226,27 @@ static void dump_kernel_log(struct fiq_debugger_state *state)
while (kmsg_dump_get_line_nolock(&dumper, true, buf,
sizeof(buf) - 1, &len)) {
buf[len] = 0;
- debug_puts(state, buf);
- }
-}
-
-static char *mode_name(unsigned cpsr)
-{
- switch (cpsr & MODE_MASK) {
- case USR_MODE: return "USR";
- case FIQ_MODE: return "FIQ";
- case IRQ_MODE: return "IRQ";
- case SVC_MODE: return "SVC";
- case ABT_MODE: return "ABT";
- case UND_MODE: return "UND";
- case SYSTEM_MODE: return "SYS";
- default: return "???";
+ fiq_debugger_puts(state, buf);
}
}
-static int debug_printf(void *cookie, const char *fmt, ...)
+static void fiq_debugger_printf(struct fiq_debugger_output *output,
+ const char *fmt, ...)
{
- struct fiq_debugger_state *state = cookie;
+ struct fiq_debugger_state *state;
char buf[256];
va_list ap;
+ state = container_of(output, struct fiq_debugger_state, output);
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
- debug_puts(state, buf);
- return state->debug_abort;
+ fiq_debugger_puts(state, buf);
}
/* Safe outside fiq context */
-static int debug_printf_nfiq(void *cookie, const char *fmt, ...)
+static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...)
{
struct fiq_debugger_state *state = cookie;
char buf[256];
@@ -264,115 +258,24 @@ static int debug_printf_nfiq(void *cookie, const char *fmt, ...)
va_end(ap);
local_irq_save(irq_flags);
- debug_puts(state, buf);
- debug_uart_flush(state);
+ fiq_debugger_puts(state, buf);
+ fiq_debugger_uart_flush(state);
local_irq_restore(irq_flags);
return state->debug_abort;
}
-static void dump_regs(struct fiq_debugger_state *state, unsigned *regs)
-{
- debug_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
- regs[0], regs[1], regs[2], regs[3]);
- debug_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
- regs[4], regs[5], regs[6], regs[7]);
- debug_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n",
- regs[8], regs[9], regs[10], regs[11],
- mode_name(regs[16]));
- if ((regs[16] & MODE_MASK) == USR_MODE)
- debug_printf(state, " ip %08x sp %08x lr %08x pc %08x "
- "cpsr %08x\n", regs[12], regs[13], regs[14],
- regs[15], regs[16]);
- else
- debug_printf(state, " ip %08x sp %08x lr %08x pc %08x "
- "cpsr %08x spsr %08x\n", regs[12], regs[13],
- regs[14], regs[15], regs[16], regs[17]);
-}
-
-struct mode_regs {
- unsigned long sp_svc;
- unsigned long lr_svc;
- unsigned long spsr_svc;
-
- unsigned long sp_abt;
- unsigned long lr_abt;
- unsigned long spsr_abt;
-
- unsigned long sp_und;
- unsigned long lr_und;
- unsigned long spsr_und;
-
- unsigned long sp_irq;
- unsigned long lr_irq;
- unsigned long spsr_irq;
-
- unsigned long r8_fiq;
- unsigned long r9_fiq;
- unsigned long r10_fiq;
- unsigned long r11_fiq;
- unsigned long r12_fiq;
- unsigned long sp_fiq;
- unsigned long lr_fiq;
- unsigned long spsr_fiq;
-};
-
-void __naked get_mode_regs(struct mode_regs *regs)
-{
- asm volatile (
- "mrs r1, cpsr\n"
- "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
- "stmia r0!, {r13 - r14}\n"
- "mrs r2, spsr\n"
- "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
- "stmia r0!, {r2, r13 - r14}\n"
- "mrs r2, spsr\n"
- "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
- "stmia r0!, {r2, r13 - r14}\n"
- "mrs r2, spsr\n"
- "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
- "stmia r0!, {r2, r13 - r14}\n"
- "mrs r2, spsr\n"
- "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
- "stmia r0!, {r2, r8 - r14}\n"
- "mrs r2, spsr\n"
- "stmia r0!, {r2}\n"
- "msr cpsr_c, r1\n"
- "bx lr\n");
-}
-
-
-static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs)
-{
- struct mode_regs mode_regs;
- dump_regs(state, regs);
- get_mode_regs(&mode_regs);
- debug_printf(state, " svc: sp %08x lr %08x spsr %08x\n",
- mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
- debug_printf(state, " abt: sp %08x lr %08x spsr %08x\n",
- mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
- debug_printf(state, " und: sp %08x lr %08x spsr %08x\n",
- mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
- debug_printf(state, " irq: sp %08x lr %08x spsr %08x\n",
- mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
- debug_printf(state, " fiq: r8 %08x r9 %08x r10 %08x r11 %08x "
- "r12 %08x\n",
- mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
- mode_regs.r11_fiq, mode_regs.r12_fiq);
- debug_printf(state, " fiq: sp %08x lr %08x spsr %08x\n",
- mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
-}
-
-static void dump_irqs(struct fiq_debugger_state *state)
+static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state)
{
int n;
struct irq_desc *desc;
- debug_printf(state, "irqnr total since-last status name\n");
+ fiq_debugger_printf(&state->output,
+ "irqnr total since-last status name\n");
for_each_irq_desc(n, desc) {
struct irqaction *act = desc->action;
if (!act && !kstat_irqs(n))
continue;
- debug_printf(state, "%5d: %10u %11u %8x %s\n", n,
+ fiq_debugger_printf(&state->output, "%5d: %10u %11u %8x %s\n", n,
kstat_irqs(n),
kstat_irqs(n) - state->last_irqs[n],
desc->status_use_accessors,
@@ -381,175 +284,86 @@ static void dump_irqs(struct fiq_debugger_state *state)
}
}
-struct stacktrace_state {
- struct fiq_debugger_state *state;
- unsigned int depth;
-};
-
-static int report_trace(struct stackframe *frame, void *d)
-{
- struct stacktrace_state *sts = d;
-
- if (sts->depth) {
- debug_printf(sts->state,
- " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
- frame->pc, frame->pc, frame->lr, frame->lr,
- frame->sp, frame->fp);
- sts->depth--;
- return 0;
- }
- debug_printf(sts->state, " ...\n");
-
- return sts->depth == 0;
-}
-
-struct frame_tail {
- struct frame_tail *fp;
- unsigned long sp;
- unsigned long lr;
-} __attribute__((packed));
-
-static struct frame_tail *user_backtrace(struct fiq_debugger_state *state,
- struct frame_tail *tail)
-{
- struct frame_tail buftail[2];
-
- /* Also check accessibility of one struct frame_tail beyond */
- if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) {
- debug_printf(state, " invalid frame pointer %p\n", tail);
- return NULL;
- }
- if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
- debug_printf(state,
- " failed to copy frame pointer %p\n", tail);
- return NULL;
- }
-
- debug_printf(state, " %p\n", buftail[0].lr);
-
- /* frame pointers should strictly progress back up the stack
- * (towards higher addresses) */
- if (tail >= buftail[0].fp)
- return NULL;
-
- return buftail[0].fp-1;
-}
-
-void dump_stacktrace(struct fiq_debugger_state *state,
- struct pt_regs * const regs, unsigned int depth, void *ssp)
-{
- struct frame_tail *tail;
- struct thread_info *real_thread_info = THREAD_INFO(ssp);
- struct stacktrace_state sts;
-
- sts.depth = depth;
- sts.state = state;
- *current_thread_info() = *real_thread_info;
-
- if (!current)
- debug_printf(state, "current NULL\n");
- else
- debug_printf(state, "pid: %d comm: %s\n",
- current->pid, current->comm);
- dump_regs(state, (unsigned *)regs);
-
- if (!user_mode(regs)) {
- struct stackframe frame;
- frame.fp = regs->ARM_fp;
- frame.sp = regs->ARM_sp;
- frame.lr = regs->ARM_lr;
- frame.pc = regs->ARM_pc;
- debug_printf(state,
- " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
- regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr,
- regs->ARM_sp, regs->ARM_fp);
- walk_stackframe(&frame, report_trace, &sts);
- return;
- }
-
- tail = ((struct frame_tail *) regs->ARM_fp) - 1;
- while (depth-- && tail && !((unsigned long) tail & 3))
- tail = user_backtrace(state, tail);
-}
-
-static void do_ps(struct fiq_debugger_state *state)
+static void fiq_debugger_do_ps(struct fiq_debugger_state *state)
{
struct task_struct *g;
struct task_struct *p;
unsigned task_state;
static const char stat_nam[] = "RSDTtZX";
- debug_printf(state, "pid ppid prio task pc\n");
+ fiq_debugger_printf(&state->output, "pid ppid prio task pc\n");
read_lock(&tasklist_lock);
do_each_thread(g, p) {
task_state = p->state ? __ffs(p->state) + 1 : 0;
- debug_printf(state,
+ fiq_debugger_printf(&state->output,
"%5d %5d %4d ", p->pid, p->parent->pid, p->prio);
- debug_printf(state, "%-13.13s %c", p->comm,
+ fiq_debugger_printf(&state->output, "%-13.13s %c", p->comm,
task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]);
if (task_state == TASK_RUNNING)
- debug_printf(state, " running\n");
+ fiq_debugger_printf(&state->output, " running\n");
else
- debug_printf(state, " %08lx\n", thread_saved_pc(p));
+ fiq_debugger_printf(&state->output, " %08lx\n",
+ thread_saved_pc(p));
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
}
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
-static void begin_syslog_dump(struct fiq_debugger_state *state)
+static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state)
{
state->syslog_dumping = true;
}
-static void end_syslog_dump(struct fiq_debugger_state *state)
+static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state)
{
state->syslog_dumping = false;
}
#else
extern int do_syslog(int type, char __user *bug, int count);
-static void begin_syslog_dump(struct fiq_debugger_state *state)
+static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state)
{
do_syslog(5 /* clear */, NULL, 0);
}
-static void end_syslog_dump(struct fiq_debugger_state *state)
+static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state)
{
- dump_kernel_log(state);
+ fiq_debugger_dump_kernel_log(state);
}
#endif
-static void do_sysrq(struct fiq_debugger_state *state, char rq)
+static void fiq_debugger_do_sysrq(struct fiq_debugger_state *state, char rq)
{
if ((rq == 'g' || rq == 'G') && !fiq_kgdb_enable) {
- debug_printf(state, "sysrq-g blocked\n");
+ fiq_debugger_printf(&state->output, "sysrq-g blocked\n");
return;
}
- begin_syslog_dump(state);
+ fiq_debugger_begin_syslog_dump(state);
handle_sysrq(rq);
- end_syslog_dump(state);
+ fiq_debugger_end_syslog_dump(state);
}
#ifdef CONFIG_KGDB
-static void do_kgdb(struct fiq_debugger_state *state)
+static void fiq_debugger_do_kgdb(struct fiq_debugger_state *state)
{
if (!fiq_kgdb_enable) {
- debug_printf(state, "kgdb through fiq debugger not enabled\n");
+ fiq_debugger_printf(&state->output, "kgdb through fiq debugger not enabled\n");
return;
}
- debug_printf(state, "enabling console and triggering kgdb\n");
+ fiq_debugger_printf(&state->output, "enabling console and triggering kgdb\n");
state->console_enable = true;
handle_sysrq('g');
}
#endif
-static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd)
+static void fiq_debugger_schedule_work(struct fiq_debugger_state *state,
+ char *cmd)
{
unsigned long flags;
spin_lock_irqsave(&state->work_lock, flags);
if (state->work_cmd[0] != '\0') {
- debug_printf(state, "work command processor busy\n");
+ fiq_debugger_printf(&state->output, "work command processor busy\n");
spin_unlock_irqrestore(&state->work_lock, flags);
return;
}
@@ -560,7 +374,7 @@ static void debug_schedule_work(struct fiq_debugger_state *state, char *cmd)
schedule_work(&state->work);
}
-static void debug_work(struct work_struct *work)
+static void fiq_debugger_work(struct work_struct *work)
{
struct fiq_debugger_state *state;
char work_cmd[DEBUG_MAX];
@@ -586,30 +400,32 @@ static void debug_work(struct work_struct *work)
else
kernel_restart(NULL);
} else {
- debug_printf(state, "unknown work command '%s'\n", work_cmd);
+ fiq_debugger_printf(&state->output, "unknown work command '%s'\n",
+ work_cmd);
}
}
/* This function CANNOT be called in FIQ context */
-static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd)
+static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd)
{
if (!strcmp(cmd, "ps"))
- do_ps(state);
+ fiq_debugger_do_ps(state);
if (!strcmp(cmd, "sysrq"))
- do_sysrq(state, 'h');
+ fiq_debugger_do_sysrq(state, 'h');
if (!strncmp(cmd, "sysrq ", 6))
- do_sysrq(state, cmd[6]);
+ fiq_debugger_do_sysrq(state, cmd[6]);
#ifdef CONFIG_KGDB
if (!strcmp(cmd, "kgdb"))
- do_kgdb(state);
+ fiq_debugger_do_kgdb(state);
#endif
if (!strncmp(cmd, "reboot", 6))
- debug_schedule_work(state, cmd);
+ fiq_debugger_schedule_work(state, cmd);
}
-static void debug_help(struct fiq_debugger_state *state)
+static void fiq_debugger_help(struct fiq_debugger_state *state)
{
- debug_printf(state, "FIQ Debugger commands:\n"
+ fiq_debugger_printf(&state->output,
+ "FIQ Debugger commands:\n"
" pc PC status\n"
" regs Register dump\n"
" allregs Extended Register dump\n"
@@ -619,20 +435,23 @@ static void debug_help(struct fiq_debugger_state *state)
" irqs Interupt status\n"
" kmsg Kernel log\n"
" version Kernel version\n");
- debug_printf(state, " sleep Allow sleep while in FIQ\n"
+ fiq_debugger_printf(&state->output,
+ " sleep Allow sleep while in FIQ\n"
" nosleep Disable sleep while in FIQ\n"
" console Switch terminal to console\n"
" cpu Current CPU\n"
" cpu <number> Switch to CPU<number>\n");
- debug_printf(state, " ps Process list\n"
+ fiq_debugger_printf(&state->output,
+ " ps Process list\n"
" sysrq sysrq options\n"
" sysrq <param> Execute sysrq with <param>\n");
#ifdef CONFIG_KGDB
- debug_printf(state, " kgdb Enter kernel debugger\n");
+ fiq_debugger_printf(&state->output,
+ " kgdb Enter kernel debugger\n");
#endif
}
-static void take_affinity(void *info)
+static void fiq_debugger_take_affinity(void *info)
{
struct fiq_debugger_state *state = info;
struct cpumask cpumask;
@@ -643,29 +462,30 @@ static void take_affinity(void *info)
irq_set_affinity(state->uart_irq, &cpumask);
}
-static void switch_cpu(struct fiq_debugger_state *state, int cpu)
+static void fiq_debugger_switch_cpu(struct fiq_debugger_state *state, int cpu)
{
- if (!debug_have_fiq(state))
- smp_call_function_single(cpu, take_affinity, state, false);
+ if (!fiq_debugger_have_fiq(state))
+ smp_call_function_single(cpu, fiq_debugger_take_affinity, state,
+ false);
state->current_cpu = cpu;
}
-static bool debug_fiq_exec(struct fiq_debugger_state *state,
- const char *cmd, unsigned *regs, void *svc_sp)
+static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state,
+ const char *cmd, const struct pt_regs *regs,
+ void *svc_sp)
{
bool signal_helper = false;
if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) {
- debug_help(state);
+ fiq_debugger_help(state);
} else if (!strcmp(cmd, "pc")) {
- debug_printf(state, " pc %08x cpsr %08x mode %s\n",
- regs[15], regs[16], mode_name(regs[16]));
+ fiq_debugger_dump_pc(&state->output, regs);
} else if (!strcmp(cmd, "regs")) {
- dump_regs(state, regs);
+ fiq_debugger_dump_regs(&state->output, regs);
} else if (!strcmp(cmd, "allregs")) {
- dump_allregs(state, regs);
+ fiq_debugger_dump_allregs(&state->output, regs);
} else if (!strcmp(cmd, "bt")) {
- dump_stacktrace(state, (struct pt_regs *)regs, 100, svc_sp);
+ fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp);
} else if (!strncmp(cmd, "reset", 5)) {
cmd += 5;
while (*cmd == ' ')
@@ -678,33 +498,33 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state,
machine_restart(NULL);
}
} else if (!strcmp(cmd, "irqs")) {
- dump_irqs(state);
+ fiq_debugger_dump_irqs(state);
} else if (!strcmp(cmd, "kmsg")) {
- dump_kernel_log(state);
+ fiq_debugger_dump_kernel_log(state);
} else if (!strcmp(cmd, "version")) {
- debug_printf(state, "%s\n", linux_banner);
+ fiq_debugger_printf(&state->output, "%s\n", linux_banner);
} else if (!strcmp(cmd, "sleep")) {
state->no_sleep = false;
- debug_printf(state, "enabling sleep\n");
+ fiq_debugger_printf(&state->output, "enabling sleep\n");
} else if (!strcmp(cmd, "nosleep")) {
state->no_sleep = true;
- debug_printf(state, "disabling sleep\n");
+ fiq_debugger_printf(&state->output, "disabling sleep\n");
} else if (!strcmp(cmd, "console")) {
- debug_printf(state, "console mode\n");
- debug_uart_flush(state);
+ fiq_debugger_printf(&state->output, "console mode\n");
+ fiq_debugger_uart_flush(state);
state->console_enable = true;
} else if (!strcmp(cmd, "cpu")) {
- debug_printf(state, "cpu %d\n", state->current_cpu);
+ fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu);
} else if (!strncmp(cmd, "cpu ", 4)) {
unsigned long cpu = 0;
if (strict_strtoul(cmd + 4, 10, &cpu) == 0)
- switch_cpu(state, cpu);
+ fiq_debugger_switch_cpu(state, cpu);
else
- debug_printf(state, "invalid cpu\n");
- debug_printf(state, "cpu %d\n", state->current_cpu);
+ fiq_debugger_printf(&state->output, "invalid cpu\n");
+ fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu);
} else {
if (state->debug_busy) {
- debug_printf(state,
+ fiq_debugger_printf(&state->output,
"command processor busy. trying to abort.\n");
state->debug_abort = -1;
} else {
@@ -715,12 +535,12 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state,
return true;
}
if (!state->console_enable)
- debug_prompt(state);
+ fiq_debugger_prompt(state);
return signal_helper;
}
-static void sleep_timer_expired(unsigned long data)
+static void fiq_debugger_sleep_timer_expired(unsigned long data)
{
struct fiq_debugger_state *state = (struct fiq_debugger_state *)data;
unsigned long flags;
@@ -729,18 +549,19 @@ static void sleep_timer_expired(unsigned long data)
if (state->uart_enabled && !state->no_sleep) {
if (state->debug_enable && !state->console_enable) {
state->debug_enable = false;
- debug_printf_nfiq(state, "suspending fiq debugger\n");
+ fiq_debugger_printf_nfiq(state,
+ "suspending fiq debugger\n");
}
state->ignore_next_wakeup_irq = true;
- debug_uart_disable(state);
+ fiq_debugger_uart_disable(state);
state->uart_enabled = false;
- enable_wakeup_irq(state);
+ fiq_debugger_enable_wakeup_irq(state);
}
wake_unlock(&state->debugger_wake_lock);
spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
-static void handle_wakeup(struct fiq_debugger_state *state)
+static void fiq_debugger_handle_wakeup(struct fiq_debugger_state *state)
{
unsigned long flags;
@@ -749,26 +570,27 @@ static void handle_wakeup(struct fiq_debugger_state *state)
state->ignore_next_wakeup_irq = false;
} else if (!state->uart_enabled) {
wake_lock(&state->debugger_wake_lock);
- debug_uart_enable(state);
+ fiq_debugger_uart_enable(state);
state->uart_enabled = true;
- disable_wakeup_irq(state);
+ fiq_debugger_disable_wakeup_irq(state);
mod_timer(&state->sleep_timer, jiffies + HZ / 2);
}
spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
-static irqreturn_t wakeup_irq_handler(int irq, void *dev)
+static irqreturn_t fiq_debugger_wakeup_irq_handler(int irq, void *dev)
{
struct fiq_debugger_state *state = dev;
if (!state->no_sleep)
- debug_puts(state, "WAKEUP\n");
- handle_wakeup(state);
+ fiq_debugger_puts(state, "WAKEUP\n");
+ fiq_debugger_handle_wakeup(state);
return IRQ_HANDLED;
}
-static void debug_handle_console_irq_context(struct fiq_debugger_state *state)
+static
+void fiq_debugger_handle_console_irq_context(struct fiq_debugger_state *state)
{
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
if (state->tty_port.ops) {
@@ -785,7 +607,7 @@ static void debug_handle_console_irq_context(struct fiq_debugger_state *state)
#endif
}
-static void debug_handle_irq_context(struct fiq_debugger_state *state)
+static void fiq_debugger_handle_irq_context(struct fiq_debugger_state *state)
{
if (!state->no_sleep) {
unsigned long flags;
@@ -795,22 +617,22 @@ static void debug_handle_irq_context(struct fiq_debugger_state *state)
mod_timer(&state->sleep_timer, jiffies + HZ * 5);
spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
- debug_handle_console_irq_context(state);
+ fiq_debugger_handle_console_irq_context(state);
if (state->debug_busy) {
- debug_irq_exec(state, state->debug_cmd);
+ fiq_debugger_irq_exec(state, state->debug_cmd);
if (!state->console_enable)
- debug_prompt(state);
+ fiq_debugger_prompt(state);
state->debug_busy = 0;
}
}
-static int debug_getc(struct fiq_debugger_state *state)
+static int fiq_debugger_getc(struct fiq_debugger_state *state)
{
return state->pdata->uart_getc(state->pdev);
}
-static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
- int this_cpu, void *regs, void *svc_sp)
+static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state,
+ int this_cpu, const struct pt_regs *regs, void *svc_sp)
{
int c;
static int last_c;
@@ -825,30 +647,31 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
MAX_UNHANDLED_FIQ_COUNT)
return false;
- debug_printf(state, "fiq_debugger: cpu %d not responding, "
+ fiq_debugger_printf(&state->output,
+ "fiq_debugger: cpu %d not responding, "
"reverting to cpu %d\n", state->current_cpu,
this_cpu);
atomic_set(&state->unhandled_fiq_count, 0);
- switch_cpu(state, this_cpu);
+ fiq_debugger_switch_cpu(state, this_cpu);
return false;
}
state->in_fiq = true;
- while ((c = debug_getc(state)) != FIQ_DEBUGGER_NO_CHAR) {
+ while ((c = fiq_debugger_getc(state)) != FIQ_DEBUGGER_NO_CHAR) {
count++;
if (!state->debug_enable) {
if ((c == 13) || (c == 10)) {
state->debug_enable = true;
state->debug_count = 0;
- debug_prompt(state);
+ fiq_debugger_prompt(state);
}
} else if (c == FIQ_DEBUGGER_BREAK) {
state->console_enable = false;
- debug_puts(state, "fiq debugger mode\n");
+ fiq_debugger_puts(state, "fiq debugger mode\n");
state->debug_count = 0;
- debug_prompt(state);
+ fiq_debugger_prompt(state);
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
} else if (state->console_enable && state->tty_rbuf) {
fiq_debugger_ringbuf_push(state->tty_rbuf, c);
@@ -857,34 +680,35 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
} else if ((c >= ' ') && (c < 127)) {
if (state->debug_count < (DEBUG_MAX - 1)) {
state->debug_buf[state->debug_count++] = c;
- debug_putc(state, c);
+ fiq_debugger_putc(state, c);
}
} else if ((c == 8) || (c == 127)) {
if (state->debug_count > 0) {
state->debug_count--;
- debug_putc(state, 8);
- debug_putc(state, ' ');
- debug_putc(state, 8);
+ fiq_debugger_putc(state, 8);
+ fiq_debugger_putc(state, ' ');
+ fiq_debugger_putc(state, 8);
}
} else if ((c == 13) || (c == 10)) {
if (c == '\r' || (c == '\n' && last_c != '\r')) {
- debug_putc(state, '\r');
- debug_putc(state, '\n');
+ fiq_debugger_putc(state, '\r');
+ fiq_debugger_putc(state, '\n');
}
if (state->debug_count) {
state->debug_buf[state->debug_count] = 0;
state->debug_count = 0;
signal_helper |=
- debug_fiq_exec(state, state->debug_buf,
- regs, svc_sp);
+ fiq_debugger_fiq_exec(state,
+ state->debug_buf,
+ regs, svc_sp);
} else {
- debug_prompt(state);
+ fiq_debugger_prompt(state);
}
}
last_c = c;
}
if (!state->console_enable)
- debug_uart_flush(state);
+ fiq_debugger_uart_flush(state);
if (state->pdata->fiq_ack)
state->pdata->fiq_ack(state->pdev, state->fiq);
@@ -898,56 +722,40 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
return signal_helper;
}
-static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
+#ifdef CONFIG_FIQ_GLUE
+static void fiq_debugger_fiq(struct fiq_glue_handler *h,
+ const struct pt_regs *regs, void *svc_sp)
{
struct fiq_debugger_state *state =
container_of(h, struct fiq_debugger_state, handler);
unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
bool need_irq;
- /* Spew regs and callstack immediately after entering FIQ handler */
- spin_lock(&state->debug_fiq_lock);
- debug_printf(state, "\nCallstack for CPU: %d\n", this_cpu);
- debug_fiq_exec(state, "allregs", regs, svc_sp);
- debug_fiq_exec(state, "bt", regs, svc_sp);
- spin_unlock(&state->debug_fiq_lock);
-
- /* handle the uart interrupts only on CPU0 */
- if (this_cpu == 0) {
-#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
- do {
- need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp);
- } while (!need_irq);
- debug_force_irq(state);
-#else
- need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp);
- if (need_irq)
- debug_force_irq(state);
-#endif
- } else {
- /* for all other CPUs do-nothing */
- for (;;); /* wait */
- }
+ need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs,
+ svc_sp);
+ if (need_irq)
+ fiq_debugger_force_irq(state);
}
+#endif
/*
* When not using FIQs, we only use this single interrupt as an entry point.
* This just effectively takes over the UART interrupt and does all the work
* in this context.
*/
-static irqreturn_t debug_uart_irq(int irq, void *dev)
+static irqreturn_t fiq_debugger_uart_irq(int irq, void *dev)
{
struct fiq_debugger_state *state = dev;
bool not_done;
- handle_wakeup(state);
+ fiq_debugger_handle_wakeup(state);
/* handle the debugger irq in regular context */
- not_done = debug_handle_uart_interrupt(state, smp_processor_id(),
+ not_done = fiq_debugger_handle_uart_interrupt(state, smp_processor_id(),
get_irq_regs(),
current_thread_info());
if (not_done)
- debug_handle_irq_context(state);
+ fiq_debugger_handle_irq_context(state);
return IRQ_HANDLED;
}
@@ -957,34 +765,36 @@ static irqreturn_t debug_uart_irq(int irq, void *dev)
* FIQ handler does what it can and then signals this interrupt to finish the
* job in irq context.
*/
-static irqreturn_t debug_signal_irq(int irq, void *dev)
+static irqreturn_t fiq_debugger_signal_irq(int irq, void *dev)
{
struct fiq_debugger_state *state = dev;
if (state->pdata->force_irq_ack)
state->pdata->force_irq_ack(state->pdev, state->signal_irq);
- debug_handle_irq_context(state);
+ fiq_debugger_handle_irq_context(state);
return IRQ_HANDLED;
}
-static void debug_resume(struct fiq_glue_handler *h)
+#ifdef CONFIG_FIQ_GLUE
+static void fiq_debugger_resume(struct fiq_glue_handler *h)
{
struct fiq_debugger_state *state =
container_of(h, struct fiq_debugger_state, handler);
if (state->pdata->uart_resume)
state->pdata->uart_resume(state->pdev);
}
+#endif
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
-struct tty_driver *debug_console_device(struct console *co, int *index)
+struct tty_driver *fiq_debugger_console_device(struct console *co, int *index)
{
*index = co->index;
return fiq_tty_driver;
}
-static void debug_console_write(struct console *co,
+static void fiq_debugger_console_write(struct console *co,
const char *s, unsigned int count)
{
struct fiq_debugger_state *state;
@@ -995,22 +805,22 @@ static void debug_console_write(struct console *co,
if (!state->console_enable && !state->syslog_dumping)
return;
- debug_uart_enable(state);
+ fiq_debugger_uart_enable(state);
spin_lock_irqsave(&state->console_lock, flags);
while (count--) {
if (*s == '\n')
- debug_putc(state, '\r');
- debug_putc(state, *s++);
+ fiq_debugger_putc(state, '\r');
+ fiq_debugger_putc(state, *s++);
}
- debug_uart_flush(state);
+ fiq_debugger_uart_flush(state);
spin_unlock_irqrestore(&state->console_lock, flags);
- debug_uart_disable(state);
+ fiq_debugger_uart_disable(state);
}
static struct console fiq_debugger_console = {
.name = "ttyFIQ",
- .device = debug_console_device,
- .write = debug_console_write,
+ .device = fiq_debugger_console_device,
+ .write = fiq_debugger_console_write,
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
};
@@ -1038,12 +848,12 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
if (!state->console_enable)
return count;
- debug_uart_enable(state);
+ fiq_debugger_uart_enable(state);
spin_lock_irq(&state->console_lock);
for (i = 0; i < count; i++)
- debug_putc(state, *buf++);
+ fiq_debugger_putc(state, *buf++);
spin_unlock_irq(&state->console_lock);
- debug_uart_disable(state);
+ fiq_debugger_uart_disable(state);
return count;
}
@@ -1065,19 +875,19 @@ static int fiq_tty_poll_get_char(struct tty_driver *driver, int line)
struct fiq_debugger_state *state = states[line];
int c = NO_POLL_CHAR;
- debug_uart_enable(state);
- if (debug_have_fiq(state)) {
+ fiq_debugger_uart_enable(state);
+ if (fiq_debugger_have_fiq(state)) {
int count = fiq_debugger_ringbuf_level(state->tty_rbuf);
if (count > 0) {
c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0);
fiq_debugger_ringbuf_consume(state->tty_rbuf, 1);
}
} else {
- c = debug_getc(state);
+ c = fiq_debugger_getc(state);
if (c == FIQ_DEBUGGER_NO_CHAR)
c = NO_POLL_CHAR;
}
- debug_uart_disable(state);
+ fiq_debugger_uart_disable(state);
return c;
}
@@ -1086,9 +896,9 @@ static void fiq_tty_poll_put_char(struct tty_driver *driver, int line, char ch)
{
struct fiq_debugger_state **states = driver->driver_state;
struct fiq_debugger_state *state = states[line];
- debug_uart_enable(state);
- debug_putc(state, ch);
- debug_uart_disable(state);
+ fiq_debugger_uart_enable(state);
+ fiq_debugger_putc(state, ch);
+ fiq_debugger_uart_disable(state);
}
#endif
@@ -1245,7 +1055,8 @@ static int fiq_debugger_probe(struct platform_device *pdev)
return -EINVAL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
- setup_timer(&state->sleep_timer, sleep_timer_expired,
+ state->output.printf = fiq_debugger_printf;
+ setup_timer(&state->sleep_timer, fiq_debugger_sleep_timer_expired,
(unsigned long)state);
state->pdata = pdata;
state->pdev = pdev;
@@ -1258,15 +1069,14 @@ static int fiq_debugger_probe(struct platform_device *pdev)
state->signal_irq = platform_get_irq_byname(pdev, "signal");
state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup");
- INIT_WORK(&state->work, debug_work);
+ INIT_WORK(&state->work, fiq_debugger_work);
spin_lock_init(&state->work_lock);
platform_set_drvdata(pdev, state);
spin_lock_init(&state->sleep_timer_lock);
- spin_lock_init(&state->debug_fiq_lock);
- if (state->wakeup_irq < 0 && debug_have_fiq(state))
+ if (state->wakeup_irq < 0 && fiq_debugger_have_fiq(state))
state->no_sleep = true;
state->ignore_next_wakeup_irq = !state->no_sleep;
@@ -1290,21 +1100,25 @@ static int fiq_debugger_probe(struct platform_device *pdev)
goto err_uart_init;
}
- debug_printf_nfiq(state, "<hit enter %sto activate fiq debugger>\n",
+ fiq_debugger_printf_nfiq(state,
+ "<hit enter %sto activate fiq debugger>\n",
state->no_sleep ? "" : "twice ");
- if (debug_have_fiq(state)) {
- state->handler.fiq = debug_fiq;
- state->handler.resume = debug_resume;
+#ifdef CONFIG_FIQ_GLUE
+ if (fiq_debugger_have_fiq(state)) {
+ state->handler.fiq = fiq_debugger_fiq;
+ state->handler.resume = fiq_debugger_resume;
ret = fiq_glue_register_handler(&state->handler);
if (ret) {
pr_err("%s: could not install fiq handler\n", __func__);
- goto err_register_fiq;
+ goto err_register_irq;
}
pdata->fiq_enable(pdev, state->fiq, 1);
- } else {
- ret = request_irq(state->uart_irq, debug_uart_irq,
+ } else
+#endif
+ {
+ ret = request_irq(state->uart_irq, fiq_debugger_uart_irq,
IRQF_NO_SUSPEND, "debug", state);
if (ret) {
pr_err("%s: could not install irq handler\n", __func__);
@@ -1321,14 +1135,15 @@ static int fiq_debugger_probe(struct platform_device *pdev)
clk_disable(state->clk);
if (state->signal_irq >= 0) {
- ret = request_irq(state->signal_irq, debug_signal_irq,
+ ret = request_irq(state->signal_irq, fiq_debugger_signal_irq,
IRQF_TRIGGER_RISING, "debug-signal", state);
if (ret)
pr_err("serial_debugger: could not install signal_irq");
}
if (state->wakeup_irq >= 0) {
- ret = request_irq(state->wakeup_irq, wakeup_irq_handler,
+ ret = request_irq(state->wakeup_irq,
+ fiq_debugger_wakeup_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_DISABLED,
"debug-wakeup", state);
if (ret) {
@@ -1345,7 +1160,7 @@ static int fiq_debugger_probe(struct platform_device *pdev)
}
}
if (state->no_sleep)
- handle_wakeup(state);
+ fiq_debugger_handle_wakeup(state);
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
spin_lock_init(&state->console_lock);
@@ -1360,7 +1175,6 @@ static int fiq_debugger_probe(struct platform_device *pdev)
return 0;
err_register_irq:
-err_register_fiq:
if (pdata->uart_free)
pdata->uart_free(pdev);
err_uart_init:
diff --git a/arch/arm/include/asm/fiq_debugger.h b/drivers/staging/android/fiq_debugger/fiq_debugger.h
index 4d274883ba6a..c9ec4f8db086 100644
--- a/arch/arm/include/asm/fiq_debugger.h
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/include/asm/fiq_debugger.h
+ * drivers/staging/android/fiq_debugger/fiq_debugger.h
*
* Copyright (C) 2010 Google, Inc.
* Author: Colin Cross <ccross@android.com>
diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c
new file mode 100644
index 000000000000..8b3e0137be1a
--- /dev/null
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/ptrace.h>
+#include <linux/uaccess.h>
+
+#include <asm/stacktrace.h>
+
+#include "fiq_debugger_priv.h"
+
+static char *mode_name(unsigned cpsr)
+{
+ switch (cpsr & MODE_MASK) {
+ case USR_MODE: return "USR";
+ case FIQ_MODE: return "FIQ";
+ case IRQ_MODE: return "IRQ";
+ case SVC_MODE: return "SVC";
+ case ABT_MODE: return "ABT";
+ case UND_MODE: return "UND";
+ case SYSTEM_MODE: return "SYS";
+ default: return "???";
+ }
+}
+
+void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+ output->printf(output, " pc %08x cpsr %08x mode %s\n",
+ regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr));
+}
+
+void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+ output->printf(output,
+ " r0 %08x r1 %08x r2 %08x r3 %08x\n",
+ regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
+ output->printf(output,
+ " r4 %08x r5 %08x r6 %08x r7 %08x\n",
+ regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
+ output->printf(output,
+ " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n",
+ regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp,
+ mode_name(regs->ARM_cpsr));
+ output->printf(output,
+ " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
+ regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc,
+ regs->ARM_cpsr);
+}
+
+struct mode_regs {
+ unsigned long sp_svc;
+ unsigned long lr_svc;
+ unsigned long spsr_svc;
+
+ unsigned long sp_abt;
+ unsigned long lr_abt;
+ unsigned long spsr_abt;
+
+ unsigned long sp_und;
+ unsigned long lr_und;
+ unsigned long spsr_und;
+
+ unsigned long sp_irq;
+ unsigned long lr_irq;
+ unsigned long spsr_irq;
+
+ unsigned long r8_fiq;
+ unsigned long r9_fiq;
+ unsigned long r10_fiq;
+ unsigned long r11_fiq;
+ unsigned long r12_fiq;
+ unsigned long sp_fiq;
+ unsigned long lr_fiq;
+ unsigned long spsr_fiq;
+};
+
+static void __naked get_mode_regs(struct mode_regs *regs)
+{
+ asm volatile (
+ "mrs r1, cpsr\n"
+ "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+ "stmia r0!, {r13 - r14}\n"
+ "mrs r2, spsr\n"
+ "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+ "stmia r0!, {r2, r13 - r14}\n"
+ "mrs r2, spsr\n"
+ "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+ "stmia r0!, {r2, r13 - r14}\n"
+ "mrs r2, spsr\n"
+ "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+ "stmia r0!, {r2, r13 - r14}\n"
+ "mrs r2, spsr\n"
+ "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
+ "stmia r0!, {r2, r8 - r14}\n"
+ "mrs r2, spsr\n"
+ "stmia r0!, {r2}\n"
+ "msr cpsr_c, r1\n"
+ "bx lr\n");
+}
+
+
+void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+ struct mode_regs mode_regs;
+ unsigned long mode = regs->ARM_cpsr & MODE_MASK;
+
+ fiq_debugger_dump_regs(output, regs);
+ get_mode_regs(&mode_regs);
+
+ output->printf(output,
+ "%csvc: sp %08x lr %08x spsr %08x\n",
+ mode == SVC_MODE ? '*' : ' ',
+ mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
+ output->printf(output,
+ "%cabt: sp %08x lr %08x spsr %08x\n",
+ mode == ABT_MODE ? '*' : ' ',
+ mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
+ output->printf(output,
+ "%cund: sp %08x lr %08x spsr %08x\n",
+ mode == UND_MODE ? '*' : ' ',
+ mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
+ output->printf(output,
+ "%cirq: sp %08x lr %08x spsr %08x\n",
+ mode == IRQ_MODE ? '*' : ' ',
+ mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
+ output->printf(output,
+ "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n",
+ mode == FIQ_MODE ? '*' : ' ',
+ mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
+ mode_regs.r11_fiq, mode_regs.r12_fiq);
+ output->printf(output,
+ " fiq: sp %08x lr %08x spsr %08x\n",
+ mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
+}
+
+struct stacktrace_state {
+ struct fiq_debugger_output *output;
+ unsigned int depth;
+};
+
+static int report_trace(struct stackframe *frame, void *d)
+{
+ struct stacktrace_state *sts = d;
+
+ if (sts->depth) {
+ sts->output->printf(sts->output,
+ " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
+ frame->pc, frame->pc, frame->lr, frame->lr,
+ frame->sp, frame->fp);
+ sts->depth--;
+ return 0;
+ }
+ sts->output->printf(sts->output, " ...\n");
+
+ return sts->depth == 0;
+}
+
+struct frame_tail {
+ struct frame_tail *fp;
+ unsigned long sp;
+ unsigned long lr;
+} __attribute__((packed));
+
+static struct frame_tail *user_backtrace(struct fiq_debugger_output *output,
+ struct frame_tail *tail)
+{
+ struct frame_tail buftail[2];
+
+ /* Also check accessibility of one struct frame_tail beyond */
+ if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) {
+ output->printf(output, " invalid frame pointer %p\n",
+ tail);
+ return NULL;
+ }
+ if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
+ output->printf(output,
+ " failed to copy frame pointer %p\n", tail);
+ return NULL;
+ }
+
+ output->printf(output, " %p\n", buftail[0].lr);
+
+ /* frame pointers should strictly progress back up the stack
+ * (towards higher addresses) */
+ if (tail >= buftail[0].fp)
+ return NULL;
+
+ return buftail[0].fp-1;
+}
+
+void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
+ const struct pt_regs *regs, unsigned int depth, void *ssp)
+{
+ struct frame_tail *tail;
+ struct thread_info *real_thread_info = THREAD_INFO(ssp);
+ struct stacktrace_state sts;
+
+ sts.depth = depth;
+ sts.output = output;
+ *current_thread_info() = *real_thread_info;
+
+ if (!current)
+ output->printf(output, "current NULL\n");
+ else
+ output->printf(output, "pid: %d comm: %s\n",
+ current->pid, current->comm);
+ fiq_debugger_dump_regs(output, regs);
+
+ if (!user_mode(regs)) {
+ struct stackframe frame;
+ frame.fp = regs->ARM_fp;
+ frame.sp = regs->ARM_sp;
+ frame.lr = regs->ARM_lr;
+ frame.pc = regs->ARM_pc;
+ output->printf(output,
+ " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
+ regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr,
+ regs->ARM_sp, regs->ARM_fp);
+ walk_stackframe(&frame, report_trace, &sts);
+ return;
+ }
+
+ tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+ while (depth-- && tail && !((unsigned long) tail & 3))
+ tail = user_backtrace(output, tail);
+}
diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c
new file mode 100644
index 000000000000..99c6584fcfa5
--- /dev/null
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/ptrace.h>
+#include <asm/stacktrace.h>
+
+#include "fiq_debugger_priv.h"
+
+static char *mode_name(const struct pt_regs *regs)
+{
+ if (compat_user_mode(regs)) {
+ return "USR";
+ } else {
+ switch (processor_mode(regs)) {
+ case PSR_MODE_EL0t: return "EL0t";
+ case PSR_MODE_EL1t: return "EL1t";
+ case PSR_MODE_EL1h: return "EL1h";
+ case PSR_MODE_EL2t: return "EL2t";
+ case PSR_MODE_EL2h: return "EL2h";
+ default: return "???";
+ }
+ }
+}
+
+void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+ output->printf(output, " pc %016lx cpsr %08lx mode %s\n",
+ regs->pc, regs->pstate, mode_name(regs));
+}
+
+void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+ output->printf(output, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
+ regs->compat_usr(0), regs->compat_usr(1),
+ regs->compat_usr(2), regs->compat_usr(3));
+ output->printf(output, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
+ regs->compat_usr(4), regs->compat_usr(5),
+ regs->compat_usr(6), regs->compat_usr(7));
+ output->printf(output, " r8 %08x r9 %08x r10 %08x r11 %08x\n",
+ regs->compat_usr(8), regs->compat_usr(9),
+ regs->compat_usr(10), regs->compat_usr(11));
+ output->printf(output, " ip %08x sp %08x lr %08x pc %08x\n",
+ regs->compat_usr(12), regs->compat_sp,
+ regs->compat_lr, regs->pc);
+ output->printf(output, " cpsr %08x (%s)\n",
+ regs->pstate, mode_name(regs));
+}
+
+void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+
+ output->printf(output, " x0 %016lx x1 %016lx\n",
+ regs->regs[0], regs->regs[1]);
+ output->printf(output, " x2 %016lx x3 %016lx\n",
+ regs->regs[2], regs->regs[3]);
+ output->printf(output, " x4 %016lx x5 %016lx\n",
+ regs->regs[4], regs->regs[5]);
+ output->printf(output, " x6 %016lx x7 %016lx\n",
+ regs->regs[6], regs->regs[7]);
+ output->printf(output, " x8 %016lx x9 %016lx\n",
+ regs->regs[8], regs->regs[9]);
+ output->printf(output, " x10 %016lx x11 %016lx\n",
+ regs->regs[10], regs->regs[11]);
+ output->printf(output, " x12 %016lx x13 %016lx\n",
+ regs->regs[12], regs->regs[13]);
+ output->printf(output, " x14 %016lx x15 %016lx\n",
+ regs->regs[14], regs->regs[15]);
+ output->printf(output, " x16 %016lx x17 %016lx\n",
+ regs->regs[16], regs->regs[17]);
+ output->printf(output, " x18 %016lx x19 %016lx\n",
+ regs->regs[18], regs->regs[19]);
+ output->printf(output, " x20 %016lx x21 %016lx\n",
+ regs->regs[20], regs->regs[21]);
+ output->printf(output, " x22 %016lx x23 %016lx\n",
+ regs->regs[22], regs->regs[23]);
+ output->printf(output, " x24 %016lx x25 %016lx\n",
+ regs->regs[24], regs->regs[25]);
+ output->printf(output, " x26 %016lx x27 %016lx\n",
+ regs->regs[26], regs->regs[27]);
+ output->printf(output, " x28 %016lx x29 %016lx\n",
+ regs->regs[28], regs->regs[29]);
+ output->printf(output, " x30 %016lx sp %016lx\n",
+ regs->regs[30], regs->sp);
+ output->printf(output, " pc %016lx cpsr %08x (%s)\n",
+ regs->pc, regs->pstate, mode_name(regs));
+}
+
+void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+ if (compat_user_mode(regs))
+ fiq_debugger_dump_regs_aarch32(output, regs);
+ else
+ fiq_debugger_dump_regs_aarch64(output, regs);
+}
+
+#define READ_SPECIAL_REG(x) ({ \
+ u64 val; \
+ asm volatile ("mrs %0, " # x : "=r"(val)); \
+ val; \
+})
+
+void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
+ const struct pt_regs *regs)
+{
+ u32 pstate = READ_SPECIAL_REG(CurrentEl);
+ bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t;
+
+ fiq_debugger_dump_regs(output, regs);
+
+ output->printf(output, " sp_el0 %016lx\n",
+ READ_SPECIAL_REG(sp_el0));
+
+ if (in_el2)
+ output->printf(output, " sp_el1 %016lx\n",
+ READ_SPECIAL_REG(sp_el1));
+
+ output->printf(output, " elr_el1 %016lx\n",
+ READ_SPECIAL_REG(elr_el1));
+
+ output->printf(output, " spsr_el1 %08lx\n",
+ READ_SPECIAL_REG(spsr_el1));
+
+ if (in_el2) {
+ output->printf(output, " spsr_irq %08lx\n",
+ READ_SPECIAL_REG(spsr_irq));
+ output->printf(output, " spsr_abt %08lx\n",
+ READ_SPECIAL_REG(spsr_abt));
+ output->printf(output, " spsr_und %08lx\n",
+ READ_SPECIAL_REG(spsr_und));
+ output->printf(output, " spsr_fiq %08lx\n",
+ READ_SPECIAL_REG(spsr_fiq));
+ output->printf(output, " spsr_el2 %08lx\n",
+ READ_SPECIAL_REG(elr_el2));
+ output->printf(output, " spsr_el2 %08lx\n",
+ READ_SPECIAL_REG(spsr_el2));
+ }
+}
+
+struct stacktrace_state {
+ struct fiq_debugger_output *output;
+ unsigned int depth;
+};
+
+static int report_trace(struct stackframe *frame, void *d)
+{
+ struct stacktrace_state *sts = d;
+
+ if (sts->depth) {
+ sts->output->printf(sts->output, "%pF:\n", frame->pc);
+ sts->output->printf(sts->output,
+ " pc %016lx sp %016lx fp %016lx\n",
+ frame->pc, frame->sp, frame->fp);
+ sts->depth--;
+ return 0;
+ }
+ sts->output->printf(sts->output, " ...\n");
+
+ return sts->depth == 0;
+}
+
+void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
+ const struct pt_regs *regs, unsigned int depth, void *ssp)
+{
+ struct thread_info *real_thread_info = THREAD_INFO(ssp);
+ struct stacktrace_state sts;
+
+ sts.depth = depth;
+ sts.output = output;
+ *current_thread_info() = *real_thread_info;
+
+ if (!current)
+ output->printf(output, "current NULL\n");
+ else
+ output->printf(output, "pid: %d comm: %s\n",
+ current->pid, current->comm);
+ fiq_debugger_dump_regs(output, regs);
+
+ if (!user_mode(regs)) {
+ struct stackframe frame;
+ frame.fp = regs->regs[29];
+ frame.sp = regs->sp;
+ frame.pc = regs->pc;
+ output->printf(output, "\n");
+ walk_stackframe(&frame, report_trace, &sts);
+ }
+}
diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h
new file mode 100644
index 000000000000..d5d051f727a8
--- /dev/null
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _FIQ_DEBUGGER_PRIV_H_
+#define _FIQ_DEBUGGER_PRIV_H_
+
+#define THREAD_INFO(sp) ((struct thread_info *) \
+ ((unsigned long)(sp) & ~(THREAD_SIZE - 1)))
+
+struct fiq_debugger_output {
+ void (*printf)(struct fiq_debugger_output *output, const char *fmt, ...);
+};
+
+struct pt_regs;
+
+void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
+ const struct pt_regs *regs);
+void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
+ const struct pt_regs *regs);
+void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
+ const struct pt_regs *regs);
+void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
+ const struct pt_regs *regs, unsigned int depth, void *ssp);
+
+#endif
diff --git a/arch/arm/common/fiq_debugger_ringbuf.h b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h
index 2649b5581088..10c3c5d09098 100644
--- a/arch/arm/common/fiq_debugger_ringbuf.h
+++ b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/common/fiq_debugger_ringbuf.c
+ * drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h
*
* simple lockless ringbuffer
*
diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.c b/drivers/staging/android/fiq_debugger/fiq_watchdog.c
new file mode 100644
index 000000000000..194b54138417
--- /dev/null
+++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/pstore_ram.h>
+
+#include "fiq_watchdog.h"
+#include "fiq_debugger_priv.h"
+
+static DEFINE_RAW_SPINLOCK(fiq_watchdog_lock);
+
+static void fiq_watchdog_printf(struct fiq_debugger_output *output,
+ const char *fmt, ...)
+{
+ char buf[256];
+ va_list ap;
+ int len;
+
+ va_start(ap, fmt);
+ len = vscnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ ramoops_console_write_buf(buf, len);
+}
+
+struct fiq_debugger_output fiq_watchdog_output = {
+ .printf = fiq_watchdog_printf,
+};
+
+void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp)
+{
+ char msg[24];
+ int len;
+
+ raw_spin_lock(&fiq_watchdog_lock);
+
+ len = scnprintf(msg, sizeof(msg), "watchdog fiq cpu %d\n",
+ THREAD_INFO(svc_sp)->cpu);
+ ramoops_console_write_buf(msg, len);
+
+ fiq_debugger_dump_stacktrace(&fiq_watchdog_output, regs, 100, svc_sp);
+
+ raw_spin_unlock(&fiq_watchdog_lock);
+}
diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.h b/drivers/staging/android/fiq_debugger/fiq_watchdog.h
new file mode 100644
index 000000000000..c6b507f8d976
--- /dev/null
+++ b/drivers/staging/android/fiq_debugger/fiq_watchdog.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _FIQ_WATCHDOG_H_
+#define _FIQ_WATCHDOG_H_
+
+void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp);
+
+#endif
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 6c7fe90ad72d..6cfe4019abc6 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2066,8 +2066,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
} else {
+ struct n_tty_data *ldata = tty->disc_data;
+
while (nr > 0) {
+ mutex_lock(&ldata->output_lock);
c = tty->ops->write(tty, b, nr);
+ mutex_unlock(&ldata->output_lock);
if (c < 0) {
retval = c;
goto break_out;
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 2ee3e4f18364..456e33f7aeda 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -558,10 +558,11 @@ static ssize_t acc_read(struct file *fp, char __user *buf,
{
struct acc_dev *dev = fp->private_data;
struct usb_request *req;
- int r = count, xfer;
+ ssize_t r = count;
+ unsigned xfer;
int ret = 0;
- pr_debug("acc_read(%d)\n", count);
+ pr_debug("acc_read(%zu)\n", count);
if (dev->disconnected) {
pr_debug("acc_read disconnected");
@@ -618,7 +619,7 @@ copy_data:
if (req->actual == 0)
goto requeue_req;
- pr_debug("rx %p %d\n", req, req->actual);
+ pr_debug("rx %p %u\n", req, req->actual);
xfer = (req->actual < count) ? req->actual : count;
r = xfer;
if (copy_to_user(buf, req->buf, xfer))
@@ -627,7 +628,7 @@ copy_data:
r = -EIO;
done:
- pr_debug("acc_read returning %d\n", r);
+ pr_debug("acc_read returning %zd\n", r);
return r;
}
@@ -636,10 +637,11 @@ static ssize_t acc_write(struct file *fp, const char __user *buf,
{
struct acc_dev *dev = fp->private_data;
struct usb_request *req = 0;
- int r = count, xfer;
+ ssize_t r = count;
+ unsigned xfer;
int ret;
- pr_debug("acc_write(%d)\n", count);
+ pr_debug("acc_write(%zu)\n", count);
if (!dev->online || dev->disconnected) {
pr_debug("acc_write disconnected or not online");
@@ -689,7 +691,7 @@ static ssize_t acc_write(struct file *fp, const char __user *buf,
if (req)
req_put(dev, &dev->tx_idle, req);
- pr_debug("acc_write returning %d\n", r);
+ pr_debug("acc_write returning %zd\n", r);
return r;
}
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 4de200a6c491..647b6fef8ad9 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -491,10 +491,11 @@ static ssize_t mtp_read(struct file *fp, char __user *buf,
struct mtp_dev *dev = fp->private_data;
struct usb_composite_dev *cdev = dev->cdev;
struct usb_request *req;
- int r = count, xfer;
+ ssize_t r = count;
+ unsigned xfer;
int ret = 0;
- DBG(cdev, "mtp_read(%d)\n", count);
+ DBG(cdev, "mtp_read(%zu)\n", count);
if (count > MTP_BULK_BUFFER_SIZE)
return -EINVAL;
@@ -558,7 +559,7 @@ done:
dev->state = STATE_READY;
spin_unlock_irq(&dev->lock);
- DBG(cdev, "mtp_read returning %d\n", r);
+ DBG(cdev, "mtp_read returning %zd\n", r);
return r;
}
@@ -568,11 +569,12 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf,
struct mtp_dev *dev = fp->private_data;
struct usb_composite_dev *cdev = dev->cdev;
struct usb_request *req = 0;
- int r = count, xfer;
+ ssize_t r = count;
+ unsigned xfer;
int sendZLP = 0;
int ret;
- DBG(cdev, "mtp_write(%d)\n", count);
+ DBG(cdev, "mtp_write(%zu)\n", count);
spin_lock_irq(&dev->lock);
if (dev->state == STATE_CANCELED) {
@@ -649,7 +651,7 @@ static ssize_t mtp_write(struct file *fp, const char __user *buf,
dev->state = STATE_READY;
spin_unlock_irq(&dev->lock);
- DBG(cdev, "mtp_write returning %d\n", r);
+ DBG(cdev, "mtp_write returning %zd\n", r);
return r;
}
@@ -855,7 +857,7 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event)
int ret;
int length = event->length;
- DBG(dev->cdev, "mtp_send_event(%d)\n", event->length);
+ DBG(dev->cdev, "mtp_send_event(%zu)\n", event->length);
if (length < 0 || length > INTR_BUFFER_SIZE)
return -EINVAL;
diff --git a/drivers/video/adf/adf.c b/drivers/video/adf/adf.c
index 933e74ac8098..231881c2b355 100644
--- a/drivers/video/adf/adf.c
+++ b/drivers/video/adf/adf.c
@@ -2,6 +2,8 @@
* Copyright (C) 2013 Google, Inc.
* adf_modeinfo_{set_name,set_vrefresh} modified from
* drivers/gpu/drm/drm_modes.c
+ * adf_format_validate_yuv modified from framebuffer_check in
+ * drivers/gpu/drm/drm_crtc.c
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -492,6 +494,7 @@ static void adf_obj_destroy(struct adf_obj *obj, struct idr *idr)
struct adf_event_refcount *refcount =
container_of(node, struct adf_event_refcount,
node);
+ rb_erase(&refcount->node, &obj->event_refcount);
kfree(refcount);
node = rb_first(&obj->event_refcount);
}
@@ -920,6 +923,7 @@ done:
return ret;
}
+EXPORT_SYMBOL(adf_attachment_allow);
/**
* adf_obj_type_str - string representation of an adf_obj_type
@@ -1070,6 +1074,7 @@ int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf,
u32 width = buf->w / (i != 0 ? hsub : 1);
u32 height = buf->h / (i != 0 ? vsub : 1);
u8 cpp = adf_format_plane_cpp(buf->format, i);
+ u32 last_line_size;
if (buf->pitch[i] < (u64) width * cpp) {
dev_err(&dev->base.dev, "plane %u pitch is shorter than buffer width (pitch = %u, width = %u, bpp = %u)\n",
@@ -1077,8 +1082,21 @@ int adf_format_validate_yuv(struct adf_device *dev, struct adf_buffer *buf,
return -EINVAL;
}
- if ((u64) height * buf->pitch[i] + buf->offset[i] >
- buf->dma_bufs[i]->size) {
+ switch (dev->ops->quirks.buffer_padding) {
+ case ADF_BUFFER_PADDED_TO_PITCH:
+ last_line_size = buf->pitch[i];
+ break;
+
+ case ADF_BUFFER_UNPADDED:
+ last_line_size = width * cpp;
+ break;
+
+ default:
+ BUG();
+ }
+
+ if ((u64) (height - 1) * buf->pitch[i] + last_line_size +
+ buf->offset[i] > buf->dma_bufs[i]->size) {
dev_err(&dev->base.dev, "plane %u buffer too small (height = %u, pitch = %u, offset = %u, size = %zu)\n",
i, height, buf->pitch[i],
buf->offset[i], buf->dma_bufs[i]->size);
diff --git a/drivers/video/adf/adf_fbdev.c b/drivers/video/adf/adf_fbdev.c
index cac34d14cbc2..9d3c245850af 100644
--- a/drivers/video/adf/adf_fbdev.c
+++ b/drivers/video/adf/adf_fbdev.c
@@ -356,18 +356,25 @@ int adf_fbdev_open(struct fb_info *info, int user)
struct adf_fbdev *fbdev = info->par;
int ret;
- if (!fbdev->open) {
+ mutex_lock(&fbdev->refcount_lock);
+
+ if (unlikely(fbdev->refcount == UINT_MAX)) {
+ ret = -EMFILE;
+ goto done;
+ }
+
+ if (!fbdev->refcount) {
struct drm_mode_modeinfo mode;
struct fb_videomode fbmode;
struct adf_device *dev = adf_interface_parent(fbdev->intf);
ret = adf_device_attach(dev, fbdev->eng, fbdev->intf);
if (ret < 0 && ret != -EALREADY)
- return ret;
+ goto done;
ret = adf_fb_alloc(fbdev);
if (ret < 0)
- return ret;
+ goto done;
adf_interface_current_mode(fbdev->intf, &mode);
adf_modeinfo_to_fb_videomode(&mode, &fbmode);
@@ -379,13 +386,15 @@ int adf_fbdev_open(struct fb_info *info, int user)
ret = adf_fbdev_post(fbdev);
if (ret < 0) {
- if (!fbdev->open)
+ if (!fbdev->refcount)
adf_fb_destroy(fbdev);
- return ret;
+ goto done;
}
- fbdev->open = true;
- return 0;
+ fbdev->refcount++;
+done:
+ mutex_unlock(&fbdev->refcount_lock);
+ return ret;
}
EXPORT_SYMBOL(adf_fbdev_open);
@@ -395,8 +404,12 @@ EXPORT_SYMBOL(adf_fbdev_open);
int adf_fbdev_release(struct fb_info *info, int user)
{
struct adf_fbdev *fbdev = info->par;
- adf_fb_destroy(fbdev);
- fbdev->open = false;
+ mutex_lock(&fbdev->refcount_lock);
+ BUG_ON(!fbdev->refcount);
+ fbdev->refcount--;
+ if (!fbdev->refcount)
+ adf_fb_destroy(fbdev);
+ mutex_unlock(&fbdev->refcount_lock);
return 0;
}
EXPORT_SYMBOL(adf_fbdev_release);
@@ -601,6 +614,7 @@ int adf_fbdev_init(struct adf_fbdev *fbdev, struct adf_interface *interface,
dev_err(dev, "allocating framebuffer device failed\n");
return -ENOMEM;
}
+ mutex_init(&fbdev->refcount_lock);
fbdev->default_xres_virtual = xres_virtual;
fbdev->default_yres_virtual = yres_virtual;
fbdev->default_format = format;
@@ -644,8 +658,8 @@ EXPORT_SYMBOL(adf_fbdev_init);
void adf_fbdev_destroy(struct adf_fbdev *fbdev)
{
unregister_framebuffer(fbdev->info);
- if (WARN_ON(fbdev->open))
- adf_fb_destroy(fbdev);
+ BUG_ON(fbdev->refcount);
+ mutex_destroy(&fbdev->refcount_lock);
framebuffer_release(fbdev->info);
}
EXPORT_SYMBOL(adf_fbdev_destroy);
diff --git a/drivers/video/adf/adf_fops.c b/drivers/video/adf/adf_fops.c
index abec58ea2ed8..7fbf33e1cb39 100644
--- a/drivers/video/adf/adf_fops.c
+++ b/drivers/video/adf/adf_fops.c
@@ -187,7 +187,7 @@ static int adf_buffer_import(struct adf_device *dev,
buf->dma_bufs[i] = dma_buf_get(user_buf.fd[i]);
if (IS_ERR(buf->dma_bufs[i])) {
ret = PTR_ERR(buf->dma_bufs[i]);
- dev_err(&dev->base.dev, "importing dma_buf fd %llu failed: %d\n",
+ dev_err(&dev->base.dev, "importing dma_buf fd %d failed: %d\n",
user_buf.fd[i], ret);
buf->dma_bufs[i] = NULL;
goto done;
@@ -200,7 +200,7 @@ static int adf_buffer_import(struct adf_device *dev,
if (user_buf.acquire_fence >= 0) {
buf->acquire_fence = sync_fence_fdget(user_buf.acquire_fence);
if (!buf->acquire_fence) {
- dev_err(&dev->base.dev, "getting fence fd %lld failed\n",
+ dev_err(&dev->base.dev, "getting fence fd %d failed\n",
user_buf.acquire_fence);
ret = -EINVAL;
goto done;
diff --git a/drivers/video/adf/adf_fops32.h b/drivers/video/adf/adf_fops32.h
index 53d43f010208..64034ce33a6b 100644
--- a/drivers/video/adf/adf_fops32.h
+++ b/drivers/video/adf/adf_fops32.h
@@ -25,7 +25,7 @@ struct adf_post_config32 {
compat_size_t custom_data_size;
compat_uptr_t custom_data;
- __s64 complete_fence;
+ __s32 complete_fence;
};
struct adf_device_data32 {
diff --git a/drivers/video/adf/adf_memblock.c b/drivers/video/adf/adf_memblock.c
index 3c99f27388db..e73a7d59f1e6 100644
--- a/drivers/video/adf/adf_memblock.c
+++ b/drivers/video/adf/adf_memblock.c
@@ -28,7 +28,7 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach,
unsigned long pfn = PFN_DOWN(pdata->base);
struct page *page = pfn_to_page(pfn);
struct sg_table *table;
- int ret;
+ int nents, ret;
table = kzalloc(sizeof(*table), GFP_KERNEL);
if (!table)
@@ -36,12 +36,21 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach,
ret = sg_alloc_table(table, 1, GFP_KERNEL);
if (ret < 0)
- goto err;
+ goto err_alloc;
sg_set_page(table->sgl, page, attach->dmabuf->size, 0);
+
+ nents = dma_map_sg(attach->dev, table->sgl, 1, direction);
+ if (!nents) {
+ ret = -EINVAL;
+ goto err_map;
+ }
+
return table;
-err:
+err_map:
+ sg_free_table(table);
+err_alloc:
kfree(table);
return ERR_PTR(ret);
}
@@ -49,6 +58,7 @@ err:
static void adf_memblock_unmap(struct dma_buf_attachment *attach,
struct sg_table *table, enum dma_data_direction direction)
{
+ dma_unmap_sg(attach->dev, table->sgl, 1, direction);
sg_free_table(table);
}
@@ -147,3 +157,4 @@ struct dma_buf *adf_memblock_export(phys_addr_t base, size_t size, int flags)
return buf;
}
+EXPORT_SYMBOL(adf_memblock_export);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 2a2b21224bc4..7fd001ccdef4 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -380,6 +380,12 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
return 0;
}
+void notrace ramoops_console_write_buf(const char *buf, size_t size)
+{
+ struct ramoops_context *cxt = &oops_cxt;
+ persistent_ram_write(cxt->cprz, buf, size);
+}
+
static int ramoops_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
diff --git a/include/linux/keycombo.h b/include/linux/keycombo.h
new file mode 100644
index 000000000000..c6db2626b0d3
--- /dev/null
+++ b/include/linux/keycombo.h
@@ -0,0 +1,36 @@
+/*
+ * include/linux/keycombo.h - platform data structure for keycombo driver
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_KEYCOMBO_H
+#define _LINUX_KEYCOMBO_H
+
+#define KEYCOMBO_NAME "keycombo"
+
+/*
+ * if key_down_fn and key_up_fn are both present, you are guaranteed that
+ * key_down_fn will return before key_up_fn is called, and that key_up_fn
+ * is called iff key_down_fn is called.
+ */
+struct keycombo_platform_data {
+ void (*key_down_fn)(void *);
+ void (*key_up_fn)(void *);
+ void *priv;
+ int key_down_delay; /* Time in ms */
+ int *keys_up;
+ int keys_down[]; /* 0 terminated */
+};
+
+#endif /* _LINUX_KEYCOMBO_H */
diff --git a/include/linux/keyreset.h b/include/linux/keyreset.h
index a2ac49e5b684..2e34afab65e4 100644
--- a/include/linux/keyreset.h
+++ b/include/linux/keyreset.h
@@ -1,7 +1,7 @@
/*
* include/linux/keyreset.h - platform data structure for resetkeys driver
*
- * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2014 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -21,6 +21,7 @@
struct keyreset_platform_data {
int (*reset_fn)(void);
+ int key_down_delay;
int *keys_up;
int keys_down[]; /* 0 terminated */
};
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 98b340d2b14c..043f89c0768a 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -91,6 +91,27 @@ extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
extern int of_flat_dt_match(unsigned long node, const char *const *matches);
extern unsigned long of_get_flat_dt_root(void);
+/*
+ * early_init_dt_scan_chosen - scan the device tree for ramdisk and bootargs
+ *
+ * The boot arguments will be placed into the memory pointed to by @data.
+ * That memory should be COMMAND_LINE_SIZE big and initialized to be a valid
+ * (possibly empty) string. Logic for what will be in @data after this
+ * function finishes:
+ *
+ * - CONFIG_CMDLINE_FORCE=true
+ * CONFIG_CMDLINE
+ * - CONFIG_CMDLINE_EXTEND=true, @data is non-empty string
+ * @data + dt bootargs (even if dt bootargs are empty)
+ * - CONFIG_CMDLINE_EXTEND=true, @data is empty string
+ * CONFIG_CMDLINE + dt bootargs (even if dt bootargs are empty)
+ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=non-empty:
+ * dt bootargs
+ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is non-empty string
+ * @data is left unchanged
+ * - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is empty string
+ * CONFIG_CMDLINE (or "" if that's not defined)
+ */
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index 9974975d40db..9e370618352a 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -67,6 +67,8 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz);
ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
char *str, size_t len);
+void ramoops_console_write_buf(const char *buf, size_t size);
+
/*
* Ramoops platform data
* @mem_size memory size for ramoops
diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h
new file mode 100644
index 000000000000..7ce50f0debc4
--- /dev/null
+++ b/include/linux/wakeup_reason.h
@@ -0,0 +1,23 @@
+/*
+ * include/linux/wakeup_reason.h
+ *
+ * Logs the reason which caused the kernel to resume
+ * from the suspend mode.
+ *
+ * Copyright (C) 2014 Google, Inc.
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_WAKEUP_REASON_H
+#define _LINUX_WAKEUP_REASON_H
+
+void log_wakeup_reason(int irq);
+
+#endif /* _LINUX_WAKEUP_REASON_H */
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 9ac65fba5cdb..3581127275ef 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -461,10 +461,14 @@ struct input_keymap_entry {
#define KEY_VIDEO_NEXT 241 /* drive next video source */
#define KEY_VIDEO_PREV 242 /* drive previous video source */
#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
-#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */
+#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual
+ brightness control is off,
+ rely on ambient */
+#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
#define KEY_DISPLAY_OFF 245 /* display device to off state */
-#define KEY_WIMAX 246
+#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
+#define KEY_WIMAX KEY_WWAN
#define KEY_RFKILL 247 /* Key that controls all radios */
#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
@@ -509,11 +513,15 @@ struct input_keymap_entry {
#define BTN_DEAD 0x12f
#define BTN_GAMEPAD 0x130
-#define BTN_A 0x130
-#define BTN_B 0x131
+#define BTN_SOUTH 0x130
+#define BTN_A BTN_SOUTH
+#define BTN_EAST 0x131
+#define BTN_B BTN_EAST
#define BTN_C 0x132
-#define BTN_X 0x133
-#define BTN_Y 0x134
+#define BTN_NORTH 0x133
+#define BTN_X BTN_NORTH
+#define BTN_WEST 0x134
+#define BTN_Y BTN_WEST
#define BTN_Z 0x135
#define BTN_TL 0x136
#define BTN_TR 0x137
@@ -626,6 +634,7 @@ struct input_keymap_entry {
#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
+#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE
#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
#define KEY_LOGOFF 0x1b1 /* AL Logoff */
@@ -710,6 +719,24 @@ struct input_keymap_entry {
#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */
#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */
+#define BTN_DPAD_UP 0x220
+#define BTN_DPAD_DOWN 0x221
+#define BTN_DPAD_LEFT 0x222
+#define BTN_DPAD_RIGHT 0x223
+
+#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
+
+#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
+#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
+#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */
+#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */
+#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
+#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
+#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
+
+#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
+#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
+
#define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
@@ -847,6 +874,7 @@ struct input_keymap_entry {
#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */
#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
#define SW_LINEIN_INSERT 0x0d /* set = inserted */
+#define SW_MUTE_DEVICE 0x0e /* set = device disabled */
#define SW_MAX 0x0f
#define SW_CNT (SW_MAX+1)
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 253856a2a8ad..28bb0b3a08bf 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -149,6 +149,12 @@
#define PR_GET_TID_ADDRESS 40
+/* Sets the timerslack for arbitrary threads
+ * arg2 slack value, 0 means "use default"
+ * arg3 pid of the thread whose timer slack needs to be set
+ */
+#define PR_SET_TIMERSLACK_PID 41
+
#define PR_SET_VMA 0x53564d41
# define PR_SET_VMA_ANON_NAME 0
diff --git a/include/uapi/video/adf.h b/include/uapi/video/adf.h
index b703bf9e9a66..c5d2e62cdb9b 100644
--- a/include/uapi/video/adf.h
+++ b/include/uapi/video/adf.h
@@ -83,7 +83,7 @@ struct adf_event {
*/
struct adf_vsync_event {
struct adf_event base;
- __u64 timestamp;
+ __aligned_u64 timestamp;
};
/**
@@ -119,12 +119,12 @@ struct adf_buffer_config {
__u32 h;
__u32 format;
- __s64 fd[ADF_MAX_PLANES];
+ __s32 fd[ADF_MAX_PLANES];
__u32 offset[ADF_MAX_PLANES];
__u32 pitch[ADF_MAX_PLANES];
__u8 n_planes;
- __s64 acquire_fence;
+ __s32 acquire_fence;
};
#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
@@ -150,7 +150,7 @@ struct adf_post_config {
size_t custom_data_size;
void __user *custom_data;
- __s64 complete_fence;
+ __s32 complete_fence;
};
#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
@@ -180,7 +180,7 @@ struct adf_simple_buffer_alloc {
__u16 h;
__u32 format;
- __s64 fd;
+ __s32 fd;
__u32 offset;
__u32 pitch;
};
@@ -195,7 +195,7 @@ struct adf_simple_buffer_alloc {
*/
struct adf_simple_post_config {
struct adf_buffer_config buf;
- __s64 complete_fence;
+ __s32 complete_fence;
};
/**
diff --git a/include/video/adf.h b/include/video/adf.h
index 2b742ab463dd..34f10e538f9e 100644
--- a/include/video/adf.h
+++ b/include/video/adf.h
@@ -193,10 +193,26 @@ struct adf_obj {
};
/**
+ * struct adf_device_quirks - common display device quirks
+ *
+ * @buffer_padding: whether the last scanline of a buffer extends to the
+ * buffer's pitch (@ADF_BUFFER_PADDED_TO_PITCH) or just to the visible
+ * width (@ADF_BUFFER_UNPADDED)
+ */
+struct adf_device_quirks {
+ /* optional, defaults to ADF_BUFFER_PADDED_TO_PITCH */
+ enum {
+ ADF_BUFFER_PADDED_TO_PITCH = 0,
+ ADF_BUFFER_UNPADDED = 1,
+ } buffer_padding;
+};
+
+/**
* struct adf_device_ops - display device implementation ops
*
* @owner: device's module
* @base: common operations (see &struct adf_obj_ops)
+ * @quirks: device's quirks (see &struct adf_device_quirks)
*
* @attach: attach overlay engine @eng to interface @intf. Return 0 on success
* or error code (<0) on failure.
@@ -228,6 +244,8 @@ struct adf_device_ops {
/* required */
struct module *owner;
const struct adf_obj_ops base;
+ /* optional */
+ const struct adf_device_quirks quirks;
/* optional */
int (*attach)(struct adf_device *dev, struct adf_overlay_engine *eng,
diff --git a/include/video/adf_fbdev.h b/include/video/adf_fbdev.h
index 9c349144b5cd..b722c6b3ab02 100644
--- a/include/video/adf_fbdev.h
+++ b/include/video/adf_fbdev.h
@@ -16,6 +16,7 @@
#define _VIDEO_ADF_FBDEV_H_
#include <linux/fb.h>
+#include <linux/mutex.h>
#include <video/adf.h>
struct adf_fbdev {
@@ -24,7 +25,8 @@ struct adf_fbdev {
struct fb_info *info;
u32 pseudo_palette[16];
- bool open;
+ unsigned int refcount;
+ struct mutex refcount_lock;
struct dma_buf *dma_buf;
u32 offset;
@@ -37,6 +39,7 @@ struct adf_fbdev {
u32 default_format;
};
+#if IS_ENABLED(CONFIG_ADF_FBDEV)
void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
struct fb_videomode *vmode);
void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
@@ -55,5 +58,67 @@ int adf_fbdev_set_par(struct fb_info *info);
int adf_fbdev_blank(int blank, struct fb_info *info);
int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
int adf_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma);
+#else
+static inline void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
+ struct fb_videomode *vmode)
+{
+ WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__);
+}
+
+static inline void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
+ struct drm_mode_modeinfo *mode)
+{
+ WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__);
+}
+
+static inline int adf_fbdev_init(struct adf_fbdev *fbdev,
+ struct adf_interface *interface,
+ struct adf_overlay_engine *eng,
+ u16 xres_virtual, u16 yres_virtual, u32 format,
+ struct fb_ops *fbops, const char *fmt, ...)
+{
+ return -ENODEV;
+}
+
+static inline void adf_fbdev_destroy(struct adf_fbdev *fbdev) { }
+
+static inline int adf_fbdev_open(struct fb_info *info, int user)
+{
+ return -ENODEV;
+}
+
+static inline int adf_fbdev_release(struct fb_info *info, int user)
+{
+ return -ENODEV;
+}
+
+static inline int adf_fbdev_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ return -ENODEV;
+}
+
+static inline int adf_fbdev_set_par(struct fb_info *info)
+{
+ return -ENODEV;
+}
+
+static inline int adf_fbdev_blank(int blank, struct fb_info *info)
+{
+ return -ENODEV;
+}
+
+static inline int adf_fbdev_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ return -ENODEV;
+}
+
+static inline int adf_fbdev_mmap(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+ return -ENODEV;
+}
+#endif
#endif /* _VIDEO_ADF_FBDEV_H_ */
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 8450b85d33c0..74c713ba61b0 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -14,3 +14,5 @@ obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o
obj-$(CONFIG_SUSPEND_TIME) += suspend_time.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
+
+obj-$(CONFIG_SUSPEND) += wakeup_reason.o
diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c
new file mode 100644
index 000000000000..187e4e9105fb
--- /dev/null
+++ b/kernel/power/wakeup_reason.c
@@ -0,0 +1,139 @@
+/*
+ * kernel/power/wakeup_reason.c
+ *
+ * Logs the reasons which caused the kernel to resume from
+ * the suspend mode.
+ *
+ * Copyright (C) 2014 Google, Inc.
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/wakeup_reason.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+#include <linux/suspend.h>
+
+
+#define MAX_WAKEUP_REASON_IRQS 32
+static int irq_list[MAX_WAKEUP_REASON_IRQS];
+static int irqcount;
+static struct kobject *wakeup_reason;
+static spinlock_t resume_reason_lock;
+
+static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ int irq_no, buf_offset = 0;
+ struct irq_desc *desc;
+ spin_lock(&resume_reason_lock);
+ for (irq_no = 0; irq_no < irqcount; irq_no++) {
+ desc = irq_to_desc(irq_list[irq_no]);
+ if (desc && desc->action && desc->action->name)
+ buf_offset += sprintf(buf + buf_offset, "%d %s\n",
+ irq_list[irq_no], desc->action->name);
+ else
+ buf_offset += sprintf(buf + buf_offset, "%d\n",
+ irq_list[irq_no]);
+ }
+ spin_unlock(&resume_reason_lock);
+ return buf_offset;
+}
+
+static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason);
+
+static struct attribute *attrs[] = {
+ &resume_reason.attr,
+ NULL,
+};
+static struct attribute_group attr_group = {
+ .attrs = attrs,
+};
+
+/*
+ * logs all the wake up reasons to the kernel
+ * stores the irqs to expose them to the userspace via sysfs
+ */
+void log_wakeup_reason(int irq)
+{
+ struct irq_desc *desc;
+ desc = irq_to_desc(irq);
+ if (desc && desc->action && desc->action->name)
+ printk(KERN_INFO "Resume caused by IRQ %d, %s\n", irq,
+ desc->action->name);
+ else
+ printk(KERN_INFO "Resume caused by IRQ %d\n", irq);
+
+ spin_lock(&resume_reason_lock);
+ if (irqcount == MAX_WAKEUP_REASON_IRQS) {
+ spin_unlock(&resume_reason_lock);
+ printk(KERN_WARNING "Resume caused by more than %d IRQs\n",
+ MAX_WAKEUP_REASON_IRQS);
+ return;
+ }
+
+ irq_list[irqcount++] = irq;
+ spin_unlock(&resume_reason_lock);
+}
+
+/* Detects a suspend and clears all the previous wake up reasons*/
+static int wakeup_reason_pm_event(struct notifier_block *notifier,
+ unsigned long pm_event, void *unused)
+{
+ switch (pm_event) {
+ case PM_SUSPEND_PREPARE:
+ spin_lock(&resume_reason_lock);
+ irqcount = 0;
+ spin_unlock(&resume_reason_lock);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block wakeup_reason_pm_notifier_block = {
+ .notifier_call = wakeup_reason_pm_event,
+};
+
+/* Initializes the sysfs parameter
+ * registers the pm_event notifier
+ */
+int __init wakeup_reason_init(void)
+{
+ int retval;
+ spin_lock_init(&resume_reason_lock);
+ retval = register_pm_notifier(&wakeup_reason_pm_notifier_block);
+ if (retval)
+ printk(KERN_WARNING "[%s] failed to register PM notifier %d\n",
+ __func__, retval);
+
+ wakeup_reason = kobject_create_and_add("wakeup_reasons", kernel_kobj);
+ if (!wakeup_reason) {
+ printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n",
+ __func__);
+ return 1;
+ }
+ retval = sysfs_create_group(wakeup_reason, &attr_group);
+ if (retval) {
+ kobject_put(wakeup_reason);
+ printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n",
+ __func__, retval);
+ }
+ return 0;
+}
+
+late_initcall(wakeup_reason_init);
diff --git a/kernel/sys.c b/kernel/sys.c
index 126b7c939d1f..875529e936ab 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -44,6 +44,7 @@
#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/mempolicy.h>
+#include <linux/sched.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -2252,6 +2253,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
{
struct task_struct *me = current;
+ struct task_struct *tsk;
unsigned char comm[sizeof(me->comm)];
long error;
@@ -2375,6 +2377,23 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
return -EINVAL;
break;
+ case PR_SET_TIMERSLACK_PID:
+ rcu_read_lock();
+ tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns);
+ if (tsk == NULL) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ get_task_struct(tsk);
+ rcu_read_unlock();
+ if (arg2 <= 0)
+ tsk->timer_slack_ns =
+ tsk->default_timer_slack_ns;
+ else
+ tsk->timer_slack_ns = arg2;
+ put_task_struct(tsk);
+ error = 0;
+ break;
default:
return -EINVAL;
}
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 5bf79864ca66..7122472d24a6 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -249,26 +249,33 @@ int ping_init_sock(struct sock *sk)
{
struct net *net = sock_net(sk);
kgid_t group = current_egid();
- struct group_info *group_info = get_current_groups();
- int i, j, count = group_info->ngroups;
+ struct group_info *group_info;
+ int i, j, count;
kgid_t low, high;
+ int ret = 0;
inet_get_ping_group_range_net(net, &low, &high);
if (gid_lte(low, group) && gid_lte(group, high))
return 0;
+ group_info = get_current_groups();
+ count = group_info->ngroups;
for (i = 0; i < group_info->nblocks; i++) {
int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
for (j = 0; j < cp_count; j++) {
kgid_t gid = group_info->blocks[i][j];
if (gid_lte(low, gid) && gid_lte(gid, high))
- return 0;
+ goto out_release_group;
}
count -= cp_count;
}
- return -EACCES;
+ ret = -EACCES;
+
+out_release_group:
+ put_group_info(group_info);
+ return ret;
}
EXPORT_SYMBOL_GPL(ping_init_sock);
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
index df91e26f55f2..f6562ba97a97 100644
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -42,6 +42,11 @@
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <linux/sysfs.h>
+#include <linux/rtc.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/suspend.h>
+#include <linux/notifier.h>
#include <net/net_namespace.h>
struct idletimer_tg_attr {
@@ -58,22 +63,65 @@ struct idletimer_tg {
struct kobject *kobj;
struct idletimer_tg_attr attr;
+ struct timespec delayed_timer_trigger;
+ struct timespec last_modified_timer;
+ struct timespec last_suspend_time;
+ struct notifier_block pm_nb;
+
+ int timeout;
unsigned int refcnt;
+ bool work_pending;
bool send_nl_msg;
bool active;
};
static LIST_HEAD(idletimer_tg_list);
static DEFINE_MUTEX(list_mutex);
+static DEFINE_SPINLOCK(timestamp_lock);
static struct kobject *idletimer_tg_kobj;
+static bool check_for_delayed_trigger(struct idletimer_tg *timer,
+ struct timespec *ts)
+{
+ bool state;
+ struct timespec temp;
+ spin_lock_bh(&timestamp_lock);
+ timer->work_pending = false;
+ if ((ts->tv_sec - timer->last_modified_timer.tv_sec) > timer->timeout ||
+ timer->delayed_timer_trigger.tv_sec != 0) {
+ state = false;
+ temp.tv_sec = timer->timeout;
+ temp.tv_nsec = 0;
+ if (timer->delayed_timer_trigger.tv_sec != 0) {
+ temp = timespec_add(timer->delayed_timer_trigger, temp);
+ ts->tv_sec = temp.tv_sec;
+ ts->tv_nsec = temp.tv_nsec;
+ timer->delayed_timer_trigger.tv_sec = 0;
+ timer->work_pending = true;
+ schedule_work(&timer->work);
+ } else {
+ temp = timespec_add(timer->last_modified_timer, temp);
+ ts->tv_sec = temp.tv_sec;
+ ts->tv_nsec = temp.tv_nsec;
+ }
+ } else {
+ state = timer->active;
+ }
+ spin_unlock_bh(&timestamp_lock);
+ return state;
+}
+
static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer)
{
char iface_msg[NLMSG_MAX_SIZE];
char state_msg[NLMSG_MAX_SIZE];
- char *envp[] = { iface_msg, state_msg, NULL };
+ char timestamp_msg[NLMSG_MAX_SIZE];
+ char *envp[] = { iface_msg, state_msg, timestamp_msg, NULL };
int res;
+ struct timespec ts;
+ uint64_t time_ns;
+ bool state;
res = snprintf(iface_msg, NLMSG_MAX_SIZE, "INTERFACE=%s",
iface);
@@ -81,12 +129,24 @@ static void notify_netlink_uevent(const char *iface, struct idletimer_tg *timer)
pr_err("message too long (%d)", res);
return;
}
+
+ get_monotonic_boottime(&ts);
+ state = check_for_delayed_trigger(timer, &ts);
res = snprintf(state_msg, NLMSG_MAX_SIZE, "STATE=%s",
- timer->active ? "active" : "inactive");
+ state ? "active" : "inactive");
+
if (NLMSG_MAX_SIZE <= res) {
pr_err("message too long (%d)", res);
return;
}
+
+ time_ns = timespec_to_ns(&ts);
+ res = snprintf(timestamp_msg, NLMSG_MAX_SIZE, "TIME_NS=%llu", time_ns);
+ if (NLMSG_MAX_SIZE <= res) {
+ timestamp_msg[0] = '\0';
+ pr_err("message too long (%d)", res);
+ }
+
pr_debug("putting nlmsg: <%s> <%s>\n", iface_msg, state_msg);
kobject_uevent_env(idletimer_tg_kobj, KOBJ_CHANGE, envp);
return;
@@ -151,9 +211,55 @@ static void idletimer_tg_expired(unsigned long data)
struct idletimer_tg *timer = (struct idletimer_tg *) data;
pr_debug("timer %s expired\n", timer->attr.attr.name);
-
+ spin_lock_bh(&timestamp_lock);
timer->active = false;
+ timer->work_pending = true;
schedule_work(&timer->work);
+ spin_unlock_bh(&timestamp_lock);
+}
+
+static int idletimer_resume(struct notifier_block *notifier,
+ unsigned long pm_event, void *unused)
+{
+ struct timespec ts;
+ unsigned long time_diff, now = jiffies;
+ struct idletimer_tg *timer = container_of(notifier,
+ struct idletimer_tg, pm_nb);
+ if (!timer)
+ return NOTIFY_DONE;
+ switch (pm_event) {
+ case PM_SUSPEND_PREPARE:
+ get_monotonic_boottime(&timer->last_suspend_time);
+ break;
+ case PM_POST_SUSPEND:
+ spin_lock_bh(&timestamp_lock);
+ if (!timer->active) {
+ spin_unlock_bh(&timestamp_lock);
+ break;
+ }
+ /* since jiffies are not updated when suspended now represents
+ * the time it would have suspended */
+ if (time_after(timer->timer.expires, now)) {
+ get_monotonic_boottime(&ts);
+ ts = timespec_sub(ts, timer->last_suspend_time);
+ time_diff = timespec_to_jiffies(&ts);
+ if (timer->timer.expires > (time_diff + now)) {
+ mod_timer_pending(&timer->timer,
+ (timer->timer.expires - time_diff));
+ } else {
+ del_timer(&timer->timer);
+ timer->timer.expires = 0;
+ timer->active = false;
+ timer->work_pending = true;
+ schedule_work(&timer->work);
+ }
+ }
+ spin_unlock_bh(&timestamp_lock);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
}
static int idletimer_tg_create(struct idletimer_tg_info *info)
@@ -187,6 +293,18 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
info->timer->refcnt = 1;
info->timer->send_nl_msg = (info->send_nl_msg == 0) ? false : true;
info->timer->active = true;
+ info->timer->timeout = info->timeout;
+
+ info->timer->delayed_timer_trigger.tv_sec = 0;
+ info->timer->delayed_timer_trigger.tv_nsec = 0;
+ info->timer->work_pending = false;
+ get_monotonic_boottime(&info->timer->last_modified_timer);
+
+ info->timer->pm_nb.notifier_call = idletimer_resume;
+ ret = register_pm_notifier(&info->timer->pm_nb);
+ if (ret)
+ printk(KERN_WARNING "[%s] Failed to register pm notifier %d\n",
+ __func__, ret);
mod_timer(&info->timer->timer,
msecs_to_jiffies(info->timeout * 1000) + jiffies);
@@ -203,6 +321,34 @@ out:
return ret;
}
+static void reset_timer(const struct idletimer_tg_info *info)
+{
+ unsigned long now = jiffies;
+ struct idletimer_tg *timer = info->timer;
+ bool timer_prev;
+
+ spin_lock_bh(&timestamp_lock);
+ timer_prev = timer->active;
+ timer->active = true;
+ /* timer_prev is used to guard overflow problem in time_before*/
+ if (!timer_prev || time_before(timer->timer.expires, now)) {
+ pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n",
+ timer->timer.expires, now);
+ /* checks if there is a pending inactive notification*/
+ if (timer->work_pending)
+ timer->delayed_timer_trigger = timer->last_modified_timer;
+ else {
+ timer->work_pending = true;
+ schedule_work(&timer->work);
+ }
+ }
+
+ get_monotonic_boottime(&timer->last_modified_timer);
+ mod_timer(&timer->timer,
+ msecs_to_jiffies(info->timeout * 1000) + now);
+ spin_unlock_bh(&timestamp_lock);
+}
+
/*
* The actual xt_tables plugin.
*/
@@ -226,9 +372,7 @@ static unsigned int idletimer_tg_target(struct sk_buff *skb,
}
/* TODO: Avoid modifying timers on each packet */
- mod_timer(&info->timer->timer,
- msecs_to_jiffies(info->timeout * 1000) + now);
-
+ reset_timer(info);
return XT_CONTINUE;
}
@@ -236,7 +380,6 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
{
struct idletimer_tg_info *info = par->targinfo;
int ret;
- unsigned long now = jiffies;
pr_debug("checkentry targinfo %s\n", info->label);
@@ -257,17 +400,7 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
info->timer = __idletimer_tg_find_by_label(info->label);
if (info->timer) {
info->timer->refcnt++;
- info->timer->active = true;
-
- if (time_before(info->timer->timer.expires, now)) {
- schedule_work(&info->timer->work);
- pr_debug("Starting Checkentry timer (Expired, Jiffies): %lu, %lu\n",
- info->timer->timer.expires, now);
- }
-
- mod_timer(&info->timer->timer,
- msecs_to_jiffies(info->timeout * 1000) + now);
-
+ reset_timer(info);
pr_debug("increased refcnt of timer %s to %u\n",
info->label, info->timer->refcnt);
} else {
@@ -298,6 +431,7 @@ static void idletimer_tg_destroy(const struct xt_tgdtor_param *par)
list_del(&info->timer->entry);
del_timer_sync(&info->timer->timer);
sysfs_remove_file(idletimer_tg_kobj, &info->timer->attr.attr);
+ unregister_pm_notifier(&info->timer->pm_nb);
kfree(info->timer->attr.attr.name);
kfree(info->timer);
} else {
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 4a16829969a6..eee667987f7d 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -594,7 +594,7 @@ static void put_tag_ref_tree(tag_t full_tag, struct uid_tag_data *utd_entry)
}
}
-static int read_proc_u64(struct file *file, char __user *buf,
+static ssize_t read_proc_u64(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
uint64_t *valuep = PDE_DATA(file_inode(file));
@@ -605,7 +605,7 @@ static int read_proc_u64(struct file *file, char __user *buf,
return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
}
-static int read_proc_bool(struct file *file, char __user *buf,
+static ssize_t read_proc_bool(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
bool *valuep = PDE_DATA(file_inode(file));
@@ -1488,7 +1488,7 @@ static int proc_iface_stat_fmt_open(struct inode *inode, struct file *file)
if (!s)
return -ENOMEM;
- s->fmt = (int)PDE_DATA(inode);
+ s->fmt = (uintptr_t)PDE_DATA(inode);
return 0;
}
@@ -2440,10 +2440,10 @@ err:
return res;
}
-static int qtaguid_ctrl_parse(const char *input, int count)
+static ssize_t qtaguid_ctrl_parse(const char *input, size_t count)
{
char cmd;
- int res;
+ ssize_t res;
CT_DEBUG("qtaguid: ctrl(%s): pid=%u tgid=%u uid=%u\n",
input, current->pid, current->tgid, current_fsuid());
@@ -2474,12 +2474,12 @@ static int qtaguid_ctrl_parse(const char *input, int count)
if (!res)
res = count;
err:
- CT_DEBUG("qtaguid: ctrl(%s): res=%d\n", input, res);
+ CT_DEBUG("qtaguid: ctrl(%s): res=%zd\n", input, res);
return res;
}
#define MAX_QTAGUID_CTRL_INPUT_LEN 255
-static int qtaguid_ctrl_proc_write(struct file *file, const char __user *buffer,
+static ssize_t qtaguid_ctrl_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *offp)
{
char input_buf[MAX_QTAGUID_CTRL_INPUT_LEN];
diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c
index 44ebdcc75965..4328562572f6 100644
--- a/net/netfilter/xt_quota2.c
+++ b/net/netfilter/xt_quota2.c
@@ -122,7 +122,7 @@ static void quota2_log(unsigned int hooknum,
}
#endif /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
-static int quota_proc_read(struct file *file, char __user *buf,
+static ssize_t quota_proc_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
struct xt_quota_counter *e = PDE_DATA(file_inode(file));
@@ -135,7 +135,7 @@ static int quota_proc_read(struct file *file, char __user *buf,
return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
}
-static int quota_proc_write(struct file *file, const char __user *input,
+static ssize_t quota_proc_write(struct file *file, const char __user *input,
size_t size, loff_t *ppos)
{
struct xt_quota_counter *e = PDE_DATA(file_inode(file));
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index dad36a6ab45f..c223a32c0bb3 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -444,11 +444,15 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
avc_dump_query(ab, ad->selinux_audit_data->ssid,
ad->selinux_audit_data->tsid,
ad->selinux_audit_data->tclass);
+ if (ad->selinux_audit_data->denied) {
+ audit_log_format(ab, " permissive=%u",
+ ad->selinux_audit_data->result ? 0 : 1);
+ }
}
/* This is the slow part of avc audit with big stack footprint */
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
- u32 requested, u32 audited, u32 denied,
+ u32 requested, u32 audited, u32 denied, int result,
struct common_audit_data *a,
unsigned flags)
{
@@ -477,6 +481,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
sad.tsid = tsid;
sad.audited = audited;
sad.denied = denied;
+ sad.result = result;
a->selinux_audit_data = &sad;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b582c7d39aeb..1a9ab5419fff 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2715,6 +2715,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
static noinline int audit_inode_permission(struct inode *inode,
u32 perms, u32 audited, u32 denied,
+ int result,
unsigned flags)
{
struct common_audit_data ad;
@@ -2725,7 +2726,7 @@ static noinline int audit_inode_permission(struct inode *inode,
ad.u.inode = inode;
rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
- audited, denied, &ad, flags);
+ audited, denied, result, &ad, flags);
if (rc)
return rc;
return 0;
@@ -2767,7 +2768,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
if (likely(!audited))
return rc;
- rc2 = audit_inode_permission(inode, perms, audited, denied, flags);
+ rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags);
if (rc2)
return rc2;
return rc;
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 92d0ab561db8..28a08a891704 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -102,7 +102,7 @@ static inline u32 avc_audit_required(u32 requested,
}
int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
- u32 requested, u32 audited, u32 denied,
+ u32 requested, u32 audited, u32 denied, int result,
struct common_audit_data *a,
unsigned flags);
@@ -137,7 +137,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
if (likely(!audited))
return 0;
return slow_avc_audit(ssid, tsid, tclass,
- requested, audited, denied,
+ requested, audited, denied, result,
a, flags);
}