Merge branch 'linaro-android-3.10-lsk' of git://git.linaro.org/people/john.stultz/android into lsk-v3.10-aosp

This commit is contained in:
Mark Brown 2014-05-12 17:41:08 +01:00
commit 95b9600d1e
113 changed files with 3288 additions and 1170 deletions

View File

@ -0,0 +1,34 @@
Tagged virtual addresses in AArch64 Linux
=========================================
Author: Will Deacon <will.deacon@arm.com>
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.

View File

@ -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

View File

@ -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

View File

@ -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.<dtb name>
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.

View File

@ -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)

View File

@ -4,4 +4,3 @@ xipImage
bootpImage
uImage
*.dtb
zImage-dtb

View File

@ -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),)

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -1,2 +1,3 @@
Image
Image.gz
Image.gz-dtb

View File

@ -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)"

View File

@ -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

View File

@ -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))

View File

@ -16,6 +16,8 @@
#ifndef __ASM_PGTABLE_3LEVEL_TYPES_H
#define __ASM_PGTABLE_3LEVEL_TYPES_H
#include <asm/types.h>
typedef u64 pteval_t;
typedef u64 pmdval_t;
typedef u64 pgdval_t;

View File

@ -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

View File

@ -423,6 +423,7 @@ el0_da:
* Data abort handling
*/
mrs x0, far_el1
bic x0, x0, #(0xff << 56)
disable_step x1
isb
enable_dbg

View File

@ -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

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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)
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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",

View File

@ -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] = {

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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 */

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
/*
* arch/arm/include/asm/fiq_debugger.h
* drivers/staging/android/fiq_debugger/fiq_debugger.h
*
* Copyright (C) 2010 Google, Inc.
* Author: Colin Cross <ccross@android.com>

View File

@ -0,0 +1,240 @@
/*
* Copyright (C) 2014 Google, Inc.
* Author: Colin Cross <ccross@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/ptrace.h>
#include <linux/uaccess.h>
#include <asm/stacktrace.h>
#include "fiq_debugger_priv.h"
static char *mode_name(unsigned cpsr)
{
switch (cpsr & MODE_MASK) {
case USR_MODE: return "USR";
case FIQ_MODE: return "FIQ";
case IRQ_MODE: return "IRQ";
case SVC_MODE: return "SVC";
case ABT_MODE: return "ABT";
case UND_MODE: return "UND";
case SYSTEM_MODE: return "SYS";
default: return "???";
}
}
void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
output->printf(output, " pc %08x cpsr %08x mode %s\n",
regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr));
}
void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
output->printf(output,
" r0 %08x r1 %08x r2 %08x r3 %08x\n",
regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
output->printf(output,
" r4 %08x r5 %08x r6 %08x r7 %08x\n",
regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
output->printf(output,
" r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n",
regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp,
mode_name(regs->ARM_cpsr));
output->printf(output,
" ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc,
regs->ARM_cpsr);
}
struct mode_regs {
unsigned long sp_svc;
unsigned long lr_svc;
unsigned long spsr_svc;
unsigned long sp_abt;
unsigned long lr_abt;
unsigned long spsr_abt;
unsigned long sp_und;
unsigned long lr_und;
unsigned long spsr_und;
unsigned long sp_irq;
unsigned long lr_irq;
unsigned long spsr_irq;
unsigned long r8_fiq;
unsigned long r9_fiq;
unsigned long r10_fiq;
unsigned long r11_fiq;
unsigned long r12_fiq;
unsigned long sp_fiq;
unsigned long lr_fiq;
unsigned long spsr_fiq;
};
static void __naked get_mode_regs(struct mode_regs *regs)
{
asm volatile (
"mrs r1, cpsr\n"
"msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
"stmia r0!, {r13 - r14}\n"
"mrs r2, spsr\n"
"msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
"stmia r0!, {r2, r13 - r14}\n"
"mrs r2, spsr\n"
"msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
"stmia r0!, {r2, r13 - r14}\n"
"mrs r2, spsr\n"
"msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
"stmia r0!, {r2, r13 - r14}\n"
"mrs r2, spsr\n"
"msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
"stmia r0!, {r2, r8 - r14}\n"
"mrs r2, spsr\n"
"stmia r0!, {r2}\n"
"msr cpsr_c, r1\n"
"bx lr\n");
}
void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
struct mode_regs mode_regs;
unsigned long mode = regs->ARM_cpsr & MODE_MASK;
fiq_debugger_dump_regs(output, regs);
get_mode_regs(&mode_regs);
output->printf(output,
"%csvc: sp %08x lr %08x spsr %08x\n",
mode == SVC_MODE ? '*' : ' ',
mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
output->printf(output,
"%cabt: sp %08x lr %08x spsr %08x\n",
mode == ABT_MODE ? '*' : ' ',
mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
output->printf(output,
"%cund: sp %08x lr %08x spsr %08x\n",
mode == UND_MODE ? '*' : ' ',
mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
output->printf(output,
"%cirq: sp %08x lr %08x spsr %08x\n",
mode == IRQ_MODE ? '*' : ' ',
mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
output->printf(output,
"%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n",
mode == FIQ_MODE ? '*' : ' ',
mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
mode_regs.r11_fiq, mode_regs.r12_fiq);
output->printf(output,
" fiq: sp %08x lr %08x spsr %08x\n",
mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
}
struct stacktrace_state {
struct fiq_debugger_output *output;
unsigned int depth;
};
static int report_trace(struct stackframe *frame, void *d)
{
struct stacktrace_state *sts = d;
if (sts->depth) {
sts->output->printf(sts->output,
" pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
frame->pc, frame->pc, frame->lr, frame->lr,
frame->sp, frame->fp);
sts->depth--;
return 0;
}
sts->output->printf(sts->output, " ...\n");
return sts->depth == 0;
}
struct frame_tail {
struct frame_tail *fp;
unsigned long sp;
unsigned long lr;
} __attribute__((packed));
static struct frame_tail *user_backtrace(struct fiq_debugger_output *output,
struct frame_tail *tail)
{
struct frame_tail buftail[2];
/* Also check accessibility of one struct frame_tail beyond */
if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) {
output->printf(output, " invalid frame pointer %p\n",
tail);
return NULL;
}
if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
output->printf(output,
" failed to copy frame pointer %p\n", tail);
return NULL;
}
output->printf(output, " %p\n", buftail[0].lr);
/* frame pointers should strictly progress back up the stack
* (towards higher addresses) */
if (tail >= buftail[0].fp)
return NULL;
return buftail[0].fp-1;
}
void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
const struct pt_regs *regs, unsigned int depth, void *ssp)
{
struct frame_tail *tail;
struct thread_info *real_thread_info = THREAD_INFO(ssp);
struct stacktrace_state sts;
sts.depth = depth;
sts.output = output;
*current_thread_info() = *real_thread_info;
if (!current)
output->printf(output, "current NULL\n");
else
output->printf(output, "pid: %d comm: %s\n",
current->pid, current->comm);
fiq_debugger_dump_regs(output, regs);
if (!user_mode(regs)) {
struct stackframe frame;
frame.fp = regs->ARM_fp;
frame.sp = regs->ARM_sp;
frame.lr = regs->ARM_lr;
frame.pc = regs->ARM_pc;
output->printf(output,
" pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr,
regs->ARM_sp, regs->ARM_fp);
walk_stackframe(&frame, report_trace, &sts);
return;
}
tail = ((struct frame_tail *) regs->ARM_fp) - 1;
while (depth-- && tail && !((unsigned long) tail & 3))
tail = user_backtrace(output, tail);
}

View File

