diff --git a/Documentation/arm64/tagged-pointers.txt b/Documentation/arm64/tagged-pointers.txt new file mode 100644 index 000000000000..d9995f1f51b3 --- /dev/null +++ b/Documentation/arm64/tagged-pointers.txt @@ -0,0 +1,34 @@ + Tagged virtual addresses in AArch64 Linux + ========================================= + +Author: Will Deacon +Date : 12 June 2013 + +This document briefly describes the provision of tagged virtual +addresses in the AArch64 translation system and their potential uses +in AArch64 Linux. + +The kernel configures the translation tables so that translations made +via TTBR0 (i.e. userspace mappings) have the top byte (bits 63:56) of +the virtual address ignored by the translation hardware. This frees up +this byte for application use, with the following caveats: + + (1) The kernel requires that all user addresses passed to EL1 + are tagged with tag 0x00. This means that any syscall + parameters containing user virtual addresses *must* have + their top byte cleared before trapping to the kernel. + + (2) Non-zero tags are not preserved when delivering signals. + This means that signal handlers in applications making use + of tags cannot rely on the tag information for user virtual + addresses being maintained for fields inside siginfo_t. + One exception to this rule is for signals raised in response + to watchpoint debug exceptions, where the tag information + will be preserved. + + (3) Special care should be taken when using tagged pointers, + since it is likely that C compilers will not hazard two + virtual addresses differing only in the upper byte. + +The architecture prevents the use of a tagged PC, so the upper byte will +be set to a sign-extension of bit 55 on exception return. diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg index 25162024f889..04c7148cf637 100644 --- a/android/configs/android-base.cfg +++ b/android/configs/android-base.cfg @@ -16,8 +16,8 @@ CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_SCHED=y CONFIG_DM_CRYPT=y +CONFIG_DM_VERITY=y CONFIG_EMBEDDED=y -CONFIG_EXPERIMENTAL=y CONFIG_FB=y CONFIG_HIGH_RES_TIMERS=y CONFIG_INET6_AH=y @@ -36,6 +36,7 @@ CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_OPTIMISTIC_DAD=y CONFIG_IPV6_PRIVACY=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 @@ -82,9 +83,11 @@ CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NET_CLS_ACT=y diff --git a/android/configs/android-recommended.cfg b/android/configs/android-recommended.cfg index b0120f678cc4..960b9de2860d 100644 --- a/android/configs/android-recommended.cfg +++ b/android/configs/android-recommended.cfg @@ -5,7 +5,6 @@ # CONFIG_NF_CONNTRACK_SIP is not set # CONFIG_PM_WAKELOCKS_GC is not set # CONFIG_VT is not set -CONFIG_ANDROID_RAM_CONSOLE=y CONFIG_ANDROID_TIMED_GPIO=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BLK_DEV_LOOP=y @@ -14,10 +13,12 @@ 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 CONFIG_GREENASIA_FF=y +CONFIG_HIDRAW=y CONFIG_HID_A4TECH=y CONFIG_HID_ACRUX=y CONFIG_HID_ACRUX_FF=y @@ -94,8 +95,10 @@ CONFIG_PM_DEBUG=y CONFIG_PM_RUNTIME=y CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_POWER_SUPPLY=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y CONFIG_SCHEDSTATS=y -CONFIG_SCHED_TRACER=y CONFIG_SMARTJOYPLUS_FF=y CONFIG_SND=y CONFIG_SOUND=y diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 99887aaa04bb..351e48e45cbb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1861,16 +1861,16 @@ config BUILD_ARM_APPENDED_DTB_IMAGE bool "Build a concatenated zImage/dtb by default" depends on OF help - Enabling this option will cause a concatenated zImage and list of - DTBs to be built by default (instead of a standalone zImage.) - The image will built in arch/arm/boot/zImage-dtb + Enabling this option will cause a concatenated zImage and DTB to + be built by default (instead of a standalone zImage.) The image + will built in arch/arm/boot/zImage-dtb. -config BUILD_ARM_APPENDED_DTB_IMAGE_NAMES - string "Default dtb names" +config BUILD_ARM_APPENDED_DTB_IMAGE_NAME + string "Default dtb name" depends on BUILD_ARM_APPENDED_DTB_IMAGE help - Space separated list of names of dtbs to append when - building a concatenated zImage-dtb. + name of the dtb to append when building a concatenated + zImage/dtb. # Compressed boot loader in ROM. Yes, we really want to ask about # TEXT and BSS so we preserve their values in the config files. diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 314c7be492a9..883e4bec807f 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -265,7 +265,7 @@ libs-y := arch/arm/lib/ $(libs-y) ifeq ($(CONFIG_XIP_KERNEL),y) KBUILD_IMAGE := xipImage else ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y) -KBUILD_IMAGE := zImage-dtb +KBUILD_IMAGE := zImage-dtb.$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAME) else KBUILD_IMAGE := zImage endif @@ -297,9 +297,6 @@ zinstall uinstall install: vmlinux dtbs: scripts $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs -zImage-dtb: vmlinux scripts dtbs - $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ - # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore index ad7a0253ea96..3c79f85975aa 100644 --- a/arch/arm/boot/.gitignore +++ b/arch/arm/boot/.gitignore @@ -4,4 +4,3 @@ xipImage bootpImage uImage *.dtb -zImage-dtb \ No newline at end of file diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 65285bbbf899..085bb96493a3 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -28,14 +28,6 @@ export ZRELADDR INITRD_PHYS PARAMS_PHYS targets := Image zImage xipImage bootpImage uImage -DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_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)) - ifeq ($(CONFIG_XIP_KERNEL),y) $(obj)/xipImage: vmlinux FORCE @@ -64,10 +56,6 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) @$(kecho) ' Kernel: $@ is ready' -$(obj)/zImage-dtb: $(obj)/zImage $(DTB_OBJS) FORCE - $(call if_changed,cat) - @echo ' Kernel: $@ is ready' - endif ifneq ($(LOADADDR),) diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b83cc5083a2c..f0895c581a89 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -210,20 +210,13 @@ dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ wm8850-w70v2.dtb dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb -DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES)) -ifneq ($(DTB_NAMES),) -DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) -else -DTB_LIST := $(dtb-y) -endif - targets += dtbs -targets += $(DTB_LIST) +targets += $(dtb-y) endif # *.dtb used to be generated in the directory above. Clean out the # old build results so people don't accidentally use them. -dtbs: $(addprefix $(obj)/, $(DTB_LIST)) +dtbs: $(addprefix $(obj)/, $(dtb-y)) $(Q)rm -f $(obj)/../*.dtb clean-files := *.dtb diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 992d4046bb8a..ce01364a96e3 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -21,49 +21,3 @@ config SHARP_SCOOP 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. 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 56b3f6d447ae..02f4d1cfd7b3 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -194,6 +194,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 @@ -201,6 +218,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 c95c5cb212fd..d69354dbd789 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -41,7 +41,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) @@ -60,6 +65,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 5a0e3ab854a5..df519849fa00 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -14,14 +14,27 @@ # Based on the ia64 boot/Makefile. # +include $(srctree)/arch/arm64/boot/dts/Makefile + targets := Image Image.gz +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)/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 68457e9e0975..8dc5d8e28a01 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -1,8 +1,15 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb targets += dtbs -targets += $(dtb-y) -dtbs: $(addprefix $(obj)/, $(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)) clean-files := *.dtb diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 8a8ce0e73a38..a8b44cad39d7 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -158,17 +158,23 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, return ret; } -#define cmpxchg(ptr,o,n) \ - ((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \ - (unsigned long)(o), \ - (unsigned long)(n), \ - sizeof(*(ptr)))) +#define cmpxchg(ptr, o, n) \ +({ \ + __typeof__(*(ptr)) __ret; \ + __ret = (__typeof__(*(ptr))) \ + __cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), \ + sizeof(*(ptr))); \ + __ret; \ +}) -#define cmpxchg_local(ptr,o,n) \ - ((__typeof__(*(ptr)))__cmpxchg((ptr), \ - (unsigned long)(o), \ - (unsigned long)(n), \ - sizeof(*(ptr)))) +#define cmpxchg_local(ptr, o, n) \ +({ \ + __typeof__(*(ptr)) __ret; \ + __ret = (__typeof__(*(ptr))) \ + __cmpxchg((ptr), (unsigned long)(o), \ + (unsigned long)(n), sizeof(*(ptr))); \ + __ret; \ +}) #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n)) #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n)) diff --git a/arch/arm64/include/asm/pgtable-3level-types.h b/arch/arm64/include/asm/pgtable-3level-types.h index 4489615f14a9..4e94424938a4 100644 --- a/arch/arm64/include/asm/pgtable-3level-types.h +++ b/arch/arm64/include/asm/pgtable-3level-types.h @@ -16,6 +16,8 @@ #ifndef __ASM_PGTABLE_3LEVEL_TYPES_H #define __ASM_PGTABLE_3LEVEL_TYPES_H +#include + typedef u64 pteval_t; typedef u64 pmdval_t; typedef u64 pgdval_t; diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index 75fd13d289b9..7eeed1ae2c5f 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -92,5 +92,6 @@ #define TCR_TG1_64K (UL(1) << 30) #define TCR_IPS_40BIT (UL(2) << 32) #define TCR_ASID16 (UL(1) << 36) +#define TCR_TBI0 (UL(1) << 37) #endif diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 1d1314280a03..1146e6f40a6b 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -423,6 +423,7 @@ el0_da: * Data abort handling */ mrs x0, far_el1 + bic x0, x0, #(0xff << 56) disable_step x1 isb enable_dbg diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index a82ae8868077..9428de8a8f37 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -151,7 +151,7 @@ ENTRY(__cpu_setup) * both user and kernel. */ ldr x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | TCR_IPS_40BIT | \ - TCR_ASID16 | (1 << 31) + TCR_ASID16 | TCR_TBI0 | (1 << 31) #ifdef CONFIG_ARM64_64K_PAGES orr x10, x10, TCR_TG0_64K orr x10, x10, TCR_TG1_64K diff --git a/drivers/char/dcc_tty.c b/drivers/char/dcc_tty.c index a787accdcb14..0a62d410286f 100644 --- a/drivers/char/dcc_tty.c +++ b/drivers/char/dcc_tty.c @@ -26,7 +26,7 @@ MODULE_DESCRIPTION("DCC TTY Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0"); -static spinlock_t g_dcc_tty_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(g_dcc_tty_lock); static struct hrtimer g_dcc_timer; static char g_dcc_buffer[16]; static int g_dcc_buffer_head; @@ -80,8 +80,8 @@ static void dcc_poll_locked(void) ); if (rch >= 0) { ch = rch; - tty_insert_flip_string(g_dcc_tty, &ch, 1); - tty_flip_buffer_push(g_dcc_tty); + tty_insert_flip_string(g_dcc_tty->port, &ch, 1); + tty_flip_buffer_push(g_dcc_tty->port); } } diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 62236d633391..e86900b03c8e 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -172,6 +172,7 @@ config CPU_FREQ_GOV_ONDEMAND config CPU_FREQ_GOV_INTERACTIVE tristate "'interactive' cpufreq policy governor" + default n help 'interactive' - This driver adds a dynamic cpufreq policy governor designed for latency-sensitive workloads. diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2d53f47d1747..3faf62bdbad0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -132,6 +132,16 @@ bool have_governor_per_policy(void) { return cpufreq_driver->have_governor_per_policy; } +EXPORT_SYMBOL_GPL(have_governor_per_policy); + +struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) +{ + if (have_governor_per_policy()) + return &policy->kobj; + else + return cpufreq_global_kobject; +} +EXPORT_SYMBOL_GPL(get_governor_parent_kobj); static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs) { diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index dc9b72e25c1a..1361bd432691 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -30,14 +30,6 @@ #include "cpufreq_governor.h" -static struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) -{ - if (have_governor_per_policy()) - return &policy->kobj; - else - return cpufreq_global_kobject; -} - static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data) { if (have_governor_per_policy()) @@ -404,6 +396,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, mutex_lock(&dbs_data->mutex); mutex_destroy(&cpu_cdbs->timer_mutex); + cpu_cdbs->cur_policy = NULL; mutex_unlock(&dbs_data->mutex); diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index d72e8c458f69..a376dfa8f412 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -46,8 +46,10 @@ struct cpufreq_interactive_cpuinfo { u64 cputime_speedadj_timestamp; 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; @@ -398,6 +400,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; @@ -423,6 +426,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; } @@ -430,8 +434,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; @@ -445,6 +451,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; } } @@ -466,6 +473,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; } @@ -473,6 +481,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); @@ -616,16 +625,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); @@ -641,9 +651,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); @@ -752,7 +763,7 @@ static ssize_t show_target_loads( ret += sprintf(buf + ret, "%u%s", tunables->target_loads[i], i & 0x1 ? ":" : " "); - ret += sprintf(buf + --ret, "\n"); + sprintf(buf + ret - 1, "\n"); spin_unlock_irqrestore(&tunables->target_loads_lock, flags); return ret; } @@ -792,7 +803,7 @@ static ssize_t show_above_hispeed_delay( tunables->above_hispeed_delay[i], i & 0x1 ? ":" : " "); - ret += sprintf(buf + --ret, "\n"); + sprintf(buf + ret - 1, "\n"); spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags); return ret; } @@ -937,6 +948,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"); } @@ -1154,6 +1166,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; @@ -1178,13 +1191,6 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, return -ENOMEM; } - rc = sysfs_create_group(get_governor_parent_kobj(policy), - get_sysfs_attr()); - if (rc) { - kfree(tunables); - return rc; - } - tunables->usage_count = 1; tunables->above_hispeed_delay = default_above_hispeed_delay; tunables->nabove_hispeed_delay = @@ -1200,16 +1206,26 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, spin_lock_init(&tunables->target_loads_lock); spin_lock_init(&tunables->above_hispeed_delay_lock); + policy->governor_data = tunables; + if (!have_governor_per_policy()) + common_tunables = tunables; + + rc = sysfs_create_group(get_governor_parent_kobj(policy), + get_sysfs_attr()); + if (rc) { + kfree(tunables); + policy->governor_data = NULL; + if (!have_governor_per_policy()) + common_tunables = NULL; + return rc; + } + if (!policy->governor->initialized) { idle_notifier_register(&cpufreq_interactive_idle_nb); cpufreq_register_notifier(&cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); } - policy->governor_data = tunables; - if (!have_governor_per_policy()) - common_tunables = tunables; - break; case CPUFREQ_GOV_POLICY_EXIT: @@ -1246,6 +1262,7 @@ 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); @@ -1281,29 +1298,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; } @@ -1339,6 +1364,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/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c2534d62911c..a35c5b932eba 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -136,7 +136,7 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio) */ static int desc_to_gpio(const struct gpio_desc *desc) { - return desc->chip->base + gpio_chip_hwgpio(desc); + return desc - &gpio_desc[0]; } @@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip) } } + spin_unlock_irqrestore(&gpio_lock, flags); + #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&chip->pin_ranges); #endif of_gpiochip_add(chip); -unlock: - spin_unlock_irqrestore(&gpio_lock, flags); - if (status) goto fail; @@ -1235,6 +1234,9 @@ int gpiochip_add(struct gpio_chip *chip) chip->label ? : "generic"); return 0; + +unlock: + spin_unlock_irqrestore(&gpio_lock, flags); fail: /* failures here can mean systems won't boot... */ pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", 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 4602d291c9bc..2df9cdcba0de 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -714,6 +714,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; @@ -754,6 +761,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; @@ -761,6 +769,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; @@ -774,6 +783,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; @@ -782,10 +793,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/of/fdt.c b/drivers/of/fdt.c index 808be06bb67e..99a2f7860255 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -659,36 +659,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)); + /* 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); - /* - * 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 */ + /* 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 6da535db2538..f07d9f2a06f9 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -19,6 +19,14 @@ config ANDROID_BINDER_IPC Android process, using Binder to identify, invoke and pass arguments between said processes. +config ANDROID_BINDER_IPC_32BIT + bool + default y + depends on !64BIT && ANDROID_BINDER_IPC + ---help--- + Enable to support an old 32-bit Android user-space. Breaks the new + Android user-space. + config ASHMEM bool "Enable the Anonymous Shared Memory Subsystem" default n @@ -110,6 +118,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 f8d5b03f5444..d4e529001934 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -229,8 +229,8 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; - void __user *ptr; - void __user *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; unsigned has_strong_ref:1; unsigned pending_strong_ref:1; unsigned has_weak_ref:1; @@ -243,7 +243,7 @@ struct binder_node { struct binder_ref_death { struct binder_work work; - void __user *cookie; + binder_uintptr_t cookie; }; struct binder_ref { @@ -516,14 +516,14 @@ static void binder_insert_allocated_buffer(struct binder_proc *proc, } static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - void __user *user_ptr) + uintptr_t user_ptr) { struct rb_node *n = proc->allocated_buffers.rb_node; struct binder_buffer *buffer; struct binder_buffer *kern_ptr; - kern_ptr = user_ptr - proc->user_buffer_offset - - offsetof(struct binder_buffer, data); + kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset + - offsetof(struct binder_buffer, data)); while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -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 ? @@ -857,7 +857,7 @@ static void binder_free_buf(struct binder_proc *proc, } static struct binder_node *binder_get_node(struct binder_proc *proc, - void __user *ptr) + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; @@ -876,8 +876,8 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, } static struct binder_node *binder_new_node(struct binder_proc *proc, - void __user *ptr, - void __user *cookie) + binder_uintptr_t ptr, + binder_uintptr_t cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; @@ -909,9 +909,9 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p created\n", + "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, - node->ptr, node->cookie); + (u64)node->ptr, (u64)node->cookie); return node; } @@ -1227,9 +1227,9 @@ static void binder_send_failed_reply(struct binder_transaction *t, static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, - size_t *failed_at) + binder_size_t *failed_at) { - size_t *offp, *off_end; + binder_size_t *offp, *off_end; int debug_id = buffer->debug_id; binder_debug(BINDER_DEBUG_TRANSACTION, @@ -1240,7 +1240,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, if (buffer->target_node) binder_dec_node(buffer->target_node, 1, 0); - offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *))); + offp = (binder_size_t *)(buffer->data + + ALIGN(buffer->data_size, sizeof(void *))); if (failed_at) off_end = failed_at; else @@ -1249,9 +1250,9 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, struct flat_binder_object *fp; if (*offp > buffer->data_size - sizeof(*fp) || buffer->data_size < sizeof(*fp) || - !IS_ALIGNED(*offp, sizeof(void *))) { - pr_err("transaction release %d bad offset %zd, size %zd\n", - debug_id, *offp, buffer->data_size); + !IS_ALIGNED(*offp, sizeof(u32))) { + pr_err("transaction release %d bad offset %lld, size %zd\n", + debug_id, (u64)*offp, buffer->data_size); continue; } fp = (struct flat_binder_object *)(buffer->data + *offp); @@ -1260,20 +1261,20 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, case BINDER_TYPE_WEAK_BINDER: { struct binder_node *node = binder_get_node(proc, fp->binder); if (node == NULL) { - pr_err("transaction release %d bad node %p\n", - debug_id, fp->binder); + pr_err("transaction release %d bad node %016llx\n", + debug_id, (u64)fp->binder); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p\n", - node->debug_id, node->ptr); + " node %d u%016llx\n", + node->debug_id, (u64)node->ptr); binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle); if (ref == NULL) { - pr_err("transaction release %d bad handle %ld\n", + pr_err("transaction release %d bad handle %d\n", debug_id, fp->handle); break; } @@ -1285,13 +1286,13 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, case BINDER_TYPE_FD: binder_debug(BINDER_DEBUG_TRANSACTION, - " fd %ld\n", fp->handle); + " fd %d\n", fp->handle); if (failed_at) task_close_fd(proc, fp->handle); break; default: - pr_err("transaction release %d bad object type %lx\n", + pr_err("transaction release %d bad object type %x\n", debug_id, fp->type); break; } @@ -1304,7 +1305,8 @@ static void binder_transaction(struct binder_proc *proc, { struct binder_transaction *t; struct binder_work *tcomplete; - size_t *offp, *off_end; + 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; @@ -1437,18 +1439,20 @@ static void binder_transaction(struct binder_proc *proc, if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_REPLY %d -> %d:%d, data %p-%p size %zd-%zd\n", + "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); else binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_TRANSACTION %d -> %d - node %d, data %p-%p size %zd-%zd\n", + "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; @@ -1477,38 +1481,47 @@ static void binder_transaction(struct binder_proc *proc, if (target_node) binder_inc_node(target_node, 1, 0, NULL); - offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); + offp = (binder_size_t *)(t->buffer->data + + ALIGN(tr->data_size, sizeof(void *))); - if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) + tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { + if (copy_from_user(offp, (const void __user *)(uintptr_t) + tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { - binder_user_error("%d:%d got transaction with invalid offsets size, %zd\n", - proc->pid, thread->pid, tr->offsets_size); + if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { + binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", + proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; 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(void *))) { - binder_user_error("%d:%d got transaction with invalid offset, %zd\n", - proc->pid, thread->pid, *offp); + !IS_ALIGNED(*offp, sizeof(u32))) { + 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: { @@ -1524,10 +1537,10 @@ static void binder_transaction(struct binder_proc *proc, node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { - binder_user_error("%d:%d sending u%p node %d, cookie mismatch %p != %p\n", + binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - fp->binder, node->debug_id, - fp->cookie, node->cookie); + (u64)fp->binder, node->debug_id, + (u64)fp->cookie, (u64)node->cookie); goto err_binder_get_ref_for_node_failed; } if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { @@ -1549,15 +1562,15 @@ static void binder_transaction(struct binder_proc *proc, trace_binder_transaction_node_to_ref(t, node, ref); binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p -> ref %d desc %d\n", - node->debug_id, node->ptr, ref->debug_id, - ref->desc); + " node %d u%016llx -> ref %d desc %d\n", + node->debug_id, (u64)node->ptr, + ref->debug_id, ref->desc); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle); if (ref == NULL) { - binder_user_error("%d:%d got transaction with invalid handle, %ld\n", + binder_user_error("%d:%d got transaction with invalid handle, %d\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; @@ -1577,9 +1590,9 @@ static void binder_transaction(struct binder_proc *proc, binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); trace_binder_transaction_ref_to_node(t, ref); binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d -> node %d u%p\n", + " ref %d desc %d -> node %d u%016llx\n", ref->debug_id, ref->desc, ref->node->debug_id, - ref->node->ptr); + (u64)ref->node->ptr); } else { struct binder_ref *new_ref; new_ref = binder_get_ref_for_node(target_proc, ref->node); @@ -1604,13 +1617,13 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { if (!(in_reply_to->flags & TF_ACCEPT_FDS)) { - binder_user_error("%d:%d got reply with fd, %ld, but target does not allow fds\n", + binder_user_error("%d:%d got reply with fd, %d, but target does not allow fds\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; } } else if (!target_node->accept_fds) { - binder_user_error("%d:%d got transaction with fd, %ld, but target does not allow fds\n", + binder_user_error("%d:%d got transaction with fd, %d, but target does not allow fds\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fd_not_allowed; @@ -1618,7 +1631,7 @@ static void binder_transaction(struct binder_proc *proc, file = fget(fp->handle); if (file == NULL) { - binder_user_error("%d:%d got transaction with invalid fd, %ld\n", + binder_user_error("%d:%d got transaction with invalid fd, %d\n", proc->pid, thread->pid, fp->handle); return_error = BR_FAILED_REPLY; goto err_fget_failed; @@ -1637,13 +1650,13 @@ static void binder_transaction(struct binder_proc *proc, task_fd_install(target_proc, target_fd, file); trace_binder_transaction_fd(t, fp->handle, target_fd); binder_debug(BINDER_DEBUG_TRANSACTION, - " fd %ld -> %d\n", fp->handle, target_fd); + " fd %d -> %d\n", fp->handle, target_fd); /* TODO: fput? */ fp->handle = target_fd; } break; default: - binder_user_error("%d:%d got transaction with invalid object type, %lx\n", + binder_user_error("%d:%d got transaction with invalid object type, %x\n", proc->pid, thread->pid, fp->type); return_error = BR_FAILED_REPLY; goto err_bad_object_type; @@ -1700,9 +1713,9 @@ static void binder_transaction(struct binder_proc *proc, err_invalid_target_handle: err_no_context_mgr_node: binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d, size %zd-%zd\n", + "%d:%d transaction failed %d, size %lld-%lld\n", proc->pid, thread->pid, return_error, - tr->data_size, tr->offsets_size); + (u64)tr->data_size, (u64)tr->offsets_size); { struct binder_transaction_log_entry *fe; @@ -1719,9 +1732,11 @@ static void binder_transaction(struct binder_proc *proc, } int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, int size, signed long *consumed) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed) { uint32_t cmd; + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -1790,33 +1805,33 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { - void __user *node_ptr; - void *cookie; + binder_uintptr_t node_ptr; + binder_uintptr_t cookie; struct binder_node *node; - if (get_user(node_ptr, (void * __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (get_user(cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); if (node == NULL) { - binder_user_error("%d:%d %s u%p no match\n", + binder_user_error("%d:%d %s u%016llx no match\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr); + (u64)node_ptr); break; } if (cookie != node->cookie) { - binder_user_error("%d:%d %s u%p node %d cookie mismatch %p != %p\n", + binder_user_error("%d:%d %s u%016llx node %d cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr, node->debug_id, - cookie, node->cookie); + (u64)node_ptr, node->debug_id, + (u64)cookie, (u64)node->cookie); break; } if (cmd == BC_ACQUIRE_DONE) { @@ -1852,27 +1867,27 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, return -EINVAL; case BC_FREE_BUFFER: { - void __user *data_ptr; + binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user(data_ptr, (void * __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); buffer = binder_buffer_lookup(proc, data_ptr); if (buffer == NULL) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p no match\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, (u64)data_ptr); break; } if (!buffer->allow_user_free) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p matched unreturned buffer\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", + proc->pid, thread->pid, (u64)data_ptr); break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, - "%d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", - proc->pid, thread->pid, data_ptr, buffer->debug_id, + "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n", + proc->pid, thread->pid, (u64)data_ptr, buffer->debug_id, buffer->transaction ? "active" : "finished"); if (buffer->transaction) { @@ -1942,16 +1957,16 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref *ref; struct binder_ref_death *death; if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); ref = binder_get_ref(proc, target); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", @@ -1964,12 +1979,12 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p ref %d desc %d s %d w %d for node %d\n", + "%d:%d %s %016llx ref %d desc %d s %d w %d for node %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", - cookie, ref->debug_id, ref->desc, + (u64)cookie, ref->debug_id, ref->desc, ref->strong, ref->weak, ref->node->debug_id); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { @@ -2007,9 +2022,9 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } death = ref->death; if (death->cookie != cookie) { - binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %p != %p\n", + binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - death->cookie, cookie); + (u64)death->cookie, (u64)cookie); break; } ref->death = NULL; @@ -2029,9 +2044,9 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(void *); @@ -2043,11 +2058,11 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, } } binder_debug(BINDER_DEBUG_DEAD_BINDER, - "%d:%d BC_DEAD_BINDER_DONE %p found %p\n", - proc->pid, thread->pid, cookie, death); + "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", + proc->pid, thread->pid, (u64)cookie, death); if (death == NULL) { - binder_user_error("%d:%d BC_DEAD_BINDER_DONE %p not found\n", - proc->pid, thread->pid, cookie); + binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", + proc->pid, thread->pid, (u64)cookie); break; } @@ -2099,9 +2114,10 @@ static int binder_has_thread_work(struct binder_thread *thread) static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, int size, - signed long *consumed, int non_block) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed, int non_block) { + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -2246,32 +2262,36 @@ static int binder_thread_read(struct binder_proc *proc, if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(node->ptr, (void * __user *)ptr)) + if (put_user(node->ptr, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (put_user(node->cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (put_user(node->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s %d u%p c%p\n", - proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie); + "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, + node->debug_id, + (u64)node->ptr, (u64)node->cookie); } else { list_del_init(&w->entry); if (!weak && !strong) { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p deleted\n", + "%d:%d node %d u%016llx c%016llx deleted\n", proc->pid, thread->pid, node->debug_id, - node->ptr, node->cookie); + (u64)node->ptr, (u64)node->cookie); rb_erase(&node->rb_node, &proc->nodes); kfree(node); binder_stats_deleted(BINDER_STAT_NODE); } else { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p state unchanged\n", - proc->pid, thread->pid, node->debug_id, node->ptr, - node->cookie); + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, node->debug_id, + (u64)node->ptr, (u64)node->cookie); } } } break; @@ -2289,17 +2309,18 @@ static int binder_thread_read(struct binder_proc *proc, if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(death->cookie, (void * __user *)ptr)) + if (put_user(death->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p\n", + "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - death->cookie); + (u64)death->cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { list_del(&w->entry); @@ -2329,8 +2350,8 @@ static int binder_thread_read(struct binder_proc *proc, binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { - tr.target.ptr = NULL; - tr.cookie = NULL; + tr.target.ptr = 0; + tr.cookie = 0; cmd = BR_REPLY; } tr.code = t->code; @@ -2347,8 +2368,9 @@ static int binder_thread_read(struct binder_proc *proc, tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (void *)t->buffer->data + - proc->user_buffer_offset; + tr.data.ptr.buffer = (binder_uintptr_t)( + (uintptr_t)t->buffer->data + + proc->user_buffer_offset); tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); @@ -2363,14 +2385,14 @@ static int binder_thread_read(struct binder_proc *proc, trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %p-%p\n", + "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", t->debug_id, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - tr.data.ptr.buffer, tr.data.ptr.offsets); + (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); list_del(&t->work.entry); t->buffer->allow_user_free = 1; @@ -2440,8 +2462,8 @@ static void binder_release_work(struct list_head *list) death = container_of(w, struct binder_ref_death, work); binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered death notification, %p\n", - death->cookie); + "undelivered death notification, %016llx\n", + (u64)death->cookie); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; @@ -2597,12 +2619,13 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d write %ld at %08lx, read %ld at %08lx\n", - proc->pid, thread->pid, bwr.write_size, - bwr.write_buffer, bwr.read_size, bwr.read_buffer); + "%d:%d write %lld at %016llx, read %lld at %016llx\n", + proc->pid, thread->pid, + (u64)bwr.write_size, (u64)bwr.write_buffer, + (u64)bwr.read_size, (u64)bwr.read_buffer); if (bwr.write_size > 0) { - ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); + ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed); trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; @@ -2612,7 +2635,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } if (bwr.read_size > 0) { - ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); + ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); @@ -2623,9 +2646,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d wrote %ld of %ld, read return %ld of %ld\n", - proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, - bwr.read_consumed, bwr.read_size); + "%d:%d wrote %lld of %lld, read return %lld of %lld\n", + proc->pid, thread->pid, + (u64)bwr.write_consumed, (u64)bwr.write_size, + (u64)bwr.read_consumed, (u64)bwr.read_size); if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto err; @@ -2657,7 +2681,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } else binder_context_mgr_uid = current->cred->euid; - binder_context_mgr_node = binder_new_node(proc, NULL, NULL); + binder_context_mgr_node = binder_new_node(proc, 0, 0); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; @@ -2924,7 +2948,7 @@ static int binder_node_release(struct binder_node *node, int refs) refs++; if (!ref->death) - goto out; + continue; death++; @@ -2937,7 +2961,6 @@ static int binder_node_release(struct binder_node *node, int refs) BUG(); } -out: binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); @@ -3153,8 +3176,9 @@ static void print_binder_work(struct seq_file *m, const char *prefix, break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); - seq_printf(m, "%snode work %d: u%p c%p\n", - prefix, node->debug_id, node->ptr, node->cookie); + seq_printf(m, "%snode work %d: u%016llx c%016llx\n", + prefix, node->debug_id, + (u64)node->ptr, (u64)node->cookie); break; case BINDER_WORK_DEAD_BINDER: seq_printf(m, "%shas dead binder\n", prefix); @@ -3214,8 +3238,8 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", - node->debug_id, node->ptr, node->cookie, + seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + node->debug_id, (u64)node->ptr, (u64)node->cookie, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, node->internal_strong_refs, count); @@ -3517,6 +3541,7 @@ static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, + .compat_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h index d4101a671718..eb0834656dfe 100644 --- a/drivers/staging/android/binder.h +++ b/drivers/staging/android/binder.h @@ -20,6 +20,10 @@ #ifndef _LINUX_BINDER_H #define _LINUX_BINDER_H +#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT +#define BINDER_IPC_32BIT 1 +#endif + #include "uapi/binder.h" #endif /* _LINUX_BINDER_H */ diff --git a/drivers/staging/android/binder_trace.h b/drivers/staging/android/binder_trace.h index 82a567c2af67..7f20f3dc8369 100644 --- a/drivers/staging/android/binder_trace.h +++ b/drivers/staging/android/binder_trace.h @@ -152,7 +152,7 @@ TRACE_EVENT(binder_transaction_node_to_ref, TP_STRUCT__entry( __field(int, debug_id) __field(int, node_debug_id) - __field(void __user *, node_ptr) + __field(binder_uintptr_t, node_ptr) __field(int, ref_debug_id) __field(uint32_t, ref_desc) ), @@ -163,8 +163,9 @@ TRACE_EVENT(binder_transaction_node_to_ref, __entry->ref_debug_id = ref->debug_id; __entry->ref_desc = ref->desc; ), - TP_printk("transaction=%d node=%d src_ptr=0x%p ==> dest_ref=%d dest_desc=%d", - __entry->debug_id, __entry->node_debug_id, __entry->node_ptr, + TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", + __entry->debug_id, __entry->node_debug_id, + (u64)__entry->node_ptr, __entry->ref_debug_id, __entry->ref_desc) ); @@ -177,7 +178,7 @@ TRACE_EVENT(binder_transaction_ref_to_node, __field(int, ref_debug_id) __field(uint32_t, ref_desc) __field(int, node_debug_id) - __field(void __user *, node_ptr) + __field(binder_uintptr_t, node_ptr) ), TP_fast_assign( __entry->debug_id = t->debug_id; @@ -186,9 +187,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, __entry->node_debug_id = ref->node->debug_id; __entry->node_ptr = ref->node->ptr; ), - TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%p", + TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", __entry->debug_id, __entry->node_debug_id, - __entry->ref_debug_id, __entry->ref_desc, __entry->node_ptr) + __entry->ref_debug_id, __entry->ref_desc, + (u64)__entry->node_ptr) ); TRACE_EVENT(binder_transaction_ref_to_ref, 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 similarity index 64% rename from arch/arm/common/fiq_debugger.c rename to drivers/staging/android/fiq_debugger/fiq_debugger.c index 65b943c76300..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 #include -#include +#ifdef CONFIG_FIQ_GLUE #include -#include +#endif #include +#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; @@ -124,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; @@ -135,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; @@ -145,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); @@ -164,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); @@ -173,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); @@ -181,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; @@ -218,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); + fiq_debugger_puts(state, buf); } } -static char *mode_name(unsigned cpsr) +static void fiq_debugger_printf(struct fiq_debugger_output *output, + const char *fmt, ...) { - 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 "???"; - } -} - -static int debug_printf(void *cookie, 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]; @@ -263,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, @@ -380,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; } @@ -559,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]; @@ -585,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" @@ -618,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 Switch to CPU\n"); - debug_printf(state, " ps Process list\n" + fiq_debugger_printf(&state->output, + " ps Process list\n" " sysrq sysrq options\n" " sysrq Execute sysrq with \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; @@ -642,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 == ' ') @@ -677,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 { @@ -714,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; @@ -728,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; @@ -748,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) { @@ -784,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; @@ -794,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; @@ -824,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); @@ -856,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); @@ -897,36 +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; - need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp); + need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs, + svc_sp); if (need_irq) - debug_force_irq(state); + 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; } @@ -936,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; @@ -974,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, }; @@ -1017,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; } @@ -1044,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; } @@ -1065,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 @@ -1224,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; @@ -1237,14 +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); - 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; @@ -1268,21 +1100,25 @@ static int fiq_debugger_probe(struct platform_device *pdev) goto err_uart_init; } - debug_printf_nfiq(state, "\n", + fiq_debugger_printf_nfiq(state, + "\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__); @@ -1299,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) { @@ -1323,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); @@ -1338,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 similarity index 97% rename from arch/arm/include/asm/fiq_debugger.h rename to 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 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 + * + * 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 +#include + +#include + +#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 + * + * 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 +#include + +#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 + * + * 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 similarity index 96% rename from arch/arm/common/fiq_debugger_ringbuf.h rename to 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 +#include +#include + +#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/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index a342d96ee4f0..0f8fec1f84e5 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -1,5 +1,6 @@ menuconfig ION - tristate "Ion Memory Manager" + bool "Ion Memory Manager" + depends on HAVE_MEMBLOCK select GENERIC_ALLOCATOR select DMA_SHARED_BUFFER ---help--- @@ -16,6 +17,16 @@ config ION_TEST Choose this option to create a device that can be used to test the kernel and device side ION functions. +config ION_DUMMY + bool "Dummy Ion driver" + depends on ION + help + Provides a dummy ION driver that registers the + /dev/ion device and some basic heaps. This can + be used for testing the ION infrastructure if + one doesn't have access to hardware drivers that + use ION. + config ION_TEGRA tristate "Ion for Tegra" depends on ARCH_TEGRA && ION diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index 75039b98eebb..b56fd2bf2b4f 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -4,4 +4,7 @@ obj-$(CONFIG_ION_TEST) += ion_test.o ifdef CONFIG_COMPAT obj-$(CONFIG_ION) += compat_ion.o endif + +obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o obj-$(CONFIG_ION_TEGRA) += tegra/ + diff --git a/drivers/staging/android/ion/compat_ion.c b/drivers/staging/android/ion/compat_ion.c index e9a8132cd56f..a5e8c408fd78 100644 --- a/drivers/staging/android/ion/compat_ion.c +++ b/drivers/staging/android/ion/compat_ion.c @@ -35,9 +35,14 @@ struct compat_ion_custom_data { compat_ulong_t arg; }; +struct compat_ion_handle_data { + compat_int_t handle; +}; + #define COMPAT_ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ struct compat_ion_allocation_data) -#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) +#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, \ + struct compat_ion_handle_data) #define COMPAT_ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, \ struct compat_ion_custom_data) @@ -64,6 +69,19 @@ static int compat_get_ion_allocation_data( return err; } +static int compat_get_ion_handle_data( + struct compat_ion_handle_data __user *data32, + struct ion_handle_data __user *data) +{ + compat_int_t i; + int err; + + err = get_user(i, &data32->handle); + err |= put_user(i, &data->handle); + + return err; +} + static int compat_put_ion_allocation_data( struct compat_ion_allocation_data __user *data32, struct ion_allocation_data __user *data) @@ -132,8 +150,8 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } case COMPAT_ION_IOC_FREE: { - struct compat_ion_allocation_data __user *data32; - struct ion_allocation_data __user *data; + struct compat_ion_handle_data __user *data32; + struct ion_handle_data __user *data; int err; data32 = compat_ptr(arg); @@ -141,7 +159,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (data == NULL) return -EFAULT; - err = compat_get_ion_allocation_data(data32, data); + err = compat_get_ion_handle_data(data32, data); if (err) return err; diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 7522b0be1749..48774e3974aa 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -59,6 +59,8 @@ struct ion_device { unsigned long arg); struct rb_root clients; struct dentry *debug_root; + struct dentry *heaps_debug_root; + struct dentry *clients_debug_root; }; /** @@ -69,6 +71,8 @@ struct ion_device { * @idr: an idr space for allocating handle ids * @lock: lock protecting the tree of handles * @name: used for debugging + * @display_name: used for debugging (unique version of @name) + * @display_serial: used for debugging (to make display_name unique) * @task: used for debugging * * A client represents a list of buffers this client may access. @@ -82,6 +86,8 @@ struct ion_client { struct idr idr; struct mutex lock; const char *name; + char *display_name; + int display_serial; struct task_struct *task; pid_t pid; struct dentry *debug_root; @@ -708,6 +714,21 @@ static const struct file_operations debug_client_fops = { .release = single_release, }; +static int ion_get_client_serial(const struct rb_root *root, + const unsigned char *name) +{ + int serial = -1; + struct rb_node *node; + for (node = rb_first(root); node; node = rb_next(node)) { + struct ion_client *client = rb_entry(node, struct ion_client, + node); + if (strcmp(client->name, name)) + continue; + serial = max(serial, client->display_serial); + } + return serial + 1; +} + struct ion_client *ion_client_create(struct ion_device *dev, const char *name) { @@ -716,9 +737,13 @@ struct ion_client *ion_client_create(struct ion_device *dev, struct rb_node **p; struct rb_node *parent = NULL; struct ion_client *entry; - char debug_name[64]; pid_t pid; + if (!name) { + pr_err("%s: Name cannot be null\n", __func__); + return ERR_PTR(-EINVAL); + } + get_task_struct(current->group_leader); task_lock(current->group_leader); pid = task_pid_nr(current->group_leader); @@ -733,21 +758,27 @@ struct ion_client *ion_client_create(struct ion_device *dev, task_unlock(current->group_leader); client = kzalloc(sizeof(struct ion_client), GFP_KERNEL); - if (!client) { - if (task) - put_task_struct(current->group_leader); - return ERR_PTR(-ENOMEM); - } + if (!client) + goto err_put_task_struct; client->dev = dev; client->handles = RB_ROOT; idr_init(&client->idr); mutex_init(&client->lock); - client->name = name; client->task = task; client->pid = pid; + client->name = kstrdup(name, GFP_KERNEL); + if (!client->name) + goto err_free_client; down_write(&dev->lock); + client->display_serial = ion_get_client_serial(&dev->clients, name); + client->display_name = kasprintf( + GFP_KERNEL, "%s-%d", name, client->display_serial); + if (!client->display_name) { + up_write(&dev->lock); + goto err_free_client_name; + } p = &dev->clients.rb_node; while (*p) { parent = *p; @@ -761,13 +792,28 @@ struct ion_client *ion_client_create(struct ion_device *dev, rb_link_node(&client->node, parent, p); rb_insert_color(&client->node, &dev->clients); - snprintf(debug_name, 64, "%u", client->pid); - client->debug_root = debugfs_create_file(debug_name, 0664, - dev->debug_root, client, - &debug_client_fops); + client->debug_root = debugfs_create_file(client->display_name, 0664, + dev->clients_debug_root, + client, &debug_client_fops); + if (!client->debug_root) { + char buf[256], *path; + path = dentry_path(dev->clients_debug_root, buf, 256); + pr_err("Failed to create client debugfs at %s/%s\n", + path, client->display_name); + } + up_write(&dev->lock); return client; + +err_free_client_name: + kfree(client->name); +err_free_client: + kfree(client); +err_put_task_struct: + if (task) + put_task_struct(current->group_leader); + return ERR_PTR(-ENOMEM); } EXPORT_SYMBOL(ion_client_create); @@ -792,6 +838,8 @@ void ion_client_destroy(struct ion_client *client) debugfs_remove_recursive(client->debug_root); up_write(&dev->lock); + kfree(client->display_name); + kfree(client->name); kfree(client); } EXPORT_SYMBOL(ion_client_destroy); @@ -1293,9 +1341,11 @@ static int ion_open(struct inode *inode, struct file *file) struct miscdevice *miscdev = file->private_data; struct ion_device *dev = container_of(miscdev, struct ion_device, dev); struct ion_client *client; + char debug_name[64]; pr_debug("%s: %d\n", __func__, __LINE__); - client = ion_client_create(dev, "user"); + snprintf(debug_name, 64, "%u", task_pid_nr(current->group_leader)); + client = ion_client_create(dev, debug_name); if (IS_ERR(client)) return PTR_ERR(client); file->private_data = client; @@ -1443,6 +1493,8 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get, void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) { + struct dentry *debug_file; + if (!heap->ops->allocate || !heap->ops->free || !heap->ops->map_dma || !heap->ops->unmap_dma) pr_err("%s: can not add heap with invalid ops struct.\n", @@ -1451,21 +1503,40 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) ion_heap_init_deferred_free(heap); + if ((heap->flags & ION_HEAP_FLAG_DEFER_FREE) || heap->ops->shrink) + ion_heap_init_shrinker(heap); + heap->dev = dev; down_write(&dev->lock); /* use negative heap->id to reverse the priority -- when traversing the list later attempt higher id numbers first */ plist_node_init(&heap->node, -heap->id); plist_add(&heap->node, &dev->heaps); - debugfs_create_file(heap->name, 0664, dev->debug_root, heap, - &debug_heap_fops); + debug_file = debugfs_create_file(heap->name, 0664, + dev->heaps_debug_root, heap, + &debug_heap_fops); + + if (!debug_file) { + char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); + pr_err("Failed to create heap debugfs at %s/%s\n", + path, heap->name); + } + #ifdef DEBUG_HEAP_SHRINKER if (heap->shrinker.shrink) { char debug_name[64]; snprintf(debug_name, 64, "%s_shrink", heap->name); - debugfs_create_file(debug_name, 0644, dev->debug_root, heap, - &debug_shrink_fops); + debug_file = debugfs_create_file( + debug_name, 0644, dev->heaps_debug_root, heap, + &debug_shrink_fops); + if (!debug_file) { + char buf[256], *path; + path = dentry_path(dev->heaps_debug_root, buf, 256); + pr_err("Failed to create heap shrinker debugfs at %s/%s\n", + path, debug_name); + } } #endif up_write(&dev->lock); @@ -1494,8 +1565,21 @@ struct ion_device *ion_device_create(long (*custom_ioctl) } idev->debug_root = debugfs_create_dir("ion", NULL); - if (!idev->debug_root) - pr_err("ion: failed to create debug files.\n"); + if (!idev->debug_root) { + pr_err("ion: failed to create debugfs root directory.\n"); + goto debugfs_done; + } + idev->heaps_debug_root = debugfs_create_dir("heaps", idev->debug_root); + if (!idev->heaps_debug_root) { + pr_err("ion: failed to create debugfs heaps directory.\n"); + goto debugfs_done; + } + idev->clients_debug_root = debugfs_create_dir("clients", + idev->debug_root); + if (!idev->clients_debug_root) + pr_err("ion: failed to create debugfs clients directory.\n"); + +debugfs_done: idev->custom_ioctl = custom_ioctl; idev->buffers = RB_ROOT; @@ -1509,6 +1593,7 @@ struct ion_device *ion_device_create(long (*custom_ioctl) void ion_device_destroy(struct ion_device *dev) { misc_deregister(&dev->dev); + debugfs_remove_recursive(dev->debug_root); /* XXX need to free the heaps and clients ? */ kfree(dev); } diff --git a/drivers/staging/android/ion/ion_dummy_driver.c b/drivers/staging/android/ion/ion_dummy_driver.c new file mode 100644 index 000000000000..55b2002753f2 --- /dev/null +++ b/drivers/staging/android/ion/ion_dummy_driver.c @@ -0,0 +1,158 @@ +/* + * drivers/gpu/ion/ion_dummy_driver.c + * + * Copyright (C) 2013 Linaro, 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 +#include +#include +#include +#include +#include +#include "ion.h" +#include "ion_priv.h" + +struct ion_device *idev; +struct ion_heap **heaps; + +void *carveout_ptr; +void *chunk_ptr; + +struct ion_platform_heap dummy_heaps[] = { + { + .id = ION_HEAP_TYPE_SYSTEM, + .type = ION_HEAP_TYPE_SYSTEM, + .name = "system", + }, + { + .id = ION_HEAP_TYPE_SYSTEM_CONTIG, + .type = ION_HEAP_TYPE_SYSTEM_CONTIG, + .name = "system contig", + }, + { + .id = ION_HEAP_TYPE_CARVEOUT, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = "carveout", + .size = SZ_4M, + }, + { + .id = ION_HEAP_TYPE_CHUNK, + .type = ION_HEAP_TYPE_CHUNK, + .name = "chunk", + .size = SZ_4M, + .align = SZ_16K, + .priv = (void *)(SZ_16K), + }, +}; + +struct ion_platform_data dummy_ion_pdata = { + .nr = 4, + .heaps = dummy_heaps, +}; + +static int __init ion_dummy_init(void) +{ + int i, err; + + idev = ion_device_create(NULL); + heaps = kzalloc(sizeof(struct ion_heap *) * dummy_ion_pdata.nr, + GFP_KERNEL); + if (!heaps) + return PTR_ERR(heaps); + + + /* Allocate a dummy carveout heap */ + carveout_ptr = alloc_pages_exact( + dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size, + GFP_KERNEL); + if (carveout_ptr) + dummy_heaps[ION_HEAP_TYPE_CARVEOUT].base = + virt_to_phys(carveout_ptr); + else + pr_err("ion_dummy: Could not allocate carveout\n"); + + /* Allocate a dummy chunk heap */ + chunk_ptr = alloc_pages_exact( + dummy_heaps[ION_HEAP_TYPE_CHUNK].size, + GFP_KERNEL); + if (chunk_ptr) + dummy_heaps[ION_HEAP_TYPE_CHUNK].base = virt_to_phys(chunk_ptr); + else + pr_err("ion_dummy: Could not allocate chunk\n"); + + for (i = 0; i < dummy_ion_pdata.nr; i++) { + struct ion_platform_heap *heap_data = &dummy_ion_pdata.heaps[i]; + + if (heap_data->type == ION_HEAP_TYPE_CARVEOUT && + !heap_data->base) + continue; + + if (heap_data->type == ION_HEAP_TYPE_CHUNK && !heap_data->base) + continue; + + heaps[i] = ion_heap_create(heap_data); + if (IS_ERR_OR_NULL(heaps[i])) { + err = PTR_ERR(heaps[i]); + goto err; + } + ion_device_add_heap(idev, heaps[i]); + } + return 0; +err: + for (i = 0; i < dummy_ion_pdata.nr; i++) { + if (heaps[i]) + ion_heap_destroy(heaps[i]); + } + kfree(heaps); + + if (carveout_ptr) { + free_pages_exact(carveout_ptr, + dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size); + carveout_ptr = NULL; + } + if (chunk_ptr) { + free_pages_exact(chunk_ptr, + dummy_heaps[ION_HEAP_TYPE_CHUNK].size); + chunk_ptr = NULL; + } + return err; +} + +static void __exit ion_dummy_exit(void) +{ + int i; + + ion_device_destroy(idev); + + for (i = 0; i < dummy_ion_pdata.nr; i++) + ion_heap_destroy(heaps[i]); + kfree(heaps); + + if (carveout_ptr) { + free_pages_exact(carveout_ptr, + dummy_heaps[ION_HEAP_TYPE_CARVEOUT].size); + carveout_ptr = NULL; + } + if (chunk_ptr) { + free_pages_exact(chunk_ptr, + dummy_heaps[ION_HEAP_TYPE_CHUNK].size); + chunk_ptr = NULL; + } + + return; +} + +module_init(ion_dummy_init); +module_exit(ion_dummy_exit); + diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 5b01e9e30a4f..750b76af0cf3 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -160,10 +160,10 @@ int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot) void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer) { - rt_mutex_lock(&heap->lock); + spin_lock(&heap->free_lock); list_add(&buffer->list, &heap->free_list); heap->free_list_size += buffer->size; - rt_mutex_unlock(&heap->lock); + spin_unlock(&heap->free_lock); wake_up(&heap->waitqueue); } @@ -171,38 +171,55 @@ size_t ion_heap_freelist_size(struct ion_heap *heap) { size_t size; - rt_mutex_lock(&heap->lock); + spin_lock(&heap->free_lock); size = heap->free_list_size; - rt_mutex_unlock(&heap->lock); + spin_unlock(&heap->free_lock); return size; } -size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) +static size_t _ion_heap_freelist_drain(struct ion_heap *heap, size_t size, + bool skip_pools) { - struct ion_buffer *buffer, *tmp; + struct ion_buffer *buffer; size_t total_drained = 0; if (ion_heap_freelist_size(heap) == 0) return 0; - rt_mutex_lock(&heap->lock); + spin_lock(&heap->free_lock); if (size == 0) size = heap->free_list_size; - list_for_each_entry_safe(buffer, tmp, &heap->free_list, list) { + while (!list_empty(&heap->free_list)) { if (total_drained >= size) break; + buffer = list_first_entry(&heap->free_list, struct ion_buffer, + list); list_del(&buffer->list); heap->free_list_size -= buffer->size; + if (skip_pools) + buffer->private_flags |= ION_PRIV_FLAG_SHRINKER_FREE; total_drained += buffer->size; + spin_unlock(&heap->free_lock); ion_buffer_destroy(buffer); + spin_lock(&heap->free_lock); } - rt_mutex_unlock(&heap->lock); + spin_unlock(&heap->free_lock); return total_drained; } +size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size) +{ + return _ion_heap_freelist_drain(heap, size, false); +} + +size_t ion_heap_freelist_shrink(struct ion_heap *heap, size_t size) +{ + return _ion_heap_freelist_drain(heap, size, true); +} + static int ion_heap_deferred_free(void *data) { struct ion_heap *heap = data; @@ -213,16 +230,16 @@ static int ion_heap_deferred_free(void *data) wait_event_freezable(heap->waitqueue, ion_heap_freelist_size(heap) > 0); - rt_mutex_lock(&heap->lock); + spin_lock(&heap->free_lock); if (list_empty(&heap->free_list)) { - rt_mutex_unlock(&heap->lock); + spin_unlock(&heap->free_lock); continue; } buffer = list_first_entry(&heap->free_list, struct ion_buffer, list); list_del(&buffer->list); heap->free_list_size -= buffer->size; - rt_mutex_unlock(&heap->lock); + spin_unlock(&heap->free_lock); ion_buffer_destroy(buffer); } @@ -235,7 +252,7 @@ int ion_heap_init_deferred_free(struct ion_heap *heap) INIT_LIST_HEAD(&heap->free_list); heap->free_list_size = 0; - rt_mutex_init(&heap->lock); + spin_lock_init(&heap->free_lock); init_waitqueue_head(&heap->waitqueue); heap->task = kthread_run(ion_heap_deferred_free, heap, "%s", heap->name); @@ -248,6 +265,44 @@ int ion_heap_init_deferred_free(struct ion_heap *heap) return 0; } +static int ion_heap_shrink(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct ion_heap *heap = container_of(shrinker, struct ion_heap, + shrinker); + int total = 0; + int freed = 0; + int to_scan = sc->nr_to_scan; + + if (to_scan == 0) + goto out; + + /* + * shrink the free list first, no point in zeroing the memory if we're + * just going to reclaim it. Also, skip any possible page pooling. + */ + if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) + freed = ion_heap_freelist_shrink(heap, to_scan * PAGE_SIZE) / + PAGE_SIZE; + + to_scan -= freed; + if (to_scan < 0) + to_scan = 0; + +out: + total = ion_heap_freelist_size(heap) / PAGE_SIZE; + if (heap->ops->shrink) + total += heap->ops->shrink(heap, sc->gfp_mask, to_scan); + return total; +} + +void ion_heap_init_shrinker(struct ion_heap *heap) +{ + heap->shrinker.shrink = ion_heap_shrink; + heap->shrinker.seeks = DEFAULT_SEEKS; + heap->shrinker.batch = 0; + register_shrinker(&heap->shrinker); +} + struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) { struct ion_heap *heap = NULL; diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index f087a02770a8..0e20e62ec4bc 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -130,15 +130,11 @@ static int ion_page_pool_total(struct ion_page_pool *pool, bool high) int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, int nr_to_scan) { - int nr_freed = 0; int i; bool high; high = !!(gfp_mask & __GFP_HIGHMEM); - if (nr_to_scan == 0) - return ion_page_pool_total(pool, high); - for (i = 0; i < nr_to_scan; i++) { struct page *page; @@ -153,10 +149,9 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, } mutex_unlock(&pool->mutex); ion_page_pool_free_pages(pool, page); - nr_freed += (1 << pool->order); } - return nr_freed; + return ion_page_pool_total(pool, high); } struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 19691c0d24c7..9bcd077f251c 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -17,6 +17,7 @@ #ifndef _ION_PRIV_H #define _ION_PRIV_H +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include "ion.h" @@ -37,6 +39,7 @@ struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); * @dev: back pointer to the ion_device * @heap: back pointer to the heap the buffer came from * @flags: buffer specific flags + * @private_flags: internal buffer specific flags * @size: size of the buffer * @priv_virt: private data to the buffer representable as * a void * @@ -65,6 +68,7 @@ struct ion_buffer { struct ion_device *dev; struct ion_heap *heap; unsigned long flags; + unsigned long private_flags; size_t size; union { void *priv_virt; @@ -97,7 +101,11 @@ void ion_buffer_destroy(struct ion_buffer *buffer); * @map_user map memory to userspace * * allocate, phys, and map_user return 0 on success, -errno on error. - * map_dma and map_kernel return pointer on success, ERR_PTR on error. + * map_dma and map_kernel return pointer on success, ERR_PTR on + * error. @free will be called with ION_PRIV_FLAG_SHRINKER_FREE set in + * the buffer's private_flags when called from a shrinker. In that + * case, the pages being free'd must be truly free'd back to the + * system, not put in a page pool or otherwise cached. */ struct ion_heap_ops { int (*allocate) (struct ion_heap *heap, @@ -113,6 +121,7 @@ struct ion_heap_ops { void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer); int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer, struct vm_area_struct *vma); + int (*shrink)(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan); }; /** @@ -120,6 +129,17 @@ struct ion_heap_ops { */ #define ION_HEAP_FLAG_DEFER_FREE (1 << 0) +/** + * private flags - flags internal to ion + */ +/* + * Buffer is being freed from a shrinker function. Skip any possible + * heap-specific caching mechanism (e.g. page pools). Guarantees that + * any buffer storage that came from the system allocator will be + * returned to the system allocator. + */ +#define ION_PRIV_FLAG_SHRINKER_FREE (1 << 0) + /** * struct ion_heap - represents a heap in the system * @node: rb node to put the heap on the device's tree of heaps @@ -131,10 +151,7 @@ struct ion_heap_ops { * allocating. These are specified by platform data and * MUST be unique * @name: used for debugging - * @shrinker: a shrinker for the heap, if the heap caches system - * memory, it must define a shrinker to return it on low - * memory conditions, this includes system memory cached - * in the deferred free lists for heaps that support it + * @shrinker: a shrinker for the heap * @free_list: free list head if deferred free is used * @free_list_size size of the deferred free list in bytes * @lock: protects the free list @@ -159,7 +176,7 @@ struct ion_heap { struct shrinker shrinker; struct list_head free_list; size_t free_list_size; - struct rt_mutex lock; + spinlock_t free_lock; wait_queue_head_t waitqueue; struct task_struct *task; int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); @@ -217,6 +234,16 @@ int ion_heap_map_user(struct ion_heap *, struct ion_buffer *, int ion_heap_buffer_zero(struct ion_buffer *buffer); int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot); +/** + * ion_heap_init_shrinker + * @heap: the heap + * + * If a heap sets the ION_HEAP_FLAG_DEFER_FREE flag or defines the shrink op + * this function will be called to setup a shrinker to shrink the freelists + * and call the heap's shrink op. + */ +void ion_heap_init_shrinker(struct ion_heap *heap); + /** * ion_heap_init_deferred_free -- initialize deferred free functionality * @heap: the heap @@ -248,6 +275,29 @@ void ion_heap_freelist_add(struct ion_heap *heap, struct ion_buffer *buffer); */ size_t ion_heap_freelist_drain(struct ion_heap *heap, size_t size); +/** + * ion_heap_freelist_shrink - drain the deferred free + * list, skipping any heap-specific + * pooling or caching mechanisms + * + * @heap: the heap + * @size: amount of memory to drain in bytes + * + * Drains the indicated amount of memory from the deferred freelist immediately. + * Returns the total amount freed. The total freed may be higher depending + * on the size of the items in the list, or lower if there is insufficient + * total memory on the freelist. + * + * Unlike with @ion_heap_freelist_drain, don't put any pages back into + * page pools or otherwise cache the pages. Everything must be + * genuinely free'd back to the system. If you're free'ing from a + * shrinker you probably want to use this. Note that this relies on + * the heap.ops.free callback honoring the ION_PRIV_FLAG_SHRINKER_FREE + * flag. + */ +size_t ion_heap_freelist_shrink(struct ion_heap *heap, + size_t size); + /** * ion_heap_freelist_size - returns the size of the freelist in bytes * @heap: the heap @@ -304,13 +354,8 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, * @low_count: number of lowmem items in the pool * @high_items: list of highmem items * @low_items: list of lowmem items - * @shrinker: a shrinker for the items * @mutex: lock protecting this struct and especially the count * item list - * @alloc: function to be used to allocate pageory when the pool - * is empty - * @free: function to be used to free pageory back to the system - * when the shrinker fires * @gfp_mask: gfp_mask to use from alloc * @order: order of pages in the pool * @list: plist node for list of pools diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 05e9dc93980f..a052418d2efc 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -90,7 +90,7 @@ static void free_buffer_page(struct ion_system_heap *heap, { bool cached = ion_buffer_cached(buffer); - if (!cached) { + if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) { struct ion_page_pool *pool = heap->pools[order_to_index(order)]; ion_page_pool_free(pool, page); } else { @@ -108,6 +108,10 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap, struct page_info *info; int i; + info = kmalloc(sizeof(struct page_info), GFP_KERNEL); + if (!info) + return NULL; + for (i = 0; i < num_orders; i++) { if (size < order_to_size(orders[i])) continue; @@ -118,11 +122,13 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap, if (!page) continue; - info = kmalloc(sizeof(struct page_info), GFP_KERNEL); info->page = page; info->order = orders[i]; + INIT_LIST_HEAD(&info->list); return info; } + kfree(info); + return NULL; } @@ -140,12 +146,15 @@ static int ion_system_heap_allocate(struct ion_heap *heap, struct list_head pages; struct page_info *info, *tmp_info; int i = 0; - long size_remaining = PAGE_ALIGN(size); + unsigned long size_remaining = PAGE_ALIGN(size); unsigned int max_order = orders[0]; if (align > PAGE_SIZE) return -EINVAL; + if (size / PAGE_SIZE > totalram_pages / 2) + return -ENOMEM; + INIT_LIST_HEAD(&pages); while (size_remaining > 0) { info = alloc_largest_available(sys_heap, buffer, size_remaining, @@ -200,7 +209,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer) /* uncached pages come from the page pools, zero them before returning for security purposes (other allocations are zerod at alloc time */ - if (!cached) + if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) ion_heap_buffer_zero(buffer); for_each_sg(table->sgl, sg, table->nents, i) @@ -222,6 +231,23 @@ static void ion_system_heap_unmap_dma(struct ion_heap *heap, return; } +static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, + int nr_to_scan) +{ + struct ion_system_heap *sys_heap; + int nr_total = 0; + int i; + + sys_heap = container_of(heap, struct ion_system_heap, heap); + + for (i = 0; i < num_orders; i++) { + struct ion_page_pool *pool = sys_heap->pools[i]; + nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); + } + + return nr_total; +} + static struct ion_heap_ops system_heap_ops = { .allocate = ion_system_heap_allocate, .free = ion_system_heap_free, @@ -230,52 +256,9 @@ static struct ion_heap_ops system_heap_ops = { .map_kernel = ion_heap_map_kernel, .unmap_kernel = ion_heap_unmap_kernel, .map_user = ion_heap_map_user, + .shrink = ion_system_heap_shrink, }; -static int ion_system_heap_shrink(struct shrinker *shrinker, - struct shrink_control *sc) { - - struct ion_heap *heap = container_of(shrinker, struct ion_heap, - shrinker); - struct ion_system_heap *sys_heap = container_of(heap, - struct ion_system_heap, - heap); - int nr_total = 0; - int nr_freed = 0; - int i; - - if (sc->nr_to_scan == 0) - goto end; - - /* shrink the free list first, no point in zeroing the memory if - we're just going to reclaim it */ - nr_freed += ion_heap_freelist_drain(heap, sc->nr_to_scan * PAGE_SIZE) / - PAGE_SIZE; - - if (nr_freed >= sc->nr_to_scan) - goto end; - - for (i = 0; i < num_orders; i++) { - struct ion_page_pool *pool = sys_heap->pools[i]; - - nr_freed += ion_page_pool_shrink(pool, sc->gfp_mask, - sc->nr_to_scan); - if (nr_freed >= sc->nr_to_scan) - break; - } - -end: - /* total number of items is whatever the page pools are holding - plus whatever's in the freelist */ - for (i = 0; i < num_orders; i++) { - struct ion_page_pool *pool = sys_heap->pools[i]; - nr_total += ion_page_pool_shrink(pool, sc->gfp_mask, 0); - } - nr_total += ion_heap_freelist_size(heap) / PAGE_SIZE; - return nr_total; - -} - static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, void *unused) { @@ -323,10 +306,6 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) heap->pools[i] = pool; } - heap->heap.shrinker.shrink = ion_system_heap_shrink; - heap->heap.shrinker.seeks = DEFAULT_SEEKS; - heap->heap.shrinker.batch = 0; - register_shrinker(&heap->heap.shrinker); heap->heap.debug_show = ion_system_heap_debug_show; return &heap->heap; err_create_pool: diff --git a/drivers/staging/android/ion/ion_test.c b/drivers/staging/android/ion/ion_test.c index 3e20349baf7c..654acb5c8eba 100644 --- a/drivers/staging/android/ion/ion_test.c +++ b/drivers/staging/android/ion/ion_test.c @@ -231,6 +231,7 @@ static int ion_test_release(struct inode *inode, struct file *file) static const struct file_operations ion_test_fops = { .owner = THIS_MODULE, .unlocked_ioctl = ion_test_ioctl, + .compat_ioctl = ion_test_ioctl, .open = ion_test_open, .release = ion_test_release, }; diff --git a/drivers/staging/android/ion/tegra/tegra_ion.c b/drivers/staging/android/ion/tegra/tegra_ion.c index 0849600bcc00..3474c65f87fa 100644 --- a/drivers/staging/android/ion/tegra/tegra_ion.c +++ b/drivers/staging/android/ion/tegra/tegra_ion.c @@ -20,12 +20,11 @@ #include "../ion.h" #include "../ion_priv.h" -struct ion_device *idev; -struct ion_mapper *tegra_user_mapper; -int num_heaps; -struct ion_heap **heaps; +static struct ion_device *idev; +static int num_heaps; +static struct ion_heap **heaps; -int tegra_ion_probe(struct platform_device *pdev) +static int tegra_ion_probe(struct platform_device *pdev) { struct ion_platform_data *pdata = pdev->dev.platform_data; int err; @@ -63,7 +62,7 @@ int tegra_ion_probe(struct platform_device *pdev) return err; } -int tegra_ion_remove(struct platform_device *pdev) +static int tegra_ion_remove(struct platform_device *pdev) { struct ion_device *idev = platform_get_drvdata(pdev); int i; @@ -81,16 +80,5 @@ static struct platform_driver ion_driver = { .driver = { .name = "ion-tegra" } }; -static int __init ion_init(void) -{ - return platform_driver_register(&ion_driver); -} - -static void __exit ion_exit(void) -{ - platform_driver_unregister(&ion_driver); -} - -module_init(ion_init); -module_exit(ion_exit); +module_platform_driver(ion_driver); diff --git a/drivers/staging/android/uapi/binder.h b/drivers/staging/android/uapi/binder.h index b6cb483592ca..4098c502fc36 100644 --- a/drivers/staging/android/uapi/binder.h +++ b/drivers/staging/android/uapi/binder.h @@ -39,6 +39,14 @@ enum { FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, }; +#ifdef BINDER_IPC_32BIT +typedef __u32 binder_size_t; +typedef __u32 binder_uintptr_t; +#else +typedef __u64 binder_size_t; +typedef __u64 binder_uintptr_t; +#endif + /* * This is the flattened representation of a Binder object for transfer * between processes. The 'offsets' supplied as part of a binder transaction @@ -48,17 +56,17 @@ enum { */ struct flat_binder_object { /* 8 bytes for large_flat_header. */ - unsigned long type; - unsigned long flags; + __u32 type; + __u32 flags; /* 8 bytes of data. */ union { - void __user *binder; /* local object */ - signed long handle; /* remote object */ + binder_uintptr_t binder; /* local object */ + __u32 handle; /* remote object */ }; /* extra data associated with local object */ - void __user *cookie; + binder_uintptr_t cookie; }; /* @@ -67,26 +75,30 @@ struct flat_binder_object { */ struct binder_write_read { - signed long write_size; /* bytes to write */ - signed long write_consumed; /* bytes consumed by driver */ - unsigned long write_buffer; - signed long read_size; /* bytes to read */ - signed long read_consumed; /* bytes consumed by driver */ - unsigned long read_buffer; + binder_size_t write_size; /* bytes to write */ + binder_size_t write_consumed; /* bytes consumed by driver */ + binder_uintptr_t write_buffer; + binder_size_t read_size; /* bytes to read */ + binder_size_t read_consumed; /* bytes consumed by driver */ + binder_uintptr_t read_buffer; }; /* Use with BINDER_VERSION, driver fills in fields. */ struct binder_version { /* driver protocol version -- increment with incompatible change */ - signed long protocol_version; + __s32 protocol_version; }; /* This is the current protocol version. */ +#ifdef BINDER_IPC_32BIT #define BINDER_CURRENT_PROTOCOL_VERSION 7 +#else +#define BINDER_CURRENT_PROTOCOL_VERSION 8 +#endif #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) -#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t) +#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) #define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32) #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) @@ -119,18 +131,18 @@ struct binder_transaction_data { * identifying the target and contents of the transaction. */ union { - size_t handle; /* target descriptor of command transaction */ - void *ptr; /* target descriptor of return transaction */ + __u32 handle; /* target descriptor of command transaction */ + binder_uintptr_t ptr; /* target descriptor of return transaction */ } target; - void *cookie; /* target object cookie */ - unsigned int code; /* transaction command */ + binder_uintptr_t cookie; /* target object cookie */ + __u32 code; /* transaction command */ /* General information about the transaction. */ - unsigned int flags; + __u32 flags; pid_t sender_pid; uid_t sender_euid; - size_t data_size; /* number of bytes of data */ - size_t offsets_size; /* number of bytes of offsets */ + binder_size_t data_size; /* number of bytes of data */ + binder_size_t offsets_size; /* number of bytes of offsets */ /* If this transaction is inline, the data immediately * follows here; otherwise, it ends with a pointer to @@ -139,32 +151,37 @@ struct binder_transaction_data { union { struct { /* transaction data */ - const void __user *buffer; + binder_uintptr_t buffer; /* offsets from buffer to flat_binder_object structs */ - const void __user *offsets; + binder_uintptr_t offsets; } ptr; - uint8_t buf[8]; + __u8 buf[8]; } data; }; struct binder_ptr_cookie { - void *ptr; - void *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; }; +struct binder_handle_cookie { + __u32 handle; + binder_uintptr_t cookie; +} __attribute__((packed)); + struct binder_pri_desc { - int priority; - int desc; + __s32 priority; + __u32 desc; }; struct binder_pri_ptr_cookie { - int priority; - void *ptr; - void *cookie; + __s32 priority; + binder_uintptr_t ptr; + binder_uintptr_t cookie; }; enum binder_driver_return_protocol { - BR_ERROR = _IOR('r', 0, int), + BR_ERROR = _IOR('r', 0, __s32), /* * int: error code */ @@ -178,7 +195,7 @@ enum binder_driver_return_protocol { * binder_transaction_data: the received command. */ - BR_ACQUIRE_RESULT = _IOR('r', 4, int), + BR_ACQUIRE_RESULT = _IOR('r', 4, __s32), /* * not currently supported * int: 0 if the last bcATTEMPT_ACQUIRE was not successful. @@ -235,11 +252,11 @@ enum binder_driver_return_protocol { * stop threadpool thread */ - BR_DEAD_BINDER = _IOR('r', 15, void *), + BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t), /* * void *: cookie */ - BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *), + BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t), /* * void *: cookie */ @@ -258,22 +275,22 @@ enum binder_driver_command_protocol { * binder_transaction_data: the sent command. */ - BC_ACQUIRE_RESULT = _IOW('c', 2, int), + BC_ACQUIRE_RESULT = _IOW('c', 2, __s32), /* * not currently supported * int: 0 if the last BR_ATTEMPT_ACQUIRE was not successful. * Else you have acquired a primary reference on the object. */ - BC_FREE_BUFFER = _IOW('c', 3, int), + BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t), /* * void *: ptr to transaction data received on a read */ - BC_INCREFS = _IOW('c', 4, int), - BC_ACQUIRE = _IOW('c', 5, int), - BC_RELEASE = _IOW('c', 6, int), - BC_DECREFS = _IOW('c', 7, int), + BC_INCREFS = _IOW('c', 4, __u32), + BC_ACQUIRE = _IOW('c', 5, __u32), + BC_RELEASE = _IOW('c', 6, __u32), + BC_DECREFS = _IOW('c', 7, __u32), /* * int: descriptor */ @@ -308,19 +325,19 @@ enum binder_driver_command_protocol { * of looping threads it has available. */ - BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie), + BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_handle_cookie), /* - * void *: ptr to binder + * int: handle * void *: cookie */ - BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie), + BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_handle_cookie), /* - * void *: ptr to binder + * int: handle * void *: cookie */ - BC_DEAD_BINDER_DONE = _IOW('c', 16, void *), + BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t), /* * void *: cookie */ diff --git a/drivers/staging/android/uapi/ion_test.h b/drivers/staging/android/uapi/ion_test.h index 352379a02690..ffef06f63133 100644 --- a/drivers/staging/android/uapi/ion_test.h +++ b/drivers/staging/android/uapi/ion_test.h @@ -20,8 +20,6 @@ #include #include -typedef int ion_user_handle_t; - /** * struct ion_test_rw_data - metadata passed to the kernel to read handle * @ptr: a pointer to an area at least as large as size @@ -34,6 +32,7 @@ struct ion_test_rw_data { __u64 offset; __u64 size; int write; + int __padding; }; #define ION_IOC_MAGIC 'I' diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c index 092964c2b506..53e50b5e8612 100644 --- a/drivers/usb/gadget/f_accessory.c +++ b/drivers/usb/gadget/f_accessory.c @@ -261,8 +261,10 @@ static void acc_complete_in(struct usb_ep *ep, struct usb_request *req) { struct acc_dev *dev = _acc_dev; - if (req->status != 0) + if (req->status == -ESHUTDOWN) { + pr_debug("acc_complete_in set disconnected"); acc_set_disconnected(dev); + } req_put(dev, &dev->tx_idle, req); @@ -274,8 +276,10 @@ static void acc_complete_out(struct usb_ep *ep, struct usb_request *req) struct acc_dev *dev = _acc_dev; dev->rx_done = 1; - if (req->status != 0) + if (req->status == -ESHUTDOWN) { + pr_debug("acc_complete_out set disconnected"); acc_set_disconnected(dev); + } wake_up(&dev->read_wq); } @@ -552,13 +556,16 @@ 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) + if (dev->disconnected) { + pr_debug("acc_read disconnected"); return -ENODEV; + } if (count > BULK_BUFFER_SIZE) count = BULK_BUFFER_SIZE; @@ -571,6 +578,12 @@ static ssize_t acc_read(struct file *fp, char __user *buf, goto done; } + if (dev->rx_done) { + // last req cancelled. try to get it. + req = dev->rx_req[0]; + goto copy_data; + } + requeue_req: /* queue a request */ req = dev->rx_req[0]; @@ -588,15 +601,23 @@ static ssize_t acc_read(struct file *fp, char __user *buf, ret = wait_event_interruptible(dev->read_wq, dev->rx_done); if (ret < 0) { r = ret; - usb_ep_dequeue(dev->ep_out, req); + ret = usb_ep_dequeue(dev->ep_out, req); + if (ret != 0) { + // cancel failed. There can be a data already received. + // it will be retrieved in the next read. + pr_debug("acc_read: cancelling failed %d", ret); + } goto done; } + +copy_data: + dev->rx_done = 0; if (dev->online) { /* If we got a 0-len packet, throw it back and try again. */ 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)) @@ -605,7 +626,7 @@ static ssize_t acc_read(struct file *fp, char __user *buf, r = -EIO; done: - pr_debug("acc_read returning %d\n", r); + pr_debug("acc_read returning %zd\n", r); return r; } @@ -614,13 +635,16 @@ 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) + if (!dev->online || dev->disconnected) { + pr_debug("acc_write disconnected or not online"); return -ENODEV; + } while (count > 0) { if (!dev->online) { @@ -665,7 +689,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 960d64fbd40b..620aeaaf2d72 100644 --- a/drivers/usb/gadget/f_mtp.c +++ b/drivers/usb/gadget/f_mtp.c @@ -466,10 +466,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; @@ -533,7 +534,7 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, 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; } @@ -543,11 +544,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) { @@ -624,7 +626,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; } @@ -823,7 +825,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 @@ int adf_attachment_allow(struct adf_device *dev, 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_client.c b/drivers/video/adf/adf_client.c index bba873d34bbb..8061d8e6b9fb 100644 --- a/drivers/video/adf/adf_client.c +++ b/drivers/video/adf/adf_client.c @@ -283,7 +283,7 @@ static int adf_buffer_map(struct adf_device *dev, struct adf_buffer *buf, attachment = dma_buf_attach(buf->dma_bufs[i], dev->dev); if (IS_ERR(attachment)) { ret = PTR_ERR(attachment); - dev_err(&dev->base.dev, "attaching plane %u failed: %d\n", + dev_err(&dev->base.dev, "attaching plane %zu failed: %d\n", i, ret); goto done; } @@ -292,12 +292,13 @@ static int adf_buffer_map(struct adf_device *dev, struct adf_buffer *buf, sg_table = dma_buf_map_attachment(attachment, DMA_TO_DEVICE); if (IS_ERR(sg_table)) { ret = PTR_ERR(sg_table); - dev_err(&dev->base.dev, "mapping plane %u failed: %d", + dev_err(&dev->base.dev, "mapping plane %zu failed: %d", i, ret); goto done; } else if (!sg_table) { ret = -ENOMEM; - dev_err(&dev->base.dev, "mapping plane %u failed\n", i); + dev_err(&dev->base.dev, "mapping plane %zu failed\n", + i); goto done; } mapping->sg_tables[i] = sg_table; 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.c b/drivers/video/adf/adf_fops32.c index 60a47cf5a781..d299a8161491 100644 --- a/drivers/video/adf/adf_fops32.c +++ b/drivers/video/adf/adf_fops32.c @@ -81,7 +81,7 @@ long adf_compat_get_device_data(struct file *file, &data->custom_data)) return -EFAULT; - ret = adf_file_ioctl(file, ADF_GET_DEVICE_DATA32, (unsigned long)data); + ret = adf_file_ioctl(file, ADF_GET_DEVICE_DATA, (unsigned long)data); if (ret < 0) return ret; @@ -122,7 +122,7 @@ long adf_compat_get_interface_data(struct file *file, &data->custom_data)) return -EFAULT; - ret = adf_file_ioctl(file, ADF_GET_DEVICE_DATA32, (unsigned long)data); + ret = adf_file_ioctl(file, ADF_GET_INTERFACE_DATA, (unsigned long)data); if (ret < 0) return ret; diff --git a/drivers/video/adf/adf_fops32.h b/drivers/video/adf/adf_fops32.h index 18c673dc5e2e..64034ce33a6b 100644 --- a/drivers/video/adf/adf_fops32.h +++ b/drivers/video/adf/adf_fops32.h @@ -7,13 +7,13 @@ #include