@ -0,0 +1,202 @@
/*
* Copyright (C) 2014 Google, Inc.
* Author: Colin Cross <ccross@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/ptrace.h>
#include <asm/stacktrace.h>
#include "fiq_debugger_priv.h"
static char *mode_name(const struct pt_regs *regs)
{
if (compat_user_mode(regs)) {
return "USR";
} else {
switch (processor_mode(regs)) {
case PSR_MODE_EL0t: return "EL0t";
case PSR_MODE_EL1t: return "EL1t";
case PSR_MODE_EL1h: return "EL1h";
case PSR_MODE_EL2t: return "EL2t";
case PSR_MODE_EL2h: return "EL2h";
default: return "???";
}
}
}
void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
output->printf(output, " pc %016lx cpsr %08lx mode %s\n",
regs->pc, regs->pstate, mode_name(regs));
}
void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
output->printf(output, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
regs->compat_usr(0), regs->compat_usr(1),
regs->compat_usr(2), regs->compat_usr(3));
output->printf(output, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
regs->compat_usr(4), regs->compat_usr(5),
regs->compat_usr(6), regs->compat_usr(7));
output->printf(output, " r8 %08x r9 %08x r10 %08x r11 %08x\n",
regs->compat_usr(8), regs->compat_usr(9),
regs->compat_usr(10), regs->compat_usr(11));
output->printf(output, " ip %08x sp %08x lr %08x pc %08x\n",
regs->compat_usr(12), regs->compat_sp,
regs->compat_lr, regs->pc);
output->printf(output, " cpsr %08x (%s)\n",
regs->pstate, mode_name(regs));
}
void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
output->printf(output, " x0 %016lx x1 %016lx\n",
regs->regs[0], regs->regs[1]);
output->printf(output, " x2 %016lx x3 %016lx\n",
regs->regs[2], regs->regs[3]);
output->printf(output, " x4 %016lx x5 %016lx\n",
regs->regs[4], regs->regs[5]);
output->printf(output, " x6 %016lx x7 %016lx\n",
regs->regs[6], regs->regs[7]);
output->printf(output, " x8 %016lx x9 %016lx\n",
regs->regs[8], regs->regs[9]);
output->printf(output, " x10 %016lx x11 %016lx\n",
regs->regs[10], regs->regs[11]);
output->printf(output, " x12 %016lx x13 %016lx\n",
regs->regs[12], regs->regs[13]);
output->printf(output, " x14 %016lx x15 %016lx\n",
regs->regs[14], regs->regs[15]);
output->printf(output, " x16 %016lx x17 %016lx\n",
regs->regs[16], regs->regs[17]);
output->printf(output, " x18 %016lx x19 %016lx\n",
regs->regs[18], regs->regs[19]);
output->printf(output, " x20 %016lx x21 %016lx\n",
regs->regs[20], regs->regs[21]);
output->printf(output, " x22 %016lx x23 %016lx\n",
regs->regs[22], regs->regs[23]);
output->printf(output, " x24 %016lx x25 %016lx\n",
regs->regs[24], regs->regs[25]);
output->printf(output, " x26 %016lx x27 %016lx\n",
regs->regs[26], regs->regs[27]);
output->printf(output, " x28 %016lx x29 %016lx\n",
regs->regs[28], regs->regs[29]);
output->printf(output, " x30 %016lx sp %016lx\n",
regs->regs[30], regs->sp);
output->printf(output, " pc %016lx cpsr %08x (%s)\n",
regs->pc, regs->pstate, mode_name(regs));
}
void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
if (compat_user_mode(regs))
fiq_debugger_dump_regs_aarch32(output, regs);
else
fiq_debugger_dump_regs_aarch64(output, regs);
}
#define READ_SPECIAL_REG(x) ({ \
u64 val; \
asm volatile ("mrs %0, " # x : "=r"(val)); \
val; \
})
void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
const struct pt_regs *regs)
{
u32 pstate = READ_SPECIAL_REG(CurrentEl);
bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t;
fiq_debugger_dump_regs(output, regs);
output->printf(output, " sp_el0 %016lx\n",
READ_SPECIAL_REG(sp_el0));
if (in_el2)
output->printf(output, " sp_el1 %016lx\n",
READ_SPECIAL_REG(sp_el1));
output->printf(output, " elr_el1 %016lx\n",
READ_SPECIAL_REG(elr_el1));
output->printf(output, " spsr_el1 %08lx\n",
READ_SPECIAL_REG(spsr_el1));
if (in_el2) {
output->printf(output, " spsr_irq %08lx\n",
READ_SPECIAL_REG(spsr_irq));
output->printf(output, " spsr_abt %08lx\n",
READ_SPECIAL_REG(spsr_abt));
output->printf(output, " spsr_und %08lx\n",
READ_SPECIAL_REG(spsr_und));
output->printf(output, " spsr_fiq %08lx\n",
READ_SPECIAL_REG(spsr_fiq));
output->printf(output, " spsr_el2 %08lx\n",
READ_SPECIAL_REG(elr_el2));
output->printf(output, " spsr_el2 %08lx\n",
READ_SPECIAL_REG(spsr_el2));
}
}
struct stacktrace_state {
struct fiq_debugger_output *output;
unsigned int depth;
};
static int report_trace(struct stackframe *frame, void *d)
{
struct stacktrace_state *sts = d;
if (sts->depth) {
sts->output->printf(sts->output, "%pF:\n", frame->pc);
sts->output->printf(sts->output,
" pc %016lx sp %016lx fp %016lx\n",
frame->pc, frame->sp, frame->fp);
sts->depth--;
return 0;
}
sts->output->printf(sts->output, " ...\n");
return sts->depth == 0;
}
void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
const struct pt_regs *regs, unsigned int depth, void *ssp)
{
struct thread_info *real_thread_info = THREAD_INFO(ssp);
struct stacktrace_state sts;
sts.depth = depth;
sts.output = output;
*current_thread_info() = *real_thread_info;
if (!current)
output->printf(output, "current NULL\n");
else
output->printf(output, "pid: %d comm: %s\n",
current->pid, current->comm);
fiq_debugger_dump_regs(output, regs);
if (!user_mode(regs)) {
struct stackframe frame;
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
output->printf(output, "\n");
walk_stackframe(&frame, report_trace, &sts);
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2014 Google, Inc.
* Author: Colin Cross <ccross@android.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _FIQ_DEBUGGER_PRIV_H_
#define _FIQ_DEBUGGER_PRIV_H_
#define THREAD_INFO(sp) ((struct thread_info *) \
((unsigned long)(sp) & ~(THREAD_SIZE - 1)))
struct fiq_debugger_output {
void (*printf)(struct fiq_debugger_output *output, const char *fmt, ...);
};
struct pt_regs;
void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
const struct pt_regs *regs);
void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
const struct pt_regs *regs);
void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
const struct pt_regs *regs);
void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
const struct pt_regs *regs, unsigned int depth, void *ssp);
#endif

View File

@ -1,5 +1,5 @@
/*
* arch/arm/common/fiq_debugger_ringbuf.c
* drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h
*
* simple lockless ringbuffer
*

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2014 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/pstore_ram.h>
#include "fiq_watchdog.h"
#include "fiq_debugger_priv.h"
static DEFINE_RAW_SPINLOCK(fiq_watchdog_lock);
static void fiq_watchdog_printf(struct fiq_debugger_output *output,
const char *fmt, ...)
{
char buf[256];
va_list ap;
int len;
va_start(ap, fmt);
len = vscnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
ramoops_console_write_buf(buf, len);
}
struct fiq_debugger_output fiq_watchdog_output = {
.printf = fiq_watchdog_printf,
};
void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp)
{
char msg[24];
int len;
raw_spin_lock(&fiq_watchdog_lock);
len = scnprintf(msg, sizeof(msg), "watchdog fiq cpu %d\n",
THREAD_INFO(svc_sp)->cpu);
ramoops_console_write_buf(msg, len);
fiq_debugger_dump_stacktrace(&fiq_watchdog_output, regs, 100, svc_sp);
raw_spin_unlock(&fiq_watchdog_lock);
}

View File

@ -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

View File

@ -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

View File

@ -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/

View File

@ -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;

View File

@ -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);
}

View File

@ -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 <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/sizes.h>
#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);

View File

@ -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;

View File

@ -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)

View File

@ -17,6 +17,7 @@
#ifndef _ION_PRIV_H
#define _ION_PRIV_H
#include <linux/device.h>
#include <linux/dma-direction.h>
#include <linux/kref.h>
#include <linux/mm_types.h>
@ -25,6 +26,7 @@
#include <linux/sched.h>
#include <linux/shrinker.h>
#include <linux/types.h>
#include <linux/device.h>
#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

View File

@ -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:

View File

@ -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,
};

View File

@ -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);

View File

@ -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
*/

View File

@ -20,8 +20,6 @@
#include <linux/ioctl.h>
#include <linux/types.h>
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'

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -7,13 +7,13 @@
#include <video/adf.h>
#define ADF_POST_CONFIG32 \
_IOW('D', 2, struct adf_post_config32)
_IOW(ADF_IOCTL_TYPE, 2, struct adf_post_config32)
#define ADF_GET_DEVICE_DATA32 \
_IOR('D', 4, struct adf_device_data32)
_IOR(ADF_IOCTL_TYPE, 4, struct adf_device_data32)
#define ADF_GET_INTERFACE_DATA32 \
_IOR('D', 5, struct adf_interface_data32)
_IOR(ADF_IOCTL_TYPE, 5, struct adf_interface_data32)
#define ADF_GET_OVERLAY_ENGINE_DATA32 \
_IOR('D', 6, struct adf_overlay_engine_data32)
_IOR(ADF_IOCTL_TYPE, 6, struct adf_overlay_engine_data32)
struct adf_post_config32 {
compat_size_t n_interfaces;
@ -25,7 +25,7 @@ struct adf_post_config32 {
compat_size_t custom_data_size;
compat_uptr_t custom_data;
__s64 complete_fence;
__s32 complete_fence;
};
struct adf_device_data32 {

View File

@ -28,7 +28,7 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach,
unsigned long pfn = PFN_DOWN(pdata->base);
struct page *page = pfn_to_page(pfn);
struct sg_table *table;
int ret;
int nents, ret;
table = kzalloc(sizeof(*table), GFP_KERNEL);
if (!table)
@ -36,12 +36,21 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach,
ret = sg_alloc_table(table, 1, GFP_KERNEL);
if (ret < 0)
goto err;
goto err_alloc;
sg_set_page(table->sgl, page, attach->dmabuf->size, 0);
nents = dma_map_sg(attach->dev, table->sgl, 1, direction);
if (!nents) {
ret = -EINVAL;
goto err_map;
}
return table;
err:
err_map:
sg_free_table(table);
err_alloc:
kfree(table);
return ERR_PTR(ret);
}
@ -49,6 +58,7 @@ static struct sg_table *adf_memblock_map(struct dma_buf_attachment *attach,
static void adf_memblock_unmap(struct dma_buf_attachment *attach,
struct sg_table *table, enum dma_data_direction direction)
{
dma_unmap_sg(attach->dev, table->sgl, 1, direction);
sg_free_table(table);
}
@ -147,3 +157,4 @@ struct dma_buf *adf_memblock_export(phys_addr_t base, size_t size, int flags)
return buf;
}
EXPORT_SYMBOL(adf_memblock_export);

View File

@ -2724,6 +2724,17 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
return memcpy(buffer, temp, sz);
}
char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
{
char *end = buffer + buflen;
/* these dentries are never renamed, so d_lock is not needed */
if (prepend(&end, &buflen, " (deleted)", 11) ||
prepend_name(&end, &buflen, &dentry->d_name) ||
prepend(&end, &buflen, "/", 1))
end = ERR_PTR(-ENAMETOOLONG);
return end;
}
/*
* Write full pathname from the root of the filesystem into the buffer.
*/

View File

@ -1819,8 +1819,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
goto error_tgt_fput;
/* Check if EPOLLWAKEUP is allowed */
if ((epds.events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND))
epds.events &= ~EPOLLWAKEUP;
ep_take_care_of_epollwakeup(&epds);
/*
* We have to check that the file structure underneath the file descriptor

View File

@ -916,14 +916,8 @@ static int get_hstate_idx(int page_size_log)
return h - hstates;
}
static char *hugetlb_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "/%s (deleted)",
dentry->d_name.name);
}
static struct dentry_operations anon_ops = {
.d_dname = hugetlb_dname
.d_dname = simple_dname
};
/*

View File

@ -377,6 +377,12 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
return 0;
}
void notrace ramoops_console_write_buf(const char *buf, size_t size)
{
struct ramoops_context *cxt = &oops_cxt;
persistent_ram_write(cxt->cprz, buf, size);
}
static int ramoops_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;

View File

@ -317,6 +317,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
(clockid != CLOCK_MONOTONIC &&
clockid != CLOCK_REALTIME &&
clockid != CLOCK_REALTIME_ALARM &&
clockid != CLOCK_BOOTTIME &&
clockid != CLOCK_BOOTTIME_ALARM))
return -EINVAL;

View File

@ -340,6 +340,7 @@ const char *cpufreq_get_current_driver(void);
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu);
bool have_governor_per_policy(void);
struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy);
#ifdef CONFIG_CPU_FREQ
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */

View File

@ -332,6 +332,7 @@ extern int d_validate(struct dentry *, struct dentry *);
* helper function for dentry_operations.d_dname() members
*/
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
extern char *simple_dname(struct dentry *, char *, int);
extern char *__d_path(const struct path *, const struct path *, char *, int);
extern char *d_absolute_path(const struct path *, char *, int);

View File

@ -91,6 +91,27 @@ extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
extern int of_flat_dt_match(unsigned long node, const char *const *matches);
extern unsigned long of_get_flat_dt_root(void);
/*
* early_init_dt_scan_chosen - scan the device tree for ramdisk and bootargs
*
* The boot arguments will be placed into the memory pointed to by @data.
* That memory should be COMMAND_LINE_SIZE big and initialized to be a valid
* (possibly empty) string. Logic for what will be in @data after this
* function finishes:
*
* - CONFIG_CMDLINE_FORCE=true
* CONFIG_CMDLINE
* - CONFIG_CMDLINE_EXTEND=true, @data is non-empty string
* @data + dt bootargs (even if dt bootargs are empty)
* - CONFIG_CMDLINE_EXTEND=true, @data is empty string
* CONFIG_CMDLINE + dt bootargs (even if dt bootargs are empty)
* - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=non-empty:
* dt bootargs
* - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is non-empty string
* @data is left unchanged
* - CMDLINE_FROM_BOOTLOADER=true, dt bootargs=empty, @data is empty string
* CONFIG_CMDLINE (or "" if that's not defined)
*/
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data);
extern void early_init_dt_check_for_initrd(unsigned long node);

View File

@ -67,6 +67,8 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz);
ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
char *str, size_t len);
void ramoops_console_write_buf(const char *buf, size_t size);
/*
* Ramoops platform data
* @mem_size memory size for ramoops

View File

@ -0,0 +1,23 @@
/*
* include/linux/wakeup_reason.h
*
* Logs the reason which caused the kernel to resume
* from the suspend mode.
*
* Copyright (C) 2014 Google, Inc.
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _LINUX_WAKEUP_REASON_H
#define _LINUX_WAKEUP_REASON_H
void log_wakeup_reason(int irq);
#endif /* _LINUX_WAKEUP_REASON_H */

View File

@ -260,6 +260,12 @@ static inline void fl6_sock_release(struct ip6_flowlabel *fl)
extern void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info);
int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
struct icmp6hdr *thdr, int len);
struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
struct sock *sk, struct flowi6 *fl6);
extern int ip6_ra_control(struct sock *sk, int sel);
extern int ipv6_parse_hopopts(struct sk_buff *skb);

View File

@ -13,6 +13,7 @@
#ifndef _PING_H
#define _PING_H
#include <net/icmp.h>
#include <net/netns/hash.h>
/* PING_HTABLE_SIZE must be power of 2 */
@ -28,6 +29,18 @@
*/
#define GID_T_MAX (((gid_t)~0U) >> 1)
/* Compatibility glue so we can support IPv6 when it's compiled as a module */
struct pingv6_ops {
int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len);
int (*ip6_datagram_recv_ctl)(struct sock *sk, struct msghdr *msg,
struct sk_buff *skb);
int (*icmpv6_err_convert)(u8 type, u8 code, int *err);
void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err,
__be16 port, u32 info, u8 *payload);
int (*ipv6_chk_addr)(struct net *net, const struct in6_addr *addr,
const struct net_device *dev, int strict);
};
struct ping_table {
struct hlist_nulls_head hash[PING_HTABLE_SIZE];
rwlock_t lock;
@ -39,10 +52,39 @@ struct ping_iter_state {
};
extern struct proto ping_prot;
extern struct ping_table ping_table;
#if IS_ENABLED(CONFIG_IPV6)
extern struct pingv6_ops pingv6_ops;
#endif
struct pingfakehdr {
struct icmphdr icmph;
struct iovec *iov;
sa_family_t family;
__wsum wcheck;
};
extern void ping_rcv(struct sk_buff *);
extern void ping_err(struct sk_buff *, u32 info);
int ping_get_port(struct sock *sk, unsigned short ident);
void ping_hash(struct sock *sk);
void ping_unhash(struct sock *sk);
int ping_init_sock(struct sock *sk);
void ping_close(struct sock *sk, long timeout);
int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len);
void ping_err(struct sk_buff *skb, int offset, u32 info);
int ping_getfrag(void *from, char *to, int offset, int fraglen, int odd,
struct sk_buff *);
int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int noblock, int flags, int *addr_len);
int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
void *user_icmph, size_t icmph_len);
int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len);
int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len);
int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
void ping_rcv(struct sk_buff *skb);
#ifdef CONFIG_PROC_FS
extern int __init ping_proc_init(void);
@ -50,6 +92,7 @@ extern void ping_proc_exit(void);
#endif
void __init ping_init(void);
int __init pingv6_init(void);
void pingv6_exit(void);
#endif /* _PING_H */

View File

@ -287,6 +287,7 @@ extern int sysctl_tcp_thin_dupack;
extern int sysctl_tcp_early_retrans;
extern int sysctl_tcp_limit_output_bytes;
extern int sysctl_tcp_challenge_ack_limit;
extern int sysctl_tcp_default_init_rwnd;
extern atomic_long_t tcp_memory_allocated;
extern struct percpu_counter tcp_sockets_allocated;

View File

@ -11,6 +11,7 @@ extern struct proto rawv6_prot;
extern struct proto udpv6_prot;
extern struct proto udplitev6_prot;
extern struct proto tcpv6_prot;
extern struct proto pingv6_prot;
struct flowi6;
@ -21,6 +22,8 @@ extern int ipv6_frag_init(void);
extern void ipv6_frag_exit(void);
/* transport protocols */
extern int pingv6_init(void);
extern void pingv6_exit(void);
extern int rawv6_init(void);
extern void rawv6_exit(void);
extern int udpv6_init(void);

View File

@ -61,5 +61,16 @@ struct epoll_event {
__u64 data;
} EPOLL_PACKED;
#ifdef CONFIG_PM_SLEEP
static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
{
if ((epev->events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND))
epev->events &= ~EPOLLWAKEUP;
}
#else
static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev)
{
epev->events &= ~EPOLLWAKEUP;
}
#endif
#endif /* _UAPI_LINUX_EVENTPOLL_H */

View File

@ -461,10 +461,14 @@ struct input_keymap_entry {
#define KEY_VIDEO_NEXT 241 /* drive next video source */
#define KEY_VIDEO_PREV 242 /* drive previous video source */
#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */
#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual
brightness control is off,
rely on ambient */
#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
#define KEY_DISPLAY_OFF 245 /* display device to off state */
#define KEY_WIMAX 246
#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
#define KEY_WIMAX KEY_WWAN
#define KEY_RFKILL 247 /* Key that controls all radios */
#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
@ -509,11 +513,15 @@ struct input_keymap_entry {
#define BTN_DEAD 0x12f
#define BTN_GAMEPAD 0x130
#define BTN_A 0x130
#define BTN_B 0x131
#define BTN_SOUTH 0x130
#define BTN_A BTN_SOUTH
#define BTN_EAST 0x131
#define BTN_B BTN_EAST
#define BTN_C 0x132
#define BTN_X 0x133
#define BTN_Y 0x134
#define BTN_NORTH 0x133
#define BTN_X BTN_NORTH
#define BTN_WEST 0x134
#define BTN_Y BTN_WEST
#define BTN_Z 0x135
#define BTN_TL 0x136
#define BTN_TR 0x137
@ -626,6 +634,7 @@ struct input_keymap_entry {
#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE
#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
#define KEY_LOGOFF 0x1b1 /* AL Logoff */
@ -710,6 +719,24 @@ struct input_keymap_entry {
#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */
#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */
#define BTN_DPAD_UP 0x220
#define BTN_DPAD_DOWN 0x221
#define BTN_DPAD_LEFT 0x222
#define BTN_DPAD_RIGHT 0x223
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */
#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */
#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
#define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
@ -847,6 +874,7 @@ struct input_keymap_entry {
#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */
#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
#define SW_LINEIN_INSERT 0x0d /* set = inserted */
#define SW_MUTE_DEVICE 0x0e /* set = device disabled */
#define SW_MAX 0x0f
#define SW_CNT (SW_MAX+1)

View File

@ -149,6 +149,12 @@
#define PR_GET_TID_ADDRESS 40
/* Sets the timerslack for arbitrary threads
* arg2 slack value, 0 means "use default"
* arg3 pid of the thread whose timer slack needs to be set
*/
#define PR_SET_TIMERSLACK_PID 41
#define PR_SET_VMA 0x53564d41
# define PR_SET_VMA_ANON_NAME 0

View File

@ -83,7 +83,7 @@ struct adf_event {
*/
struct adf_vsync_event {
struct adf_event base;
__u64 timestamp;
__aligned_u64 timestamp;
};
/**
@ -119,12 +119,12 @@ struct adf_buffer_config {
__u32 h;
__u32 format;
__s64 fd[ADF_MAX_PLANES];
__s32 fd[ADF_MAX_PLANES];
__u32 offset[ADF_MAX_PLANES];
__u32 pitch[ADF_MAX_PLANES];
__u8 n_planes;
__s64 acquire_fence;
__s32 acquire_fence;
};
#define ADF_MAX_BUFFERS (4096 / sizeof(struct adf_buffer_config))
@ -150,7 +150,7 @@ struct adf_post_config {
size_t custom_data_size;
void __user *custom_data;
__s64 complete_fence;
__s32 complete_fence;
};
#define ADF_MAX_INTERFACES (4096 / sizeof(__u32))
@ -180,7 +180,7 @@ struct adf_simple_buffer_alloc {
__u16 h;
__u32 format;
__s64 fd;
__s32 fd;
__u32 offset;
__u32 pitch;
};
@ -195,7 +195,7 @@ struct adf_simple_buffer_alloc {
*/
struct adf_simple_post_config {
struct adf_buffer_config buf;
__s64 complete_fence;
__s32 complete_fence;
};
/**
@ -295,17 +295,27 @@ struct adf_overlay_engine_data {
};
#define ADF_MAX_SUPPORTED_FORMATS (4096 / sizeof(__u32))
#define ADF_SET_EVENT _IOW('D', 0, struct adf_set_event)
#define ADF_BLANK _IOW('D', 1, __u8)
#define ADF_POST_CONFIG _IOW('D', 2, struct adf_post_config)
#define ADF_SET_MODE _IOW('D', 3, struct drm_mode_modeinfo)
#define ADF_GET_DEVICE_DATA _IOR('D', 4, struct adf_device_data)
#define ADF_GET_INTERFACE_DATA _IOR('D', 5, struct adf_interface_data)
#define ADF_IOCTL_TYPE 'D'
#define ADF_IOCTL_NR_CUSTOM 128
#define ADF_SET_EVENT _IOW(ADF_IOCTL_TYPE, 0, struct adf_set_event)
#define ADF_BLANK _IOW(ADF_IOCTL_TYPE, 1, __u8)
#define ADF_POST_CONFIG _IOW(ADF_IOCTL_TYPE, 2, struct adf_post_config)
#define ADF_SET_MODE _IOW(ADF_IOCTL_TYPE, 3, \
struct drm_mode_modeinfo)
#define ADF_GET_DEVICE_DATA _IOR(ADF_IOCTL_TYPE, 4, struct adf_device_data)
#define ADF_GET_INTERFACE_DATA _IOR(ADF_IOCTL_TYPE, 5, \
struct adf_interface_data)
#define ADF_GET_OVERLAY_ENGINE_DATA \
_IOR('D', 6, struct adf_overlay_engine_data)
#define ADF_SIMPLE_POST_CONFIG _IOW('D', 7, struct adf_simple_post_config)
#define ADF_SIMPLE_BUFFER_ALLOC _IOW('D', 8, struct adf_simple_buffer_alloc)
#define ADF_ATTACH _IOW('D', 9, struct adf_attachment_config)
#define ADF_DETACH _IOW('D', 10, struct adf_attachment_config)
_IOR(ADF_IOCTL_TYPE, 6, \
struct adf_overlay_engine_data)
#define ADF_SIMPLE_POST_CONFIG _IOW(ADF_IOCTL_TYPE, 7, \
struct adf_simple_post_config)
#define ADF_SIMPLE_BUFFER_ALLOC _IOW(ADF_IOCTL_TYPE, 8, \
struct adf_simple_buffer_alloc)
#define ADF_ATTACH _IOW(ADF_IOCTL_TYPE, 9, \
struct adf_attachment_config)
#define ADF_DETACH _IOW(ADF_IOCTL_TYPE, 10, \
struct adf_attachment_config)
#endif /* _UAPI_VIDEO_ADF_H_ */

View File

@ -192,11 +192,27 @@ struct adf_obj {
int minor;
};
/**
* struct adf_device_quirks - common display device quirks
*
* @buffer_padding: whether the last scanline of a buffer extends to the
* buffer's pitch (@ADF_BUFFER_PADDED_TO_PITCH) or just to the visible
* width (@ADF_BUFFER_UNPADDED)
*/
struct adf_device_quirks {
/* optional, defaults to ADF_BUFFER_PADDED_TO_PITCH */
enum {
ADF_BUFFER_PADDED_TO_PITCH = 0,
ADF_BUFFER_UNPADDED = 1,
} buffer_padding;
};
/**
* struct adf_device_ops - display device implementation ops
*
* @owner: device's module
* @base: common operations (see &struct adf_obj_ops)
* @quirks: device's quirks (see &struct adf_device_quirks)
*
* @attach: attach overlay engine @eng to interface @intf. Return 0 on success
* or error code (<0) on failure.
@ -228,6 +244,8 @@ struct adf_device_ops {
/* required */
struct module *owner;
const struct adf_obj_ops base;
/* optional */
const struct adf_device_quirks quirks;
/* optional */
int (*attach)(struct adf_device *dev, struct adf_overlay_engine *eng,

View File

@ -16,6 +16,7 @@
#define _VIDEO_ADF_FBDEV_H_
#include <linux/fb.h>
#include <linux/mutex.h>
#include <video/adf.h>
struct adf_fbdev {
@ -24,7 +25,8 @@ struct adf_fbdev {
struct fb_info *info;
u32 pseudo_palette[16];
bool open;
unsigned int refcount;
struct mutex refcount_lock;
struct dma_buf *dma_buf;
u32 offset;
@ -37,6 +39,7 @@ struct adf_fbdev {
u32 default_format;
};
#if IS_ENABLED(CONFIG_ADF_FBDEV)
void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
struct fb_videomode *vmode);
void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
@ -55,5 +58,67 @@ int adf_fbdev_set_par(struct fb_info *info);
int adf_fbdev_blank(int blank, struct fb_info *info);
int adf_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
int adf_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma);
#else
static inline void adf_modeinfo_to_fb_videomode(const struct drm_mode_modeinfo *mode,
struct fb_videomode *vmode)
{
WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__);
}
static inline void adf_modeinfo_from_fb_videomode(const struct fb_videomode *vmode,
struct drm_mode_modeinfo *mode)
{
WARN_ONCE(1, "%s: CONFIG_ADF_FBDEV is disabled\n", __func__);
}
static inline int adf_fbdev_init(struct adf_fbdev *fbdev,
struct adf_interface *interface,
struct adf_overlay_engine *eng,
u16 xres_virtual, u16 yres_virtual, u32 format,
struct fb_ops *fbops, const char *fmt, ...)
{
return -ENODEV;
}
static inline void adf_fbdev_destroy(struct adf_fbdev *fbdev) { }
static inline int adf_fbdev_open(struct fb_info *info, int user)
{
return -ENODEV;
}
static inline int adf_fbdev_release(struct fb_info *info, int user)
{
return -ENODEV;
}
static inline int adf_fbdev_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
return -ENODEV;
}
static inline int adf_fbdev_set_par(struct fb_info *info)
{
return -ENODEV;
}
static inline int adf_fbdev_blank(int blank, struct fb_info *info)
{
return -ENODEV;
}
static inline int adf_fbdev_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
return -ENODEV;
}
static inline int adf_fbdev_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
return -ENODEV;
}
#endif
#endif /* _VIDEO_ADF_FBDEV_H_ */

View File

@ -14,3 +14,5 @@ obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o
obj-$(CONFIG_SUSPEND_TIME) += suspend_time.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
obj-$(CONFIG_SUSPEND) += wakeup_reason.o

View File

@ -9,7 +9,6 @@
* manipulate wakelocks on Android.
*/
#include <linux/capability.h>
#include <linux/ctype.h>
#include <linux/device.h>
#include <linux/err.h>
@ -189,9 +188,6 @@ int pm_wake_lock(const char *buf)
size_t len;
int ret = 0;
if (!capable(CAP_BLOCK_SUSPEND))
return -EPERM;
while (*str && !isspace(*str))
str++;
@ -235,9 +231,6 @@ int pm_wake_unlock(const char *buf)
size_t len;
int ret = 0;
if (!capable(CAP_BLOCK_SUSPEND))
return -EPERM;
len = strlen(buf);
if (!len)
return -EINVAL;

View File

@ -0,0 +1,139 @@
/*
* kernel/power/wakeup_reason.c
*
* Logs the reasons which caused the kernel to resume from
* the suspend mode.
*
* Copyright (C) 2014 Google, Inc.
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/wakeup_reason.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
#include <linux/suspend.h>
#define MAX_WAKEUP_REASON_IRQS 32
static int irq_list[MAX_WAKEUP_REASON_IRQS];
static int irqcount;
static struct kobject *wakeup_reason;
static spinlock_t resume_reason_lock;
static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
int irq_no, buf_offset = 0;
struct irq_desc *desc;
spin_lock(&resume_reason_lock);
for (irq_no = 0; irq_no < irqcount; irq_no++) {
desc = irq_to_desc(irq_list[irq_no]);
if (desc && desc->action && desc->action->name)
buf_offset += sprintf(buf + buf_offset, "%d %s\n",
irq_list[irq_no], desc->action->name);
else
buf_offset += sprintf(buf + buf_offset, "%d\n",
irq_list[irq_no]);
}
spin_unlock(&resume_reason_lock);
return buf_offset;
}
static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason);
static struct attribute *attrs[] = {
&resume_reason.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
/*
* logs all the wake up reasons to the kernel
* stores the irqs to expose them to the userspace via sysfs
*/
void log_wakeup_reason(int irq)
{
struct irq_desc *desc;
desc = irq_to_desc(irq);
if (desc && desc->action && desc->action->name)
printk(KERN_INFO "Resume caused by IRQ %d, %s\n", irq,
desc->action->name);
else
printk(KERN_INFO "Resume caused by IRQ %d\n", irq);
spin_lock(&resume_reason_lock);
if (irqcount == MAX_WAKEUP_REASON_IRQS) {
spin_unlock(&resume_reason_lock);
printk(KERN_WARNING "Resume caused by more than %d IRQs\n",
MAX_WAKEUP_REASON_IRQS);
return;
}
irq_list[irqcount++] = irq;
spin_unlock(&resume_reason_lock);
}
/* Detects a suspend and clears all the previous wake up reasons*/
static int wakeup_reason_pm_event(struct notifier_block *notifier,
unsigned long pm_event, void *unused)
{
switch (pm_event) {
case PM_SUSPEND_PREPARE:
spin_lock(&resume_reason_lock);
irqcount = 0;
spin_unlock(&resume_reason_lock);
break;
default:
break;
}
return NOTIFY_DONE;
}
static struct notifier_block wakeup_reason_pm_notifier_block = {
.notifier_call = wakeup_reason_pm_event,
};
/* Initializes the sysfs parameter
* registers the pm_event notifier
*/
int __init wakeup_reason_init(void)
{
int retval;
spin_lock_init(&resume_reason_lock);
retval = register_pm_notifier(&wakeup_reason_pm_notifier_block);
if (retval)
printk(KERN_WARNING "[%s] failed to register PM notifier %d\n",
__func__, retval);
wakeup_reason = kobject_create_and_add("wakeup_reasons", kernel_kobj);
if (!wakeup_reason) {
printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n",
__func__);
return 1;
}
retval = sysfs_create_group(wakeup_reason, &attr_group);
if (retval) {
kobject_put(wakeup_reason);
printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n",
__func__, retval);
}
return 0;
}
late_initcall(wakeup_reason_init);

View File

@ -51,10 +51,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/printk.h>
#ifdef CONFIG_EARLY_PRINTK_DIRECT
extern void printascii(char *);
#endif
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL

View File

@ -44,6 +44,7 @@
#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/mempolicy.h>
#include <linux/sched.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@ -2252,6 +2253,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
{
struct task_struct *me = current;
struct task_struct *tsk;
unsigned char comm[sizeof(me->comm)];
long error;
@ -2375,6 +2377,23 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
return -EINVAL;
break;
case PR_SET_TIMERSLACK_PID:
rcu_read_lock();
tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns);
if (tsk == NULL) {
rcu_read_unlock();
return -EINVAL;
}
get_task_struct(tsk);
rcu_read_unlock();
if (arg2 <= 0)
tsk->timer_slack_ns =
tsk->default_timer_slack_ns;
else
tsk->timer_slack_ns = arg2;
put_task_struct(tsk);
error = 0;
break;
default:
return -EINVAL;
}

View File

@ -2879,14 +2879,8 @@ EXPORT_SYMBOL_GPL(shmem_truncate_range);
/* common code */
static char *shmem_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "/%s (deleted)",
dentry->d_name.name);
}
static struct dentry_operations anon_ops = {
.d_dname = shmem_dname
.d_dname = simple_dname
};
/**

View File

@ -167,7 +167,6 @@ static int debug_shrinker_show(struct seq_file *s, void *unused)
down_read(&shrinker_rwsem);
list_for_each_entry(shrinker, &shrinker_list, list) {
char name[64];
int num_objs;
num_objs = shrinker->shrink(shrinker, &sc);

View File

@ -83,13 +83,13 @@ endif # if INET
config ANDROID_PARANOID_NETWORK
bool "Only allow certain groups to create sockets"
default y
default ANDROID
help
none
config NET_ACTIVITY_STATS
bool "Network activity statistics tracking"
default y
default ANDROID
help
Network activity statistics are useful for tracking wireless
modem activity on 2G, 3G, 4G wireless networks. Counts number of

View File

@ -939,7 +939,8 @@ int icmp_rcv(struct sk_buff *skb)
void icmp_err(struct sk_buff *skb, u32 info)
{
struct iphdr *iph = (struct iphdr *)skb->data;
struct icmphdr *icmph = (struct icmphdr *)(skb->data+(iph->ihl<<2));
int offset = iph->ihl<<2;
struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset);
int type = icmp_hdr(skb)->type;
int code = icmp_hdr(skb)->code;
struct net *net = dev_net(skb->dev);
@ -949,7 +950,7 @@ void icmp_err(struct sk_buff *skb, u32 info)
* triggered by ICMP_ECHOREPLY which sent from kernel.
*/
if (icmph->type != ICMP_ECHOREPLY) {
ping_err(skb, info);
ping_err(skb, offset, info);
return;
}

View File

@ -33,7 +33,6 @@
#include <linux/netdevice.h>
#include <net/snmp.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
@ -46,8 +45,18 @@
#include <net/inet_common.h>
#include <net/checksum.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <linux/in6.h>
#include <linux/icmpv6.h>
#include <net/addrconf.h>
#include <net/ipv6.h>
#include <net/transp_v6.h>
#endif
static struct ping_table ping_table;
struct ping_table ping_table;
struct pingv6_ops pingv6_ops;
EXPORT_SYMBOL_GPL(pingv6_ops);
static u16 ping_port_rover;
@ -58,6 +67,7 @@ static inline int ping_hashfn(struct net *net, unsigned int num, unsigned int ma
pr_debug("hash(%d) = %d\n", num, res);
return res;
}
EXPORT_SYMBOL_GPL(ping_hash);
static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
struct net *net, unsigned int num)
@ -65,7 +75,7 @@ static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table,
return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)];
}
static int ping_v4_get_port(struct sock *sk, unsigned short ident)
int ping_get_port(struct sock *sk, unsigned short ident)
{
struct hlist_nulls_node *node;
struct hlist_nulls_head *hlist;
@ -103,6 +113,10 @@ static int ping_v4_get_port(struct sock *sk, unsigned short ident)
ping_portaddr_for_each_entry(sk2, node, hlist) {
isk2 = inet_sk(sk2);
/* BUG? Why is this reuse and not reuseaddr? ping.c
* doesn't turn off SO_REUSEADDR, and it doesn't expect
* that other ping processes can steal its packets.
*/
if ((isk2->inet_num == ident) &&
(sk2 != sk) &&
(!sk2->sk_reuse || !sk->sk_reuse))
@ -125,17 +139,18 @@ static int ping_v4_get_port(struct sock *sk, unsigned short ident)
write_unlock_bh(&ping_table.lock);
return 1;
}
EXPORT_SYMBOL_GPL(ping_get_port);
static void ping_v4_hash(struct sock *sk)
void ping_hash(struct sock *sk)
{
pr_debug("ping_v4_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
pr_debug("ping_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
BUG(); /* "Please do not press this button again." */
}
static void ping_v4_unhash(struct sock *sk)
void ping_unhash(struct sock *sk)
{
struct inet_sock *isk = inet_sk(sk);
pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
if (sk_hashed(sk)) {
write_lock_bh(&ping_table.lock);
hlist_nulls_del(&sk->sk_nulls_node);
@ -146,31 +161,61 @@ static void ping_v4_unhash(struct sock *sk)
write_unlock_bh(&ping_table.lock);
}
}
EXPORT_SYMBOL_GPL(ping_unhash);
static struct sock *ping_v4_lookup(struct net *net, __be32 saddr, __be32 daddr,
u16 ident, int dif)
static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
{
struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident);
struct sock *sk = NULL;
struct inet_sock *isk;
struct hlist_nulls_node *hnode;
int dif = skb->dev->ifindex;
if (skb->protocol == htons(ETH_P_IP)) {
pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
(int)ident, &ip_hdr(skb)->daddr, dif);
#if IS_ENABLED(CONFIG_IPV6)
} else if (skb->protocol == htons(ETH_P_IPV6)) {
pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d\n",
(int)ident, &ipv6_hdr(skb)->daddr, dif);
#endif
}
pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
(int)ident, &daddr, dif);
read_lock_bh(&ping_table.lock);
ping_portaddr_for_each_entry(sk, hnode, hslot) {
isk = inet_sk(sk);
pr_debug("found: %p: num = %d, daddr = %pI4, dif = %d\n", sk,
(int)isk->inet_num, &isk->inet_rcv_saddr,
sk->sk_bound_dev_if);
pr_debug("iterate\n");
if (isk->inet_num != ident)
continue;
if (isk->inet_rcv_saddr && isk->inet_rcv_saddr != daddr)
continue;
if (skb->protocol == htons(ETH_P_IP) &&
sk->sk_family == AF_INET) {
pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk,
(int) isk->inet_num, &isk->inet_rcv_saddr,
sk->sk_bound_dev_if);
if (isk->inet_rcv_saddr &&
isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
continue;
#if IS_ENABLED(CONFIG_IPV6)
} else if (skb->protocol == htons(ETH_P_IPV6) &&
sk->sk_family == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk,
(int) isk->inet_num,
&inet6_sk(sk)->rcv_saddr,
sk->sk_bound_dev_if);
if (!ipv6_addr_any(&np->rcv_saddr) &&
!ipv6_addr_equal(&np->rcv_saddr,
&ipv6_hdr(skb)->daddr))
continue;
#endif
}
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
continue;
@ -200,33 +245,41 @@ static void inet_get_ping_group_range_net(struct net *net, kgid_t *low,
}
static int ping_init_sock(struct sock *sk)
int ping_init_sock(struct sock *sk)
{
struct net *net = sock_net(sk);
kgid_t group = current_egid();
struct group_info *group_info = get_current_groups();
int i, j, count = group_info->ngroups;
struct group_info *group_info;
int i, j, count;
kgid_t low, high;
int ret = 0;
inet_get_ping_group_range_net(net, &low, &high);
if (gid_lte(low, group) && gid_lte(group, high))
return 0;
group_info = get_current_groups();
count = group_info->ngroups;
for (i = 0; i < group_info->nblocks; i++) {
int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
for (j = 0; j < cp_count; j++) {
kgid_t gid = group_info->blocks[i][j];
if (gid_lte(low, gid) && gid_lte(gid, high))
return 0;
goto out_release_group;
}
count -= cp_count;
}
return -EACCES;
}
ret = -EACCES;
static void ping_close(struct sock *sk, long timeout)
out_release_group:
put_group_info(group_info);
return ret;
}
EXPORT_SYMBOL_GPL(ping_init_sock);
void ping_close(struct sock *sk, long timeout)
{
pr_debug("ping_close(sk=%p,sk->num=%u)\n",
inet_sk(sk), inet_sk(sk)->inet_num);
@ -234,36 +287,122 @@ static void ping_close(struct sock *sk, long timeout)
sk_common_release(sk);
}
EXPORT_SYMBOL_GPL(ping_close);
/* Checks the bind address and possibly modifies sk->sk_bound_dev_if. */
int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
struct sockaddr *uaddr, int addr_len) {
struct net *net = sock_net(sk);
if (sk->sk_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
int chk_addr_ret;
if (addr_len < sizeof(*addr))
return -EINVAL;
pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
chk_addr_ret = RTN_LOCAL;
if ((sysctl_ip_nonlocal_bind == 0 &&
isk->freebind == 0 && isk->transparent == 0 &&
chk_addr_ret != RTN_LOCAL) ||
chk_addr_ret == RTN_MULTICAST ||
chk_addr_ret == RTN_BROADCAST)
return -EADDRNOTAVAIL;
#if IS_ENABLED(CONFIG_IPV6)
} else if (sk->sk_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
int addr_type, scoped, has_addr;
struct net_device *dev = NULL;
if (addr_len < sizeof(*addr))
return -EINVAL;
pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n",
sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
addr_type = ipv6_addr_type(&addr->sin6_addr);
scoped = __ipv6_addr_needs_scope_id(addr_type);
if ((addr_type != IPV6_ADDR_ANY &&
!(addr_type & IPV6_ADDR_UNICAST)) ||
(scoped && !addr->sin6_scope_id))
return -EINVAL;
rcu_read_lock();
if (addr->sin6_scope_id) {
dev = dev_get_by_index_rcu(net, addr->sin6_scope_id);
if (!dev) {
rcu_read_unlock();
return -ENODEV;
}
}
has_addr = pingv6_ops.ipv6_chk_addr(net, &addr->sin6_addr, dev,
scoped);
rcu_read_unlock();
if (!(isk->freebind || isk->transparent || has_addr ||
addr_type == IPV6_ADDR_ANY))
return -EADDRNOTAVAIL;
if (scoped)
sk->sk_bound_dev_if = addr->sin6_scope_id;
#endif
} else {
return -EAFNOSUPPORT;
}
return 0;
}
void ping_set_saddr(struct sock *sk, struct sockaddr *saddr)
{
if (saddr->sa_family == AF_INET) {
struct inet_sock *isk = inet_sk(sk);
struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
#if IS_ENABLED(CONFIG_IPV6)
} else if (saddr->sa_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
struct ipv6_pinfo *np = inet6_sk(sk);
np->rcv_saddr = np->saddr = addr->sin6_addr;
#endif
}
}
void ping_clear_saddr(struct sock *sk, int dif)
{
sk->sk_bound_dev_if = dif;
if (sk->sk_family == AF_INET) {
struct inet_sock *isk = inet_sk(sk);
isk->inet_rcv_saddr = isk->inet_saddr = 0;
#if IS_ENABLED(CONFIG_IPV6)
} else if (sk->sk_family == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
memset(&np->rcv_saddr, 0, sizeof(np->rcv_saddr));
memset(&np->saddr, 0, sizeof(np->saddr));
#endif
}
}
/*
* We need our own bind because there are no privileged id's == local ports.
* Moreover, we don't allow binding to multi- and broadcast addresses.
*/
static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
struct inet_sock *isk = inet_sk(sk);
unsigned short snum;
int chk_addr_ret;
int err;
int dif = sk->sk_bound_dev_if;
if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;
pr_debug("ping_v4_bind(sk=%p,sa_addr=%08x,sa_port=%d)\n",
sk, addr->sin_addr.s_addr, ntohs(addr->sin_port));
chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
chk_addr_ret = RTN_LOCAL;
if ((sysctl_ip_nonlocal_bind == 0 &&
isk->freebind == 0 && isk->transparent == 0 &&
chk_addr_ret != RTN_LOCAL) ||
chk_addr_ret == RTN_MULTICAST ||
chk_addr_ret == RTN_BROADCAST)
return -EADDRNOTAVAIL;
err = ping_check_bind_addr(sk, isk, uaddr, addr_len);
if (err)
return err;
lock_sock(sk);
@ -272,42 +411,50 @@ static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
goto out;
err = -EADDRINUSE;
isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
snum = ntohs(addr->sin_port);
if (ping_v4_get_port(sk, snum) != 0) {
isk->inet_saddr = isk->inet_rcv_saddr = 0;
ping_set_saddr(sk, uaddr);
snum = ntohs(((struct sockaddr_in *)uaddr)->sin_port);
if (ping_get_port(sk, snum) != 0) {
ping_clear_saddr(sk, dif);
goto out;
}
pr_debug("after bind(): num = %d, daddr = %pI4, dif = %d\n",
pr_debug("after bind(): num = %d, dif = %d\n",
(int)isk->inet_num,
&isk->inet_rcv_saddr,
(int)sk->sk_bound_dev_if);
err = 0;
if (isk->inet_rcv_saddr)
if ((sk->sk_family == AF_INET && isk->inet_rcv_saddr) ||
(sk->sk_family == AF_INET6 &&
!ipv6_addr_any(&inet6_sk(sk)->rcv_saddr)))
sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
if (snum)
sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
isk->inet_sport = htons(isk->inet_num);
isk->inet_daddr = 0;
isk->inet_dport = 0;
#if IS_ENABLED(CONFIG_IPV6)
if (sk->sk_family == AF_INET6)
memset(&inet6_sk(sk)->daddr, 0, sizeof(inet6_sk(sk)->daddr));
#endif
sk_dst_reset(sk);
out:
release_sock(sk);
pr_debug("ping_v4_bind -> %d\n", err);
return err;
}
EXPORT_SYMBOL_GPL(ping_bind);
/*
* Is this a supported type of ICMP message?
*/
static inline int ping_supported(int type, int code)
static inline int ping_supported(int family, int type, int code)
{
if (type == ICMP_ECHO && code == 0)
return 1;
return 0;
return (family == AF_INET && type == ICMP_ECHO && code == 0) ||
(family == AF_INET6 && type == ICMPV6_ECHO_REQUEST && code == 0);
}
/*
@ -315,30 +462,42 @@ static inline int ping_supported(int type, int code)
* sort of error condition.
*/
static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
void ping_err(struct sk_buff *skb, u32 info)
void ping_err(struct sk_buff *skb, int offset, u32 info)
{
struct iphdr *iph = (struct iphdr *)skb->data;
struct icmphdr *icmph = (struct icmphdr *)(skb->data+(iph->ihl<<2));
int family;
struct icmphdr *icmph;
struct inet_sock *inet_sock;
int type = icmp_hdr(skb)->type;
int code = icmp_hdr(skb)->code;
int type;
int code;
struct net *net = dev_net(skb->dev);
struct sock *sk;
int harderr;
int err;
if (skb->protocol == htons(ETH_P_IP)) {
family = AF_INET;
type = icmp_hdr(skb)->type;
code = icmp_hdr(skb)->code;
icmph = (struct icmphdr *)(skb->data + offset);
} else if (skb->protocol == htons(ETH_P_IPV6)) {
family = AF_INET6;
type = icmp6_hdr(skb)->icmp6_type;
code = icmp6_hdr(skb)->icmp6_code;
icmph = (struct icmphdr *) (skb->data + offset);
} else {
BUG();
}
/* We assume the packet has already been checked by icmp_unreach */
if (!ping_supported(icmph->type, icmph->code))
if (!ping_supported(family, icmph->type, icmph->code))
return;
pr_debug("ping_err(type=%04x,code=%04x,id=%04x,seq=%04x)\n", type,
code, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence));
pr_debug("ping_err(proto=0x%x,type=%d,code=%d,id=%04x,seq=%04x)\n",
skb->protocol, type, code, ntohs(icmph->un.echo.id),
ntohs(icmph->un.echo.sequence));
sk = ping_v4_lookup(net, iph->daddr, iph->saddr,
ntohs(icmph->un.echo.id), skb->dev->ifindex);
sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
if (sk == NULL) {
pr_debug("no socket, dropping\n");
return; /* No socket for error */
@ -349,72 +508,83 @@ void ping_err(struct sk_buff *skb, u32 info)
harderr = 0;
inet_sock = inet_sk(sk);
switch (type) {
default:
case ICMP_TIME_EXCEEDED:
err = EHOSTUNREACH;
break;
case ICMP_SOURCE_QUENCH:
/* This is not a real error but ping wants to see it.
* Report it with some fake errno. */
err = EREMOTEIO;
break;
case ICMP_PARAMETERPROB:
err = EPROTO;
harderr = 1;
break;
case ICMP_DEST_UNREACH:
if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
ipv4_sk_update_pmtu(skb, sk, info);
if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
err = EMSGSIZE;
harderr = 1;
break;
if (skb->protocol == htons(ETH_P_IP)) {
switch (type) {
default:
case ICMP_TIME_EXCEEDED:
err = EHOSTUNREACH;
break;
case ICMP_SOURCE_QUENCH:
/* This is not a real error but ping wants to see it.
* Report it with some fake errno.
*/
err = EREMOTEIO;
break;
case ICMP_PARAMETERPROB:
err = EPROTO;
harderr = 1;
break;
case ICMP_DEST_UNREACH:
if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
ipv4_sk_update_pmtu(skb, sk, info);
if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) {
err = EMSGSIZE;
harderr = 1;
break;
}
goto out;
}
goto out;
err = EHOSTUNREACH;
if (code <= NR_ICMP_UNREACH) {
harderr = icmp_err_convert[code].fatal;
err = icmp_err_convert[code].errno;
}
break;
case ICMP_REDIRECT:
/* See ICMP_SOURCE_QUENCH */
ipv4_sk_redirect(skb, sk);
err = EREMOTEIO;
break;
}
err = EHOSTUNREACH;
if (code <= NR_ICMP_UNREACH) {
harderr = icmp_err_convert[code].fatal;
err = icmp_err_convert[code].errno;
}
break;
case ICMP_REDIRECT:
/* See ICMP_SOURCE_QUENCH */
ipv4_sk_redirect(skb, sk);
err = EREMOTEIO;
break;
#if IS_ENABLED(CONFIG_IPV6)
} else if (skb->protocol == htons(ETH_P_IPV6)) {
harderr = pingv6_ops.icmpv6_err_convert(type, code, &err);
#endif
}
/*
* RFC1122: OK. Passes ICMP errors back to application, as per
* 4.1.3.3.
*/
if (!inet_sock->recverr) {
if ((family == AF_INET && !inet_sock->recverr) ||
(family == AF_INET6 && !inet6_sk(sk)->recverr)) {
if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out;
} else {
ip_icmp_error(sk, skb, err, 0 /* no remote port */,
info, (u8 *)icmph);
if (family == AF_INET) {
ip_icmp_error(sk, skb, err, 0 /* no remote port */,
info, (u8 *)icmph);
#if IS_ENABLED(CONFIG_IPV6)
} else if (family == AF_INET6) {
pingv6_ops.ipv6_icmp_error(sk, skb, err, 0,
info, (u8 *)icmph);
#endif
}
}
sk->sk_err = err;
sk->sk_error_report(sk);
out:
sock_put(sk);
}
EXPORT_SYMBOL_GPL(ping_err);
/*
* Copy and checksum an ICMP Echo packet from user space into a buffer.
* Copy and checksum an ICMP Echo packet from user space into a buffer
* starting from the payload.
*/
struct pingfakehdr {
struct icmphdr icmph;
struct iovec *iov;
__wsum wcheck;
};
static int ping_getfrag(void *from, char *to,
int offset, int fraglen, int odd, struct sk_buff *skb)
int ping_getfrag(void *from, char *to,
int offset, int fraglen, int odd, struct sk_buff *skb)
{
struct pingfakehdr *pfh = (struct pingfakehdr *)from;
@ -425,20 +595,33 @@ static int ping_getfrag(void *from, char *to,
pfh->iov, 0, fraglen - sizeof(struct icmphdr),
&pfh->wcheck))
return -EFAULT;
return 0;
} else if (offset < sizeof(struct icmphdr)) {
BUG();
} else {
if (csum_partial_copy_fromiovecend
(to, pfh->iov, offset - sizeof(struct icmphdr),
fraglen, &pfh->wcheck))
return -EFAULT;
}
if (offset < sizeof(struct icmphdr))
BUG();
if (csum_partial_copy_fromiovecend
(to, pfh->iov, offset - sizeof(struct icmphdr),
fraglen, &pfh->wcheck))
return -EFAULT;
#if IS_ENABLED(CONFIG_IPV6)
/* For IPv6, checksum each skb as we go along, as expected by
* icmpv6_push_pending_frames. For IPv4, accumulate the checksum in
* wcheck, it will be finalized in ping_v4_push_pending_frames.
*/
if (pfh->family == AF_INET6) {
skb->csum = pfh->wcheck;
skb->ip_summed = CHECKSUM_NONE;
pfh->wcheck = 0;
}
#endif
return 0;
}
EXPORT_SYMBOL_GPL(ping_getfrag);
static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
struct flowi4 *fl4)
static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
struct flowi4 *fl4)
{
struct sk_buff *skb = skb_peek(&sk->sk_write_queue);
@ -450,24 +633,9 @@ static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
return ip_push_pending_frames(sk, fl4);
}
static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len)
{
struct net *net = sock_net(sk);
struct flowi4 fl4;
struct inet_sock *inet = inet_sk(sk);
struct ipcm_cookie ipc;
struct icmphdr user_icmph;
struct pingfakehdr pfh;
struct rtable *rt = NULL;
struct ip_options_data opt_copy;
int free = 0;
__be32 saddr, daddr, faddr;
u8 tos;
int err;
pr_debug("ping_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
void *user_icmph, size_t icmph_len) {
u8 type, code;
if (len > 0xFFFF)
return -EMSGSIZE;
@ -482,15 +650,53 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
/*
* Fetch the ICMP header provided by the userland.
* iovec is modified!
* iovec is modified! The ICMP header is consumed.
*/
if (memcpy_fromiovec((u8 *)&user_icmph, msg->msg_iov,
sizeof(struct icmphdr)))
if (memcpy_fromiovec(user_icmph, msg->msg_iov, icmph_len))
return -EFAULT;
if (!ping_supported(user_icmph.type, user_icmph.code))
if (family == AF_INET) {
type = ((struct icmphdr *) user_icmph)->type;
code = ((struct icmphdr *) user_icmph)->code;
#if IS_ENABLED(CONFIG_IPV6)
} else if (family == AF_INET6) {
type = ((struct icmp6hdr *) user_icmph)->icmp6_type;
code = ((struct icmp6hdr *) user_icmph)->icmp6_code;
#endif
} else {
BUG();
}
if (!ping_supported(family, type, code))
return -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(ping_common_sendmsg);
int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len)
{
struct net *net = sock_net(sk);
struct flowi4 fl4;
struct inet_sock *inet = inet_sk(sk);
struct ipcm_cookie ipc;
struct icmphdr user_icmph;
struct pingfakehdr pfh;
struct rtable *rt = NULL;
struct ip_options_data opt_copy;
int free = 0;
__be32 saddr, daddr, faddr;
u8 tos;
int err;
pr_debug("ping_v4_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
err = ping_common_sendmsg(AF_INET, msg, len, &user_icmph,
sizeof(user_icmph));
if (err)
return err;
/*
* Get and verify the address.
*/
@ -595,13 +801,14 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence;
pfh.iov = msg->msg_iov;
pfh.wcheck = 0;
pfh.family = AF_INET;
err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len,
0, &ipc, &rt, msg->msg_flags);
if (err)
ip_flush_pending_frames(sk);
else
err = ping_push_pending_frames(sk, &pfh, &fl4);
err = ping_v4_push_pending_frames(sk, &pfh, &fl4);
release_sock(sk);
out:
@ -622,11 +829,13 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
goto out;
}
static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int noblock, int flags, int *addr_len)
int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int noblock, int flags, int *addr_len)
{
struct inet_sock *isk = inet_sk(sk);
struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
int family = sk->sk_family;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct sk_buff *skb;
int copied, err;
@ -636,11 +845,22 @@ static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (flags & MSG_OOB)
goto out;
if (addr_len)
*addr_len = sizeof(*sin);
if (addr_len) {
if (family == AF_INET)
*addr_len = sizeof(*sin);
else if (family == AF_INET6 && addr_len)
*addr_len = sizeof(*sin6);
}
if (flags & MSG_ERRQUEUE)
return ip_recv_error(sk, msg, len);
if (flags & MSG_ERRQUEUE) {
if (family == AF_INET) {
return ip_recv_error(sk, msg, len);
#if IS_ENABLED(CONFIG_IPV6)
} else if (family == AF_INET6) {
return pingv6_ops.ipv6_recv_error(sk, msg, len);
#endif
}
}
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
@ -659,15 +879,44 @@ static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
sock_recv_timestamp(msg, sk, skb);
/* Copy the address. */
if (sin) {
sin->sin_family = AF_INET;
sin->sin_port = 0 /* skb->h.uh->source */;
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
/* Copy the address and add cmsg data. */
if (family == AF_INET) {
sin = (struct sockaddr_in *) msg->msg_name;
if (sin) {
sin->sin_family = AF_INET;
sin->sin_port = 0 /* skb->h.uh->source */;
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
}
if (isk->cmsg_flags)
ip_cmsg_recv(msg, skb);
#if IS_ENABLED(CONFIG_IPV6)
} else if (family == AF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6hdr *ip6 = ipv6_hdr(skb);
sin6 = (struct sockaddr_in6 *) msg->msg_name;
if (sin6) {
sin6->sin6_family = AF_INET6;
sin6->sin6_port = 0;
sin6->sin6_addr = ip6->saddr;
sin6->sin6_flowinfo = 0;
if (np->sndflow)
sin6->sin6_flowinfo = ip6_flowinfo(ip6);
sin6->sin6_scope_id =
ipv6_iface_scope_id(&sin6->sin6_addr,
IP6CB(skb)->iif);
}
if (inet6_sk(sk)->rxopt.all)
pingv6_ops.ip6_datagram_recv_ctl(sk, msg, skb);
#endif
} else {
BUG();
}
if (isk->cmsg_flags)
ip_cmsg_recv(msg, skb);
err = copied;
done:
@ -676,8 +925,9 @@ static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
pr_debug("ping_recvmsg -> %d\n", err);
return err;
}
EXPORT_SYMBOL_GPL(ping_recvmsg);
static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n",
inet_sk(sk), inet_sk(sk)->inet_num, skb);
@ -688,6 +938,7 @@ static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
return 0;
}
EXPORT_SYMBOL_GPL(ping_queue_rcv_skb);
/*
@ -698,10 +949,7 @@ void ping_rcv(struct sk_buff *skb)
{
struct sock *sk;
struct net *net = dev_net(skb->dev);
struct iphdr *iph = ip_hdr(skb);
struct icmphdr *icmph = icmp_hdr(skb);
__be32 saddr = iph->saddr;
__be32 daddr = iph->daddr;
/* We assume the packet has already been checked by icmp_rcv */
@ -711,8 +959,7 @@ void ping_rcv(struct sk_buff *skb)
/* Push ICMP header back */
skb_push(skb, skb->data - (u8 *)icmph);
sk = ping_v4_lookup(net, saddr, daddr, ntohs(icmph->un.echo.id),
skb->dev->ifindex);
sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
if (sk != NULL) {
pr_debug("rcv on socket %p\n", sk);
ping_queue_rcv_skb(sk, skb_get(skb));
@ -723,6 +970,7 @@ void ping_rcv(struct sk_buff *skb)
/* We're called from icmp_rcv(). kfree_skb() is done there. */
}
EXPORT_SYMBOL_GPL(ping_rcv);
struct proto ping_prot = {
.name = "PING",
@ -733,14 +981,14 @@ struct proto ping_prot = {
.disconnect = udp_disconnect,
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
.sendmsg = ping_sendmsg,
.sendmsg = ping_v4_sendmsg,
.recvmsg = ping_recvmsg,
.bind = ping_bind,
.backlog_rcv = ping_queue_rcv_skb,
.release_cb = ip4_datagram_release_cb,
.hash = ping_v4_hash,
.unhash = ping_v4_unhash,
.get_port = ping_v4_get_port,
.hash = ping_hash,
.unhash = ping_unhash,
.get_port = ping_get_port,
.obj_size = sizeof(struct inet_sock),
};
EXPORT_SYMBOL(ping_prot);

View File

@ -135,6 +135,21 @@ static int ipv4_ping_group_range(ctl_table *table, int write,
return ret;
}
/* Validate changes from /proc interface. */
static int proc_tcp_default_init_rwnd(ctl_table *ctl, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
int old_value = *(int *)ctl->data;
int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
int new_value = *(int *)ctl->data;
if (write && ret == 0 && (new_value < 3 || new_value > 100))
*(int *)ctl->data = old_value;
return ret;
}
static int proc_tcp_congestion_control(ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
@ -732,7 +747,7 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
{
{
.procname = "tcp_thin_dupack",
.data = &sysctl_tcp_thin_dupack,
.maxlen = sizeof(int),
@ -748,6 +763,13 @@ static struct ctl_table ipv4_table[] = {
.extra1 = &zero,
.extra2 = &four,
},
{
.procname = "tcp_default_init_rwnd",
.data = &sysctl_tcp_default_init_rwnd,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_tcp_default_init_rwnd
},
{
.procname = "udp_mem",
.data = &sysctl_udp_mem,

View File

@ -3471,7 +3471,7 @@ static int tcp_is_local(struct net *net, __be32 addr) {
return rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#if defined(CONFIG_IPV6)
static int tcp_is_local6(struct net *net, struct in6_addr *addr) {
struct rt6_info *rt6 = rt6_lookup(net, addr, addr, 0, 0);
return rt6 && rt6->dst.dev && (rt6->dst.dev->flags & IFF_LOOPBACK);
@ -3528,7 +3528,7 @@ int tcp_nuke_addr(struct net *net, struct sockaddr *addr)
continue;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#if defined(CONFIG_IPV6)
if (family == AF_INET6) {
struct in6_addr *s6;
if (!inet->pinet6)

View File

@ -98,6 +98,7 @@ int sysctl_tcp_thin_dupack __read_mostly;
int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
int sysctl_tcp_early_retrans __read_mostly = 3;
int sysctl_tcp_default_init_rwnd __read_mostly = TCP_DEFAULT_INIT_RCVWND;
#define FLAG_DATA 0x01 /* Incoming frame contained data. */
#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
@ -351,14 +352,14 @@ static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb)
static void tcp_fixup_rcvbuf(struct sock *sk)
{
u32 mss = tcp_sk(sk)->advmss;
u32 icwnd = TCP_DEFAULT_INIT_RCVWND;
u32 icwnd = sysctl_tcp_default_init_rwnd;
int rcvmem;
/* Limit to 10 segments if mss <= 1460,
* or 14600/mss segments, with a minimum of two segments.
*/
if (mss > 1460)
icwnd = max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2);
icwnd = max_t(u32, (1460 * icwnd) / mss, 2);
rcvmem = SKB_TRUESIZE(mss + MAX_TCP_HEADER);
while (tcp_win_from_space(rcvmem) < mss)

View File

@ -231,14 +231,13 @@ void tcp_select_initial_window(int __space, __u32 mss,
}
/* Set initial window to a value enough for senders starting with
* initial congestion window of TCP_DEFAULT_INIT_RCVWND. Place
* initial congestion window of sysctl_tcp_default_init_rwnd. Place
* a limit on the initial window when mss is larger than 1460.
*/
if (mss > (1 << *rcv_wscale)) {
int init_cwnd = TCP_DEFAULT_INIT_RCVWND;
int init_cwnd = sysctl_tcp_default_init_rwnd;
if (mss > 1460)
init_cwnd =
max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2);
init_cwnd = max_t(u32, (1460 * init_cwnd) / mss, 2);
/* when initializing use the value from init_rcv_wnd
* rather than the default from above
*/

Some files were not shown because too many files have changed in this diff Show More